1

I am trying to develop my own operating system. I had written some code for 32 bit and came until paging when I suddendly decided I want to go 64 bit. I enabled long mode, set up basic paging, fire up the kernel, kernel sets better paging (first 4 MiBs paged and also start of the framebuffer). Now I want to enable interrupts, I reorganized my 32 bit idt code to be 64 bit and tried enabling it, it does work miracolously. The moment I enable it I get a general protection fault. Here are things to consider, I seem to have all irq's and isr's handlers' in place, I know that because when the general protection fault occurs, it prints it on the screen. I am almost certain that it is caused by the timer but I cannot confirm since my timer interrupt handler also exists. No I didnt forget the iretq :D. Here is my idt.c and belove it the entire github repo.


#include "IDT.h"

#define PUSHALL \
     ".intel_syntax noprefix\n\t" \
    "push    r15\n\t"\
    "push    r14\n\t"\
    "push    r13\n\t"\
    "push    r12\n\t"\
    "push    r11\n\t"\
    "push    r10\n\t"\
    "push    r9\n\t"\
    "push    r8\n\t"\
    "push    rax\n\t"\
    "push    rcx\n\t"\
    "push    rdx\n\t"\
    "push    rbx\n\t"\
    "push    rsp\n\t"\
    "push    rbp\n\t"\
    "push    rsi\n\t"\
    "push    rdi\n\t"\
     ".att_syntax\n\t" \

#define POPALL\
    ".intel_syntax noprefix\n\t" \
    "pop     rdi\n\t"\
    "pop     rsi\n\t"\
    "pop     rbp\n\t"\
    "add     rsp, 10\n\t"\
    "pop     rbx\n\t"\
    "pop     rdx\n\t"\
    "pop     rcx\n\t"\
    "pop     rax\n\t"\
    "pop     r8\n\t"\
    "pop     r9\n\t"\
    "pop     r10\n\t"\
    "pop     r11\n\t"\
    "pop     r12\n\t"\
    "pop     r13\n\t"\
    "pop     r14\n\t"\
    "pop     r15\n\t"\
    "add     rsp, 0x10\n\t"\
    ".att_syntax\n\t" \
    

/* Common body for interrupt handler */
#define MAKE_INTERRUPT_COMMON_STUB(intno, intfunc) \
            "push $"#intno"\n\t" \
            PUSHALL  \
            "cld\n\t" \
            "push %rsp\n\t" \
            "call " #intfunc "\n\t" \
            POPALL \
            "add $10, %rsp\n\t"       /* Skip int_num and err_code */ \
            "iretq \n\t" \
            "#.popsection\n\t"

/* Make interrupt for exception without error code. Push a dummy value for the
 * error code in it place. Push all the segment registers and the segment registers
 * so that they are available to interrupt function (intfun). Pushes a unique
 * interrupt number (intno) after the error code so that a handler can be multiplexed
 * if needed. Restore all the registers upon exit.
 *
 * intentry: Is the interrupt entry point that can be used in an Interrupt
 *           Descriptor Table (IDT) entry.
 * intfunc:  Is the C interrupt function that the stub calls to do processing
 * intno:    Interrupt number. Can be used to multiplex multiple interrupts to one
 *           intfunc handler.
 */
#define MAKE_INTERRUPT(intentry, intfunc, intno) \
    extern void intentry (void); \
    __asm__("#.pushsection .text\n\t" \
            ".global " #intentry "\n\t" \
            ".align 16\n\t" \
            #intentry ":\n\t" \
            "push $0\n\t"            /* Push dummy error code */ \
            MAKE_INTERRUPT_COMMON_STUB(intno, intfunc));

/* Make interrupt for exception with error code. Processor pushes the error code
 * after the return address automatically. Push all the segment registers and the
 * segment registers so that they are available to interrupt function (intfun).
 * Pushes a unique interrupt number (intno) after the error code so that a handler
 * can be multiplexed if needed. Restore all the registers upon exit.
 *
 * intentry: Is the interrupt entry point that can be used in an Interrupt
 *           Descriptor Table (IDT) entry.
 * intfunc:  Is the C interrupt function that the stub calls to do processing
 * intno:    Interrupt number. Can be used to multiplex multiple interrupts to one
 *           intfunc handler.
*/
#define MAKE_INTERRUPT_ERRCODE(intentry, intfunc, intno) \
    extern void intentry (void); \
    __asm__("#.pushsection .text\n\t" \
            ".global " #intentry "\n" \
            ".align 16\n\t" \
            #intentry ":\n\t" \
            MAKE_INTERRUPT_COMMON_STUB(intno, intfunc));

