summaryrefslogtreecommitdiff
path: root/src/apic.c
blob: 26adfaeaa642c5192577a62f833c199e375704d8 (plain) (blame)
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;
}