Random tripple fault in bochs in protected mode

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Je06
Posts: 11
Joined: Mon Dec 09, 2019 10:37 pm

Random tripple fault in bochs in protected mode

Post by Je06 »

I'm having trouble tracking down a bug in my code. It onlyhappens some of the time. I'm using bochs.

I have a GDT and IDT setup.

It usually faults in a while loop

Code: Select all

    while (true) {}

Code: Select all

#define     ALIGN(a) __attribute__((aligned(a)))

GDT::GDT_Ptr GDT_Ptr ALIGN(16);
GDT::GDT_Entry GDT_Entries[4] ALIGN(16);

IDT::IDT_Ptr IDT_Ptr ALIGN(16);
IDT::IDT_Entry IDT_Entries[0x40] ALIGN(16);

    // Setup GDT
    GDT::set_gdt_entry(GDT_Entries, 1, 0, -1, true);
    GDT::set_gdt_entry(GDT_Entries, 2, 0, -1, false);

    GDT::set_gdt(&GDT_Ptr, GDT_Entries, sizeof(GDT_Entries));
    enable_gdt(&GDT_Ptr, 0x08, 0x10);

    // Setup interrupts
    
    for (size_t i = 0; i < 0x40; i++) {
        IDT::set_idt_entry(IDT_Entries, i, 0x08, (uint32_t)test, true);
    }

    IDT::set_idt_entry(IDT_Entries, 8, 0x08, (uint32_t)test2, true);
    IDT::set_idt_entry(IDT_Entries, 10, 0x08, (uint32_t)test2, true);
    IDT::set_idt_entry(IDT_Entries, 11, 0x08, (uint32_t)test2, true);
    IDT::set_idt_entry(IDT_Entries, 12, 0x08, (uint32_t)test2, true);
    IDT::set_idt_entry(IDT_Entries, 13, 0x08, (uint32_t)test2, true);
    IDT::set_idt_entry(IDT_Entries, 14, 0x08, (uint32_t)test2, true);
    IDT::set_idt_entry(IDT_Entries, 17, 0x08, (uint32_t)test2, true);
    IDT::set_idt_entry(IDT_Entries, 30, 0x08, (uint32_t)test2, true);

    IDT::set_idt(&IDT_Ptr, IDT_Entries, sizeof(IDT_Entries));

    PIC::reload_pic(0x30, 0x38);

    enable_idt(&IDT_Ptr);

Code: Select all

typedef struct __attribute__((packed)){
    uint16_t size;
    uint32_t addr;
} GDT_Ptr;

typedef struct __attribute__((packed)){
    uint16_t limit;
    uint16_t base0;
    uint8_t base1;
    uint8_t access;
    uint8_t limit_flags;
    uint8_t base2;
} GDT_Entry;

typedef struct __attribute__((packed)) {
    uint16_t size;
    uint32_t addr;
} IDT_Ptr;

typedef struct __attribute__((packed)) {
    uint16_t base0;
    uint16_t selector;
    uint8_t zero;
    uint8_t type;
    uint16_t base1;
} IDT_Entry;

Code: Select all

void set_gdt(GDT_Ptr *ptr, GDT_Entry *gdt, size_t size) {
    ptr->size = size - 1;
    ptr->addr = (uint32_t)gdt;
}

void set_gdt_entry(GDT_Entry *gdt, size_t index, uint32_t base, uint32_t limit, bool code) {
    gdt[index].base0 = (uint16_t)base;
    gdt[index].base1 = (uint8_t)(base >> 16);
    gdt[index].base2 = (uint8_t)(base >> 24);
    
    gdt[index].limit = (uint16_t)limit;
    gdt[index].limit_flags = (uint8_t)((limit >> 16) & 0xf) | 0b11000000;

    if (limit != 0)
        gdt[index].access = 0b10010010;
    else
        gdt[index].access = 0b00010010;

    if (code)
        gdt[index].access |= 0b1000;
}

void set_idt(IDT_Ptr *ptr, IDT_Entry *idt, size_t size) {
    ptr->size = size - 1;
    ptr->addr = (uint32_t)idt;
}

void set_idt_entry(IDT_Entry *idt, size_t index, uint16_t selector, uint32_t base, bool present) {
    idt[index].base0 = (uint16_t)base;
    idt[index].base1 = (uint16_t)(base >> 16);

    idt[index].selector = selector;

    if (present)
        idt[index].type = 0b10001111;
    
    else
        idt[index].type = 0;

    idt[index].zero = 0;
}

Code: Select all

global enable_gdt
enable_gdt:
    mov     eax, [esp+4]
    mov     ecx, [esp+8]
    mov     edx, [esp+12]

    lgdt    [eax]

    mov     ax, dx
    mov     ds, ax
    mov     es, ax
    mov     ss, ax
    mov     fs, ax
    mov     gs, ax

    ; For some reason, retf mangles the esp
    mov     eax, esp

    push    cx
    push    _reload_code
    retf

_reload_code:
    mov     esp, eax
    ret

global enable_idt
enable_idt:
    mov     eax, [esp+4]
    lidt    [eax]
    sti
    ret

Code: Select all

global test
test:
    xchg    bx, bx
    iret

global test2
test2:
    xchg    bx, bx
    add     esp, 4
    iret
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Random tripple fault in bochs in protected mode

Post by iansjack »

Disable reset_on_triple_fault and use Boch's debugger to determine the address of the faulting instruction and the exception number of the first exception.

As you have rudimentary handlers for exceptions that should halt the processor, the most likely cause is an invalid stack.
Je06
Posts: 11
Joined: Mon Dec 09, 2019 10:37 pm

Re: Random tripple fault in bochs in protected mode

Post by Je06 »

iansjack wrote:Disable reset_on_triple_fault and use Boch's debugger to determine the address of the faulting instruction and the exception number of the first exception.

As you have rudimentary handlers for exceptions that should halt the processor, the most likely cause is an invalid stack.
Thanks for the tip! As it turns out, for some unknown reason, the CPU was trying to access memory that was not assigned to a linear address yet in my linear page mapper. I also looked at the stack, and it looks like it just the triple fault is the only one called. Adding more memory to my linear address space solved the problem
Post Reply