MAKE_INTERRUPT        (isr0,  isr0_handler,  0x00)
MAKE_INTERRUPT        (isr1,  isr1_handler,  0x01)
MAKE_INTERRUPT        (isr2,  isr2_handler,  0x02)
MAKE_INTERRUPT        (isr3,  isr3_handler,  0x03)
MAKE_INTERRUPT        (isr4,  isr4_handler,  0x04)
MAKE_INTERRUPT        (isr5,  isr5_handler,  0x05)
MAKE_INTERRUPT        (isr6,  isr6_handler,  0x06)
MAKE_INTERRUPT        (isr7,  isr7_handler,  0x07)
MAKE_INTERRUPT_ERRCODE(isr8,  isr8_handler,  0x08)
MAKE_INTERRUPT        (isr9,  isr9_handler,  0x09)
MAKE_INTERRUPT_ERRCODE(isr10, isr10_handler, 0x0a)
MAKE_INTERRUPT_ERRCODE(isr11, isr11_handler, 0x0b)
MAKE_INTERRUPT_ERRCODE(isr12, isr12_handler, 0x0c)
MAKE_INTERRUPT_ERRCODE(isr13, isr13_handler, 0x0d)
MAKE_INTERRUPT_ERRCODE(isr14, isr14_handler, 0x0e)
/* Reserved 0x0f */
MAKE_INTERRUPT        (isr16, isr0_handler,  0x10)
MAKE_INTERRUPT_ERRCODE(isr17, isr0_handler,  0x11)
MAKE_INTERRUPT        (isr18, isr0_handler,  0x12)
MAKE_INTERRUPT        (isr19, isr0_handler,  0x13)
MAKE_INTERRUPT        (isr20, isr0_handler,  0x14)
/* Reserved 0x15 to 0x1d */
MAKE_INTERRUPT_ERRCODE(isr30, isr0_handler,  0x1e)
/* Reserved 0x1f */

/* IRQ handlers */
MAKE_INTERRUPT        (irq0,  irq0_handler,  0x00)
MAKE_INTERRUPT        (irq1,  irq1_handler,  0x01)
MAKE_INTERRUPT        (irq2,  irq2_handler,  0x02)
MAKE_INTERRUPT        (irq3,  irq3_handler,  0x03)
MAKE_INTERRUPT        (irq4,  irq4_handler,  0x04)
MAKE_INTERRUPT        (irq5,  irq5_handler,  0x05)
MAKE_INTERRUPT        (irq6,  irq6_handler,  0x06)
MAKE_INTERRUPT        (irq7,  irq7_handler,  0x07)
MAKE_INTERRUPT        (irq8,  irq8_handler,  0x08)
MAKE_INTERRUPT        (irq9,  irq9_handler,  0x09)
MAKE_INTERRUPT        (irq10, irq10_handler,  0x0A)
MAKE_INTERRUPT        (irq11, irq11_handler,  0x0B)
MAKE_INTERRUPT        (irq12, irq12_handler,  0x0C)
MAKE_INTERRUPT        (irq13, irq13_handler,  0x0D)
MAKE_INTERRUPT        (irq14, irq14_handler,  0x0E)
MAKE_INTERRUPT        (irq15, irq15_handler,  0x0F)

void init_idt_entry(int num, unsigned int offset, unsigned short select, 
    unsigned short flags)
    {
        
        _idt_entries[num].offset0 = (unsigned short)(offset & 0x000000000000FFFF);
        _idt_entries[num].offset1 = (unsigned short)((offset & 0x00000000FFFF0000) >> 16);
        _idt_entries[num].offset2 = (unsigned int)((offset & 0xFFFFFFFF00000000) >> 32);

        _idt_entries[num].selector = select;
        _idt_entries[num].flags = flags;
         return;
    }




///////////////////////////////////////
void idt_flush(struct idt *idtr)
{
    asm volatile("lidt %0" :: "m"(*idtr));
}

void init_pic()
{

    outb(0x20,0x11);
    outb(0xA0,0x11);

    outb(0x21, 0x20);
    outb(0xA1, 40);

    outb(0x21, 0x04);
    outb(0xA1, 0x02);

    outb(0x21, 0x01);
    outb(0xA1, 0x01);

    outb(0x21, 0x0);
    outb(0xA1, 0x0);

    
}


