summaryrefslogtreecommitdiff
path: root/src/arch/amd64/idt.c
blob: c903ca8470310c9f9a65d9510d184f53d8f690c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include <stdint.h>
#include <stddef.h>
#include <panic.h>
#include <lib.h>
#include <serial.h>

#include "idt.h"

#define IDT_SIZE 256

struct idt_entry {
	uint16_t isr_low;    // low 16 bits of isr
	uint16_t kernel_cs;  // kernel segment selector
	uint8_t ist;         // interrupt stack table
	uint8_t flags;       // gate type, privilege level, present bit
	uint16_t isr_mid;    // middle 16 bits of isr
	uint32_t isr_high;   // high 32 bits of isr
	uint32_t reserved;
} __attribute__((packed));

struct idtr {
	uint16_t size;
	uint64_t address;
} __attribute__((packed));

// interrupt gate
#define GATE_64BIT_INT  0x0E
// trap gate
#define GATE_64BIT_TRAP 0x0F

// privilege ring allowed to call interrupt
#define RING0 0x00
#define RING1 0x20
#define RING2 0x40
#define RING3 0x60

// interrupt is present in IDT
#define PRESENT 0x80

__attribute__((aligned(0x10)))
static struct idt_entry idt[256];

static struct idtr idtr;
// from idt.S
extern void *isr_stub_table[];

// initialize and load the IDT
void idt_init(void) {
	// initialize idtr
	idtr.address = (uint64_t)&idt;
	idtr.size = (uint16_t)sizeof(struct idt_entry) * IDT_SIZE - 1;

	// initialize idt
	for(size_t vector = 0; vector < IDT_SIZE; vector++) {
		struct idt_entry* entry = &idt[vector];

		uint64_t isr = (uint64_t)isr_stub_table[vector];
		// interrupts before 0x20 are for cpu exceptions
		uint8_t gate_type = (vector < 0x20) ? GATE_64BIT_TRAP : GATE_64BIT_INT;

		entry->kernel_cs = 0x08; // offset of 1 into GDT
		entry->ist = 0;
		entry->flags = PRESENT | RING0 | gate_type;
		entry->isr_low = isr & 0xffff;
		entry->isr_mid = (isr >> 16) & 0xffff;
		entry->isr_high = (isr >> 32) & 0xffffffff;
		entry->reserved = 0;
	}

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

// Intel manual vol 3 ch 6.3.1
char *EXCEPTIONS[] = {
	"Exception 0x00 Divide Error",
	"Exception 0x01 Debug Exception",
	"Exception 0x02 NMI Interrupt",
	"Exception 0x03 Breakpoint",
	"Exception 0x04 Overflow",
	"Exception 0x05 BOUND Range Exceeded",
	"Exception 0x06 Invalid Opcode",
	"Exception 0x07 Device Not Available",
	"Exception 0x08 Double Fault",
	"Exception 0x09 Coprocessor Segment Overrun",
	"Exception 0x0A Invalid TSS",
	"Exception 0x0B Segment Not Present",
	"Exception 0x0C Stack-Segment Fault",
	"Exception 0x0D General Protection",
	"Exception 0x0E Page Fault",
	"Exception 0x0F Reserved",
	"Exception 0x10 x87 FPU Floating-Point Error",
	"Exception 0x11 Alignment Check",
	"Exception 0x12 Machine Check",
	"Exception 0x13 SIMD Floaing-Point Exception",
	"Exception 0x14 Virtualization Exception",
	"Exception 0x15 Control Protection Exception",
	"Exception 0x16 Reserved",
	"Exception 0x17 Reserved",
	"Exception 0x18 Reserved",
	"Exception 0x19 Reserved",
	"Exception 0x1A Reserved",
	"Exception 0x1B Reserved",
	"Exception 0x1C Reserved",
	"Exception 0x1D Reserved",
	"Exception 0x1E Reserved",
	"Exception 0x1F Reserved",
};

void idt_exception_handler(uint64_t exception, uint64_t code) {
	// TODO don't just panic
	char buf[80];
	char *end = strcpy(buf, EXCEPTIONS[exception]);
	end = strcpy(end, "\nError code 0x");
	ltoa(code, end, 16);
	panic(buf);
}