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
|
#include "aplos.h"
enum {
SDT_HEADER_SIZE = 36,
SDT_LENGTH_OFFSET = 4,
RSDT_VERSION_OFFSET = 15,
RSDT_VENDOR_OFFSET = 9,
RSDT_VENDOR_SIZE = 6,
RSDT_RSDP_OFFSET = 16
};
static uint8_t *rsdp;
static uint8_t *rsdt;
static uint8_t *madt;
static void parse_rsdt(uint64_t);
static void parse_madt(struct ioapic_info *);
static uint8_t *map_sdt(uint64_t);
void
setup_acpi(uint64_t rsdp_physical, struct ioapic_info *ioapic)
{
rsdp = (uint8_t *)map_page(rsdp_physical, 1, true);
uint8_t version = rsdp[RSDT_VERSION_OFFSET];
char8_t vendor[RSDT_VENDOR_SIZE+1];
memcpy(vendor, rsdp+RSDT_VENDOR_OFFSET, RSDT_VENDOR_SIZE);
vendor[RSDT_VENDOR_SIZE] = 0;
switch(version){
case 0:
parse_rsdt(read_uint32_le(rsdp+RSDT_RSDP_OFFSET));
break;
default:
print(u8"Unknown RSDP version :(\n");
panic();
}
parse_madt(ioapic);
}
void
parse_rsdt(uint64_t rsdt_physical)
{
rsdt = map_sdt(rsdt_physical);
uint32_t length = read_uint32_le(rsdt+SDT_LENGTH_OFFSET);
uint32_t entries = (length - SDT_HEADER_SIZE) / 4;
uint32_t *ptrs = (uint32_t *)(((uint64_t)rsdt)+SDT_HEADER_SIZE);
for(uint32_t i = 0; i < entries; i++){
uint8_t *ptr = map_sdt(ptrs[i]);
if(utf8_cmp_n(ptr, u8"APIC", 4) == 0)
madt = ptr;
}
}
void
parse_madt(struct ioapic_info *ioapic)
{
assert(madt != NULL);
uint32_t length = read_uint32_le(madt+SDT_LENGTH_OFFSET);
uint32_t offset = SDT_HEADER_SIZE + 8;
while(offset < length){
uint8_t type = madt[offset];
uint8_t record_length = madt[offset+1];
switch(type){
case 1:
/* I/O APIC */
ioapic->base = read_uint32_le(madt+offset+4);
ioapic->interrupt_base = read_uint32_le(madt+offset+8);
break;
}
offset += record_length;
}
}
static uint8_t *
map_sdt(uint64_t sdt_physical)
{
uint8_t *p = (uint8_t *)map_page(sdt_physical, 1, true);
uint32_t length = read_uint32_le(p+4);
uint32_t pages = (length + PAGE_SIZE - 1) / PAGE_SIZE;
if(pages > 1){
/* Remap the thing */
p = (uint8_t *)map_page(sdt_physical, pages, true);
}
return p;
}
|