void init_idt()
{
    init_pic();
    
    _idt_entries = RequestPage();
    Tidt.limit = 16 * 256;
    Tidt.base  = _idt_entries;
    
    memset(_idt_entries, 0, 16*256);
    
    
    
    for(int i = 0; i < 256 ; i++){
        init_idt_entry(i,(int)&isr0,0x08, 0x8E); 
    }
    init_idt_entry(0,(int)&isr0,0x08, 0x8E);
    init_idt_entry(1,(int)&isr1,0x08, 0x8E);
    init_idt_entry(2,(int)&isr2,0x08, 0x8E);
    init_idt_entry(3,(int)&isr3,0x08, 0x8E);
    init_idt_entry(4,(int)&isr4,0x08, 0x8E);
    init_idt_entry(5,(int)&isr5,0x08, 0x8E);
    init_idt_entry(6,(int)&isr6,0x08, 0x8E);
    init_idt_entry(7,(int)&isr7,0x08, 0x8E);
    init_idt_entry(8,(int)&isr8,0x08, 0x8E);
    init_idt_entry(9,(int)&isr9,0x08, 0x8E);
    init_idt_entry(10,(int)&isr10,0x08, 0x8E);
    init_idt_entry(11,(int)&isr11,0x08, 0x8E);
    init_idt_entry(12,(int)&isr12,0x08, 0x8E);
    init_idt_entry(13,(int)&isr13,0x08, 0x8E);
    init_idt_entry(14,(int)&isr14,0x08, 0x8E);
    /* ISR15 is reserved */
    init_idt_entry(16,(int)&isr16,0x08, 0x8E);
    init_idt_entry(17,(int)&isr17,0x08, 0x8E);
    init_idt_entry(18,(int)&isr18,0x08, 0x8E);
    init_idt_entry(19,(int)&isr19,0x08, 0x8E);
    init_idt_entry(20,(int)&isr20,0x08, 0x8E);
    /* ISR21 to ISR2F are reserved */
    init_idt_entry(30,(int)&isr30,0x08, 0x8E);

    /* IRQ handlers */
    init_idt_entry(32,(int)&irq0,0x08, 0x8E);
    init_idt_entry(33,(int)&irq1,0x08, 0x8E);
    init_idt_entry(34,(int)&irq2,0x08, 0x8E);
    init_idt_entry(35,(int)&irq3,0x08, 0x8E);
    init_idt_entry(36,(int)&irq4,0x08, 0x8E);
    init_idt_entry(37,(int)&irq5,0x08, 0x8E);
    init_idt_entry(38,(int)&irq6,0x08, 0x8E);
    init_idt_entry(39,(int)&irq7,0x08, 0x8E);
    init_idt_entry(40,(int)&irq8,0x08, 0x8E);
    init_idt_entry(41,(int)&irq9,0x08, 0x8E);
    init_idt_entry(42,(int)&irq10,0x08, 0x8E);
    init_idt_entry(43,(int)&irq11,0x08, 0x8E);
    init_idt_entry(44,(int)&irq12,0x08, 0x8E);
    init_idt_entry(45,(int)&irq13,0x08, 0x8E);
    init_idt_entry(46,(int)&irq14,0x08, 0x8E);
    init_idt_entry(47,(int)&irq15,0x08, 0x8E);
    
    
    idt_flush(&Tidt);
    
    asm volatile("sti;");
    
    
}

Here is my isr.c and irq.c

ISR:

#include "isr.h"

