x86中断服务程序会导致一般性保护错误

时间:2014-08-28 04:48:12

标签: assembly x86 interrupt interrupt-handling gdt

我的常见isr存根定义为:

isr_common_stub:
pusha                    ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax

mov ax, ds               ; Lower 16-bits of eax = ds.
push eax                 ; save the data segment descriptor

mov ax, 0x10  ; load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

call isr_handler
;call saySomething
pop ebx        ; reload the original data segment descriptor
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
;call saySomething
popa                     ; Pops edi,esi,ebp...
;add esp, 8     ; Cleans up the pushed error code and pushed ISR number
;sti
;call saySomething
;iret           ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
ret ;Return to the caller. Iret and interrupt enabling is handled within caller.

从每个中断调用此代码如下:

%macro ISR_NOERRCODE 1
global isr%1
isr%1:
   cli                         ; Disable interrupts firstly.
   push byte 0                 ; Push a dummy error code.
   push byte %1                ; Push the interrupt number.
   jmp isr_common_stub         ; Go to our common handler code.
   sub esp, 2 ;Removes 2 bytes from stack
   ;sti ;Iret enables interrupts again
   iret ;Return from interrupt
%endmacro

此代码适当地调用外部处理方法,但在从外部处理方法返回后导致gpf中断。

此外,我已经将我的gdt映射到覆盖整个4G地址空间,其中包含0个特权级别数据和代码描述符(以及空描述符)。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:2)

我们走了......

a)在宏中,做cli是愚蠢的。使用"中断门" (而不是"陷阱门")并且CPU将自动禁用IRQ而不存在竞争条件的风险(例如,在中断处理程序启动之后但在完成执行cli之前的IRQ)。 / p>

b)在宏中,jmp之后的代码永远不会执行,因此毫无意义。

c)如果你将2个字节压入堆栈,那么你就搞乱了堆栈对齐,并且应该得到你将要获得的性能损失。推两个双字来避免这种情况。

d)CPU为某些异常提供32位错误代码;因此,您的虚拟错误代码也应该是32位。

是的,你没有向ISR传递任何东西。大多数异常处理程序需要在异常发生时知道通用寄存器的状态等。

f)您不能指望ret从中断返回并需要取消注释iret

g)删除所有段寄存器(DS,ES,FS,GS)可能是一个坏主意。操作系统将它们视为常量,您没有理由在从ISR返回之前加载它们,或者必须保存它们然后重新加载。

h)不同的异常有不同的要求,所以有一个常见的异常处理程序"很傻。为不同的异常提供不同的异常处理程序会更好,这就是IDT提供的内容(在这种情况下,没有必要在堆栈上推送"中断号")。

j)IRQ与例外情况不同。对于IRQ,中断处理程序永远不需要无意义的错误代码(或中断代码的状态)。请注意,处理/隐藏PIC芯片"虚假IRQ"在汇编存根中,这意味着检查服务寄存器中的PIC""告诉真正的IRQ7和虚假IRQ7之间的区别,以及真实IRQ15和虚假IRQ15之间的区别。对于虚假IRQ15,您需要将EOI发送给主设备而不是从设备,对于虚假的IRQ7,您根本不能发送任何EOI。如果您正在使用IO APIC,那么没有理智的方法来禁用/屏蔽PIC芯片的虚假IRQ,因此您仍然需要为两个PIC芯片提供伪IRQ处理程序(除了处理器之外) APIC自己的虚假中断)。