Jérémy Compostella has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/83608?usp=email )
Change subject: acpi: Add an ACPI table override mechanism for debug purposes ......................................................................
acpi: Add an ACPI table override mechanism for debug purposes
During various development stages it can very handy to dump any ACPI tables, de-compile, modify and reload without having to touch coreboot code. This commit offers a mechanism to load ACPI tables stored back-to-back in a CBFS raw file and override coreboot matching generated ACPI tables right before handing over to the second stage bootloader.
Two Kconfig are introduced: 1. `ACPI_REPLACE_TABLES_WITH_CBFS_TABLES' to enable the feature. 2. `ACPI_CBFS_TABLES_FILE' to provide the path and filename of the ACPI tables binary.
The following two Kconfig may need some adjustment to work: - `MAX_ACPI_TABLE_SIZE_KB' to fit the new content - `MAX_ACPI_TABLES' if the number of tables is different. Typically if many SSDT are replacing the single SSDT that coreboot generates. - `RAMSTAGE_CBFS_CACHE_SIZE' to have enough space to load the CBFS file which is LZ4 compressed by default.
Change-Id: Ifed6953db1a634d62852c4162a97a5b00b1d6b51 Signed-off-by: Jeremy Compostella jeremy.compostella@intel.com --- M src/acpi/Kconfig M src/acpi/Makefile.mk M src/acpi/acpi.c 3 files changed, 161 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/08/83608/1
diff --git a/src/acpi/Kconfig b/src/acpi/Kconfig index 2bb56ba..c63ed49 100644 --- a/src/acpi/Kconfig +++ b/src/acpi/Kconfig @@ -6,6 +6,19 @@ Provide common definitions for AMD hardware PM1_CNT register sleep values.
+config ACPI_REPLACE_TABLES_WITH_CBFS_TABLES + bool + help + coreboot replaces ACPI tables, at the last minute, with ACPI + tables loaded from CBFS file content. If a table is not in + the CBFS file, the coreboot one is kept. + +config ACPI_CBFS_TABLES_FILE + string "Back to back ACPI table binary path and filename" + depends on ACPI_REPLACE_TABLES_WITH_CBFS_TABLES + help + The path and filename of the ACPI tables binary. + config ACPI_CPU_STRING string default "CP%02X" diff --git a/src/acpi/Makefile.mk b/src/acpi/Makefile.mk index e9d5cb0..5d14b5c 100644 --- a/src/acpi/Makefile.mk +++ b/src/acpi/Makefile.mk @@ -27,6 +27,13 @@ all-y += acpi_pm.c smm-y += acpi_pm.c
+ifeq ($(CONFIG_ACPI_REPLACE_TABLES_WITH_CBFS_TABLES),y) +cbfs-files-y += acpi_tables.bin +acpi_tables.bin-file := $(call strip_quotes,$(CONFIG_ACPI_CBFS_TABLES_FILE)) +acpi_tables.bin-compression := LZ4 +acpi_tables.bin-type := raw +endif + ifneq ($(wildcard src/mainboard/$(MAINBOARDDIR)/acpi_tables.c),) ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/acpi_tables.c endif diff --git a/src/acpi/acpi.c b/src/acpi/acpi.c index 06aa038c..e8e89b7 100644 --- a/src/acpi/acpi.c +++ b/src/acpi/acpi.c @@ -27,6 +27,7 @@ #include <device/pci.h> #include <drivers/crb/tpm.h> #include <drivers/uart/pl011.h> +#include <lib.h> #include <security/tpm/tss.h> #include <string.h> #include <types.h> @@ -44,6 +45,138 @@ return -ret; }
+static acpi_header_t *find_table(acpi_header_t *tables, acpi_header_t *end, + const char *signature) +{ + acpi_header_t *table = tables; + for (table = tables; tables < end && table->signature[0] != '\0'; + table = (acpi_header_t *)((uintptr_t)table + table->length)) + if (!memcmp(table->signature, signature, sizeof(table->signature))) + return table; + return NULL; +} + +static unsigned long add_tables(acpi_rsdp_t *rsdp, + unsigned long current, + acpi_header_t *tables, + acpi_header_t *end_tables, + acpi_header_t *excluded, + acpi_header_t *end_excluded) +{ + for (acpi_header_t *table = tables; table < end_tables; + table = (acpi_header_t *)((uintptr_t)table + table->length)) { + if (!memcmp(table->signature, "FACP", sizeof(table->signature)) + || !memcmp(table->signature, "DSDT", sizeof(table->signature)) + || !memcmp(table->signature, "FACS", sizeof(table->signature)) + || (excluded && find_table(excluded, end_excluded, table->signature))) + continue; + memcpy((void *)current, table, table->length); + acpi_add_table(rsdp, (void *)current); + + current += table->length; + current = acpi_align_current(current); + } + + return current; +} + +static void backup_table(acpi_header_t *table, acpi_header_t **buffer) +{ + memcpy(*buffer, table, table->length); + *buffer = (acpi_header_t *)((uintptr_t)*buffer + table->length); +} + +static unsigned long replace_table_with_CBFS(acpi_rsdp_t *rsdp, unsigned long current) +{ + static char buffer[CONFIG_MAX_ACPI_TABLE_SIZE_KB * KiB]; + int i, entries_num; + size_t tables_size; + acpi_header_t *tables, *end_tables, *table; + acpi_xsdt_t *xsdt; + acpi_rsdt_t *rsdt; + acpi_fadt_t *fadt = NULL; + acpi_header_t *backup = (acpi_header_t *)buffer, *end_backup = backup; + + tables = cbfs_map("acpi_tables.bin", &tables_size); + if (!tables) { + printk(BIOS_ERR, "Could not load ACPI tables\n"); + return 0; + } + + if (tables_size < sizeof(*table)) { + printk(BIOS_ERR, "CBFS file too small to contain ACPI tables\n"); + return 0; + } + + end_tables = (acpi_header_t *)((uintptr_t)tables + tables_size); + + /* Back all the coreboot generated ACPI table and clear the table list. */ + xsdt = (acpi_xsdt_t *)(uintptr_t)rsdp->xsdt_address; + rsdt = (acpi_rsdt_t *)(uintptr_t)rsdp->rsdt_address; + entries_num = ARRAY_SIZE(xsdt->entry); + for (i = 0; i < entries_num && xsdt->entry[i] != 0; i++) { + table = (acpi_header_t *)(uintptr_t)xsdt->entry[i]; + backup_table(table, &end_backup); + + if (!memcmp(table->signature, "FACP", sizeof(table->signature))) { + fadt = (acpi_fadt_t *)table; + if (fadt->dsdt) + backup_table((acpi_header_t *)fadt->dsdt, &end_backup); + if (fadt->firmware_ctrl) + backup_table((acpi_header_t *)fadt->firmware_ctrl, &end_backup); + } + + xsdt->entry[i] = (u64)0; + rsdt->entry[i] = (u64)0; + } + + /* Pick FACT, DSDT and FACS from CBFS supplied table or use backup. */ + fadt = (acpi_fadt_t *)find_table(tables, end_tables, "FACP"); + if (!fadt) + fadt = (acpi_fadt_t *)backup; + memcpy((void *)current, fadt, fadt->header.length); + + acpi_add_table(rsdp, (void *)current); + + current += fadt->header.length; + current = acpi_align_current(current); + + table = find_table(tables, end_tables, "DSDT"); + if (!table) + table = find_table((acpi_header_t *)backup, end_backup, "DSDT"); + if (table) { + memcpy((void *)current, table, table->length); + if ((uintptr_t)table <= UINT32_MAX) + fadt->dsdt = (uintptr_t)table; + else + fadt->x_dsdt_h = (uint32_t)((uint64_t)(uintptr_t)table >> 32); + fadt->x_dsdt_l = (uint32_t)(uintptr_t)table; + current += table->length; + } + + table = find_table(tables, end_tables, "FACS"); + if (!table) + table = find_table(backup, end_backup, "FACS"); + if (table) { + if ((uintptr_t)table <= UINT32_MAX) + fadt->firmware_ctrl = (uintptr_t)table; + else + fadt->x_firmware_ctl_h = (uint32_t)((uint64_t)(uintptr_t)table >> 32); + fadt->x_firmware_ctl_l = (uint32_t)(uintptr_t)table; + } + + fadt->header.checksum = 0; + fadt->header.checksum = acpi_checksum((void *)fadt, sizeof(acpi_fadt_t)); + + /* Install all the CBFS supplied ACPI tables. */ + current = add_tables(rsdp, current, tables, end_tables, NULL, NULL); + /* Install backup ACPI tables which are missing in CBFS. */ + current = add_tables(rsdp, current, backup, end_backup, tables, end_tables); + + cbfs_unmap(tables); + return current; +} + /** * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length * and checksum. @@ -1602,6 +1735,7 @@
/* clear all table memory */ memset((void *)start, 0, current - start); + unsigned long tables_start = current;
acpi_write_rsdp(rsdp, rsdt, xsdt, oem_id); acpi_write_rsdt(rsdt, oem_id, oem_table_id); @@ -1666,6 +1800,13 @@ printk(BIOS_DEBUG, "Done printing ACPI tables in ACPICA compatible format\n"); }
+ if (CONFIG(ACPI_REPLACE_TABLES_WITH_CBFS_TABLES)) { + unsigned long ret; + ret = replace_table_with_CBFS(rsdp, tables_start); + if (ret != 0) + current = ret; + } + return current; }