void isr0_handler(interrupt_frame_t *frame)
{
    panic("Divide by zero");
    while(1);
    //fillRect(0, 0, 1080, 1920, 0xff0000);
}
void isr1_handler(interrupt_frame_t *frame)
{
    panic("Debug");
    while(1);
    //fillRect(0, 0, 1080, 1920, 0xff0000);
}
void isr2_handler(interrupt_frame_t *frame)
{
    panic("NMI");
    while(1);
    //fillRect(0, 0, 1080, 1920, 0xff0000);
}
void isr3_handler(interrupt_frame_t *frame)
{
    panic("Breakpoint");
    while(1);
    //fillRect(0, 0, 1080, 1920, 0xff0000);
}
void isr4_handler(interrupt_frame_t *frame)
{
    panic("Overflow");
    while(1);
   //fillRect(0, 0, 1080, 1920, 0xff0000);
}
void isr5_handler(interrupt_frame_t *frame)
{
    panic("Bound range exceeded");
    while(1);
   //fillRect(0, 0, 1080, 1920, 0xff0000);
}
void isr6_handler(interrupt_frame_t *frame)
{
    panic("Invalid Opcode");
    while(1);
    //fillRect(0, 0, 1080, 1920, 0xff0000);
}
void isr7_handler(interrupt_frame_t *frame)
{
    panic("Device Not Available");
    while(1);
   //fillRect(0, 0, 1080, 1920, 0xff0000);
}
void isr8_handler(interrupt_frame_t *frame)
{
    panic("Double Fault");
    while(1);
    //fillRect(0, 0, 1080, 1920, 0xff0000);
}
void isr9_handler(interrupt_frame_t *frame)
{
    panic("COPRO SEGMENT OVERRUN");
    
    while(1);
   //fillRect(0, 0, 1080, 1920, 0xff0000);
}
void isr10_handler(interrupt_frame_t *frame)
{
    panic("Invalid TSS");
    
    while(1);
   //fillRect(0, 0, 1080, 1920, 0xff0000);
}
void isr11_handler(interrupt_frame_t *frame)
{
    panic("Segment Not present");
    
    while(1);
    //fillRect(0, 0, 1080, 1920, 0xff0000);
}
void isr12_handler(interrupt_frame_t *frame)
{
    panic("Stack Segment Fault");
    
    while(1);
    //fillRect(0, 0, 1080, 1920, 0xff0000);
}
void isr13_handler(interrupt_frame_t *frame)
{
    panic("General Protection Fault");
    while(1);
    //fillRect(0, 0, 1080, 1920, 0xff0000);
}
void isr14_handler(interrupt_frame_t *frame)
{
    panic("Page Fault");
    
    while(1);
   //fillRect(0, 0, 1080, 1920, 0xff0000);
}

IRQ:


#include "irq.h"
#include "../../PS2/ps2.h"
#include "../../PS2/keyboard/keyboard.h"
#include "../../PS2/mouse/mouse.h"
#include "../../video/video.h" 
#include "../../string/string.h"

void default_irq_handler(interrupt_frame_t *frame)
{
        /* If IRQ # on slave PIC send EOI to slave */
        if (frame->int_no >= 8)
            outb(0xA0,0x20);

        /* Send EOI to master PIC */
        outb(0x20,0x20);
}

/* -------------------------- Programable Interval Timer ------------------------- */
void irq0_handler(interrupt_frame_t* frame)
{
    EnvironmentTick++;
    default_irq_handler(frame);
}

void Sleep(int ticks)
{
    int now = EnvironmentTick;

    while (EnvironmentTick != now + ticks);

    return;

}
void SetPITSpeed(int hz)
{
    int divisor = 1193180 / hz;       /* Calculate our divisor */
    outb(0x43, 0x36);             /* Set our command byte 0x36 */
    outb(0x40, divisor & 0xFF);   /* Set low byte of divisor */
    outb(0x40, divisor >> 8);     /* Set high byte of divisor */
}
/*  ------------------------------------------------------------------------------ */


/* -------------------------- Keyboard Controller -------------------------------- */
unsigned char currentCharInScancode;
unsigned char currentCharInKeycode;
unsigned char currentCharInASCII;

int isE0 = 0;
int isE1 = 0;
int pause = 0;
int prntscrn = 0;   
int isKeyPressed = 0;
int ignore = 0;
int isShift = 0;
char kbd_buffer[100];
int bufferIterator = 0;
char buffer[8];

