source: trunk/hal/x86_64/core/hal_acpi.c @ 315

Last change on this file since 315 was 275, checked in by max@…, 7 years ago

Add a SRAT parser. For some reason, QEMU does not want to enable the
memory ranges...

File size: 8.0 KB
Line 
1/*
2 * hal_acpi.c - ACPI parser
3 *
4 * Copyright (c) 2017 Maxime Villard
5 *
6 * This file is part of ALMOS-MKH.
7 *
8 * ALMOS-MKH is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2.0 of the License.
11 *
12 * ALMOS-MKH is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include <hal_types.h>
23#include <hal_boot.h>
24#include <hal_acpi.h>
25#include <hal_internal.h>
26
27#include <memcpy.h>
28#include <thread.h>
29#include <string.h>
30#include <process.h>
31#include <printk.h>
32#include <vmm.h>
33#include <core.h>
34#include <cluster.h>
35
36/* -------------------------------------------------------------------------- */
37
38#define RSDT_NENTRIES(rsdt) \
39        ( (rsdt->Header.Length - sizeof(rsdt_t) + sizeof(uint32_t)) / sizeof(uint32_t) )
40#define RSDT_ENTRIES(rsdt) \
41        ((uint32_t *)&rsdt->TableOffsetEntry[0])
42
43static bool_t hal_acpi_table_correct(header_t *header)
44{
45        uint8_t *ptr, sum = 0;
46        size_t i, n;
47
48        ptr = (uint8_t *)header;
49        n = header->Length;
50
51        /* Verify checksum */
52        for (i = 0; i < n; i++) {
53                sum += ptr[i];
54        }
55
56        return (sum == 0);
57}
58
59static vaddr_t hal_acpi_map_table(paddr_t headerpa, const char *sig)
60{
61        paddr_t basepa, pa;
62        vaddr_t baseva, retva, va;
63        size_t off, size;
64        size_t npages, ngrow, n;
65        header_t *header;
66
67        /* Allocate the VA for the header */
68        basepa = rounddown(headerpa, PAGE_SIZE);
69        npages = roundup(headerpa + sizeof(header_t), PAGE_SIZE) - basepa;
70        baseva = hal_gpt_bootstrap_valloc(npages);
71        off = headerpa - basepa;
72
73        /* Enter the VA, and get the total size of the structure */
74        hal_gpt_enter_range(baseva, basepa, npages);
75        retva = (vaddr_t)(baseva + off);
76        header = (header_t *)retva;
77        size = header->Length;
78        XASSERT(size >= sizeof(header_t));
79
80        /* Check the signature */
81        if (memcmp((void *)&header->Signature, sig, ACPI_NAME_SIZE))
82                return 0;
83
84        /* Grow the VA to map the rest */
85        ngrow = roundup(headerpa + size, PAGE_SIZE) - basepa;
86        n = ngrow - npages;
87        va = hal_gpt_bootstrap_valloc(n);
88        pa = basepa + npages * PAGE_SIZE;
89        hal_gpt_enter_range(va, pa, n);
90
91        /* Verify the checksum */
92        if (!hal_acpi_table_correct(header))
93                x86_panic("Wrong checksum for table");
94
95        return retva;
96}
97
98/* -------------------------------------------------------------------------- */
99
100static void hal_acpi_parse_ioapic(madt_ioapic_t *ioapic)
101{
102        extern paddr_t ioapic_pa;
103        uint32_t irqbase;
104        ioapic_pa = ioapic->Address;
105        irqbase = ioapic->GlobalIrqBase;
106
107        x86_printf("-> IOAPIC address: %Z\n", ioapic_pa);
108        x86_printf("-> IOAPIC irqbase: %z\n", (uint64_t)irqbase);
109}
110
111static void hal_acpi_parse_madt(madt_t *madt)
112{
113        madt_lapic_t *lapic;
114        madt_lapic_override_t *override;
115        void *ptr, *end;
116        subheader_t *sub;
117        size_t nioapic = 0;
118        extern size_t ncpu;
119
120        extern paddr_t lapic_pa;
121        lapic_pa = (paddr_t)madt->Address;
122
123        ptr = (void *)(madt + 1);
124        end = (void *)madt + madt->Header.Length;
125
126        while (ptr < end) {
127                sub = (subheader_t *)ptr;
128                if (sub->Type == ACPI_MADT_TYPE_IO_APIC) {
129                        hal_acpi_parse_ioapic((madt_ioapic_t *)sub);
130                        nioapic++;
131                } else if (sub->Type == ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE) {
132                        override = (madt_lapic_override_t *)sub;
133                        lapic_pa = (paddr_t)override->Address;
134                        x86_printf("-> found LAPIC override\n");
135                } else if (sub->Type == ACPI_MADT_TYPE_LOCAL_APIC) {
136                        lapic = (madt_lapic_t *)sub;
137                        if (lapic->LapicFlags & ACPI_MADT_LAPIC_ENABLED) {
138                                cpu_activate(lapic->Id);
139                                x86_printf("-> found LAPIC %z\n", (uint64_t)lapic->Id);
140                                ncpu++;
141                        }
142                }
143
144                ptr += sub->Length;
145        }
146
147        x86_printf("-> LAPIC address: %Z\n", lapic_pa);
148        x86_printf("-> number of CPUs: %z\n", ncpu);
149        x86_printf("-> number of IOAPICs: %z\n", nioapic);
150}
151
152static madt_t *hal_acpi_map_madt(rsdt_t *rsdt)
153{
154        vaddr_t va;
155        paddr_t pa;
156        uint32_t *ent;
157        size_t i, n;
158
159        n = RSDT_NENTRIES(rsdt);
160        ent = RSDT_ENTRIES(rsdt);
161
162        for (i = 0; i < n; i++) {
163                pa = (paddr_t)ent[i];
164                va = hal_acpi_map_table(pa, "APIC");
165                if (va == 0)
166                        continue;
167                return (madt_t *)va;
168        }
169
170        return NULL;
171}
172
173/* -------------------------------------------------------------------------- */
174
175static void hal_acpi_parse_srat(srat_t *srat)
176{
177        srat_cpu_affinity_t *cpu;
178        srat_mem_affinity_t *mem;
179        void *ptr, *end;
180        subheader_t *sub;
181        uint32_t dom;
182
183        ptr = (void *)(srat + 1);
184        end = (void *)srat + srat->Header.Length;
185
186        while (ptr < end) {
187                sub = (subheader_t *)ptr;
188                if (sub->Type == ACPI_SRAT_TYPE_CPU_AFFINITY) {
189                        cpu = (srat_cpu_affinity_t *)sub;
190                        if (cpu->Flags & ACPI_SRAT_CPU_USE_AFFINITY) {
191                                dom = ((uint32_t)cpu->ProximityDomainHi[2] << 24) |
192                                      ((uint32_t)cpu->ProximityDomainHi[1] << 16) |
193                                      ((uint32_t)cpu->ProximityDomainHi[0] << 8) |
194                                       (uint32_t)cpu->ProximityDomainLo;
195                                x86_printf("-> found CPU affinity: %z->%z\n",
196                                    (uint64_t)cpu->ApicId, (uint64_t)dom);
197                        }
198                } else if (sub->Type == ACPI_SRAT_TYPE_MEMORY_AFFINITY) {
199                        mem = (srat_mem_affinity_t *)sub;
200//                      if (mem->Flags & ACPI_SRAT_MEM_ENABLED)
201                                x86_printf("-> found MEM affinity: %z->[%Z,%Z,%Z]\n",
202                                    mem->ProximityDomain,
203                                    mem->BaseAddress, mem->Length,(uint64_t)mem->Flags);
204                } 
205
206                ptr += sub->Length;
207        }
208
209}
210
211static srat_t *hal_acpi_map_srat(rsdt_t *rsdt)
212{
213        vaddr_t va;
214        paddr_t pa;
215        uint32_t *ent;
216        size_t i, n;
217
218        n = RSDT_NENTRIES(rsdt);
219        ent = RSDT_ENTRIES(rsdt);
220
221        for (i = 0; i < n; i++) {
222                pa = (paddr_t)ent[i];
223                va = hal_acpi_map_table(pa, "SRAT");
224                if (va == 0)
225                        continue;
226
227                return (srat_t *)va;
228        }
229
230        return NULL;
231}
232
233/* -------------------------------------------------------------------------- */
234
235static rsdt_t *hal_acpi_map_rsdt(rsdp_t *rsdp)
236{
237        paddr_t rsdt_pa;
238        rsdt_t *rsdt;
239
240        rsdt_pa = (paddr_t)rsdp->RsdtPhysicalAddress;
241        rsdt = (rsdt_t *)hal_acpi_map_table(rsdt_pa, "RSDT");
242        if (rsdt == 0)
243                x86_panic("RSDT invalid");
244
245        return rsdt;
246}
247
248/* -------------------------------------------------------------------------- */
249
250static bool_t hal_acpi_rsdp_correct(uint8_t *ptr)
251{
252        uint8_t sum = 0;
253        size_t i;
254
255        /* Verify checksum */
256        for (i = 0; i < 20; i++) {
257                sum += ptr[i];
258        }
259
260        return (sum == 0);
261}
262
263static rsdp_t *hal_acpi_find_rsdp(vaddr_t va_start, vaddr_t va_end)
264{
265        rsdp_t *rsdp;
266        vaddr_t va = va_start;
267        size_t i, n = PAGE_SIZE / ACPI_RSDP_ALIGN;
268        char oem[ACPI_OEM_ID_SIZE + 1];
269        uint8_t *ptr;
270
271        /* The table is on a 16bit boundary */
272        for (va = va_start; va < va_end; va += PAGE_SIZE) {
273                for (i = 0; i < n; i++) {
274                        ptr = (uint8_t *)va + i * ACPI_RSDP_ALIGN;
275                        if (memcmp(ptr, ACPI_RSDP_SIGNATURE, ACPI_RSDP_SIGNATURE_SIZE))
276                                continue;
277                        if (!hal_acpi_rsdp_correct(ptr))
278                                continue;
279                        goto found;
280                }
281        }
282
283        return NULL;
284
285found:
286        rsdp = (rsdp_t *)ptr;
287
288        memcpy(&oem, rsdp->OemId, ACPI_OEM_ID_SIZE);
289        oem[ACPI_OEM_ID_SIZE] = '\0';
290        x86_printf("-> OEM: %s\n", oem);
291        if (rsdp->Revision != 0)
292                x86_printf("[!] Using ACPI 1.0\n");
293
294        return rsdp;
295}
296
297/* -------------------------------------------------------------------------- */
298
299void hal_acpi_init()
300{
301        rsdp_t *rsdp;
302        rsdt_t *rsdt;
303        madt_t *madt;
304        srat_t *srat;
305        paddr_t bios_min = 0x0E0000;
306        paddr_t bios_max = 0x100000;
307        vaddr_t vabase;
308        size_t npages;
309
310        npages = (bios_max - bios_min) / PAGE_SIZE;
311        vabase = hal_gpt_bootstrap_valloc(npages);
312
313        hal_gpt_enter_range(vabase, bios_min, npages);
314
315        /* First, find RSDP */
316        rsdp = hal_acpi_find_rsdp(vabase, vabase + npages * PAGE_SIZE);
317        if (rsdp == NULL)
318                x86_panic("RSDP not found");
319
320        /* Then, map RSDT */
321        rsdt = hal_acpi_map_rsdt(rsdp);
322        if (rsdt == NULL)
323                x86_panic("RSDT not found");
324
325        /* Map MADT and parse it */
326        madt = hal_acpi_map_madt(rsdt);
327        if (madt == NULL)
328                x86_panic("MADT not found");
329        hal_acpi_parse_madt(madt);
330
331        /* Map SRAT and parse it */
332        srat = hal_acpi_map_srat(rsdt);
333        if (srat != NULL)
334                hal_acpi_parse_srat(srat);
335        else
336                x86_printf("-> SRAT not found, single cluster\n");
337}
338
Note: See TracBrowser for help on using the repository browser.