c - 中断三重故障

标签 c assembly x86 osdev gdt

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

因此,我尝试在 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 $0x03");  // 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 将为您提供很多帮助(论坛也是)。

关于c - 中断三重故障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64879698/

相关文章:

c++ - 计算保存在文本文件中的 2 个纬度和经度之间的距离?

c - 尝试专门使用内部函数时出现段错误 _mm256_storeu_pd()

c++ - 内联 assembly 约束修饰符 = 和 +

assembly - nasm 中的第 16 位和第 32 位

C++ Hook 我自己的程序函数

assembly - 为什么 Ice Lake 没有像 tremont 那样的 MOVDIRx?他们已经有更好的了吗?

c - 如何在 memcpy 之前 malloc 结构数组

c - 非动态加载代码的类似 dlsym 的功能?

assembly - 有什么方法可以触发 RDTSC 的传统模式吗?

c - 如何修改从 C 生成的现有汇编代码