void irq1_handler(interrupt_frame_t* frame)
{
    
    currentCharInScancode = readKeyboard();
    
    if(ignore > 0)
    {
        ignore--;
        default_irq_handler(frame);
        return;
    }
    else if(currentCharInScancode == 0xE1 && pause == 0)
    {
        pause = 1;
        ignore = 5;
    }
    else if(currentCharInScancode == 0xE0)
    {
        isE0 = 1;
        default_irq_handler(frame);
        return;
    }
    else if(currentCharInScancode == 0xF0)
    {
        isKeyPressed = 2;
        default_irq_handler(frame);
        return;
    }
    else if(currentCharInScancode == 0x7C && isE0 == 1)
    {   
        prntscrn = 1;
        ignore = 2;
    }
    
    
    if(isKeyPressed == 0)
        isKeyPressed = 1;
    else if(isKeyPressed == 2)
        isKeyPressed = 0;
    
    currentCharInKeycode = ScancodeToKeyCode(currentCharInScancode, isE0, prntscrn, pause);
    if(isE0 == 1) isE0 = 0;
    if(pause == 1) pause = 0;
    if(prntscrn == 1) prntscrn = 0;
    
    //drawStringToCursor(itoa(isKeyPressed, buffer, 16), 0xffffff, 0x000000);
    
    KeyPressed[currentCharInKeycode] = isKeyPressed; 
    
    //drawStringToCursor(itoa(isKeyPressed, buffer, 16), 0xffffff, 0x000000);
    
    kbd_buffer[bufferIterator] = currentCharInKeycode;
    if(bufferIterator == 99) bufferIterator = 0;
    else bufferIterator++;
    
    /*
    if((KeyCodeToASCII(currentCharInKeycode, KeyPressed[LSHIFT] | KeyPressed[RSHIFT]) != 0) && isKeyPressed == 1) 
    {
        drawCharToCursor(KeyCodeToASCII(currentCharInKeycode, KeyPressed[LSHIFT] | KeyPressed[RSHIFT]), 0xffffff, 0x000000);
        incrementCursor();
    }*/
    default_irq_handler(frame);
}
/*  ------------------------------------------------------------------------------ */

 
void irq2_handler(interrupt_frame_t* frame)
{
    default_irq_handler(frame);
}
void irq3_handler(interrupt_frame_t* frame)
{
    default_irq_handler(frame);
}
void irq4_handler(interrupt_frame_t* frame)
{
    default_irq_handler(frame);
}
void irq5_handler(interrupt_frame_t* frame)
{
    default_irq_handler(frame);
}
void irq6_handler(interrupt_frame_t* frame)
{
    default_irq_handler(frame);
}
void irq7_handler(interrupt_frame_t* frame)
{
    default_irq_handler(frame);
}
void irq8_handler(interrupt_frame_t* frame)
{
    default_irq_handler(frame);
}
void irq9_handler(interrupt_frame_t* frame)
{
    default_irq_handler(frame);
}
void irq10_handler(interrupt_frame_t* frame)
{
    default_irq_handler(frame);
}
void irq11_handler(interrupt_frame_t* frame)
{
    default_irq_handler(frame);
}

// -------------------------------- Mouse Controller ------------------------

unsigned char mouse_cycle = 0;
signed char mouse_byte[3];    //signed char
signed char mouse_x = 0;         //signed char
signed char mouse_y = 0;         //signed char
signed char state = 0;
signed char d = 0;

int LeftButton = 0;
int MiddleButton = 0;
int RightButton = 0;

unsigned char buff[16];
void irq12_handler(interrupt_frame_t* frame)
{
    switch(mouse_cycle)
    {
        case 0:
            mouse_byte[0]=readMouse();
            mouse_cycle++;
            break;
        case 1:
            mouse_byte[1]=readMouse();
            mouse_cycle++;
            break;
        case 2:
            mouse_byte[2]=readMouse();
            
            
            state = mouse_byte[2];
            d = mouse_byte[0];
            mouse_x = d - ((state << 4) & 0x100);
            d = mouse_byte[1];      
            mouse_y = d - ((state << 3) & 0x100);
            
            MouseX = MouseX + mouse_x;
            MouseY = MouseY - mouse_y;
            
            putpixel(MouseX, MouseY, 0xffffff);
            
            if( (state & 0b00001100) == 0b00001100 ) MiddleButton = 1;
            else if( (state & 0b00001100) == 0b00001000 ) MiddleButton = 0;
            
            if( (state & 0b000010001) == 0b00001001 ) LeftButton = 1;
            else if( (state & 0b00001001) == 0b00001000 ) LeftButton = 0;
            
            if( (state & 0b00001010) == 0b00001010 ) RightButton = 1;
            else if( (state & 0b00001010) == 0b00001000 ) RightButton = 0;
            
            //drawStringToCursor(itoa(RightButton, buffer, 16), 0xffffff, 0x000000);
            //incrementCursor();
            mouse_cycle=0;
            break;
    }
    default_irq_handler(frame);
}
// --------------------------------------------------------------------------

void irq13_handler(interrupt_frame_t* frame)
{
    default_irq_handler(frame);
}
void irq14_handler(interrupt_frame_t* frame)
{
    default_irq_handler(frame);
}
void irq15_handler(interrupt_frame_t* frame)
{
    default_irq_handler(frame);
}

