What is the process of setting up interrupts for protected mode?
This link says one should:
- Make space for the interrupt descriptor table
- Tell the CPU where that space is (see GDT Tutorial: lidt works the very same way as lgdt)
- Tell the PIC that you no longer want to use the BIOS defaults (see Programming the PIC chips)
- Write a couple of ISR handlers (see Interrupt Service Routines) for both IRQs and exceptions
- Put the addresses of the ISR handlers in the appropriate descriptors
- Enable all supported interrupts in the IRQ mask (of the PIC)
The third step makes no sense to me (I looked at this link but there wasn't anything about telling the PIC anything) so I ignored it and completed the next two steps, only to be clueless once again when I reached the final step. However, from my understanding of interrupts, both of the steps I didn't understand relate to hardware interrupts from the PIC controller and shouldn't affect the interrupts raised by the PIT on IRQ 0. I therefore ignored this step as well.
When I ran my code it compiled fine and even ran in a virtual machine, but the interrupt seemed to fire only once. I then realised that I wasn't sending EOI to the PIC, preventing it from raising any more interrupts. However, adding mov al, 0x20
and out 0x20, al
just before the iret
instruction makes the virtual machine crash.
Here's my IDT:
; idt
idt_start :
dw 0x00 ; The interrupt handler is located at absolute address 0x00
dw CODE_SEG ; CODE_SEG points to the GDT entry for code
db 0x0 ; The unused byte
db 0b11101001 ; 1110 Defines a 32 bit Interrupt gate, 0 is mandatory, privilege level = 0 (0b00), the last bit is one so that the CPU knows that the interrupt will be used
dw 0x00 ; The higher part of the offset (0x00) is 0x00
idt_end:
idt_descriptor :
dw idt_end - idt_start - 1 ; Size of our idt, always one less than the actual size
dd idt_start ; Start address of our idt
Here's my interrupt handler (located at absolute location 0x00 in memory):
ISR_0:
push eax
add [0x300], byte
mov al, 0x20
out 0x20, al
pop eax
iret
times 512-($-$$) db 0
This is the code I use to enter protected mode and load the GDT and IDT into memory:
[bits 16]
switch_to_pm:
cli
lgdt [gdt_descriptor]
lidt [idt_descriptor]
mov eax, cr0
or eax, 1
mov cr0,eax
jmp CODE_SEG:init_pm
[bits 32]
init_pm :
mov ax, DATA_SEG
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, 0x90000
mov esp, ebp
sti
call BEGIN_PM
My main function (that checks the value of 0x300) is as follows:
void main() {
char iii[15];
int * aa = (int *)0x300;
for (;;)
{
setCursor(0, 0);
print(itoab(*aa, iii));
}
}
By the way, I have verified using a memory dump that everything is loaded at the correct address and everything is exactly where it is expected. For example, 0x300 is a free part of memory used simply to simplify my code.
int 0x08
? Why do the IRQ lines overlap? – DividedByZero