From d8f2dcebd8b4c384ceb553c7222d54b26b322151 Mon Sep 17 00:00:00 2001 From: Arthur Heymans Date: Thu, 22 Jun 2023 13:42:36 +0200 Subject: acpi.c: Swap XSDT and RSDT for adding/finding tables 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 architectures 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. This also deal with the ACPI pointer being above 4G. This currently never happens with x86 platforms. Signed-off-by: Arthur Heymans Change-Id: I6588676186faa896b6076f871d7f8f633db21e70 Reviewed-on: https://review.coreboot.org/c/coreboot/+/76000 Tested-by: build bot (Jenkins) Reviewed-by: Lean Sheng Tan Reviewed-by: Eric Lai --- src/acpi/acpi.c | 68 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/acpi/acpi.c b/src/acpi/acpi.c index a2e9fdb8d8..07ca408634 100644 --- a/src/acpi/acpi.c +++ b/src/acpi/acpi.c @@ -49,18 +49,15 @@ void acpi_add_table(acpi_rsdp_t *rsdp, void *table) acpi_rsdt_t *rsdt; acpi_xsdt_t *xsdt = NULL; - /* The RSDT is mandatory... */ + /* The 32bit RSDT may not be valid if tables live above 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; } @@ -70,36 +67,34 @@ void acpi_add_table(acpi_rsdp_t *rsdp, void *table) 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)); + /* Fix XSDT length or the kernel will assume invalid entries. */ + 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 && (uintptr_t)table < UINT32_MAX) { + /* 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 enum cb_err acpi_fill_header(acpi_header_t *header, const char name[4], @@ -1451,14 +1446,19 @@ unsigned long write_acpi_tables(const unsigned long start) printk(BIOS_INFO, "ACPI: Writing ACPI tables at %lx.\n", start); - /* We need at least an RSDP and an RSDT Table */ + /* We need at least an RSDP, RSDT for ACPI 1.0 compat, otherwise XSDT */ rsdp = (acpi_rsdp_t *)current; 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 + sizeof(acpi_rsdt_t) - 1 <= UINT32_MAX) { + rsdt = (acpi_rsdt_t *)current; + current += sizeof(acpi_rsdt_t); + current = acpi_align_current(current); + } else { + printk(BIOS_INFO, "Not adding RSDT because tables reside above 4G."); + } + xsdt = (acpi_xsdt_t *)current; current += sizeof(acpi_xsdt_t); current = acpi_align_current(current); @@ -1554,7 +1554,7 @@ static acpi_rsdp_t *valid_rsdp(acpi_rsdp_t *rsdp) void *acpi_find_wakeup_vector(void) { char *p, *end; - acpi_rsdt_t *rsdt; + acpi_xsdt_t *xsdt; acpi_facs_t *facs; acpi_fadt_t *fadt = NULL; acpi_rsdp_t *rsdp = NULL; @@ -1580,13 +1580,13 @@ void *acpi_find_wakeup_vector(void) } printk(BIOS_DEBUG, "RSDP found at %p\n", rsdp); - rsdt = (acpi_rsdt_t *)(uintptr_t)rsdp->rsdt_address; + xsdt = (acpi_xsdt_t *)(uintptr_t)rsdp->xsdt_address; - end = (char *)rsdt + rsdt->header.length; - printk(BIOS_DEBUG, "RSDT found at %p ends at %p\n", rsdt, end); + end = (char *)xsdt + xsdt->header.length; + printk(BIOS_DEBUG, "XSDT found at %p ends at %p\n", xsdt, end); - for (i = 0; ((char *)&rsdt->entry[i]) < end; i++) { - fadt = (acpi_fadt_t *)(uintptr_t)rsdt->entry[i]; + for (i = 0; ((char *)&xsdt->entry[i]) < end; i++) { + fadt = (acpi_fadt_t *)(uintptr_t)xsdt->entry[i]; if (strncmp((char *)fadt, "FACP", 4) == 0) break; fadt = NULL; -- cgit v1.2.3