x86-64 Kernel crashing on setting up the IDT

3

I am currently trying to create an x86-64 Kernel from scratch (using GRUB Multiboot2 as a bootloader). I set up my GDT just fine, but when setting up my IDT, there seems to be a problem. I isolated the issue to be my call of lidt by hlting before and after most instructions of my code. Here are my C and ASM files that define my IDT:

global irq0
global irq1
global irq2
global irq3
global irq4
global irq5
global irq6
global irq7
global irq8
global irq9
global irq10
global irq11
global irq12
global irq13
global irq14
global irq15
 
global load_idt
global remap_pic
 
global irq0_handler
global irq1_handler
global irq2_handler
global irq3_handler
global irq4_handler
global irq5_handler
global irq6_handler
global irq7_handler
global irq8_handler
global irq9_handler
global irq10_handler
global irq11_handler
global irq12_handler
global irq13_handler
global irq14_handler
global irq15_handler

extern handle_keyboard_in

%macro pushAll 0
    push rax
    push rcx
    push rdx
    push rbx
    push rbp
    push rsi
    push rdi
%endmacro

%macro popAll 0
    pop rdi
    pop rsi
    pop rbp
    pop rbx
    pop rdx
    pop rcx
    pop rax
%endmacro

section .text
bits 64
irq0:
    pushAll

    mov al, 0x20
    out 0x20, al
    popAll
    iret
 
irq1:
    pushAll

    in al, 0x60
    push ax
    call handle_keyboard_in

    mov al, 0x20
    out 0x20, al
    popAll
    iret
 
irq2:
    pushAll

    mov al, 0x20
    out 0x20, al
    popAll
    iret
 
irq3:
    pushAll

    mov al, 0x20
    out 0x20, al
    popAll
    iret
 
irq4:
    pushAll

    mov al, 0x20
    out 0x20, al
    popAll
    iret
 
irq5:
    pushAll

    mov al, 0x20
    out 0x20, al
    popAll
    iret
 
irq6:
    pushAll

    mov al, 0x20
    out 0x20, al
    popAll
    iret
 
irq7:
    pushAll

    mov al, 0x20
    out 0x20, al
    popAll
    iret
 
irq8:
    pushAll

    mov al, 0x20
    out 0xa0, al
    out 0x20, al
    popAll
    iret
 
irq9:
    pushAll

    mov al, 0x20
    out 0xa0, al
    out 0x20, al
    popAll
    iret
 
irq10:
    pushAll

    mov al, 0x20
    out 0xa0, al
    out 0x20, al
    popAll
    iret
 
irq11:
    pushAll

    mov al, 0x20
    out 0xa0, al
    out 0x20, al
    popAll
    iret
 
irq12:
    pushAll

    mov al, 0x20
    out 0xa0, al
    out 0x20, al
    popAll
    iret
 
irq13:
    pushAll

    mov al, 0x20
    out 0xa0, al
    out 0x20, al
    popAll
    iret
 
irq14:
    pushAll

    mov al, 0x20
    out 0xa0, al
    out 0x20, al
    popAll
    iret
 
irq15:
    pushAll

    mov al, 0x20
    out 0xa0, al
    out 0x20, al
    popAll
    iret
 
load_idt:
    mov edx, [esp + 4]
    lidt [edx]
    ret

remap_pic:
    mov al, 0x11
    out 0x20, al
    out 0xA0, al
    mov al, 0x20
    out 0x21, al
    mov al, 0x40
    out 0xA1, al
    mov al, 0x04
    out 0x21, al
    mov al, 0x02
    out 0xA1, al
    mov al, 0x01
    out 0x21, al
    out 0xA1, al
    mov al, 0x00
    out 0x21, al
    out 0xA1, al
    ret
#include <stdint.h>
#include <stddef.h>

struct IDT_entry{
    unsigned short int offset_lowerbits;
    unsigned short int selector;
    unsigned char zero;
    unsigned char type_attr;
    unsigned short int offset_higherbits;
};
 
struct IDT_entry IDT[256];

