中断三重故障

Triple fault on interrupts

我是新手,所以如果我错过了一些非常明显的事情,我提前道歉

所以,我试图在 x86 汇编和 C 中制作一个简单的内核。我试图让中断工作。我在汇编中定义了GDT、IDT。

我什至不确定是 GDT 还是 IDT 出了什么问题。问题是,在我真正触发中断之前,一切似乎都很好。

我查看了 OSDev、英特尔手册、James Molloy 的指南和随机博客文章,但我就是想不通。

代码如下:

; interrupts.asm
%macro ISRNOERR 1
isr%1:
    cli
    push byte 0
    push byte %1
    jmp isr_common_stub
isr%1_end:      
%endmacro

%macro ISRERR 1
isr%1:
    cli
    push byte %1
    jmp isr_common_stub
isr%1_end:      
%endmacro

    ISRNOERR 0
    ISRNOERR 1
    ISRNOERR 2
    ISRNOERR 3
    ISRNOERR 4
    ISRNOERR 5
    ISRNOERR 6
    ISRNOERR 7
    ISRERR 8
    ISRNOERR 9
    ISRERR 10
    ISRERR 11
    ISRERR 12
    ISRERR 13
    ISRERR 14
    ISRNOERR 15
    ISRNOERR 16
    ISRNOERR 17
    ISRNOERR 18
    ISRNOERR 19
    ISRNOERR 20
    ISRNOERR 21
    ISRNOERR 22
    ISRNOERR 23
    ISRNOERR 24
    ISRNOERR 25
    ISRNOERR 26
    ISRNOERR 27
    ISRNOERR 28
    ISRNOERR 29
    ISRNOERR 30
    ISRNOERR 31
    ISRNOERR 32

isr_common_stub:
    pusha
    mov ax, ds
    push eax

    mov ax, 0x10 ; Data segment descriptor (gdt.asm)
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    extern handler
    call handler

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

    popa
    add esp, 8
    sti
    iret
; idt.asm
section .text
global _load_idt
_load_idt:
    lidt [idt_info]
    ret

%macro IRQ 1
irq%1:
    dd isr%1
    dw 0x0008
    db 0x00
    db 10101110b
    dd isr%1_end
%endmacro

    %include "interrupts.asm"
    
section .rodata
idt:
    IRQ 0
    IRQ 1
    IRQ 2
    IRQ 3
    IRQ 4
    IRQ 5
    IRQ 6
    IRQ 7
    IRQ 8
    IRQ 9
    IRQ 10
    IRQ 11
    IRQ 12
    IRQ 13
    IRQ 14
    IRQ 15
    IRQ 16
    IRQ 17
    IRQ 18
    IRQ 19
    IRQ 20
    IRQ 21
    IRQ 22
    IRQ 23
    IRQ 24
    IRQ 25
    IRQ 26
    IRQ 27
    IRQ 28
    IRQ 29
    IRQ 30
    IRQ 31
    IRQ 32

idt_info:
    dw idt_info - idt - 1
    dd idt
// lime_main.c
#include <kernel/lime_tty.h>

extern void _load_gdt();  // From assembly
extern void _load_idt();

void lime_main()
{
    lime_tty_init(TtyTextMode);
    lime_tty_put_string("[ LIME ] Welcome to the Lime kernel!\n");
    
    _load_gdt();
    lime_tty_put_string("[ LIME ] Loaded GDT successfully!\n");

    _load_idt();
    lime_tty_put_string("[ LIME ] Loaded IDT successfully!\n");

    asm ("int [=12=]x03");  // It's not crashing if I remove this 
}
; gdt.asm
section .data
    ALIGN 4

section .text
global _load_gdt
_load_gdt:
    cli
    lgdt [gdt_desc]
    jmp 0x08:gdt_flush

gdt_flush:
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    ret


section .rodata
gdt:
gdt_null:
    dd 0h
    dd 0h
    
gdt_code:
    dw 0FFFFh
    dw 00000h
    db 00h
    db 10011010b
    db 11001111b
    db 0
gdt_data:
    dw 0FFFFh
    dw 00000h
    db 00h
    db 10010010b
    db 11001111b
    db 0

gdt_desc:
    dw gdt_desc - gdt - 1
    dd gdt

我同时在@MichaelPetch 的帮助下修复了它。基本上,正如他试图告诉我的那样,问题是我为 IDT 中的值定义了错误的大小。我正在为高位和低位定义双字 (dd),但我必须定义 16 位字 (dw)。

由于重定位问题,如果没有链接器脚本之类的东西,我无法真正静态地定义它。我试图避免这种情况,所以我最终采用了动态方法,我在 C 中做到了。

没有太多需要解释的地方,有很多我错过(或误解)的资源。

如果你像我一样是初学者,什么都不懂,我的建议是休息一下,然后带着新鲜的心态回来。 OSDev Wiki 将为您提供很多帮助(论坛也是)。