assemblyx86osdevbochsgdt

bochs: fetch_raw_descriptor: GDT: index (bf) 17 > limit (17)


I'm trying to make a simple OS and I'm currently working on interrupts and the IDT.
So I implemented the IDT and a default exception handler that currently doe's nothing.
And when I run my OS in bochs I see that the OS triple faults right when it is jumping to the kernel.

bochs logs:

fetch_raw_descriptor: GDT: index (bf) 17 > limit (17)
interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
interrupt(): gate descriptor is not valid sys seg (vector=0x08)

Exception 0x0d is General Protection Fault so My guess is that it has something to do with the GDT so here is my code for the GDT and how I load it:

LoadGDT:
    lgdt [g_GDTDesc]
    ret

g_GDT:
    ; NULL descrytpor
    dq 0

    ; 32 code segment
    dw 0FFFFh                   ; limit
    dw 0                        ; base
    db 0                        ; base
    db 10011010b                ; access
    db 11001111b                ; granularity
    db 0                        ; base high

    ; 32 data segment
    dw 0FFFFh                   ; limit
    dw 0                        ; base
    db 0                        ; base
    db 10010010b                ; access
    db 11001111b                ; granularity
    db 0                        ; base high

g_GDTDesc:
    dw g_GDTDesc - g_GDT - 1    ; size of gdt
    dd g_GDT                    ; address of gdt

But if it is because the IDT then I followed this tutorial from osDev wiki.

idt.c:

#define INTERRUPT_GATE_FLAGS 0x8e
typedef struct {
    u16     isr_low;            // lower 16 bit of ISR's address
    u16     kernel_cs;          // gdt segment selector
    u8      reserved;           // set to zero
    u8      flags;              // attribute flags
    u16     isr_high;           // higher 16 bit of ISR's address
} PACKED idt_entry_t;

typedef struct {
    u16     limit;
    u32     ptr;
} PACKED idtr_t;

__attribute__((aligned(0x10))) static idt_entry_t idt[256];
static idtr_t idtr;


void exception_handler(){
    __asm__ volatile("cli; hlt"); // currently doe's nothing
}

void IDT_set_descriptor(u8 interrupt, void* isr, u8 flags){
    idt_entry_t* descriptor = &idt[interrupt];

    descriptor->isr_low     = (u32)isr & 0xFFFF;
    descriptor->kernel_cs   = 0x08;
    descriptor->reserved    = 0;
    descriptor->flags       = flags;
    descriptor->isr_high    = ((u32)isr >> 16) & 0xFFFF;
}

extern void* isr_stub_table[];
void IDT_init(){
    idtr.ptr = (u32)&idt[0];
    idtr.limit = (u16)sizeof(idt) - 1;

    for(u8 interrupt=0; interrupt<32; interrupt++){
        IDT_set_descriptor(interrupt, isr_stub_table[interrupt], INTERRUPT_GATE_FLAGS);
    }

    __asm__ volatile("lidt %0": :"m"(idtr));
    STI();
}

idt.asm:

; exceptions with error code
%macro isr_err_stub 1
isr_stub_%+%1:
    call exception_handler
    iret
%endmacro

; exceptions without error code
%macro isr_no_err_stub 1
isr_stub_%+%1:
    call exception_handler
    iret
%endmacro

extern exception_handler
isr_no_err_stub 0
isr_no_err_stub 1
isr_no_err_stub 2
isr_no_err_stub 3
......
isr_no_err_stub 29
isr_err_stub    30
isr_no_err_stub 31

; defining the isr_stub_table
global isr_stub_table
isr_stub_table:
%assign i 0
%rep 32
    dd isr_stub_%+i
%assign i i+1
%endrep

Solution

  • As Michael Petch pointed out, turned out my code had two main issues.

    The first is that in my boot loader I loaded only one sector even though my kernel is bigger than that.
    The second is that in link.ldt, my linking script, I had:

     .entry              : { __entry_start = .;      *(.entry)   }
     .text               : { __text_start = .;       *(.text)    }
    

    that means that the section .entry will be linked before the .text sectoin.
    But in kernel_entry.asm which is a file that calls the main kernel function I started with .text, so my kernel wasn't linked properly.