来自 x86 中断处理程序的意外跳转

Unexpected jump from an x86 interrupt handler

我正在制作我的自定义 8x86 64 位OS,但我遇到了一些中断处理程序问题。

当我为常见的异常和中断添加中断处理程序时,我通过 "sti" 指令启用了中断。

然后,"General Protection Fault"在启用中断后立即发生。

所以,我检查了 GDB。

堆栈是

(gdb) bt
#0  kISR::kISRGeneralProtection () at /home/xaliver/WorkSpace/kOdin/kernel64/./ISR.cpp:70
#1  0x000000000000fee8 in ?? ()
#2  0x0000000000202e30 in _kISRTimer ()
Backtrace stopped: frame did not save the PC

奇怪的部分是0xfee8。我使用 0x10000 以下的内存作为 32 位保护模式的堆栈。现在,系统处于 64 位模式,因此值为空,如“00 00”。

所以,我检查了第 2 帧,_kISRTimer。

0xfee8保存的rip为0x202e30。是_kISRTimer的"iretq"指令。

这里是汇编代码。

; #32, Timer ISR
_kISRTimer:
    KSAVECONTEXT                    ; Store the context and change selector to
  202dd3:   55                      push   %rbp
  202dd4:   48 89 e5                mov    %rsp,%rbp
  202dd7:   50                      push   %rax
  202dd8:   53                      push   %rbx
  202dd9:   51                      push   %rcx
  202dda:   52                      push   %rdx
  202ddb:   57                      push   %rdi
  202ddc:   56                      push   %rsi
  202ddd:   41 50                   push   %r8
  202ddf:   41 51                   push   %r9
  202de1:   41 52                   push   %r10
  202de3:   41 53                   push   %r11
  202de5:   41 54                   push   %r12
  202de7:   41 55                   push   %r13
  202de9:   41 56                   push   %r14
  202deb:   41 57                   push   %r15
  202ded:   66 8c d8                mov    %ds,%ax
  202df0:   50                      push   %rax
  202df1:   66 8c c0                mov    %es,%ax
  202df4:   50                      push   %rax
  202df5:   0f a0                   pushq  %fs
  202df7:   0f a8                   pushq  %gs
  202df9:   66 b8 10 00             mov    [=11=]x10,%ax
  202dfd:   8e d8                   mov    %eax,%ds
  202dff:   8e c0                   mov    %eax,%es
  202e01:   8e e8                   mov    %eax,%gs
  202e03:   8e e0                   mov    %eax,%fs
                                    ; kernel data descriptor

    ; Insert interrupt number to the hander and call the handler
    mov rdi, 32
  202e05:   bf 20 00 00 00          mov    [=11=]x20,%edi
    call _kCommonInterruptHandler
  202e0a:   e8 75 e3 ff ff          callq  201184 <_kCommonInterruptHandler>

    KLOADCONTEXT                    ; Restore the context
  202e0f:   0f a9                   popq   %gs
  202e11:   0f a1                   popq   %fs
  202e13:   58                      pop    %rax
  202e14:   8e c0                   mov    %eax,%es
  202e16:   58                      pop    %rax
  202e17:   8e d8                   mov    %eax,%ds
  202e19:   41 5f                   pop    %r15
  202e1b:   41 5e                   pop    %r14
  202e1d:   41 5d                   pop    %r13
  202e1f:   41 5c                   pop    %r12
  202e21:   41 5b                   pop    %r11
  202e23:   41 5a                   pop    %r10
  202e25:   41 59                   pop    %r9
  202e27:   41 58                   pop    %r8
  202e29:   5e                      pop    %rsi
  202e2a:   5f                      pop    %rdi
  202e2b:   5a                      pop    %rdx
  202e2c:   59                      pop    %rcx
  202e2d:   5b                      pop    %rbx
  202e2e:   58                      pop    %rax
  202e2f:   5d                      pop    %rbp
    iretq                           ; Return the event point after interrupt
  202e30:   48 cf                   iretq  

我认为跳0xfee8没有意义。

我还尝试删除定时器的中断处理程序。但是,"GPF" 出现在其他中断处理程序中。其他中断处理程序与_kISRTimer相同,只是调用函数不同

从代码中知道为什么会出现GPF吗? 或者,跳转不是来自代码? 请让我知道为什么会出现这个问题。 谢谢。

The iretq instruction 或 return 从中断处理程序到 64 位地址,期望 return 地址和标志位于堆栈顶部,并产生一个如果 return 地址无效(例如,因为它指向一个不执行的内存页面),则一般保护错误。因此,当您的处理程序被调用时,您应该检查堆栈上的值、调用代码和 CS 选择器。如果其中任何一个发生了变化,您的堆栈可能包含垃圾。您对“0x10000 以下的内存作为 32 位保护模式的堆栈”的评论表明,其中一种或两种情况都可能是这种情况。