And the entire github repo: https://github.com/Danyy427/OSDEV5.git

You can find idt related stuff in source/kernel/idt

you can find paging related stuff in source/kernel/memory/paging

you can find gdt related stuff in source/bootloader/AfterBoot.asm which sets a 64 bit gdt.

Edit:

New IDT.c fixed some issues (hopefully)

#include "IDT.h"

#define PUSHALL \
     ".intel_syntax noprefix\n\t" \
    "push    r15\n\t"\
    "push    r14\n\t"\
    "push    r13\n\t"\
    "push    r12\n\t"\
    "push    r11\n\t"\
    "push    r10\n\t"\
    "push    r9\n\t"\
    "push    r8\n\t"\
    "push    rax\n\t"\
    "push    rcx\n\t"\
    "push    rdx\n\t"\
    "push    rbx\n\t"\
    "push    rsp\n\t"\
    "push    rbp\n\t"\
    "push    rsi\n\t"\
    "push    rdi\n\t"\
     ".att_syntax\n\t" \

#define POPALL\
    ".intel_syntax noprefix\n\t" \
    "pop     rdi\n\t"\
    "pop     rsi\n\t"\
    "pop     rbp\n\t"\
    "add     rsp, 10\n\t"\
    "pop     rbx\n\t"\
    "pop     rdx\n\t"\
    "pop     rcx\n\t"\
    "pop     rax\n\t"\
    "pop     r8\n\t"\
    "pop     r9\n\t"\
    "pop     r10\n\t"\
    "pop     r11\n\t"\
    "pop     r12\n\t"\
    "pop     r13\n\t"\
    "pop     r14\n\t"\
    "pop     r15\n\t"\
    "add     rsp, 0x10\n\t"\
    ".att_syntax\n\t" \
    

/* Common body for interrupt handler */
#define MAKE_INTERRUPT_COMMON_STUB(intno, intfunc) \
            "push $"#intno"\n\t" \
            PUSHALL  \
            "mov %rsp, %rdi\n\t"\
            "sub $0x28, %rsp\n\t"\
            "cld\n\t" \
            "call " #intfunc "\n\t" \
            "add $28, %rsp\n\t"       /* Skip int_num and err_code */ \
            POPALL \
            "iretq \n\t" 

/* Make interrupt for exception without error code. Push a dummy value for the
 * error code in it place. Push all the segment registers and the segment registers
 * so that they are available to interrupt function (intfun). Pushes a unique
 * interrupt number (intno) after the error code so that a handler can be multiplexed
 * if needed. Restore all the registers upon exit.
 *
 * intentry: Is the interrupt entry point that can be used in an Interrupt
 *           Descriptor Table (IDT) entry.
 * intfunc:  Is the C interrupt function that the stub calls to do processing
 * intno:    Interrupt number. Can be used to multiplex multiple interrupts to one
 *           intfunc handler.
 */
#define MAKE_INTERRUPT(intentry, intfunc, intno) \
    extern void intentry (void); \
    __asm__(".global " #intentry "\n\t" \
            ".align 16\n\t" \
            #intentry ":\n\t" \
            "push $0\n\t"            /* Push dummy error code */ \
            MAKE_INTERRUPT_COMMON_STUB(intno, intfunc));

/* Make interrupt for exception with error code. Processor pushes the error code
 * after the return address automatically. Push all the segment registers and the
 * segment registers so that they are available to interrupt function (intfun).
 * Pushes a unique interrupt number (intno) after the error code so that a handler
 * can be multiplexed if needed. Restore all the registers upon exit.
 *
 * intentry: Is the interrupt entry point that can be used in an Interrupt
 *           Descriptor Table (IDT) entry.
 * intfunc:  Is the C interrupt function that the stub calls to do processing
 * intno:    Interrupt number. Can be used to multiplex multiple interrupts to one
 *           intfunc handler.
*/
#define MAKE_INTERRUPT_ERRCODE(intentry, intfunc, intno) \
    extern void intentry (void); \
    __asm__(".global " #intentry "\n" \
            ".align 16\n\t" \
            #intentry ":\n\t" \
            MAKE_INTERRUPT_COMMON_STUB(intno, intfunc));

