CPU Triple Faults when booting from drive instead of cdrom

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
tretornesp
Posts: 18
Joined: Mon Aug 15, 2022 12:30 pm

CPU Triple Faults when booting from drive instead of cdrom

Post by tretornesp »

Update: I have solved the issue simply by zeroing the IDT before initializing the page:

Code: Select all

    memset((void*)idtr.offset, 0, 256 * sizeof(struct idtdescentry));
But, as long as the previous code yielded a page fault (or a double fault), as the idt entry
was correct, it shouldn't matter that the page has trash somewhere else. As every entry is
initialiced by the default handler, I'm not sure why this "fixed" the problem.

I migrate my original question to: This is weird, do you see anything wrong here?

Original question:

Hello everyone.

I'm facing trouble with interrupts on my kernel. I'm forcing a general protection fault to
test interrupt handling works.

Code: Select all

   
    void * target = request_page(); //Request a physical page with page frame allocator
    memset(target, 0, 4096);
    map_memory((void*)0xffffffffdeadb000, target); //Map it to the address

    uint64_t* ptr1 = (uint64_t*)0xffffffffdeadb000;	
    PAGE_RESTRICT_WRITE((void*)ptr1); //Clear writable bit in page table

    *ptr1 = 0xdeadbeef;
When I create an iso with xorriso and boot it with qemu by doing:

Code: Select all

qemu-system-x86_64 -cpu qemu64 -d cpu_reset -machine q35 -m 512 -boot d -cdrom ./image.iso
Everything works as a charm.

But if I create a limine compatible .img and run it like:

Code: Select all

qemu-system-x86_64 -cpu qemu64 -d cpu_reset -machine q35 -m 512 -boot d -cdrom ./test/useless.iso -drive if=pflash,format=raw,unit=0,file=./OVMFbin/OVMF_CODE-pure-efi.fd,readonly=on -drive if=pflash,format=raw,unit=1,file=./OVMFbin/OVMF_VARS-pure-efi.fd -net none -drive file=./image.img
The cpu triple faults.

It is mandatory to point out that some interrupts work fine, i can handle keyboard input, pit, mouse, divbyzero, etc just fine. But the PageFault and general protection fault handlers
don't seem to work.

My initialization code:

Code: Select all

struct idtr idtr;

void set_idt_gate(uint64_t handler, uint8_t entry_offset, uint8_t type_attr, uint8_t selector) {
    struct idtdescentry* interrupt = (struct idtdescentry*)(idtr.offset + entry_offset * sizeof(struct idtdescentry));
    set_offset(interrupt, handler);
    interrupt->type_attr = type_attr;
    interrupt->selector = selector;
}

void init_interrupts(uint8_t pit_disable) {

    __asm__("cli");

    idtr.limit = 0x0FFF;
    idtr.offset = (uint64_t)request_page(); //Request physical page

    for (int i = 0; i < 256; i++) {
        set_idt_gate((uint64_t)UncaughtInt_Handler, i, IDT_TA_InterruptGate, 0x28);
    }

    set_idt_gate((uint64_t)PageFault_Handler,   0xE,    IDT_TA_InterruptGate, 0x28);
    set_idt_gate((uint64_t)DoubleFault_Handler, 0x8,    IDT_TA_InterruptGate, 0x28);
    set_idt_gate((uint64_t)GPFault_Handler,     0xD,    IDT_TA_InterruptGate, 0x28);
    set_idt_gate((uint64_t)KeyboardInt_Handler, 0x21,   IDT_TA_InterruptGate, 0x28);
    set_idt_gate((uint64_t)MouseInt_Handler,    0x2C,   IDT_TA_InterruptGate, 0x28);
    set_idt_gate((uint64_t)PitInt_Handler,      0x20,   IDT_TA_InterruptGate, 0x28);
    set_idt_gate((uint64_t)DivByZero_Handler,   0x0,    IDT_TA_InterruptGate, 0x28);
    


    __asm__("lidt %0" : : "m"(idtr));

    remap_pic();

    init_keyboard();

    outb(PIC1_DATA, 0xf8 + pit_disable); //PIT IS DISABLED
    outb(PIC2_DATA, 0xef);

    __asm__("sti");

}
Every handler but pit,kb and mouse is just printing its name and halting.

Code: Select all

__attribute__((interrupt)) void UncaughtInt_Handler(struct interrupt_frame* frame) {
    dbg_print("UncaughtInt_Handler\n");
    (void)frame;
    while(1);
}
Any idea on what may be going on here?

P.S. The entire code is available here: https://github.com/TretornESP/bloodmoon

P.S.v2. I can't log interrupts with qemu's

Code: Select all

-d int
as booting with OVMF and Limine generate too many interrupts, slowing the program down
to the point where it will never boot. cpu_reset just tells me what I was already expecting (A triple fault on the write operation).

Code: Select all

Triple fault
CPU Reset (CPU 0)
RAX=00000000deadbeef RBX=0000000000000000 RCX=0000000000a78000 RDX=0000000000a77001
RSI=0000000000000000 RDI=ffffffff8000c93b RBP=0000000000a77000 RSP=ffff80001d98aff0
R8 =00000000000000f5 R9 =ffffffffdeadb000 R10=000000001fe13200 R11=0000000000000009
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=ffffffff8000bb33 RFL=00000202 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0030 0000000000000000 00000000 00009300 DPL=0 DS   [-WA]
CS =0028 0000000000000000 00000000 00209a00 DPL=0 CS64 [-R-]
SS =0030 0000000000000000 00000000 00009300 DPL=0 DS   [-WA]
DS =0030 0000000000000000 00000000 00009300 DPL=0 DS   [-WA]
FS =0030 0000000000000000 00000000 00009300 DPL=0 DS   [-WA]
GS =0030 0000000000000000 00000000 00009300 DPL=0 DS   [-WA]
LDT=0000 0000000000000000 00000000 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT=     ffff80001fee7000 00000037
IDT=     0000000000a09000 00000fff
CR0=80010011 CR2=0000000000000044 CR3=000000001d97a000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000018 CCD=0000000000a77001 CCO=LOGICQ
EFER=0000000000000d00
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=0000000000000000 0000000000000000 XMM01=0000000000000000 0000000000000000
XMM02=0000000000000000 0000000000000000 XMM03=0000000000000000 0000000000000000
XMM04=0000000000000000 0000000000000000 XMM05=0000000000000000 0000000000000000
XMM06=0000000000000000 0000000000000000 XMM07=0000000000000000 0000000000000000
XMM08=0000000000000000 0000000000000000 XMM09=0000000000000000 0000000000000000
XMM10=0000000000000000 0000000000000000 XMM11=0000000000000000 0000000000000000
XMM12=0000000000000000 0000000000000000 XMM13=0000000000000000 0000000000000000
XMM14=0000000000000000 0000000000000000 XMM15=0000000000000000 0000000000000000
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: CPU Triple Faults when booting from drive instead of cdr

Post by Octocontrabass »

tretornesp wrote:I migrate my original question to: This is weird, do you see anything wrong here?
It looks like your set_idt_gate() function doesn't set the entire descriptor.
tretornesp
Posts: 18
Joined: Mon Aug 15, 2022 12:30 pm

Re: CPU Triple Faults when booting from drive instead of cdr

Post by tretornesp »

It looks like your set_idt_gate() function doesn't set the entire descriptor.
You are absolutely right. It assumes zeroed memory.

After spending too much time with a piece of code I usually start making wrong assumptions about it...

Thank you so much.
Post Reply