cpu triple fault / general protection fault reset after sti

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
User avatar
gnhnjac
Posts: 1
Joined: Sat Jan 21, 2023 6:59 am
Location: Israel

cpu triple fault / general protection fault reset after sti

Post by gnhnjac »

My cpu triple faults with a general protection fault after I run the sti command, on the qemu log it shows v=0x0d which means general protection fault and e=0x0042 which means its about the idt
my gdt is initialized correctly in 0x7cec and with size 0x17 which all sounds correct (24 bytes for null+code+data segment descriptors) and for some reason the idt part of the qemu int log shows:
IDT= 50000000 000007ff
I have no idea why it says its initialized to 0x50000000 although my size seems correct (7ff=256*8 which is the size i wanted).

Code: Select all

#include "memory.h"
#include "screen.h"
#include "isrs.h"
#include "idt.h"
#include <stdint.h>

/* Defines an IDT entry */
typedef struct {
    uint16_t    isr_low;      // The lower 16 bits of the ISR's address
    uint16_t    kernel_cs;    // The GDT segment selector that the CPU will load into CS before calling the ISR
    uint8_t     reserved;     // Set to zero
    uint8_t     attributes;   // Type and attributes; see the IDT page
    uint16_t    isr_high;     // The higher 16 bits of the ISR's address
} __attribute__((packed)) idt_entry_t;

typedef struct {
    uint16_t    limit;
    uint32_t    base;
} __attribute__((packed)) idtr_t;

__attribute__((aligned(0x10))) 
idt_entry_t idt[IDT_MAX_DESCRIPTORS]; // Create an array of IDT entries; aligned for performance
idtr_t idtr;

void idt_set_gate(uint8_t vector, void* isr, uint8_t flags) {
    idt_entry_t* descriptor = &idt[vector];
 
    descriptor->isr_low        = (uint32_t)isr & 0xFFFF;
    descriptor->kernel_cs      = 0x08; // offset of code segment descriptor in the GDT
    descriptor->attributes     = flags;
    descriptor->isr_high       = (uint32_t)isr >> 16;
    descriptor->reserved       = 0;
}

void idt_install(void);
/* Installs the IDT */
void idt_install()
{
	
    /* Sets the special IDT pointer up */
    idtr.limit = (uint16_t)sizeof(idt_entry_t) * IDT_MAX_DESCRIPTORS - 1;
    idtr.base = (uintptr_t)&idt[0];

    /* Clear out the entire IDT, initializing it to zeros */
    memset((unsigned char *)&idt, 0, sizeof(idt_entry_t) * IDT_MAX_DESCRIPTORS);

    /* Add any new ISRs to the IDT here using idt_set_gate */
    isrs_install();
    __asm__ __volatile__ ("lidt %0" : : "m"(idtr)); // load the new IDT
    __asm__ __volatile__ ("sti"); // load the new IDT
}
this is the code which loads my idt into memory, everything seems correct as I have also checked the memory with the qemu command line, everything apart from the excerpt I've attacked from the qemu log.

Does someone have any idea to what is causing the gp?
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: cpu triple fault / general protection fault reset after

Post by Octocontrabass »

I don't see anything in this code that could cause that problem. The bug is most likely somewhere else.
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: cpu triple fault / general protection fault reset after

Post by MichaelPetch »

If you aren't expecting the IDT to be at 0x50000000 that will eventually be a problem, but there are some hints of what might be causing the interrupt after STI. You say you got a v=0d . That is in fact the generel protection fault as you say. e=0042 says a little bit more than the exception/interrupt being in the IDT (bit 1 and 2 = 01b). Bits 3 to 15 are the interrupt/exception number in the IDT that caused the problems. If you right shift 0x42 right 3 bits the index is 0x08. 0x08 is Double Fault.

A GPF on a Double Fault isn't likely. But something that would make sense is that you never remapped PIC1 so it wasn't overlapping the exception table. The default when a legacy BIOS boots is to map PIC1 to interrupt vector 0x08 through 0x0f. This does in fact conflict with the exceptions on 286+ processors (This was an oversight by IBM when they developed the IBM-PC). It just so happens Interrupt 0 on PIC1 (which is mapped to interrupt vector 0x08) is the TIMER interrupt. I suspect that when you did STI, a timer interrupt occurred shortly after and that caused the fault. Since your IDT is effectively all zero any interrupt will cause a General Protection Fault (0x0d).

Was there a v=08 entry in the log just prior to the v=0d?

Information on initializing and remapping the PICs can be found here: https://wiki.osdev.org/8259_PIC .

Without seeing the rest of your code it is rather difficult to troubleshoot. You may have issues in your bootloader, how you load things in memory, or even how you assemble and link everything together.
Last edited by MichaelPetch on Mon Jan 23, 2023 4:41 pm, edited 1 time in total.
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: cpu triple fault / general protection fault reset after

Post by Schol-R-LEA »

If you have a hosted repository, could you please provide a link to it? That would allow us to review your whole codebase, if necessary.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
Post Reply