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
|
#include "aplos.h"
enum {
APIC_BASE = 0x1B,
SPURIOUS_INTERRUPT_VECTOR = 0xF0,
END_OF_INTERRUPT = 0xB0
};
static volatile uint32_t *apic_base;
static volatile uint8_t *ioapic_reg;
static volatile uint32_t *ioapic_data;
static uint8_t ioapic_max_entries;
static uint32_t read_apic_reg(uint64_t);
static void write_apic_reg(uint64_t, uint32_t);
static uint32_t read_ioapic_reg(uint8_t);
static void write_ioapic_reg(uint8_t, uint32_t);
void
setup_apic(struct ioapic_info *ioapic)
{
uint64_t v = get_msr(APIC_BASE);
uint64_t addr = v & 0x0000000FFFFFF000;
apic_base = (uint32_t *)map_page(addr, 1, false);
write_apic_reg(SPURIOUS_INTERRUPT_VECTOR, read_apic_reg(SPURIOUS_INTERRUPT_VECTOR) | 0x1FF);
uint8_t *ioapic_base = (uint8_t*)map_page(ioapic->base, 1, false);
ioapic_reg = ioapic_base;
ioapic_data = (uint32_t*)(ioapic_base+16);
ioapic_max_entries = (read_ioapic_reg(1) >> 16)&0xFF;
}
void
apic_end_of_interrupt(void)
{
write_apic_reg(END_OF_INTERRUPT, 0);
}
struct ioapic_redirection
read_redirection(uint8_t n)
{
assert(n <= ioapic_max_entries);
struct ioapic_redirection r;
uint32_t low = read_ioapic_reg(0x10+2*n);
uint32_t high = read_ioapic_reg(0x11+2*n);
r.vector = low & 0xFF;
r.delivery_mode = (low >> 8) & 0x7;
r.destination_mode = (low >> 11) & 0x1;
r.delivery_status = (low >> 12) & 0x1;
r.pin_polarity = (low >> 13) & 0x1;
r.remote_irr = (low >> 14) & 0x1;
r.trigger_mode = (low >> 15) & 0x1;
r.mask = (low >> 16) & 0x1;
r.reserved = (low >> 17) & 0xFF;
r.reserved |= high & 0xFFFFFF;
if(r.destination_mode)
r.destination = (high >> 24) & 0xF;
else
r.destination = (high >> 24) & 0xFF;
return r;
}
void
write_redirection(uint8_t n, struct ioapic_redirection r)
{
uint32_t high, low;
high = low = 0;
assert(n <= ioapic_max_entries);
assert(r.vector >= 0x10 && r.vector <= 0xFE);
low |= r.vector & 0xFF;
low |= (r.delivery_mode & 0x7) << 8;
low |= (r.destination_mode & 0x1) << 11;
low |= (r.delivery_status & 0x1) << 12;
low |= (r.pin_polarity & 0x1) << 13;
low |= (r.remote_irr & 0x1) << 14;
low |= (r.trigger_mode & 0x1) << 15;
low |= (r.mask & 0x1) << 16;
low |= (r.reserved & 0xF) << 17;
high |= (r.reserved & 0xFFFFFF00) >> 8;
if(r.destination_mode)
high |= (r.destination & 0xF) << 24;
else
high |= (r.destination & 0xFF) << 24;
write_ioapic_reg(0x10+2*n, low);
write_ioapic_reg(0x11+2*n, high);
}
static uint32_t
read_apic_reg(uint64_t r)
{
r /= 4;
return apic_base[r];
}
static void
write_apic_reg(uint64_t r, uint32_t v)
{
r /= 4;
apic_base[r] = v;
}
static uint32_t
read_ioapic_reg(uint8_t r)
{
*ioapic_reg = r;
return *ioapic_data;
}
static void
write_ioapic_reg(uint8_t r, uint32_t v)
{
*ioapic_reg = r;
*ioapic_data = v;
}
|