Interrupts seem to invalidate stack

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
hoiblij
Posts: 4
Joined: Sat Aug 13, 2022 4:57 am

Interrupts seem to invalidate stack

Post by hoiblij »

I have an issue where my interrupt code seems to be corrupting the stack, which in very specific cases causes a page fault.

This is such a case:

Code: Select all

 
0xffffff8000011fce: mov    -0x8(%rbp),%rax
0xffffff8000011fd2: movb  $0x0,(%rax)
When the return address is the first instruction a page fault is thrown at the second instruction which complains that the address 0x0 is unmapped. These page faults are thrown whenever this pattern occurs in the interrupted code.
My assembly interrupt code:

Code: Select all

mouse_asm:
    cli
    sub rsp, 8

    push rax
    push rbx
    push rcx
    push rdx
    push rsp
    push rbp
    push rsi
    push rdi
    push r8
    push r9
    push r10
    push r11
    push r12
    push r13
    push r14
    push r15

    mov ax, ds
    push rax

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    call _ZN11MouseDriver15HandleInterruptE9int_frame

    pop rax
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    pop r15
    pop r14
    pop r13
    pop r12
    pop r11
    pop r10
    pop r9
    pop r8
    pop rdi
    pop rsi
    pop rbp
    pop rsp
    pop rdx
    pop rcx
    pop rbx
    pop rax

    add rsp, 8

    sti
    iretq
(I know not all these registers have to be stored I just did to make sure. Also, I normally use a common stub which is why the stack pointer is incremented by 8 in the beginning.)

And the called C++ code:

Code: Select all

void MouseDriver::HandleInterrupt(int_frame frame){
    while(IO::In(0x64) & 0x1) IO::In(0x60);
    IO::Out(PIC1_COMMAND_PORT, 0x20);
    IO::Out(PIC2_COMMAND_PORT, 0x20);
    return;
}
The page faults also occurs for keyboard and PIT interrupts, I'm just using the mouse for convenience's sake. I can also post the disassembled interrupted code if necessary.

I have been stuck on this for a while now so it would be really awesome if this issue were finally resolved, thanks in advance.
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Interrupts seem to invalidate stack

Post by Octocontrabass »

You're following a buggy tutorial and you've run into one of the bugs. When you pass a struct by value, the contents of the struct may be overwritten by the function. You need to pass a pointer (or perhaps a reference?) to the struct in order to preserve its contents.

Also, you shouldn't push/pop RSP.

Also, your handler shouldn't start with CLI. If you want interrupts disabled, use an interrupt gate.

Also, your handler shouldn't have STI before IRETQ. IRETQ will update RFLAGS.IF according to the value on the stack.

Also, you need CLD before you call any C++ functions inside an interrupt handler.

Also, you need to ensure your stack is correctly aligned before you call any C++ functions. (The CPU automatically aligns the stack before pushing the return address and return stack pointer, so you can align the stack by making sure you push the right number of values. It might already be correctly aligned - I haven't checked.)
hoiblij
Posts: 4
Joined: Sat Aug 13, 2022 4:57 am

Re: Interrupts seem to invalidate stack

Post by hoiblij »

I'm not following specifically his tutorial, but bad code seems to be very widespread online if you can't use the struct itself as an argument.

I have changed the things you commented on however, and my assembly code now looks like this:
mouse_asm:
cli
cld

PUSHALL

mov ax, ds
push rax

mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

mov rdi, rsp
mov r12, rsp
and rsp, -16

call _ZN11MouseDriver15HandleInterruptEP9int_frame

mov rsp, r12

pop rax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

POPALL

iretq
(PUSHALL and POPALL are macros that push and pop the registers, not including rsp)

I still get the same issue I got before however, even now that I'm passing a pointer to the struct. Maybe noteworthy: I used to have the same issue when using GCC's interrupt attribute. It's why I switched to assembly stubs in the first place, but that hasn't changed anything. Could that mean the error isn't in my assembly code?
User avatar
Demindiro
Member
Member
Posts: 96
Joined: Fri Jun 11, 2021 6:02 am
Libera.chat IRC: demindiro
Location: Belgium
Contact:

Re: Interrupts seem to invalidate stack

Post by Demindiro »

hoiblij wrote:

Code: Select all

    pop rax
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
I keep seeing this so I decided to take a look at the tutorial. AFAICT the tutorial only deals with protected (32-bit) mode, not long (64-bit) mode where setting the segment registers is useless.

The exceptions are SS and CS, which are saved and restored by the interrupt and iretq automatically anyways.

Please read the Features section on the X86-64 page.

Also, a minor nit but you don't need to save all registers if you don't modify them directly and follow the calling conventions.

(FWIW, I checked Linux' source and they don't save segment registers in long mode either.)
My OS is Norost B (website, Github, sourcehut)
My filesystem is NRFS (Github, sourcehut)
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Interrupts seem to invalidate stack

Post by Gigasoft »

Never copy code you found online, period. You have no way to know if the author knows what he's doing.

This anti-pattern is beyond stupid, and whenever encountered should be an indication to stop wasting your time and close the page:

Code: Select all

push ds
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax ; just in case I feel like decorating my code with random FS prefixes
mov gs, ax ; or GS prefixes, for variety
; do stuff
pop eax
mov ds, ax
mov es, ax ; one segment should be enough for everyone
mov fs, ax ; I assume no one was using these for anything important
mov gs, ax ; God knows what these registers do anyway
This is what happens when code is copied and pasted on the internet indiscriminately. Completely ridiculous and pointless.
hoiblij
Posts: 4
Joined: Sat Aug 13, 2022 4:57 am

Re: Interrupts seem to invalidate stack

Post by hoiblij »

I was aware that (re)storing the segment registers was likely useless, I just did to be sure. I have removed it from my code, but it is still not working as expected.
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Interrupts seem to invalidate stack

Post by Octocontrabass »

I don't see anything else in your interrupt code that might corrupt the stack. Are you sure the problem is stack corruption and not red zone corruption?
hoiblij
Posts: 4
Joined: Sat Aug 13, 2022 4:57 am

Re: Interrupts seem to invalidate stack

Post by hoiblij »

Wow, I had never heard about the red zone at all before. Perhaps it was mentioned on the wiki but I simply missed it. I added the -mno-red-zone flag and the issue is gone now, what a stupid thing to miss. Thanks a ton for all the help tho!
Post Reply