I tried to setup a GDT and an IDT for the x86_64 target following multiple sources, from this website and other.
From what I can understand, qemu crashes when I make the call
Code: Select all
asm volatile("int $30");Running qemu with -D -d int gives me this :
Code: Select all
...
0: v=1e e=0000 i=1 cpl=0 IP=0008:ffffffff80003535 pc=ffffffff80003535 SP=0010:ffff800007f9afd8 env->regs[R_EAX]=0000000000000000
RAX=0000000000000000 RBX=ffffffff80003530 RCX=00000000000003e8 RDX=0000000000000000
RSI=0000000000000000 RDI=000000000000001e RBP=ffff800007f9aff0 RSP=ffff800007f9afd8
R8 =ffffffff80006d40 R9 =0000000000000019 R10=0000000000000028 R11=0000000000000500
R12=ffffffff800036e0 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=ffffffff80003535 RFL=00000246 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 ffffffff 00af9300 DPL=0 DS [-WA]
CS =0008 0000000000000000 ffffffff 00af9a00 DPL=0 CS64 [-R-]
SS =0010 0000000000000000 ffffffff 00af9300 DPL=0 DS [-WA]
DS =0010 0000000000000000 ffffffff 00af9300 DPL=0 DS [-WA]
FS =0010 0000000000000000 ffffffff 00af9300 DPL=0 DS [-WA]
GS =0010 0000000000000000 ffffffff 00af9300 DPL=0 DS [-WA]
LDT=0000 0000000000000000 00000000 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= ffffffff8005ae40 00000017
IDT= ffffffff80059e40 0000000f
CR0=80010011 CR2=0000000000000000 CR3=0000000007f8a000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=000000000000001e CCD=0000000000000000 CCO=SUBL
EFER=0000000000000d00
check_exception old: 0xffffffff new 0xd
1: v=0d e=01e2 i=0 cpl=0 IP=0008:ffffffff80003535 pc=ffffffff80003535 SP=0010:ffff800007f9afd8 env->regs[R_EAX]=0000000000000000
RAX=0000000000000000 RBX=ffffffff80003530 RCX=00000000000003e8 RDX=0000000000000000
RSI=0000000000000000 RDI=000000000000001e RBP=ffff800007f9aff0 RSP=ffff800007f9afd8
R8 =ffffffff80006d40 R9 =0000000000000019 R10=0000000000000028 R11=0000000000000500
R12=ffffffff800036e0 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=ffffffff80003535 RFL=00000246 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 ffffffff 00af9300 DPL=0 DS [-WA]
CS =0008 0000000000000000 ffffffff 00af9a00 DPL=0 CS64 [-R-]
SS =0010 0000000000000000 ffffffff 00af9300 DPL=0 DS [-WA]
DS =0010 0000000000000000 ffffffff 00af9300 DPL=0 DS [-WA]
FS =0010 0000000000000000 ffffffff 00af9300 DPL=0 DS [-WA]
GS =0010 0000000000000000 ffffffff 00af9300 DPL=0 DS [-WA]
LDT=0000 0000000000000000 00000000 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= ffffffff8005ae40 00000017
IDT= ffffffff80059e40 0000000f
CR0=80010011 CR2=0000000000000000 CR3=0000000007f8a000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=000000000000001e CCD=0000000000000000 CCO=SUBL
EFER=0000000000000d00
check_exception old: 0xd new 0xd
2: v=08 e=0000 i=0 cpl=0 IP=0008:ffffffff80003535 pc=ffffffff80003535 SP=0010:ffff800007f9afd8 env->regs[R_EAX]=0000000000000000
RAX=0000000000000000 RBX=ffffffff80003530 RCX=00000000000003e8 RDX=0000000000000000
RSI=0000000000000000 RDI=000000000000001e RBP=ffff800007f9aff0 RSP=ffff800007f9afd8
R8 =ffffffff80006d40 R9 =0000000000000019 R10=0000000000000028 R11=0000000000000500
R12=ffffffff800036e0 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=ffffffff80003535 RFL=00000246 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 ffffffff 00af9300 DPL=0 DS [-WA]
CS =0008 0000000000000000 ffffffff 00af9a00 DPL=0 CS64 [-R-]
SS =0010 0000000000000000 ffffffff 00af9300 DPL=0 DS [-WA]
DS =0010 0000000000000000 ffffffff 00af9300 DPL=0 DS [-WA]
FS =0010 0000000000000000 ffffffff 00af9300 DPL=0 DS [-WA]
GS =0010 0000000000000000 ffffffff 00af9300 DPL=0 DS [-WA]
LDT=0000 0000000000000000 00000000 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= ffffffff8005ae40 00000017
IDT= ffffffff80059e40 0000000f
CR0=80010011 CR2=0000000000000000 CR3=0000000007f8a000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=000000000000001e CCD=0000000000000000 CCO=SUBL
EFER=0000000000000d00
check_exception old: 0x8 new 0xd
Here, pc point to my call to int mentioned in the beginning. The GTF does not occur during the setup of GDT&IDT because qemu crashes only there in the kernel : (Note : test_interrupt(k) print k on the screen if k!=30 else call `int $30`)
Code: Select all
void kmain(void) {
// Ensure the bootloader actually understands our base revision (see spec).
if (LIMINE_BASE_REVISION_SUPPORTED == false) abort();
GDT_initialize();
IDT_initialize();
terminal_initialize();
wait(1000);
test_interrupt(1);
wait(1000);
test_interrupt(30); // There, it crashes
// We're done, just hang...
abort();
}- it may be an error of paging but Limine (the bootloader) already set a working paging
- I may have messed up my setup of IDT or GDT but according to GDB, just before calling test_interrupt(30), IDTR and GDTR are both well defined
- I already do a long jump after the GDT setup (ref https://wiki.osdev.org/I_Can%27t_Get_In ... _interrupt)
Here are my GDT & IDT Files
GDT
load.asm
Code: Select all
[bits 64]
; Tells the CPU where the GDT is located
global GDT_load
GDT_load:
lgdt [rdi]
call reload_segments
reload_segments:
push 0x08
lea rax, [rel .reload_cs]
push rax
retfq
.reload_cs:
; reload data segments
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
retCode: Select all
#include <stdlib.h>
#include <stdint.h>
#include <kernel/gdt.h>
typedef struct {
uint16_t LimitLow; // limit (bits 0-15)
uint16_t BaseLow; // base (bits 0-15)
uint8_t BaseMiddle; // base (bits 16-13)
uint8_t Access; // access (bits 0-7)
uint8_t FlagsLimitHi; // limit (bits 16-19) | flags
uint8_t BaseHigh; // base (bits 24-31)
} __attribute__((packed)) GDTEntry;
typedef struct {
uint16_t Limit; // sizeof(gdt) - 1
GDTEntry* Ptr; // address of GDT
} __attribute__((packed)) GDTDescriptor;
typedef enum {
GDT_ACCESS_CODE_READABLE = 0x02,
GDT_ACCESS_DATA_WRITABLE = 0x02,
GDT_ACCESS_CODE_CONFORMING = 0x04,
GDT_ACCESS_DATA_DIRECTION_NORMAL = 0x00,
GDT_ACCESS_DATA_DIRECTION_DOWN = 0x04,
GDT_ACCESS_DATA_SEGMENT = 0x10,
GDT_ACCESS_CODE_SEGMENT = 0x18,
GDT_ACCESS_DSECRIPTOR_TSS = 0x00,
GDT_ACCESS_RING0 = 0x00,
GDT_ACCESS_RING1 = 0x20,
GDT_ACCESS_RING2 = 0x40,
GDT_ACCESS_RING3 = 0x60,
GDT_ACCESS_PRESENT = 0x80,
} GDT_ACCESS;
typedef enum {
GDT_FLAG_64BIT = 0x20,
GDT_FLAG_32BIT = 0x40,
GDT_FLAG_16BIT = 0x00,
GDT_FLAG_GRANULARITY_1B = 0x00,
GDT_FLAG_GRANULARITY_4K = 0x80,
} GDT_FLAGS;
GDTEntry g_GDT[3];
GDTDescriptor g_GDTDescriptor = { sizeof(g_GDT) - 1, g_GDT};
// Asm Function
void GDT_load(GDTDescriptor* descriptor, uint16_t codeSegment, uint16_t dataSegment);
GDTEntry encodeGDTEntry(uint32_t base, uint32_t limit, uint8_t access, uint8_t flags) {
return (GDTEntry) {
limit & 0xFFFF,
base & 0xFFFF,
((base >> 16) & 0xFF),
access,
(((limit>>16) & 0x0F) | (flags & 0xF0)),
((base >> 24) & 0xFF)
};
}
void GDT_initialize(void){
asm volatile("cli");
// Null
g_GDT[0] = encodeGDTEntry(0, 0, 0, 0);
// Kernel 64-bit code segment
g_GDT[1] = encodeGDTEntry(0,
0xFFFFF,
GDT_ACCESS_PRESENT | GDT_ACCESS_RING0 | GDT_ACCESS_CODE_SEGMENT | GDT_ACCESS_CODE_READABLE,
GDT_FLAG_64BIT | GDT_FLAG_GRANULARITY_4K);
// Kernel 64-bit data segment
g_GDT[2] = encodeGDTEntry(0,
0xFFFFF,
GDT_ACCESS_PRESENT | GDT_ACCESS_RING0 | GDT_ACCESS_DATA_SEGMENT | GDT_ACCESS_DATA_WRITABLE,
GDT_FLAG_64BIT | GDT_FLAG_GRANULARITY_4K);
GDT_load(&g_GDTDescriptor, x86_64_GDT_CODE_SEGMENT, x86_64_GDT_DATA_SEGMENT);
asm volatile("sti");
}
Code: Select all
#ifndef _GDT_H
#define _GDT_H
#define x86_64_GDT_CODE_SEGMENT 0x8
#define x86_64_GDT_DATA_SEGMENT 0x10
void GDT_initialize(void);
#endifidt.c
Code: Select all
#include <stdint.h>
#include <stdio.h>
#include <kernel/idt.h>
#include <kernel/gdt.h>
#include <kernel/tty.h>
#include "irq.h"
#include "isr.h"
uint64_t irq(){return 1LL<<63;};
typedef struct {
uint16_t BaseLow;
uint16_t SegmentSelector;
uint8_t IstReserved;
uint8_t Flags;
uint16_t BaseHigh;
uint32_t Offset;
uint32_t Zeros;
} __attribute__((packed)) IDTEntry;
typedef struct {
uint16_t Limit;
IDTEntry* Ptr;
} __attribute__((packed)) IDTDescriptor;
typedef enum {
IDT_FLAG_GATE_TASK = 0x05,
IDT_FLAG_GATE_16BIT_INT = 0x06,
IDT_FLAG_GATE_16BIT_TRAP = 0x07,
IDT_FLAG_GATE_32BIT_INT = 0x0E,
IDT_FLAG_GATE_32BIT_TRAP = 0x0F,
IDT_FLAG_RING0 = (0 << 5),
IDT_FLAG_RING1 = (1 << 5),
IDT_FLAG_RING2 = (2 << 5),
IDT_FLAG_RING3 = (3 << 5),
IDT_FLAG_PRESENT = 0x80,
} IDT_FLAGS;
IDTEntry g_IDT[256];
IDTDescriptor g_IDTDescriptor = { sizeof(*g_IDT) - 1, g_IDT };
// Asm Function
extern void IDT_load(IDTDescriptor* descriptor);
IDTEntry IDT_set_gate(uint64_t base, uint16_t segmentDescriptor, uint8_t flags){
return (IDTEntry) {
base & 0xFFFF,
segmentDescriptor,
0,
flags,
(base >> 16) & 0xFFFF,
(base >> 32) & 0xFFFFFFFF,
0
};
}
void IDT_enable_gate(int interrupt){
g_IDT[interrupt].Flags |= IDT_FLAG_PRESENT;
}
void IDT_disable_gate(int interrupt){
g_IDT[interrupt].Flags &= ~(IDT_FLAG_PRESENT);
}
void IDT_mapping(IDTEntry* g_IDT){
// Software input
g_IDT[0] = IDT_set_gate((uint64_t) &isr0, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[1] = IDT_set_gate((uint64_t) &isr1, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[2] = IDT_set_gate((uint64_t) &isr2, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[3] = IDT_set_gate((uint64_t) &isr3, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[4] = IDT_set_gate((uint64_t) &isr4, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[5] = IDT_set_gate((uint64_t) &isr5, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[6] = IDT_set_gate((uint64_t) &isr6, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[7] = IDT_set_gate((uint64_t) &isr7, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[8] = IDT_set_gate((uint64_t) &isr8, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[9] = IDT_set_gate((uint64_t) &isr9, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[10] = IDT_set_gate((uint64_t) &isr10, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[11] = IDT_set_gate((uint64_t) &isr11, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[12] = IDT_set_gate((uint64_t) &isr12, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[13] = IDT_set_gate((uint64_t) &isr13, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[14] = IDT_set_gate((uint64_t) &isr14, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[15] = IDT_set_gate((uint64_t) &isr15, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[16] = IDT_set_gate((uint64_t) &isr16, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[17] = IDT_set_gate((uint64_t) &isr17, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[18] = IDT_set_gate((uint64_t) &isr18, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[19] = IDT_set_gate((uint64_t) &isr19, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[20] = IDT_set_gate((uint64_t) &isr20, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[21] = IDT_set_gate((uint64_t) &isr21, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[22] = IDT_set_gate((uint64_t) &isr22, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[23] = IDT_set_gate((uint64_t) &isr23, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[24] = IDT_set_gate((uint64_t) &isr24, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[25] = IDT_set_gate((uint64_t) &isr25, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[26] = IDT_set_gate((uint64_t) &isr26, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[27] = IDT_set_gate((uint64_t) &isr27, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[28] = IDT_set_gate((uint64_t) &isr28, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[29] = IDT_set_gate((uint64_t) &isr29, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[30] = IDT_set_gate((uint64_t) &isr30, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[31] = IDT_set_gate((uint64_t) &isr31, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
// Hardware input
g_IDT[32] = IDT_set_gate((uint64_t) &irq0, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[33] = IDT_set_gate((uint64_t) &irq1, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[34] = IDT_set_gate((uint64_t) &irq2, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[35] = IDT_set_gate((uint64_t) &irq3, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[36] = IDT_set_gate((uint64_t) &irq4, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[37] = IDT_set_gate((uint64_t) &irq5, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[38] = IDT_set_gate((uint64_t) &irq6, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[39] = IDT_set_gate((uint64_t) &irq7, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[40] = IDT_set_gate((uint64_t) &isr8, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[41] = IDT_set_gate((uint64_t) &isr9, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[42] = IDT_set_gate((uint64_t) &irq10, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[43] = IDT_set_gate((uint64_t) &irq11, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[44] = IDT_set_gate((uint64_t) &irq12, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[45] = IDT_set_gate((uint64_t) &irq13, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[46] = IDT_set_gate((uint64_t) &irq14, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
g_IDT[47] = IDT_set_gate((uint64_t) &irq15, x86_64_GDT_CODE_SEGMENT, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
// ... Systems calls etc
}
void IDT_initialize(){
asm volatile("cli");
IDT_mapping(g_IDT);
IDT_load(&g_IDTDescriptor);
asm volatile("sti");
}
void test_interrupt(int int_no){
if (int_no == 30){
asm volatile("int $30");
} else {
printf("Interrupt test on %d called !\n", int_no);
}
}Code: Select all
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <kernel/idt.h>
#include <kernel/tty.h>
char* exception_messages[] = {
"Division by 0",
"Debug",
"Non Maskable Interrupt",
"Breakpoint",
"Into Detected Overflow",
"Out of bounds",
"Invalid Opcode",
"No Coprocessor",
"Double fault (pushes an error code)",
"Coprocessor Segment Overrun",
"Bad TSS (pushes an error code)",
"Segment not present (pushed an error code)",
"Stack Fault (pushed an error code)",
"General Protection fault (pushed an error code)",
"Page Fault (pushed an error code)",
"Unknown Interrupt",
"Coprocessor Fault",
"Alignement Fault",
"Machine Check",
"SIMD (SSE/AVX) error",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
};
void cpu_exception_handler(registers_t* regs){
printf("Received Interrupt : %d\n%s\nError Code :%d\nSystem Halted!\n",
regs->int_no, exception_messages[regs->int_no], regs->err_code);
abort();
}
// Handler for general page fault
void gpf_handler(registers_t* regs){
printf("%s\n", exception_messages[regs->int_no]);
printf("Received Interrupt: %d\n", regs->int_no);
printf("Error code: %d\n", regs->err_code);
printf("CS: %d, RIP: %d\n", regs->iret_cs, regs->iret_rip);
uint64_t* rsp = (uint64_t*) regs->iret_rsp;
printf("Stack (rsp = %d) Contents(First 26):\n", (int) rsp);
for(int i=0; i<26; i++){
printf(" [%d] = %d\n", rsp+i, rsp[i]);
}
printf("System Halted! \n");
abort();
}
void page_fault_handler(registers_t* regs){
uint64_t faulting_address;
asm volatile("mov %%cr2, %0" : "=r"(faulting_address));
int present = !(regs->err_code & 0x1); // Page not present
int rw = regs->err_code & 0x2; // Write operation
int us = regs->err_code & 0x4; // Processor was in user mode ?
int reserved = regs->err_code & 0x8; // Overwritten CPU-reserved bits of page entry ?
int id = regs->err_code & 0x10; // Cased by an intruction fetch ?
printf("Page fault ! (");
if (present) printf("Page not present, ");
if (rw) printf("Not writable, ");
if (us) printf("User-mode, ");
if (reserved) printf("Reserved, ");
if (id) printf("Intruction fetch, ");
printf(") at address %d\n", 0);
printf("Halting the system due to page fault.\n");
abort();
}
void isr_handler(registers_t* regs){
if (regs->int_no == 14){
// page fault
abort();
return;
} else if (regs->int_no == 13){
gpf_handler(regs);
return;
} else if (regs->int_no < 32){
cpu_exception_handler(regs);
return;
} else {
terminal_setcolor(0x00FF00);
for(int i=0; i<regs->int_no; i++) printf("Received Interrupt : %d\n", regs->int_no);
terminal_setcolor(0xFFFFFF);
return;
}
}
// All IRQ Routines (256 - 32 first reserved)
void (*irq_routines[224])(registers_t *) = {0};
void irq_handler(registers_t* regs){
void (*handler)(registers_t *regs); // Blank function pointer
int irq_no = regs->int_no - 32; // Int number without the 32 first reserved
handler = irq_routines[irq_no];
if (handler){
handler(regs);
}
// Apic ?
}
void irq_install(int irq_no, void(*handler)(registers_t *r)){
irq_routines[irq_no] = handler;
}
void irq_uninstall(int irq_no){
irq_routines[irq_no] = 0;
}Code: Select all
[extern isr_handler]
%macro ISR_NOERRCODE 1
[global isr%1]
isr%1:
cli;
push 0 ; Push dummy error code
push %1 ; Interrupt number
push r15 ; Save general-purpose registers in reverse order (to match restore_registers)
push r14
push r13
push r12
push r11
push r10
push r9
push r8
push rsi
push rdi
push rbp
push rdx
push rcx
push rbx
push rax
mov ax, ds ; save segment registers
push rax
mov ax, es
push rax
push fs
push gs
mov rdi, rsp ; pass pointer to the registers_t structure
cld
call isr_handler
pop gs ; restore segment registers
pop fs
pop rax
mov es, ax
pop rax
mov ds, ax
pop rax ; restore general-purpose registers
pop rbx
pop rcx
pop rdx
pop rbp
pop rdi
pop rsi
pop r8
pop r9
pop r10
pop r11
pop r12
pop r13
pop r14
pop r15
add rsp, 16 ; clean up interrupt no & dummy error
iretq ; return from interrupt
%endmacro
%macro ISR_ERRCODE 1
[global isr%1]
isr%1:
cli;
push %1 ; Interrupt number
push r15 ; Save general-purpose registers in reverse order (to match restore_registers)
push r14
push r13
push r12
push r11
push r10
push r9
push r8
push rsi
push rdi
push rbp
push rdx
push rcx
push rbx
push rax
mov ax, ds ; save segment registers
push rax
mov ax, es
push rax
push fs
push gs
mov rdi, rsp ; pass pointer to the registers_t structure
cld
call isr_handler
pop gs ; restore segment registers
pop fs
pop rax
mov es, ax
pop rax
mov ds, ax
pop rax ; restore general-purpose registers
pop rbx
pop rcx
pop rdx
pop rbp
pop rdi
pop rsi
pop r8
pop r9
pop r10
pop r11
pop r12
pop r13
pop r14
pop r15
add rsp, 16 ; clean up interrupt no & dummy error
iretq ; return from interrupt
%endmacro
ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
ISR_NOERRCODE 3
ISR_NOERRCODE 4
ISR_NOERRCODE 5
ISR_NOERRCODE 6
ISR_NOERRCODE 7
ISR_ERRCODE 8
ISR_NOERRCODE 9
ISR_ERRCODE 10
ISR_ERRCODE 11
ISR_ERRCODE 12
ISR_ERRCODE 13
ISR_ERRCODE 14
ISR_NOERRCODE 15
ISR_NOERRCODE 16
ISR_NOERRCODE 17
ISR_NOERRCODE 18
ISR_NOERRCODE 19
ISR_NOERRCODE 20
ISR_NOERRCODE 21
ISR_NOERRCODE 22
ISR_NOERRCODE 23
ISR_NOERRCODE 24
ISR_NOERRCODE 25
ISR_NOERRCODE 26
ISR_NOERRCODE 27
ISR_NOERRCODE 28
ISR_NOERRCODE 29
ISR_NOERRCODE 30
ISR_NOERRCODE 31
ISR_NOERRCODE 48 ; APIC Timer
ISR_NOERRCODE 49 ; HPET Timer
Code: Select all
[extern irq_handler]
%macro IRQ 2
[global irq%1]
irq%1:
cli;
push 0 ; Dummy errorcode
push %2 ; Interrupt number
push r15 ; Save general-purpose registers in reverse order (to match restore_registers)
push r14
push r13
push r12
push r11
push r10
push r9
push r8
push rsi
push rdi
push rbp
push rdx
push rcx
push rbx
push rax
mov ax, ds ; save segment registers
push rax
mov ax, es
push rax
push fs
push gs
mov rdi, rsp ; pass pointer to the registers_t structure
cld
call irq_handler
pop gs ; restore segment registers
pop fs
pop rax
mov es, ax
pop rax
mov ds, ax
pop rax ; restore general-purpose registers
pop rbx
pop rcx
pop rdx
pop rbp
pop rdi
pop rsi
pop r8
pop r9
pop r10
pop r11
pop r12
pop r13
pop r14
pop r15
add rsp, 16 ; clean up interrupt no & dummy error
iretq ; return from interrupt
%endmacro
; First the irq number then the interrupt number
IRQ 0, 32
IRQ 1, 33 ; Keyboard Interrupt
IRQ 2, 34
IRQ 3, 35
IRQ 4, 36
IRQ 5, 37
IRQ 6, 38
IRQ 7, 39
IRQ 8, 40
IRQ 9, 41
IRQ 10, 42
IRQ 11, 43
IRQ 12, 44 ; Mouse Interrupt
IRQ 13, 45
IRQ 14, 46
IRQ 15, 47
IRQ 16, 48 ; APIC Timer Interrupt
IRQ 17, 49 ; HPET Timer Interrupt
IRQ 18, 50 ; IPI
IRQ 19, 51
IRQ 96, 128 ; System CallCode: Select all
[bits 64]
; Tells the CPU where the IDT is located
global IDT_load
IDT_load:
cli
lidt [rdi]
sti
ret
Code: Select all
#ifndef _IDT_H
#define _IDT_H
#include <stdint.h>
typedef struct {
// Segment registers
uint64_t gs;
uint64_t fs;
uint64_t es;
uint64_t ds;
// General purpose registers
uint64_t rax;
uint64_t rbx;
uint64_t rcx;
uint64_t rdx;
uint64_t rbp;
uint64_t rdi;
uint64_t rsi;
uint64_t r9;
uint64_t r10;
uint64_t r11;
uint64_t r12;
uint64_t r13;
uint64_t r14;
uint64_t r15;
uint64_t int_no;
uint64_t err_code;
// Automattically pushed registers during interrupt
uint64_t iret_rip;
uint64_t iret_cs;
uint64_t iret_rflags;
uint64_t iret_rsp;
uint64_t iret_ss;
} __attribute__((packed)) registers_t;
void IDT_initialize(void);
void test_interrupt(int int_no);
extern void irq_install(int irq_no, void(*handler)(registers_t*));
#endif

