I am currently writing a toy operating system, and I have been having this issue for a while now. When setting up the IDT for a hobby OS, and triggering an interrupt, the interrupt at first happens with what seems like no error's, however I then start receiving general protection faults in a loop.
I assume this is a problem with my assembly, as when rewriting the C functions, the error still occurs.
idt.asm
jmp Idt_End ;Jump to prevent any functions from being called
[GLOBAL Idt_Flush] ;Allow C to call the flush function
Idt_Flush: ;Load an IDT passed from a pointer
mov eax, [esp+4] ;IDT is going to be passed as a pointer
lidt [eax] ;Load the IDT passed
ret ;Return from the function
%macro ISR_NOERRCODE 1 ;Macro for generating errorless ISR's
[GLOBAL Idt_Isr%1] ;Create a ISR with peram number
Idt_Isr%1: ;Actual ISR code
;cli
push byte 0
push byte %1
jmp isr_common_stub
%endmacro
%macro ISR_ERRCODE 1 ;Same macro as above with with errors
[GLOBAL Idt_Isr%1]
Idt_Isr%1:
;cli
push byte %1
jmp isr_common_stub
%endmacro
ISR_NOERRCODE 0 ;ISR num 0
ISR_NOERRCODE 1 ;ISR num 1
ISR_NOERRCODE 2 ;ISR num 2
ISR_NOERRCODE 3 ;ISR num 3
ISR_NOERRCODE 4 ;ISR num 4
ISR_NOERRCODE 5 ;ISR num 5
ISR_NOERRCODE 6 ;ISR num 6
ISR_NOERRCODE 7 ;ISR num 7
ISR_ERRCODE 8 ;ISR num 8 (ISR WITH ERROR CODE)
ISR_NOERRCODE 9 ;ISR num 9
ISR_ERRCODE 10 ;ISR num 10 (ISR WITH ERROR CODE)
ISR_ERRCODE 11 ;ISR num 11 (ISR WITH ERROR CODE)
ISR_ERRCODE 12 ;ISR num 12 (ISR WITH ERROR CODE)
ISR_ERRCODE 13 ;ISR num 13 (ISR WITH ERROR CODE)
ISR_ERRCODE 14 ;ISR num 14 (ISR WITH ERROR CODE)
ISR_NOERRCODE 15 ;ISR num 15
ISR_NOERRCODE 16 ;ISR num 16
ISR_ERRCODE 17 ;ISR num 17 (ISR WITH ERROR CODE)
ISR_NOERRCODE 18 ;ISR num 18
ISR_NOERRCODE 19 ;ISR num 19
ISR_NOERRCODE 20 ;ISR num 20
ISR_NOERRCODE 21 ;ISR num 21
ISR_NOERRCODE 22 ;ISR num 22
ISR_NOERRCODE 23 ;ISR num 23
ISR_NOERRCODE 24 ;ISR num 24
ISR_NOERRCODE 25 ;ISR num 25
ISR_NOERRCODE 26 ;ISR num 26
ISR_NOERRCODE 27 ;ISR num 27
ISR_NOERRCODE 28 ;ISR num 28
ISR_NOERRCODE 29 ;ISR num 29
ISR_ERRCODE 30 ;ISR num 30
ISR_NOERRCODE 31 ;ISR num 31
[extern IDT_IsrHandler] ;Extern the ISR handling code
isr_common_stub:
pusha ;Push registers to the stack
mov ax, ds ;lower 16 bits is in the ds register
push eax ;Save the segment descriptor onto stack
mov ax, 0x10 ;Load the kernel segment descriptor
mov ds, ax ;Set the segment register's
mov es, ax ;Set the segment register's
mov fs, ax ;Set the segment register's
mov gs, ax ;Set the segment register's
call IDT_IsrHandler ;C function to handle ISR's
pop eax ;Reload the original segment descripors
mov ds, ax ;Clear segment register's
mov es, ax ;Clear segment register's
mov fs, ax ;Clear segment register's
mov gs, ax ;Clear segment register's
popa ;Pops registers pushed in `pusha`
add esp, 8 ;Clean up error code and push number
sti ;Set the current interrupt being handled
iret ;Pop CS, EIP, EFLAGS, ESP, and SS and return
Idt_End:
idt.h
#ifndef __KERNEL_IDT_H__
#define __KERNEL_IDT_H__
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "./tty.h"
#define IDT_ENTRIES 246
#define KERNEL_CS 0x08
#define low_16(addr) (uint16_t)((addr) & 0xFFFF)
#define high_16(addr) (uint16_t)(((addr) >> 16) & 0xFFFF)
typedef struct { /*Struct containing IDT gate info */
uint16_t low_offset; /*Lower 16 bits of function address */
uint16_t sel; /*Kernel selector */
uint8_t zero; /*Has to be zero for some reason */
uint8_t flags; /*Table flags */
uint16_t high_offset; /*HIgher 16 bits of function address */
} __attribute__((packed)) Idt_gate_t; /*Idt gate struct */
typedef struct { /*Used to tell where handlers are */
uint16_t limit;
uint32_t base;
} __attribute__((packed)) Idt_register_t;
typedef struct { /*Struct containing register data */
uint32_t ds; /*Data segment selector */
uint32_t edi; /*Register pushed by pusha */
uint32_t esi; /*Register pushed by pusha */
uint32_t ebp; /*Register pushed by pusha */
uint32_t esp; /*Register pushed by pusha */
uint32_t ebx; /*Register pushed by pusha */
uint32_t edx; /*Register pushed by pusha */
uint32_t ecx; /*Register pushed by pusha */
uint32_t eax; /*Register pushed by pusha */
uint32_t int_number; /*Current interupt number given */
uint32_t err_number; /*Error number that the CPU passes to us */
uint32_t eip; /*Pushed by the CPU */
uint32_t cs; /*Pushed by the CPU */
uint32_t eflags; /*Pushed by the CPU */
uint32_t useresp; /*Pushed by the CPU */
uint32_t ss; /*Pushed by the CPU */
} Reg_registers_t; /*Structure containing register data */
Idt_gate_t Idt_idt[IDT_ENTRIES]; /*The actual interupt descriptor table */
Idt_register_t idt_reg; /*IDT register pointer */
extern void Idt_Flush(uint32_t); /*Initalize the Interupt descriptor table*/
extern void Idt_Isr0();
extern void Idt_Isr1();
extern void Idt_Isr2();
extern void Idt_Isr3();
extern void Idt_Isr4();
extern void Idt_Isr5();
extern void Idt_Isr6();
extern void Idt_Isr7();
extern void Idt_Isr8();
extern void Idt_Isr9();
extern void Idt_Isr10();
extern void Idt_Isr11();
extern void Idt_Isr12();
extern void Idt_Isr13();
extern void Idt_Isr14();
extern void Idt_Isr15();
extern void Idt_Isr16();
extern void Idt_Isr17();
extern void Idt_Isr18();
extern void Idt_Isr19();
extern void Idt_Isr20();
extern void Idt_Isr21();
extern void Idt_Isr22();
extern void Idt_Isr23();
extern void Idt_Isr24();
extern void Idt_Isr25();
extern void Idt_Isr26();
extern void Idt_Isr27();
extern void Idt_Isr28();
extern void Idt_Isr29();
extern void Idt_Isr30();
extern void Idt_Isr31();
void Idt_SetGate(int number, uint32_t handler) { /*Set the value to for 1 gate */
Idt_idt[number].low_offset = low_16(handler); /*Set the lower 16 bytes of the address */
Idt_idt[number].high_offset = high_16(handler); /*Set the higher 16 bytes of the address */
Idt_idt[number].zero = 0; /*No idea why intel thought this was good*/
Idt_idt[number].flags = 0x8E; /*Set the flags of the current IDT */
Idt_idt[number].sel = KERNEL_CS; /*Set the selector of IDT to kernel CS */
}
void Idt_Install() { /*Install idt **assuming already setup** */
idt_reg.base = (uint32_t) &Idt_idt; /*Set the base to IDT addr */
idt_reg.limit = IDT_ENTRIES * sizeof(Idt_gate_t) - 1; /*Limit to size of the IDT array */
__asm__ volatile ("lidtl (%0)" : : "r" (&idt_reg)); /*Assembly function to load the IDT */
}
void Idt_Isr_Install() { /*Install isr's for interrupts to work */
Idt_SetGate(0 , (uint32_t)Idt_Isr0); /*Install the current IDT gate */
Idt_SetGate(1 , (uint32_t)Idt_Isr1); /*Install the current IDT gate */
Idt_SetGate(2 , (uint32_t)Idt_Isr2); /*Install the current IDT gate */
Idt_SetGate(3 , (uint32_t)Idt_Isr3); /*Install the current IDT gate */
Idt_SetGate(4 , (uint32_t)Idt_Isr4); /*Install the current IDT gate */
Idt_SetGate(5 , (uint32_t)Idt_Isr5); /*Install the current IDT gate */
Idt_SetGate(6 , (uint32_t)Idt_Isr6); /*Install the current IDT gate */
Idt_SetGate(7 , (uint32_t)Idt_Isr7); /*Install the current IDT gate */
Idt_SetGate(8 , (uint32_t)Idt_Isr8); /*Install the current IDT gate */
Idt_SetGate(9 , (uint32_t)Idt_Isr9); /*Install the current IDT gate */
Idt_SetGate(10 ,(uint32_t)Idt_Isr10); /*Install the current IDT gate */
Idt_SetGate(11 ,(uint32_t)Idt_Isr11); /*Install the current IDT gate */
Idt_SetGate(12 ,(uint32_t)Idt_Isr12); /*Install the current IDT gate */
Idt_SetGate(13 ,(uint32_t)Idt_Isr13); /*Install the current IDT gate */
Idt_SetGate(14 ,(uint32_t)Idt_Isr14); /*Install the current IDT gate */
Idt_SetGate(15 ,(uint32_t)Idt_Isr15); /*Install the current IDT gate */
Idt_SetGate(16 ,(uint32_t)Idt_Isr16); /*Install the current IDT gate */
Idt_SetGate(17 ,(uint32_t)Idt_Isr17); /*Install the current IDT gate */
Idt_SetGate(18 ,(uint32_t)Idt_Isr18); /*Install the current IDT gate */
Idt_SetGate(19 ,(uint32_t)Idt_Isr19); /*Install the current IDT gate */
Idt_SetGate(20 ,(uint32_t)Idt_Isr20); /*Install the current IDT gate */
Idt_SetGate(21 ,(uint32_t)Idt_Isr21); /*Install the current IDT gate */
Idt_SetGate(22 ,(uint32_t)Idt_Isr22); /*Install the current IDT gate */
Idt_SetGate(23 ,(uint32_t)Idt_Isr23); /*Install the current IDT gate */
Idt_SetGate(24 ,(uint32_t)Idt_Isr24); /*Install the current IDT gate */
Idt_SetGate(25 ,(uint32_t)Idt_Isr25); /*Install the current IDT gate */
Idt_SetGate(26 ,(uint32_t)Idt_Isr26); /*Install the current IDT gate */
Idt_SetGate(27 ,(uint32_t)Idt_Isr27); /*Install the current IDT gate */
Idt_SetGate(28 ,(uint32_t)Idt_Isr28); /*Install the current IDT gate */
Idt_SetGate(29 ,(uint32_t)Idt_Isr29); /*Install the current IDT gate */
Idt_SetGate(30 ,(uint32_t)Idt_Isr30); /*Install the current IDT gate */
Idt_SetGate(31 ,(uint32_t)Idt_Isr31); /*Install the current IDT gate */
Idt_Install(); /*Actually install the current gate */
}
static void Idt_Init() { /*Init the IDT descriptor table */
Idt_Isr_Install();
}
void IDT_IsrHandler(Reg_registers_t reg) {
Terminal_WriteString("Interrupt executed: ");
Terminal_WriteHex(reg.int_number);
Terminal_WriteString("\n");
}
#endif