Search code examples
assemblyx86gdbstackinterrupt

Unexpected jump from an x86 interrupt handler


I am making my custom 8x86 64 bit OS, and I have some problem for an interrupt handler.

When I added interrupt handlers for common exceptions and interrupts, I enabled interrupt by "sti" instruction.

Then, "General Protection Fault" occurs right after enabling interrupt.

So, I checked GDB.

The stack is

(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

The weird part is 0xfee8. I uses memory below 0x10000 as a stack for the 32 bit protected mode. Now, the system is in 64 bit mode, so the value is empty as "00 00".

So, I checked the frame 2, _kISRTimer.

The saved rip of 0xfee8 is 0x202e30. It is "iretq" instruction of _kISRTimer.

here is assembly code.

; #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    $0x10,%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    $0x20,%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  

I think there is no point to jump 0xfee8.

I also tried to remove the interrupt handler for timer. However, "GPF" occurs at other interrupt handler. The other interrupt handler is the same as _kISRTimer, but the call function is different.

Do you know why GPF occurs from the code? Or, the jump is not from code? Please let me know why this problem happens. Thank you.


Solution

  • The iretq instruction, or return from interrupt handler to a 64-bit address, expects the return address and the flags to be on the top of the stack, and produces a general protection fault if the return address is not valid (for example, because it points to a no-execute memory page). Therefore, you should inspect the values on the stack when your handler gets called, the calling code, and the CS selector. If any of these have changed, your stack might contain garbage. Your comment about “memory below 0x10000 as a stack for the 32 bit protected mode” suggests that one or both of these might be the case.