furix
cute os
kernel/acpi.c
7262 bytes raw
1#include <acpi.h>
2
3#include <types.h>
4
5/* ACPI 2.0 RSDP: eb9d2d30-2d88-11d3-9a16-0090273fc14d */
6static const uint8_t guid_rsdp_v2[16] = {
7 0x30, 0x2D, 0x9D, 0xEB, 0x88, 0x2D, 0xD3, 0x11,
8 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D
9};
10
11/* ACPI 1.0 RSDP: 8868e871-e4f1-11d3-bc22-0080c73c8881 */
12static const uint8_t guid_rsdp_v1[16] = {
13 0x71, 0xE8, 0x68, 0x88, 0xF1, 0xE4, 0xD3, 0x11,
14 0xBC, 0x22, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81
15};
16
17#define MADT_TYPE_LOCAL_APIC 0
18#define MADT_TYPE_IO_APIC 1
19/* x2APIC: replaces type 0 when the firmware enabled x2APIC mode */
20#define MADT_TYPE_X2APIC 9
21
22/* signatures read little-endian via read_u32(): the first four ASCII bytes. */
23#define ACPI_SIG_RSDP 0x20445352u /* "RSD " */
24#define ACPI_SIG_RSDT 0x54445352u /* "RSDT" */
25#define ACPI_SIG_MADT 0x43495041u /* "APIC" */
26
27#define ACPI_SDT_HEADER_SIZE 36
28
29/*
30 * the MADT header is 8 bytes longer than a plain SDT header: it appends
31 * LocalAPICAddress (4), PCATCompatibility (1), PCATCompatCount (1) and
32 * Reserved (2). Structure entries therefore begin at 44, not 36.
33 */
34#define ACPI_MADT_HEADER_SIZE 44
35
36#define ACPI_RSDT_ENTRY_SIZE 8
37
38/* Local APIC structure: Type, Length, ACPI ID, APIC ID, Flags(4). */
39#define MADT_LOCAL_APIC_FLAGS_OFFSET 4
40#define MADT_LOCAL_APIC_ENABLED 0x1
41
42/*
43 * x2APIC structure: Type, Length, Reserved(2), ACPI UID(4), APIC ID(4),
44 * Flags(4), ... so the APIC ID is a full 32-bit field at offset 8 and the
45 * enabled flag sits at offset 12. the entry is 16 bytes minimum.
46 */
47#define MADT_X2APIC_ID_OFFSET 8
48#define MADT_X2APIC_FLAGS_OFFSET 12
49#define MADT_X2APIC_ENABLED 0x1
50#define MADT_X2APIC_MIN_LEN 16
51
52static uint32_t read_u32(const uint8_t *p) {
53 return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
54}
55
56/* EFI_GUID is { u32, u16, u16, u8[8] } with no padding, so its memory image is
57 exactly the 16-byte wire form we compare against. */
58static bool guid_equal(const EFI_GUID *guid, const uint8_t *bytes) {
59 const uint8_t *p = (const uint8_t *)guid;
60 int i;
61
62 for (i = 0; i < 16; i++) {
63 if (p[i] != bytes[i]) {
64 return false;
65 }
66 }
67 return true;
68}
69
70/* an SDT's checksum is the sum of all its bytes, modulo 256, taken to zero. */
71static bool checksum_ok(const uint8_t *table, uint32_t len) {
72 uint8_t sum = 0;
73 uint32_t i;
74
75 for (i = 0; i < len; i++) {
76 sum = (uint8_t)(sum + table[i]);
77 }
78 return sum == 0;
79}
80
81static void madt_parse(const uint8_t *madt, uint32_t madt_len, struct acpi_madt_info *out) {
82 const uint8_t *entry = madt + ACPI_MADT_HEADER_SIZE;
83 const uint8_t *end = madt + madt_len;
84
85 while (entry + 2 <= end) {
86 uint8_t type = entry[0];
87 uint8_t len = entry[1];
88
89 /* length 0 would not advance us and could not be a valid structure. */
90 if (len < 2 || entry + len > end) {
91 break;
92 }
93
94 if ((type == MADT_TYPE_LOCAL_APIC && len >= 8) ||
95 (type == MADT_TYPE_X2APIC && len >= MADT_X2APIC_MIN_LEN)) {
96 bool is_x2apic = (type == MADT_TYPE_X2APIC);
97 uint32_t flags = read_u32(entry + (is_x2apic ? MADT_X2APIC_FLAGS_OFFSET
98 : MADT_LOCAL_APIC_FLAGS_OFFSET));
99 uint32_t enabled_bit = is_x2apic ? MADT_X2APIC_ENABLED : MADT_LOCAL_APIC_ENABLED;
100
101 /*
102 * bit 0 of flags is "enabled"; skip CPUs the firmware marked unusable.
103 *
104 * the two entry types are handled together because a MADT uses one or the
105 * other, never both, and reading a type 0 entry as type 9 would pick up a
106 * 32-bit field spanning the flags and the following entry's header.
107 */
108 if ((flags & enabled_bit) != 0 && out->cpu_count < ACPI_MAX_APIC_IDS) {
109 out->apic_ids[out->cpu_count] =
110 is_x2apic ? read_u32(entry + MADT_X2APIC_ID_OFFSET) : (uint32_t)entry[3];
111
112 /*
113 * the slot is dense rather than the APIC ID, because an x2APIC ID may
114 * exceed the per-CPU array we reserve. the BSP passes the slot to the
115 * trampoline, so the AP never has to index anything by ID itself.
116 */
117 out->slots[out->cpu_count] = (uint8_t)out->cpu_count;
118 out->cpu_count++;
119 }
120 } else if (type == MADT_TYPE_IO_APIC && len >= 12) {
121 out->ioapic_count++;
122 }
123
124 entry += len;
125 }
126}
127
128/*
129 * locate a table by the signature of the table itself rather than by the
130 * Type byte recorded in the RSDT entry. it costs one extra read and needs no
131 * trust in the entry metadata, which some firmware images get wrong.
132 */
133static const uint8_t *rsdt_find_table(const uint8_t *rsdt, uint32_t rsdt_len, uint32_t sig) {
134 const uint8_t *entry = rsdt + ACPI_SDT_HEADER_SIZE;
135 const uint8_t *end = rsdt + rsdt_len;
136
137 while (entry + ACPI_RSDT_ENTRY_SIZE <= end) {
138 const uint8_t *t = (const uint8_t *)(uint64_t)read_u32(entry + 4);
139
140 if (t != NULL && read_u32(t) == sig) {
141 return t;
142 }
143 entry += ACPI_RSDT_ENTRY_SIZE;
144 }
145 return NULL;
146}
147
148bool acpi_madt_parse(const EFI_SYSTEM_TABLE *st, struct acpi_madt_info *out) {
149 const uint8_t *rsdp = NULL;
150 const uint8_t *rsdt;
151 const uint8_t *madt;
152 uint32_t rsdt_len;
153 uint32_t madt_len;
154 UINTN i;
155
156 out->cpu_count = 0;
157 out->ioapic_count = 0;
158
159 /* some firmware installs the MADT directly in the UEFI configuration table. */
160 for (i = 0; i < st->NumberOfTableEntries; i++) {
161 const uint8_t *t = (const uint8_t *)st->ConfigurationTable[i].VendorTable;
162
163 if (t != NULL && read_u32(t) == ACPI_SIG_MADT) {
164 madt_len = read_u32(t + 4);
165 if (madt_len >= ACPI_MADT_HEADER_SIZE && checksum_ok(t, madt_len)) {
166 madt_parse(t, madt_len, out);
167 return out->cpu_count > 0;
168 }
169 }
170 }
171
172 for (i = 0; i < st->NumberOfTableEntries; i++) {
173 const EFI_CONFIGURATION_TABLE *ct = &st->ConfigurationTable[i];
174
175 if (guid_equal(&ct->VendorGuid, guid_rsdp_v2) || guid_equal(&ct->VendorGuid, guid_rsdp_v1)) {
176 rsdp = (const uint8_t *)ct->VendorTable;
177 break;
178 }
179 }
180
181 if (rsdp == NULL || read_u32(rsdp) != ACPI_SIG_RSDP) {
182 return false;
183 }
184 /* signature is 8 bytes: "RSD PTR " -> R(0) S(1) D(2) ' '(3) P(4) T(5) R(6) ' '(7). */
185 if (rsdp[4] != 'P' || rsdp[5] != 'T' || rsdp[6] != 'R' || rsdp[7] != ' ') {
186 return false;
187 }
188
189 /* RsdtPhysicalAddress is a 32-bit field at offset 16. */
190 rsdt = (const uint8_t *)(uint64_t)read_u32(rsdp + 16);
191 if (rsdt == NULL || read_u32(rsdt) != ACPI_SIG_RSDT) {
192 return false;
193 }
194
195 rsdt_len = read_u32(rsdt + 4);
196 if (rsdt_len < ACPI_SDT_HEADER_SIZE || !checksum_ok(rsdt, rsdt_len)) {
197 return false;
198 }
199
200 madt = rsdt_find_table(rsdt, rsdt_len, ACPI_SIG_MADT);
201 if (madt == NULL) {
202 return false;
203 }
204
205 madt_len = read_u32(madt + 4);
206 if (madt_len < ACPI_MADT_HEADER_SIZE || !checksum_ok(madt, madt_len)) {
207 return false;
208 }
209
210 madt_parse(madt, madt_len, out);
211 return out->cpu_count > 0;
212}
213
214uint32_t acpi_madt_ap_count(const struct acpi_madt_info *madt) {
215 /*
216 * one of the listed processors is the BSP, which is already running. the
217 * subtraction is guarded rather than written as `cpu_count - 1`: a MADT with
218 * no enabled processor entries would otherwise wrap to UINT32_MAX and send
219 * the bring-up loop looking for four billion APs.
220 */
221 return (madt->cpu_count > 0) ? (madt->cpu_count - 1) : 0;
222}