堆栈内存将在中断期间用于存储CPU状态?

问题描述 投票:0回答:1

当中断将在基于X86体系结构的64位CPU中发生时,CPU将自动推动一些IRET寄存器值,然后按照堆栈

+-------------------------+
| err. code(if applicable)|
+-------------------------+
| rip                     |
+-------------------------+
| cs                      |
+-------------------------+
| rflags                  |
+-------------------------+
| rsp                     |
+-------------------------+
| ss                      |
+-------------------------+

现在我已经通过follwoing方式定义了CPU状态结构

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)
功能将管理中断服务例程。要按正确顺序在堆栈中创建上述结构以及16个字节对齐,然后调用
isr_handler
函数和构造_start指针放入rdi中,所以当CPU不推动错误代码,但我推出虚拟错误代码时,我已经写下了以下宏。

%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
不幸的是,当我试图通过测试中断时,这个宏无法使用

asm volatile ("int $0x3");

应打印在带错误代码0的中断3中,但显示带有错误代码的中断0。
这显示堆栈内存可能无法正确存储值。
错误中断代码的原因是什么?

full代码

link.

我如何解决此问题,因为它没有显示正确的中断代码。

x86 x86-64 interrupt osdev
1个回答
3
投票
struct

中,宣布的第一个成员处于最低地址。 因此,您将它们逆转。

也是,您对CPU推动的图表不正确。  如果您从页面上向下移动(这与英特尔的手册相反)的低地址读取它,这几乎是正确的,但是错误代码应处于最低地址。
为了与您的ASM代码保持一致,声明的声明应该看起来像:

struct registers

通过方式,这里是不必要的,因为所有成员的大小都是相同的(8个字节),并且结构应始终与8个字节保持一致。 编译器不会在这样的结构中插入填充物; ABI禁止它。

	

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.