summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorPatrick Rudolph <[email protected]>2024-10-23 15:19:56 +0200
committerTom Rini <[email protected]>2024-10-27 17:24:13 -0600
commit5dc22f767c249cd8df724b172840acb7321fc4f8 (patch)
tree41a7676b4ba0584e2212fda102b517cbdad72aa7 /lib
parent3451e03238fbd22240eee9dcee7bee857afd931a (diff)
acpi_table: Support platforms with unusable RSDT
Since ACPI 2.0 the RSDT is deprecated and the XSDT should be preferred. Until now the RSDT and XSDT entries were keept in sync as all platforms that installed ACPI tables placed them below 4GiB and thus the address would fit into the 32bit RSDT. On platforms that do not have usable DRAM below 4GiB, like QEMU sbsa, the RSDT cannot be used. Allow both RSDT and XSDT to be null and only fill those tables that are present in acpi_add_table(). TEST: Fixes a crash on QEMU sbsa and allows to boot on QEMU sbsa. Signed-off-by: Patrick Rudolph <[email protected]> Reviewed-by: Simon Glass <[email protected]> Cc: Simon Glass <[email protected]> Cc: Tom Rini <[email protected]>
Diffstat (limited to 'lib')
-rw-r--r--lib/acpi/acpi_table.c87
1 files changed, 53 insertions, 34 deletions
diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
index 9d9c8befe85..d6357bdc4db 100644
--- a/lib/acpi/acpi_table.c
+++ b/lib/acpi/acpi_table.c
@@ -157,51 +157,70 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table)
struct acpi_rsdt *rsdt;
struct acpi_xsdt *xsdt;
- /* The RSDT is mandatory while the XSDT is not */
- rsdt = ctx->rsdt;
+ /* On legacy x86 platforms the RSDT is mandatory while the XSDT is not.
+ * On other platforms there might be no memory below 4GiB, thus RSDT is NULL.
+ */
+ if (ctx->rsdt) {
+ rsdt = ctx->rsdt;
- /* This should always be MAX_ACPI_TABLES */
- entries_num = ARRAY_SIZE(rsdt->entry);
+ /* This should always be MAX_ACPI_TABLES */
+ entries_num = ARRAY_SIZE(rsdt->entry);
- for (i = 0; i < entries_num; i++) {
- if (rsdt->entry[i] == 0)
- break;
- }
+ for (i = 0; i < entries_num; i++) {
+ if (rsdt->entry[i] == 0)
+ break;
+ }
+
+ if (i >= entries_num) {
+ log_err("ACPI: Error: too many tables\n");
+ return -E2BIG;
+ }
+
+ /* Add table to the RSDT */
+ rsdt->entry[i] = nomap_to_sysmem(table);
- if (i >= entries_num) {
- log_err("ACPI: Error: too many tables\n");
- return -E2BIG;
+ /* Fix RSDT length or the kernel will assume invalid entries */
+ rsdt->header.length = sizeof(struct acpi_table_header) +
+ (sizeof(u32) * (i + 1));
+
+ /* Re-calculate checksum */
+ rsdt->header.checksum = 0;
+ rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
+ rsdt->header.length);
}
- /* Add table to the RSDT */
- rsdt->entry[i] = nomap_to_sysmem(table);
+ if (ctx->xsdt) {
+ /*
+ * And now the same thing for the XSDT. We use the same index as for
+ * now we want the XSDT and RSDT to always be in sync in U-Boot
+ */
+ xsdt = ctx->xsdt;
- /* Fix RSDT length or the kernel will assume invalid entries */
- rsdt->header.length = sizeof(struct acpi_table_header) +
- (sizeof(u32) * (i + 1));
+ /* This should always be MAX_ACPI_TABLES */
+ entries_num = ARRAY_SIZE(xsdt->entry);
- /* Re-calculate checksum */
- rsdt->header.checksum = 0;
- rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
- rsdt->header.length);
+ for (i = 0; i < entries_num; i++) {
+ if (xsdt->entry[i] == 0)
+ break;
+ }
- /*
- * And now the same thing for the XSDT. We use the same index as for
- * now we want the XSDT and RSDT to always be in sync in U-Boot
- */
- xsdt = ctx->xsdt;
+ if (i >= entries_num) {
+ log_err("ACPI: Error: too many tables\n");
+ return -E2BIG;
+ }
- /* Add table to the XSDT */
- xsdt->entry[i] = nomap_to_sysmem(table);
+ /* Add table to the XSDT */
+ xsdt->entry[i] = nomap_to_sysmem(table);
- /* Fix XSDT length */
- xsdt->header.length = sizeof(struct acpi_table_header) +
- (sizeof(u64) * (i + 1));
+ /* Fix XSDT length */
+ xsdt->header.length = sizeof(struct acpi_table_header) +
+ (sizeof(u64) * (i + 1));
- /* Re-calculate checksum */
- xsdt->header.checksum = 0;
- xsdt->header.checksum = table_compute_checksum((u8 *)xsdt,
- xsdt->header.length);
+ /* Re-calculate checksum */
+ xsdt->header.checksum = 0;
+ xsdt->header.checksum = table_compute_checksum((u8 *)xsdt,
+ xsdt->header.length);
+ }
return 0;
}