source: trunk/hal/x86_64/hal_acpi.c @ 39

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

Parse RSDP->RSDT->MADT, and get the LAPIC PA.

File size: 5.4 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/* XXX XXX libk XXX XXX */
37int memcmp(char *s1, char *s2, size_t n)
38{
39        size_t i;
40        for(i = 0; i < n; i++) {
41                if (s1[i] != s2[i])
42                        return 1;
43        }
44        return 0;
45}
46
47/* -------------------------------------------------------------------------- */
48
49#define RSDT_NENTRIES(rsdt) \
50        ( (rsdt->Header.Length - sizeof(rsdt_t) + sizeof(uint32_t)) / sizeof(uint32_t) )
51#define RSDT_ENTRIES(rsdt) \
52        ((uint32_t *)&rsdt->TableOffsetEntry[0])
53
54static bool_t hal_acpi_table_correct(header_t *header)
55{
56        uint8_t *ptr, sum = 0;
57        size_t i, n;
58
59        ptr = (uint8_t *)header;
60        n = header->Length;
61
62        /* Verify checksum */
63        for (i = 0; i < n; i++) {
64                sum += ptr[i];
65        }
66
67        return (sum == 0);
68}
69
70static vaddr_t hal_acpi_map_table(paddr_t headerpa, const char *sig)
71{
72        paddr_t basepa, pa;
73        vaddr_t baseva, retva, va;
74        size_t i, off, size;
75        size_t npages, ngrow, n;
76        header_t *header;
77
78        /* Allocate the VA for the header */
79        basepa = rounddown(headerpa, PAGE_SIZE);
80        npages = roundup(headerpa + sizeof(header_t), PAGE_SIZE) - basepa;
81        baseva = hal_gpt_bootstrap_valloc(npages);
82        off = headerpa - basepa;
83
84        /* Enter the VA, and get the total size of the structure */
85        hal_gpt_enter_range(baseva, basepa, npages);
86        retva = (vaddr_t)(baseva + off);
87        header = (header_t *)retva;
88        size = header->Length;
89        XASSERT(size >= sizeof(header_t));
90
91        /* Check the signature */
92        if (memcmp((void *)&header->Signature, sig, ACPI_NAME_SIZE))
93                return 0;
94
95        /* Grow the VA to map the rest */
96        ngrow = roundup(headerpa + size, PAGE_SIZE) - basepa;
97        n = ngrow - npages;
98        va = hal_gpt_bootstrap_valloc(n);
99        pa = basepa + npages * PAGE_SIZE;
100        hal_gpt_enter_range(va, pa, n);
101
102        /* Verify the checksum */
103        if (!hal_acpi_table_correct(header))
104                x86_panic("Wrong checksum for table");
105
106        return retva;
107}
108
109/* -------------------------------------------------------------------------- */
110
111static void hal_acpi_parse_madt(madt_t *madt)
112{
113        paddr_t lapic_pa = (paddr_t)madt->Address;
114        x86_printf("-> LAPIC address: %Z\n", lapic_pa);
115}
116
117static madt_t *hal_acpi_map_madt(rsdt_t *rsdt)
118{
119        vaddr_t va;
120        paddr_t basepa, pa;
121        uint32_t *ent;
122        size_t i, n;
123
124        n = RSDT_NENTRIES(rsdt);
125        ent = RSDT_ENTRIES(rsdt);
126
127        for (i = 0; i < n; i++) {
128                pa = (paddr_t)ent[i];
129                va = hal_acpi_map_table(pa, "APIC");
130                if (va == 0)
131                        continue;
132                return (madt_t *)va;
133        }
134
135        return NULL;
136}
137
138/* -------------------------------------------------------------------------- */
139
140static rsdt_t *hal_acpi_map_rsdt(rsdp_t *rsdp)
141{
142        paddr_t rsdt_pa;
143        rsdt_t *rsdt;
144
145        rsdt_pa = (paddr_t)rsdp->RsdtPhysicalAddress;
146        rsdt = (rsdt_t *)hal_acpi_map_table(rsdt_pa, "RSDT");
147        if (rsdt == 0)
148                x86_panic("RSDT invalid");
149
150        return rsdt;
151}
152
153/* -------------------------------------------------------------------------- */
154
155static bool_t hal_acpi_rsdp_correct(uint8_t *ptr)
156{
157        uint8_t sum = 0;
158        size_t i;
159
160        /* Verify checksum */
161        for (i = 0; i < 20; i++) {
162                sum += ptr[i];
163        }
164
165        return (sum == 0);
166}
167
168static rsdp_t *hal_acpi_find_rsdp(vaddr_t va_start, vaddr_t va_end)
169{
170        rsdp_t *rsdp;
171        vaddr_t va = va_start;
172        size_t i, n = PAGE_SIZE / ACPI_RSDP_ALIGN;
173        char oem[ACPI_OEM_ID_SIZE + 1];
174        uint8_t *ptr;
175
176        /* The table is on a 16bit boundary */
177        for (va = va_start; va < va_end; va += PAGE_SIZE) {
178                for (i = 0; i < n; i++) {
179                        ptr = (uint8_t *)va + i * ACPI_RSDP_ALIGN;
180                        if (memcmp(ptr, ACPI_RSDP_SIGNATURE, ACPI_RSDP_SIGNATURE_SIZE))
181                                continue;
182                        if (!hal_acpi_rsdp_correct(ptr))
183                                continue;
184                        goto found;
185                }
186        }
187
188        return NULL;
189
190found:
191        rsdp = (rsdp_t *)ptr;
192
193        memcpy(&oem, rsdp->OemId, ACPI_OEM_ID_SIZE);
194        oem[ACPI_OEM_ID_SIZE] = '\0';
195        x86_printf("-> OEM: %s\n", oem);
196        if (rsdp->Revision != 0)
197                x86_printf("[!] Using ACPI 1.0\n");
198
199        return rsdp;
200}
201
202/* -------------------------------------------------------------------------- */
203
204void hal_acpi_init()
205{
206        rsdp_t *rsdp;
207        rsdt_t *rsdt;
208        madt_t *madt;
209        paddr_t bios_min = 0x0E0000;
210        paddr_t bios_max = 0x100000;
211        vaddr_t vabase;
212        vaddr_t va;
213        paddr_t pa;
214        size_t i, npages;
215
216        npages = (bios_max - bios_min) / PAGE_SIZE;
217        vabase = hal_gpt_bootstrap_valloc(npages);
218
219        for (i = 0; i < npages; i++) {
220                va = vabase + i * PAGE_SIZE;
221                pa = bios_min + i * PAGE_SIZE;
222                hal_gpt_enter(va, pa);
223                invlpg(va);
224        }
225
226        /* First, find RSDP */
227        rsdp = hal_acpi_find_rsdp(vabase, vabase + npages * PAGE_SIZE);
228        if (rsdp == NULL)
229                x86_panic("RSDP not found");
230
231        /* Then, map RSDT */
232        rsdt = hal_acpi_map_rsdt(rsdp);
233        if (rsdt == NULL)
234                x86_panic("RSDT not found");
235
236        /* Now, map MADT */
237        madt = hal_acpi_map_madt(rsdt);
238        if (madt == NULL)
239                x86_panic("MADT not found");
240
241        /* Parse it */
242        hal_acpi_parse_madt(madt);
243}
244
Note: See TracBrowser for help on using the repository browser.