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 <acpi.h>
#include <lib.h>
#include <memory.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <panic.h>
#define ACPI_INTERNAL
#include <sys/acpi.h>
/* global state, idk a better way rn */
static struct acpi_state state;
static bool checksum(uint8_t *data, size_t len) {
unsigned char sum = 0;
for (size_t i = 0; i < len; i++)
sum += data[i];
return sum == 0;
}
static int read_s5_addr(struct dsdt *dsdt) {
char *s5_addr = dsdt->s5_addr;
int dsdt_len = dsdt->h.length - sizeof(struct acpi_header);
while (0 < dsdt_len--) {
if (memcmp(s5_addr, "_S5_", 4) == 0)
break;
s5_addr++;
}
if (dsdt_len > 0) {
// check for valid AML structure
if ( ( *(s5_addr-1) == 0x08 || ( *(s5_addr-2) == 0x08 && *(s5_addr-1) == '\\') ) && *(s5_addr+4) == 0x12 ) {
s5_addr += 5;
s5_addr += ((*s5_addr &0xC0)>>6) +2; // calculate PkgLength size
if (*s5_addr == 0x0A)
s5_addr++; // skip byteprefix
state.SLP_TYPa = *(s5_addr)<<10;
s5_addr++;
if (*s5_addr == 0x0A)
s5_addr++; // skip byteprefix
state.SLP_TYPb = *(s5_addr)<<10;
state.SLP_EN = 1<<13;
state.SCI_EN = 1;
} else {
return -1;
}
} else {
return -1;
}
return -1;
}
static void acpi_load_table(uint64_t addr);
static void acpi_load_rsdt_tables(struct rsdt *rsdt) {
int entries = (rsdt->h.length - sizeof(rsdt->h)) / 4;
for (int i = 0; i < entries; i++) {
uint32_t addr = rsdt->sdt_pointers[i];
acpi_load_table(addr);
}
}
static void acpi_load_xsdt_tables(struct xsdt *xsdt) {
int entries = (xsdt->h.length - sizeof(xsdt->h)) / 8;
for (int i = 0; i < entries; i++) {
uint64_t addr = xsdt->sdt_pointers[i];
acpi_load_table(addr);
}
}
#define SIG_RSDT 0x54445352
#define SIG_XSDT 0x54445358
#define SIG_FACP 0x50434146
#define SIG_DSDT 0x54445344
#define SIG_APIC 0x43495041
#define SIG_HEPT 0x54455048
#define SIG_WAET 0x54454157
static void acpi_handle_table(struct acpi_header *header) {
switch (header->signature) {
case SIG_RSDT:
state.sdt.rsdt = (struct rsdt *) header;
acpi_load_rsdt_tables(state.sdt.rsdt);
break;
case SIG_XSDT:
state.sdt.xsdt = (struct xsdt *) header;
acpi_load_xsdt_tables(state.sdt.xsdt);
break;
case SIG_FACP:
state.fadt = (struct fadt *) header;
acpi_load_table(state.fadt->dsdt);
break;
case SIG_DSDT:
state.dsdt = (struct dsdt *) header;
read_s5_addr(state.dsdt);
break;
case SIG_APIC:
state.apic = (struct apic *) header;
break;
case SIG_HEPT:
state.hept = (struct hept *) header;
break;
case SIG_WAET:
state.waet = (struct waet *) header;
break;
default:
break;
}
}
static void acpi_load_table(uint64_t addr) {
struct acpi_header *temp, *mapped;
uint32_t length;
temp = (struct acpi_header * ) (uintptr_t) addr;
mapped = mmap(temp, sizeof(struct acpi_header));
length = mapped->length;
unmap(mapped);
mapped = mmap(temp, length);
if (!checksum((uint8_t *) mapped, mapped->length)) {
unmap(mapped);
return;
}
kprintf("%.*s: %#016lx\n", 4, (char*)&mapped->signature, (size_t)temp);
acpi_handle_table(mapped);
}
int acpi_init(void *rootsdp) {
memset(&state, 0, sizeof(struct acpi_state));
struct rsdp *rsdp = (struct rsdp *) rootsdp;
if (!checksum((uint8_t *)rsdp, sizeof(struct rsdp))) {
return -1;
}
if (memcmp(rsdp->signature, "RSD PTR ", 8) != 0) {
panic("invalid acpi rsdp signature: %.*s\n", 8, rsdp->signature);
}
if (rsdp->revision == 0) {
state.version = 0;
kprintf("ACPI 1.0\n");
acpi_load_table(rsdp->rsdt_addr);
} else if (rsdp->revision == 2) {
state.version = 2;
struct xsdp *xsdp = (struct xsdp *) rsdp;
kprintf("ACPI 2.0\n");
acpi_load_table(xsdp->xsdt_addr);
} else {
panic("invalid acpi rev: %d\n", rsdp->revision);
}
kprintf("\n");
acpi_sys_enable(&state);
return 0;
}
int acpi_shutdown(void) {
return acpi_sys_shutdown(&state);
}
|