MAKE_INTERRUPT        (isr0,  isr0_handler,  0x00)
MAKE_INTERRUPT        (isr1,  isr1_handler,  0x01)
MAKE_INTERRUPT        (isr2,  isr2_handler,  0x02)
MAKE_INTERRUPT        (isr3,  isr3_handler,  0x03)
MAKE_INTERRUPT        (isr4,  isr4_handler,  0x04)
MAKE_INTERRUPT        (isr5,  isr5_handler,  0x05)
MAKE_INTERRUPT        (isr6,  isr6_handler,  0x06)
MAKE_INTERRUPT        (isr7,  isr7_handler,  0x07)
MAKE_INTERRUPT_ERRCODE(isr8,  isr8_handler,  0x08)
MAKE_INTERRUPT        (isr9,  isr9_handler,  0x09)
MAKE_INTERRUPT_ERRCODE(isr10, isr10_handler, 0x0a)
MAKE_INTERRUPT_ERRCODE(isr11, isr11_handler, 0x0b)
MAKE_INTERRUPT_ERRCODE(isr12, isr12_handler, 0x0c)
MAKE_INTERRUPT_ERRCODE(isr13, isr13_handler, 0x0d)
MAKE_INTERRUPT_ERRCODE(isr14, isr14_handler, 0x0e)
/* Reserved 0x0f */
MAKE_INTERRUPT        (isr16, isr0_handler,  0x10)
MAKE_INTERRUPT_ERRCODE(isr17, isr0_handler,  0x11)
MAKE_INTERRUPT        (isr18, isr0_handler,  0x12)
MAKE_INTERRUPT        (isr19, isr0_handler,  0x13)
MAKE_INTERRUPT        (isr20, isr0_handler,  0x14)
/* Reserved 0x15 to 0x1d */
MAKE_INTERRUPT_ERRCODE(isr30, isr0_handler,  0x1e)
/* Reserved 0x1f */

/* IRQ handlers */
MAKE_INTERRUPT        (irq0,  irq0_handler,  0)
MAKE_INTERRUPT        (irq1,  irq1_handler,  1)
MAKE_INTERRUPT        (irq2,  irq2_handler,  2)
MAKE_INTERRUPT        (irq3,  irq3_handler,  3)
MAKE_INTERRUPT        (irq4,  irq4_handler,  4)
MAKE_INTERRUPT        (irq5,  irq5_handler,  5)
MAKE_INTERRUPT        (irq6,  irq6_handler,  6)
MAKE_INTERRUPT        (irq7,  irq7_handler,  7)
MAKE_INTERRUPT        (irq8,  irq8_handler,  8)
MAKE_INTERRUPT        (irq9,  irq9_handler,  9)
MAKE_INTERRUPT        (irq10, irq10_handler,  10)
MAKE_INTERRUPT        (irq11, irq11_handler,  11)
MAKE_INTERRUPT        (irq12, irq12_handler,  12)
MAKE_INTERRUPT        (irq13, irq13_handler,  13)
MAKE_INTERRUPT        (irq14, irq14_handler,  14)
MAKE_INTERRUPT        (irq15, irq15_handler,  15)

void init_idt_entry(int num, unsigned int offset, unsigned short select, 
    unsigned short flags)
    {
        
        _idt_entries[num].offset0 = (unsigned short)(offset & 0x000000000000FFFF);
        _idt_entries[num].offset1 = (unsigned short)((offset & 0x00000000FFFF0000) >> 16);
        _idt_entries[num].offset2 = (unsigned int)((offset & 0xFFFFFFFF00000000) >> 32);

        _idt_entries[num].selector = select;
        _idt_entries[num].flags = flags;
         return;
    }




///////////////////////////////////////
void idt_flush(struct idt *idtr)
{
    asm volatile("lidt %0" :: "m"(*idtr));
}

void init_pic()
{

    outb(0x20,0x11);
    outb(0xA0,0x11);

    outb(0x21, 0x20);
    outb(0xA1, 40);

    outb(0x21, 0x04);
    outb(0xA1, 0x02);

    outb(0x21, 0x01);
    outb(0xA1, 0x01);

    outb(0x21, 0x0);
    outb(0xA1, 0x0);

    
}


