Reputation: 1300
I am developing an operating system. My GDT has three entries. I've created the IDT and implemented ISR and IQR. I also remapped the PIC. The problem is that after every interrupt handler follows a General Protection Fault. This is the assembly code which calls the interrupts:
.extern fault_handler
isr_common_stub:
pusha
push %ds
push %es
push %fs
push %gs
movw $0x10,%ax # Load the Kernel Data Segment descriptor!
movw %ax,%ds
movw %ax,%es
movw %ax,%fs
movw %ax,%gs
movl %esp,%eax # Push us the stack
pushl %eax
movl $fault_handler, %eax
call *%eax # A special call, preserves the 'eip' register
popl %eax
popl %gs # I discovered that the error occures on this line
popl %fs
popl %es
popl %ds
popa
addl $8,%esp # Cleans up the pushed error code and pushed ISR number
iret # pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP!
.extern irq_handler
irq_common_stub:
pusha
push %ds
push %es
push %fs
push %gs
movw $0x10,%ax
movw %ax,%ds
movw %ax,%es
movw %ax,%fs
movw %ax,%gs
movl %esp,%eax
pushl %eax
movl $irq_handler, %eax
call *%eax
popl %eax
popl %gs # I discovered that the error occures on this line
popl %fs
popl %es
popl %ds
popa
addl $8,%esp
iret
I found out something strange. When I run the operating system with QEMU as an .iso
disk image, it does not work. But when I called it as a kernel by specifying the -kernel
option, it worked as expected. I decided to change the code below:
popl %gs # I discovered that the error occures on this line
popl %fs
popl %es
popl %ds
I changed the code above to this:
pop %gs
pop %fs
pop %es
pop %ds
I am still getting the GPF. Am I doing something wrong? Any suggestions?
Upvotes: 1
Views: 648
Reputation: 39166
addl $8,%esp # Cleans up the pushed error code and pushed ISR number
Your isr_common_stub routine thinks that an error code will always be there. Some faults don't push an error code! Only faults related to interrupt numbers 10, 11, 12, 13, 14, and 17 use an error code.
From http://www.brokenthorn.com/Resources/OSDev15.html we learn:
If the handler is going to be executed at a lower privilege level (bits 42-45 of descriptor), a stack switch occurs.
The segment selector and stack pointer for the stack to be used by the handler are abtained from the TSS for the currently executing task. The processor pushes the stack segment selector and stack pointer of the interrupt handler on this new stack.The processor saves the current state of EFLAGS,CS, and EIP on the new stack.
If an exception causes an error code to be saved, the error code is pushed on the new stack after EIP.
and also
If the handler is going to be executed at the same privilege level (current privilege level (cpl) is the same as (bits 42-45 of descriptor)
The processor saves the current state of EFLAGS, CS, EIP on the current stack.
If an exception causes an error code to be saved, the error code is pushed on the current stack after EIP
It is very important to know how the stack is pushed when our interrupt handler is called, and what exceptions also push error codes.
Upvotes: 3
Reputation: 11028
If my old memory serves me correctly, the segment registers are 16 bits, and you're trying to do a popl
which pops a 32-bit value... thus that's a problem.
Since you're doing a push %gs
above, you should also do a pop %gs
. Same with the other registers, make sure you pop
them the same way you push
them.
Upvotes: 3