Arthur Heymans has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/76000?usp=email )
Change subject: acpi: Swap XSDT and RSDT in acpi_add_table() ......................................................................
acpi: Swap XSDT and RSDT in acpi_add_table()
If ACPI is above 4G it's not possible to have a valid RSDT pointer in RSDP, therefore swap RSDT and XSDT. Both are always generated on x86. On other architecures RSDT is often skipped, e.g. aarch64. On top of that the OS looks at XSDT first. So unconditionally using XSDT and not RSDT is fine.
Signed-off-by: Arthur Heymans arthur@aheymans.xyz Change-Id: I6588676186faa896b6076f871d7f8f633db21e70 --- M src/acpi/acpi.c 1 file changed, 25 insertions(+), 26 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/00/76000/1
diff --git a/src/acpi/acpi.c b/src/acpi/acpi.c index aa1cd1c..5e03bf4 100644 --- a/src/acpi/acpi.c +++ b/src/acpi/acpi.c @@ -57,18 +57,15 @@ acpi_rsdt_t *rsdt; acpi_xsdt_t *xsdt = NULL;
- /* The RSDT is mandatory... */ + /* RSDT may not be valid if ACPI is > 4GiB */ rsdt = (acpi_rsdt_t *)(uintptr_t)rsdp->rsdt_address; - - /* ...while the XSDT is not. */ - if (rsdp->xsdt_address) - xsdt = (acpi_xsdt_t *)((uintptr_t)rsdp->xsdt_address); + xsdt = (acpi_xsdt_t *)((uintptr_t)rsdp->xsdt_address);
/* This should always be MAX_ACPI_TABLES. */ - entries_num = ARRAY_SIZE(rsdt->entry); + entries_num = ARRAY_SIZE(xsdt->entry);
for (i = 0; i < entries_num; i++) { - if (rsdt->entry[i] == 0) + if (xsdt->entry[i] == 0) break; }
@@ -78,36 +75,36 @@ return; }
- /* Add table to the RSDT. */ - rsdt->entry[i] = (uintptr_t)table; + /* Add table to the XSDT. */ + xsdt->entry[i] = (u64)(uintptr_t)table;
/* Fix RSDT length or the kernel will assume invalid entries. */ - rsdt->header.length = sizeof(acpi_header_t) + (sizeof(u32) * (i + 1)); + xsdt->header.length = sizeof(acpi_header_t) + (sizeof(u64) * (i + 1));
/* Re-calculate checksum. */ - rsdt->header.checksum = 0; /* Hope this won't get optimized away */ - rsdt->header.checksum = acpi_checksum((u8 *)rsdt, rsdt->header.length); + xsdt->header.checksum = 0; /* Hope this won't get optimized away */ + xsdt->header.checksum = acpi_checksum((u8 *)xsdt, xsdt->header.length);
/* - * And now the same thing for the XSDT. We use the same index as for + * And now the same thing for the RSDT. We use the same index as for * now we want the XSDT and RSDT to always be in sync in coreboot. */ - if (xsdt) { - /* Add table to the XSDT. */ - xsdt->entry[i] = (u64)(uintptr_t)table; + if (rsdt) { + /* Add table to the RSDT. */ + rsdt->entry[i] = (u32)(uintptr_t)table;
- /* Fix XSDT length. */ - xsdt->header.length = sizeof(acpi_header_t) + - (sizeof(u64) * (i + 1)); + /* Fix RSDT length. */ + rsdt->header.length = sizeof(acpi_header_t) + + (sizeof(u32) * (i + 1));
/* Re-calculate checksum. */ - xsdt->header.checksum = 0; - xsdt->header.checksum = acpi_checksum((u8 *)xsdt, - xsdt->header.length); + rsdt->header.checksum = 0; + rsdt->header.checksum = acpi_checksum((u8 *)rsdt, + rsdt->header.length); }
printk(BIOS_DEBUG, "ACPI: added table %d/%d, length now %d\n", - i + 1, entries_num, rsdt->header.length); + i + 1, entries_num, xsdt->header.length); }
static int acpi_create_mcfg_mmconfig(acpi_mcfg_mmconfig_t *mmconfig, u32 base, @@ -1967,9 +1964,11 @@ coreboot_rsdp = (uintptr_t)rsdp; current += sizeof(acpi_rsdp_t); current = acpi_align_current(current); - rsdt = (acpi_rsdt_t *)current; - current += sizeof(acpi_rsdt_t); - current = acpi_align_current(current); + if (current < 4ULL * GiB) { + rsdt = (acpi_rsdt_t *)current; + current += sizeof(acpi_rsdt_t); + current = acpi_align_current(current); + } xsdt = (acpi_xsdt_t *)current; current += sizeof(acpi_xsdt_t); current = acpi_align_current(current);