void init_idt()
{
    init_pic();
    
    _idt_entries = RequestPage();
    Tidt.limit = 16 * 256;
    Tidt.base  = _idt_entries;
    
    memset(_idt_entries, 0, 16*256);
    
    
    
    for(int i = 0; i < 256 ; i++){
        init_idt_entry(i,(int)&isr0,0x08, 0x8E); 
    }
    init_idt_entry(0,(int)&isr0,0x08, 0x8E);
    init_idt_entry(1,(int)&isr1,0x08, 0x8E);
    init_idt_entry(2,(int)&isr2,0x08, 0x8E);
    init_idt_entry(3,(int)&isr3,0x08, 0x8E);
    init_idt_entry(4,(int)&isr4,0x08, 0x8E);
    init_idt_entry(5,(int)&isr5,0x08, 0x8E);
    init_idt_entry(6,(int)&isr6,0x08, 0x8E);
    init_idt_entry(7,(int)&isr7,0x08, 0x8E);
    init_idt_entry(8,(int)&isr8,0x08, 0x8E);
    init_idt_entry(9,(int)&isr9,0x08, 0x8E);
    init_idt_entry(10,(int)&isr10,0x08, 0x8E);
    init_idt_entry(11,(int)&isr11,0x08, 0x8E);
    init_idt_entry(12,(int)&isr12,0x08, 0x8E);
    init_idt_entry(13,(int)&isr13,0x08, 0x8E);
    init_idt_entry(14,(int)&isr14,0x08, 0x8E);
    /* ISR15 is reserved */
    init_idt_entry(16,(int)&isr16,0x08, 0x8E);
    init_idt_entry(17,(int)&isr17,0x08, 0x8E);
    init_idt_entry(18,(int)&isr18,0x08, 0x8E);
    init_idt_entry(19,(int)&isr19,0x08, 0x8E);
    init_idt_entry(20,(int)&isr20,0x08, 0x8E);
    /* ISR21 to ISR2F are reserved */
    init_idt_entry(30,(int)&isr30,0x08, 0x8E);

    /* IRQ handlers */
    init_idt_entry(32,(int)&irq0,0x08, 0x8E);
    init_idt_entry(33,(int)&irq1,0x08, 0x8E);
    init_idt_entry(34,(int)&irq2,0x08, 0x8E);
    init_idt_entry(35,(int)&irq3,0x08, 0x8E);
    init_idt_entry(36,(int)&irq4,0x08, 0x8E);
    init_idt_entry(37,(int)&irq5,0x08, 0x8E);
    init_idt_entry(38,(int)&irq6,0x08, 0x8E);
    init_idt_entry(39,(int)&irq7,0x08, 0x8E);
    init_idt_entry(40,(int)&irq8,0x08, 0x8E);
    init_idt_entry(41,(int)&irq9,0x08, 0x8E);
    init_idt_entry(42,(int)&irq10,0x08, 0x8E);
    init_idt_entry(43,(int)&irq11,0x08, 0x8E);
    init_idt_entry(44,(int)&irq12,0x08, 0x8E);
    init_idt_entry(45,(int)&irq13,0x08, 0x8E);
    init_idt_entry(46,(int)&irq14,0x08, 0x8E);
    init_idt_entry(47,(int)&irq15,0x08, 0x8E);
    
    
    
    SetPITSpeed(100);
    drawStringToCursor("Set PIT speed\n",0xffffff, 0x000000);       
    
    idt_flush(&Tidt);
    
    //int d = 5 / 0;
    //asm volatile("sti;");
    //while(1);
    
}

The general protection fault dissappeared as soon as I commented sti and isr's fire normally, i tried that with the divide by zero error, however now irq's dont fire, I have no idea what is going on.

EDIT: I fixed the issue, the problem was I wasn't setting the stack properly

"sub $0x28, %rsp\n\t"\
            "cld\n\t" \
            "call " #intfunc "\n\t" \
            "add $28, %rsp\n\t"  

I forgot the 0x in front of 28 in the last instruction. So embarrassing. Also I wrote 10 instead of 8 here

#define POPALL\
    ".intel_syntax noprefix\n\t" \
    "pop     rdi\n\t"\
    "pop     rsi\n\t"\
    "pop     rbp\n\t"\
    "add     rsp, 10\n\t"\
    "pop     rbx\n\t"\
    "pop     rdx\n\t"\


  • 1
    I would suggest to not mix different asm flavors in the same file - it makes the source more difficult to read. At what instruction does the GPF actually occur? Have you tried running the code through gdb+qemu or bochs? At least one visible issue here seems to be in the way you are handling the stack in the ISR macros: it adds decimal 10 to `rsp` in multiple occasions, which conflicts with the size of what's actually pushed. – Chris Smeele Apr 16 '21 at 01:21

0 Answers0