Loading...
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 | /*
* Copyright (c) 2019 Intel Corporation
* SPDX-License-Identifier: Apache-2.0
*/
#include <kernel.h>
#include <arch/x86/acpi.h>
/*
* Finding and walking the ACPI tables can be time consuming, so we do
* it once, early, and then cache the "interesting" results for later.
*/
static struct acpi_madt *madt;
/*
* ACPI structures use a simple checksum, such that
* summing all the bytes in the structure yields 0.
*/
static bool validate_checksum(void *buf, int len)
{
u8_t *cp = buf;
u8_t checksum = 0;
while (len--) {
checksum += *(cp++);
}
return (checksum == 0);
}
/*
* Called very early during initialization to find ACPI tables of interest.
* First, we find the RDSP, and if found, use that to find the RSDT, which
* we then use to find the MADT. (This function is long, but easy to follow.)
*/
void z_acpi_init(void)
{
/*
* First, find the RSDP by probing "well-known" areas of memory.
*/
struct acpi_rsdp *rsdp = NULL;
static const struct {
uintptr_t base;
uintptr_t top;
} area[] = {
{ 0x000E0000, 0x00100000 }, /* BIOS ROM */
{ 0, 0 }
};
for (int i = 0; area[i].base && area[i].top && !rsdp; ++i) {
uintptr_t addr = area[i].base;
while (addr < area[i].top) {
struct acpi_rsdp *probe = UINT_TO_POINTER(addr);
if ((probe->signature == ACPI_RSDP_SIGNATURE) &&
(validate_checksum(probe, sizeof(*probe)))) {
rsdp = probe;
break;
}
addr += 0x10;
}
}
if (rsdp == NULL) {
return;
}
/*
* Then, validate the RSDT fingered by the RSDP.
*/
struct acpi_rsdt *rsdt = UINT_TO_POINTER(rsdp->rsdt);
if ((rsdt->sdt.signature != ACPI_RSDT_SIGNATURE) ||
!validate_checksum(rsdt, rsdt->sdt.length)) {
rsdt = NULL;
return;
}
/*
* Finally, probe each SDT listed in the RSDT to find the MADT.
* If it's valid, then remember it for later.
*/
int nr_sdts = (rsdt->sdt.length - sizeof(rsdt)) / sizeof(u32_t);
for (int i = 0; i < nr_sdts; ++i) {
struct acpi_sdt *sdt = UINT_TO_POINTER(rsdt->sdts[i]);
if ((sdt->signature == ACPI_MADT_SIGNATURE)
&& validate_checksum(sdt, sdt->length)) {
madt = (struct acpi_madt *) sdt;
break;
}
}
}
/*
* Return the 'n'th CPU entry from the ACPI MADT, or NULL if not available.
*/
struct acpi_cpu *z_acpi_get_cpu(int n)
{
uintptr_t base = POINTER_TO_UINT(madt);
uintptr_t offset;
if (madt) {
offset = POINTER_TO_UINT(madt->entries) - base;
while (offset < madt->sdt.length) {
struct acpi_madt_entry *entry;
entry = (struct acpi_madt_entry *) (offset + base);
if (entry->type == ACPI_MADT_ENTRY_CPU) {
if (n) {
--n;
} else {
return (struct acpi_cpu *) entry;
}
}
offset += entry->length;
}
}
return NULL;
}
|