我正在开发一个操作系统。我的GDT有三个条目。我创建了IDT并实现了ISR和IQR。我还重新制作了PIC。问题是每个中断处理程序都遵循一般保护错误。 这是调用中断的汇编代码:
.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
我发现了一些奇怪的东西。当我使用QEMU作为.iso
磁盘映像运行操作系统时,它不起作用。但是当我通过指定-kernel
选项将其称为内核时,它按预期工作。我决定更改以下代码:
popl %gs # I discovered that the error occures on this line
popl %fs
popl %es
popl %ds
我将上面的代码更改为:
pop %gs
pop %fs
pop %es
pop %ds
我还在接受GPF。难道我做错了什么?有什么建议吗?
答案 0 :(得分:3)
如果我的旧内存正确地为我服务,则段寄存器为16位,并且您正在尝试执行弹出32位值的popl
...因此这是一个问题。
由于您正在执行上述push %gs
,因此您还应该执行pop %gs
。与其他寄存器相同,请确保pop
与push
它们相同。
答案 1 :(得分:3)
addl $8,%esp # Cleans up the pushed error code and pushed ISR number
您的 isr_common_stub 例程认为错误代码将始终存在。有些故障不会推送错误代码!只有与中断号10,11,12,13,14和17相关的故障才会使用错误代码。
从http://www.brokenthorn.com/Resources/OSDev15.html我们了解到:
如果处理程序将以较低的权限级别(描述符的第42-45位)执行,则会发生堆栈切换。
处理程序使用的堆栈的段选择器和堆栈指针从TSS获取,用于当前正在执行的任务。处理器在这个新堆栈上推送堆栈段选择器和中断处理程序的堆栈指针。处理器将EFLAGS,CS和EIP的当前状态保存在新堆栈上。
如果异常导致保存错误代码,则在EIP之后将错误代码推送到新堆栈上。
以及
如果处理程序将在相同的权限级别执行(当前权限级别(cpl)与描述符的位42-45相同) 处理器将EFLAGS,CS,EIP的当前状态保存在当前堆栈上 如果异常导致保存错误代码,则在EIP之后将错误代码推送到当前堆栈
了解调用中断处理程序时如何推送堆栈非常重要,以及哪些异常也会推送错误代码。