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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
#include <stdint.h>
#include <stddef.h>
#include <lib.h>
#include <panic.h>
#include "idt.h"
#include "debugger.h"
#include "../paging.h"
#include "../drivers/pic.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[] = {
"Division Error",
"Debug",
"NMI",
"Breakpoint",
"Overflow",
"BOUND Range Exceeded",
"Invalid Opcode",
"Device Not Available",
"Double Fault",
"Coprocessor Segment Overrun",
"Invalid TSS",
"Segment Not Present",
"Stack-Segment Fault",
"General Protection Fault",
"Page Fault",
"Reserved",
"x87 Floating-Point Error",
"Alignment Check",
"Machine Check",
"SIMD Floaing-Point Exception",
"Virtualization Exception",
"Control Protection Exception",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Hypervisor Injection Exception",
"VMM Communication Exception",
"Security Exception",
"Reserved",
};
void idt_exception_handler(uint64_t exception, uint64_t code, struct isr_regs *state) {
switch (exception) {
case 0x01: // debug
debugger(state, DEBUG_DBG);
return;
case 0x03: // breakpoint
debugger(state, DEBUG_INT3);
return;
}
char custom[64];
*custom = '\0';
// page faults store the offending address in cr2
if (exception == 0x0E) {
strcat(custom, "\nPage fault address: 0x");
uint64_t cr2;
__asm__ volatile ("mov %%cr2, %0" : "=r"(cr2));
ultoa((size_t)cr2, custom + 23, 16);
}
panic_interrupt(
(void *)state->rip,
(void *)state->rbp,
"Exception %s\nError code 0x%lu%s",
EXCEPTIONS[exception],
code,
custom
);
}
void idt_pic_eoi(uint8_t exception) {
pic_eoi(exception - PIC_REMAP_OFFSET);
}
int counter = 0;
void idt_pic_timer(void) {
// print a message once we know the timer works
// but avoid spamming the logs
if (counter == 3) {
//kputs("pic timer!\n");
}
if (counter <= 3) {
counter++;
}
}
void idt_pic_keyboard(void) {}
void idt_pic_mouse(void) {}
|