-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterrupts.cpp
126 lines (104 loc) · 3.26 KB
/
interrupts.cpp
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
#include "interrupts.h"
InterruptHandler::InterruptHandler(int num, InterruptManager* manager) :
num(num), manager(manager)
{
manager->handlers[num] = this;
}
InterruptHandler::~InterruptHandler() {
if (manager->handlers[num] == this) {
manager->handlers[num] = 0;
}
}
uint32_t InterruptHandler::operator()(uint32_t esp) {
return esp;
}
InterruptManager::GateDescriptor InterruptManager::interruptDescriptorTable[256];
InterruptManager* InterruptManager::current = 0;
uint32_t InterruptManager::handleInterrupt(uint8_t num, uint32_t esp) {
if (current != 0) {
current->instHandleInterrupt(num, esp);
}
return esp;
}
uint32_t InterruptManager::instHandleInterrupt(uint8_t num, uint32_t esp) {
if (handlers[num] != 0) {
esp = (*handlers[num])(esp);
} else if (num != 0x20) {
printf("UNHANDLED INTERRUPT ");
printh(num);
printf("! ");
}
// if its a hardware interrupt 0x20-0x30, then acknowlage the pic
if (0x20 <= num && num <= 0x30) {
pic_master_command.write(0x20);
if (0x28 <= num) {
pic_slave_command.write(0x20);
}
}
return esp;
}
void InterruptManager::setInterruptDescriptorTableEntry(uint8_t intnum,
uint16_t gdt_code_segment,
uint8_t privilege_level,
uint8_t type,
void (*handler)()) {
InterruptManager::GateDescriptor* ent = &interruptDescriptorTable[intnum];
const uint8_t IDT_DESC_PRESENT = 0x80;
ent->handler_low = ((uint32_t)handler) & 0xFFFF;
ent->handler_high = ((uint32_t)handler >> 16) & 0xFFFF;
ent->gdt_code_segment = gdt_code_segment;
ent->access = IDT_DESC_PRESENT | ((privilege_level & 3) << 5) | type;
ent->reserved = 0;
}
InterruptManager::InterruptManager(GlobalDescriptorTable* gdt) :
pic_master_command(0x20), pic_master_data(0x21),
pic_slave_command(0xA0), pic_slave_data(0xA1)
{
uint16_t code = gdt->code_offset();
const uint8_t IDT_INTERRUPT_GATE = 0xE;
for (uint16_t i = 0; i < 256; i++) {
setInterruptDescriptorTableEntry(i, code, 0, IDT_INTERRUPT_GATE,
&ignoreInterrupt);
handlers[i] = 0;
}
setInterruptDescriptorTableEntry(0x20, code, 0, IDT_INTERRUPT_GATE,
&handleInterruptRequest0x00);
setInterruptDescriptorTableEntry(0x21, code, 0, IDT_INTERRUPT_GATE,
&handleInterruptRequest0x01);
setInterruptDescriptorTableEntry(0xCD, code, 0, IDT_INTERRUPT_GATE,
&handleInterruptRequest0xCD);
// begin sending interupts
pic_master_command.write(0x11);
pic_slave_command.write(0x11);
// offset so we don't reuse interupts 0-20
// these interupts are reserved by cpu for exceptions
pic_master_data.write(0x20);
pic_slave_data.write(0x28);
// tell slave and master who is who
pic_master_data.write(0x04);
pic_slave_data.write(0x02);
// ??
pic_master_data.write(0x01);
pic_slave_data.write(0x01);
pic_master_data.write(0x00);
pic_slave_data.write(0x00);
InterruptDescriptorTable idt;
idt.size = 256 * sizeof(GateDescriptor) - 1;
idt.base = (uint32_t)interruptDescriptorTable;
asm volatile("lidt %0" : : "m"(idt));
}
InterruptManager::~InterruptManager() {
}
void InterruptManager::activate() {
if (current != 0) {
current->deactivate();
}
current = this;
asm("sti");
}
void InterruptManager::deactivate() {
if (current = this) {
asm("cli");
current = 0;
}
}