1

我的通用 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 映射为使用 0 特权级数据和代码描述符(和空描述符)覆盖整个 4G 地址空间。任何帮助表示赞赏。

4

1 回答 1

2

开始了...

a) 在宏观上,做事cli是愚蠢的。使用“中断门”(而不是“陷阱门”),CPU 将自动为您禁用 IRQ,而不会有竞争条件的风险(例如,在中断处理程序启动后但在完成执行之前的 IRQ cli)。

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

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

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

e) 您没有向 ISR 传递任何内容。大多数异常处理程序需要知道异常发生时通用寄存器等的状态。

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

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

h) 不同的异常有不同的要求,所以有一个“通用异常处理程序”是愚蠢的。最好为不同的异常设置不同的异常处理程序,这是 IDT 提供的(在这种情况下,将“中断号”推入堆栈是没有意义的)。

j) IRQ 不同于异常。对于 IRQ,中断处理程序永远不需要无意义的错误代码(或中断代码的状态)。请注意,在程序集存根中处理/隐藏 PIC 芯片的“虚假 IRQ”很好,这意味着检查 PIC 的“服务中寄存器”以区分真实 IRQ7 和虚假 IRQ7 之间的区别,以及真实 IRQ15 之间的区别和一个虚假的 IRQ15。对于虚假的 IRQ15,您需要将 EOI 发送给 master 而不是从机,对于虚假的 IRQ7,您根本不能发送任何 EOI。如果您使用的是 IO APIC,那么就没有明智的方法来禁用/屏蔽 PIC 芯片的虚假 IRQ,因此您仍然需要两个 PIC 芯片的虚假 IRQ 处理程序(除了 APIC 自己的虚假中断的处理程序)。

于 2014-08-28T07:52:29.490 回答