How can I resolve stack memory during interrupt?

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
User avatar
gamingjam60
Posts: 19
Joined: Sat Aug 24, 2024 10:06 pm
Libera.chat IRC: gamingjam60
Location: India
GitHub: https://github.com/baponkar
Contact:

How can I resolve stack memory during interrupt?

Post by gamingjam60 »

When interrupt will happen in x86 architecture based 64 bit cpu the cpu will push automatically some iret registers values following way into the stack

Code: Select all

+-------------------------+
| err. code(if applicable)|
+-------------------------+
| rip                     |
+-------------------------+
| cs                      |
+-------------------------+
| rflags                  |
+-------------------------+
| rsp                     |
+-------------------------+
| ss                      |
+-------------------------+
Now I have defined cpu state structure by follwoing way

Code: Select all

struct registers { // Total 26*8 = 208 bytes which is 16 bytes aligned
    // CPU state
    uint64_t iret_rip;      // Offset 8*0
    uint64_t iret_cs;       // Offset 8*1
    uint64_t iret_rflags;   // Offset 8*2
    uint64_t iret_rsp;      // Offset 8*3
    uint64_t iret_ss;       // Offset 8*4

    uint64_t err_code;      // Offset 8*5
    uint64_t int_no;        // Offset 8*6

    // General purpose registers
    uint64_t r15;           // Offset 8*7
    uint64_t r14;           // Offset 8*8
    uint64_t r13;           // Offset 8*9
    uint64_t r12;           // Offset 8*10
    uint64_t r11;           // Offset 8*11
    uint64_t r10;           // Offset 8*12
    uint64_t r9;           // Offset 8*13
    uint64_t r8;            // Offset 8*14
    uint64_t rsi;            // Offset 8*15
    uint64_t rdi;           // Offset 8*16
    uint64_t rbp;           // Offset 8*17
    uint64_t rdx;           // Offset 8*18
    uint64_t rcx;           // Offset 8*19
    uint64_t rbx;           // Offset 8*20
    uint64_t rax;           // Offset 8*21

    // Segment registers
    uint64_t ds;            // Offset 8*22
    uint64_t es;            // Offset 8*23
    uint64_t fs;            // Offset 8*24
    uint64_t gs;            // Offset 8*25
} __attribute__((packed));
typedef struct registers registers_t;
A
void isr_handler(registers_t *regs)
function will manage interrupt service routine. To create above structure in stack by proper order along with 16 byte align and then call isr_handler function and struction_start pointer placed into rdi so I have written the below macro when cpu do not push a error code but I push a dummy error code.

Code: Select all

%macro ISR_NOERRCODE 1
    [global isr%1]
    isr%1:
        cli;

        push 0          ; Dummy error code
        push %1         ; Interrupt number
        
        push r15        ; Save general-purpose registers in reverse order (to match RESTORE_REGISTERS)
        push r14
        push r13
        push r12
        push r11
        push r10
        push r9
        push r8
        push rsi
        push rdi
        push rbp
        push rdx
        push rcx
        push rbx
        push rax
        mov ax, ds      ; Save segment registers
        push rax
        mov ax, es
        push rax
        push fs
        push gs
        
        mov rdi, rsp         ; Pass pointer to the `registers_t` structure
        cld                  ; Clear the direction flag
        call isr_handler     ; Call the interrupt handler

        pop gs              ; Restore segment registers
        pop fs
        pop rax
        mov es, ax
        pop rax
        mov ds, ax
        pop rax             ; Restore general-purpose registers
        pop rbx
        pop rcx
        pop rdx
        pop rbp
        pop rdi
        pop rsi
        pop r8
        pop r9
        pop r10
        pop r11
        pop r12
        pop r13
        pop r14
        pop r15
        add rsp, 16         ; Clean up interrupt no and dummy error code

        iretq               ; Return from the interrupt using IRETQ (iret values remain intact)
%endmacro
Bu unfortunately this macro is not working when I am trying to test interrupt by

Code: Select all

asm volatile ("int $0x3");
which should print received interrupt 3 with error code 0 but showing received interrupt 0 with error code.
This is showing stack memory may not properly store values.
What is the reason of wrong interrupt code?

Full code https://github.com/baponkar/KeblaOS
Last edited by gamingjam60 on Sun Jan 26, 2025 4:45 am, edited 1 time in total.
User avatar
iansjack
Member
Member
Posts: 4733
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: How can I resolve stack memory during interrupt?

Post by iansjack »

You can gain an insight into such problems by single-stepping through the code in a debugger. Inspection of the stack, and various registers throughout should show you where the error lies.
sebihepp
Member
Member
Posts: 196
Joined: Tue Aug 26, 2008 11:24 am
GitHub: https://github.com/sebihepp

Re: How can I resolve stack memory during interrupt?

Post by sebihepp »

Hi gamingjam60,

the problem comes from your registers struct and the stack growing downwards. You need to reverse the order of the members of your struct.

The stack grows downwards, so after pushing all the registers, esp is pointing to gs and on the top you will find rip. Your struct is defined the other way around.

Best regards
Sebi
User avatar
gamingjam60
Posts: 19
Joined: Sat Aug 24, 2024 10:06 pm
Libera.chat IRC: gamingjam60
Location: India
GitHub: https://github.com/baponkar
Contact:

Re: How can I resolve stack memory during interrupt?

Post by gamingjam60 »

Yes correct order of registers_t structure would be

Code: Select all

struct registers { // Total 26*8 = 208 bytes, 16 bytes aligned
    // Segment registers
    uint64_t gs;            // Offset 8*0
    uint64_t fs;            // Offset 8*1
    uint64_t es;            // Offset 8*2
    uint64_t ds;            // Offset 8*3

    // General purpose registers
    uint64_t rax;           // Offset 8*4
    uint64_t rbx;           // Offset 8*5
    uint64_t rcx;           // Offset 8*6
    uint64_t rdx;           // Offset 8*7
    uint64_t rbp;           // Offset 8*8
    uint64_t rdi;           // Offset 8*9
    uint64_t rsi;           // Offset 8*10
    uint64_t r8;            // Offset 8*11
    uint64_t r9;            // Offset 8*12
    uint64_t r10;           // Offset 8*13
    uint64_t r11;           // Offset 8*14
    uint64_t r12;           // Offset 8*15
    uint64_t r13;           // Offset 8*16
    uint64_t r14;           // Offset 8*17
    uint64_t r15;           // Offset 8*18

    uint64_t int_no;        // Offset 8*19
    uint64_t err_code;      // Offset 8*20

    // CPU state
    uint64_t iret_rip;      // Offset 8*21
    uint64_t iret_cs;       // Offset 8*22
    uint64_t iret_rflags;   // Offset 8*23
    uint64_t iret_rsp;      // Offset 8*24
    uint64_t iret_ss;       // Offset 8*25
    
} __attribute__((packed));
typedef struct registers registers_t;
Post Reply