cassemblyx86osdevgdt

Triple fault on interrupts


I'm new to all this, so I apologize in advance if I missed something really obvious

So, I'm trying to make a simple kernel in x86 assembly and C. I was trying to get interrupts working. I am defining the GDT, IDT in assembly.

I'm not even sure what's wrong, the GDT or the IDT. The thing is, everything seems fine until I actually trigger an interrupt.

I checked OSDev, the Intel Manuals, James Molloy's guide, and random blog posts, and I just can't figure this out.

Here's the code:

; 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

Solution

  • I fixed it in the meantime, with the help of @MichaelPetch. Basically, the problem was, as he was trying to tell me, that I was defining wrong sizes for the values in the IDT. I was defining double words (dd) for the higher and lower bits, but I had to define 16-bit words (dw).

    Because of relocation problems, I can't really statically define this without linker scripts and stuff. I tried to avoid this, so I ended up going for a dynamic approach, I did it in C.

    There's not really a lot to explain, there are tons of resources out there that I missed (or misunderstanded).

    If you are like me, a beginner, and don't really understand anything, my advice is to just take a break, and come back with a fresh mind. The OSDev Wiki is going to help you a lot (the forums too).