void idt_init() {

    extern int load_idt();
    extern int remap_pic();
    extern int irq0();
    extern int irq1();
    extern int irq2();
    extern int irq3();
    extern int irq4();
    extern int irq5();
    extern int irq6();
    extern int irq7();
    extern int irq8();
    extern int irq9();
    extern int irq10();
    extern int irq11();
    extern int irq12();
    extern int irq13();
    extern int irq14();
    extern int irq15();
 
    unsigned long irq0_address;
    unsigned long irq1_address;
    unsigned long irq2_address;
    unsigned long irq3_address;          
    unsigned long irq4_address; 
    unsigned long irq5_address;
    unsigned long irq6_address;
    unsigned long irq7_address;
    unsigned long irq8_address;
    unsigned long irq9_address;          
    unsigned long irq10_address;
    unsigned long irq11_address;
    unsigned long irq12_address;
    unsigned long irq13_address;
    unsigned long irq14_address;          
    unsigned long irq15_address;         
    unsigned long idt_address;
    unsigned long idt_ptr[2];

    remap_pic();
 
    irq0_address = (unsigned long)irq0; 
    IDT[32].offset_lowerbits = irq0_address & 0xffff;
    IDT[32].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[32].zero = 0;
    IDT[32].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[32].offset_higherbits = (irq0_address & 0xffff0000) >> 16;
 
    irq1_address = (unsigned long)irq1; 
    IDT[33].offset_lowerbits = irq1_address & 0xffff;
    IDT[33].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[33].zero = 0;
    IDT[33].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[33].offset_higherbits = (irq1_address & 0xffff0000) >> 16;
 
    irq2_address = (unsigned long)irq2; 
    IDT[34].offset_lowerbits = irq2_address & 0xffff;
    IDT[34].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[34].zero = 0;
    IDT[34].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[34].offset_higherbits = (irq2_address & 0xffff0000) >> 16;
 
    irq3_address = (unsigned long)irq3; 
    IDT[35].offset_lowerbits = irq3_address & 0xffff;
    IDT[35].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[35].zero = 0;
    IDT[35].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[35].offset_higherbits = (irq3_address & 0xffff0000) >> 16;
 
    irq4_address = (unsigned long)irq4; 
    IDT[36].offset_lowerbits = irq4_address & 0xffff;
    IDT[36].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[36].zero = 0;
    IDT[36].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[36].offset_higherbits = (irq4_address & 0xffff0000) >> 16;
 
    irq5_address = (unsigned long)irq5; 
    IDT[37].offset_lowerbits = irq5_address & 0xffff;
    IDT[37].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[37].zero = 0;
    IDT[37].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[37].offset_higherbits = (irq5_address & 0xffff0000) >> 16;
 
    irq6_address = (unsigned long)irq6; 
    IDT[38].offset_lowerbits = irq6_address & 0xffff;
    IDT[38].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[38].zero = 0;
    IDT[38].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[38].offset_higherbits = (irq6_address & 0xffff0000) >> 16;
 
    irq7_address = (unsigned long)irq7; 
    IDT[39].offset_lowerbits = irq7_address & 0xffff;
    IDT[39].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[39].zero = 0;
    IDT[39].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[39].offset_higherbits = (irq7_address & 0xffff0000) >> 16;
 
    irq8_address = (unsigned long)irq8; 
    IDT[40].offset_lowerbits = irq8_address & 0xffff;
    IDT[40].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[40].zero = 0;
    IDT[40].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[40].offset_higherbits = (irq8_address & 0xffff0000) >> 16;
 
    irq9_address = (unsigned long)irq9; 
    IDT[41].offset_lowerbits = irq9_address & 0xffff;
    IDT[41].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[41].zero = 0;
    IDT[41].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[41].offset_higherbits = (irq9_address & 0xffff0000) >> 16;
 
    irq10_address = (unsigned long)irq10; 
    IDT[42].offset_lowerbits = irq10_address & 0xffff;
    IDT[42].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[42].zero = 0;
    IDT[42].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[42].offset_higherbits = (irq10_address & 0xffff0000) >> 16;
 
    irq11_address = (unsigned long)irq11; 
    IDT[43].offset_lowerbits = irq11_address & 0xffff;
    IDT[43].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[43].zero = 0;
    IDT[43].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[43].offset_higherbits = (irq11_address & 0xffff0000) >> 16;
 
    irq12_address = (unsigned long)irq12; 
    IDT[44].offset_lowerbits = irq12_address & 0xffff;
    IDT[44].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[44].zero = 0;
    IDT[44].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[44].offset_higherbits = (irq12_address & 0xffff0000) >> 16;
 
    irq13_address = (unsigned long)irq13; 
    IDT[45].offset_lowerbits = irq13_address & 0xffff;
    IDT[45].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[45].zero = 0;
    IDT[45].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[45].offset_higherbits = (irq13_address & 0xffff0000) >> 16;
 
    irq14_address = (unsigned long)irq14; 
    IDT[46].offset_lowerbits = irq14_address & 0xffff;
    IDT[46].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[46].zero = 0;
    IDT[46].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[46].offset_higherbits = (irq14_address & 0xffff0000) >> 16;
 
    irq15_address = (unsigned long)irq15; 
    IDT[47].offset_lowerbits = irq15_address & 0xffff;
    IDT[47].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
    IDT[47].zero = 0;
    IDT[47].type_attr = 0x8e; /* INTERRUPT_GATE */
    IDT[47].offset_higherbits = (irq15_address & 0xffff0000) >> 16;
 
    /* fill the IDT descriptor */
    idt_address = (unsigned long)IDT ;
    idt_ptr[0] = (sizeof (struct IDT_entry) * 256) + ((idt_address & 0xffff) << 16);
    idt_ptr[1] = idt_address >> 16 ;

    load_idt(idt_ptr); 

}

I used the OSDev wiki as a source (a good portion of that code has even been copy-and-pasted from there).

I use x86_64-elf-gcc as my cross-compiler, NASM as my assembler and x86_64-elf-ld to link everything together. I also use QEMU as my emulator

NB: My code didn't want to compile when using inline assembly, this is why I ported a few functions to the NASM file.

c
assembly
x86-64
nasm
osdev
asked on Stack Overflow Apr 23, 2021 by Hacked • edited Apr 23, 2021 by Michael Petch

1 Answer

2

Your load_idt function is written as a 32-bit function where the first parameter is passed on the stack. In the 64-bit System V ABI the first parameter is passed in register RDI. Use this instead:

load_idt:
    lidt [rdi]
    ret
answered on Stack Overflow Apr 23, 2021 by Michael Petch

User contributions licensed under CC BY-SA 3.0