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
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).