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
161
162
|
#include <stdint.h>
#include <stddef.h>
#include <lib.h>
#include <serial.h>
#include <panic.h>
#include "debugger.h"
#include "idt.h"
#include "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[] = {
"0x00 Division Error",
"0x01 Debug",
"0x02 NMI",
"0x03 Breakpoint",
"0x04 Overflow",
"0x05 BOUND Range Exceeded",
"0x06 Invalid Opcode",
"0x07 Device Not Available",
"0x08 Double Fault",
"0x09 Coprocessor Segment Overrun",
"0x0A Invalid TSS",
"0x0B Segment Not Present",
"0x0C Stack-Segment Fault",
"0x0D General Protection Fault",
"0x0E Page Fault",
"0x0F Reserved",
"0x10 x87 Floating-Point Error",
"0x11 Alignment Check",
"0x12 Machine Check",
"0x13 SIMD Floaing-Point Exception",
"0x14 Virtualization Exception",
"0x15 Control Protection Exception",
"0x16 Reserved",
"0x17 Reserved",
"0x18 Reserved",
"0x19 Reserved",
"0x1A Reserved",
"0x1B Reserved",
"0x1C Hypervisor Injection Exception",
"0x1D VMM Communication Exception",
"0x1E Security Exception",
"0x1F Reserved",
};
void idt_exception_handler(uint64_t exception, uint64_t code, struct isr_regs *state) {
// breakpoint interrupt
if (exception == 0x03) {
debugger(state, DEBUG_INT3);
return;
} else if (exception == 0x01) {
debugger(state, DEBUG_DBG);
return;
}
char custom[64];
*custom = '\0';
// page faults store the offending address in cr2
if (exception == 0x0E) {
strcat(custom, "\nPage fault address: 0x");
void *addr;
__asm__ volatile ("mov %%cr2, %0" : "=r"(addr));
ultoa((size_t)addr, 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) {
serial_out_str("pic timer!\n");
}
if (counter <= 3) {
counter++;
}
}
void idt_pic_keyboard(void) {}
void idt_pic_mouse(void) {}
|