
On Mon, Mar 30, 2020 at 17:13:05 -0600, Simon Glass wrote:
It is useful to dump ACPI tables in U-Boot to see what has been generated. Add a command to handle this.
To allow the command to find the tables, add a position into the global data.
Support subcommands to list and dump the tables.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Wolfgang Wallner wolfgang.wallner@br-automation.com
Changes in v3: None Changes in v2: None
arch/sandbox/include/asm/global_data.h | 1 + arch/x86/include/asm/global_data.h | 1 + cmd/Kconfig | 14 ++ cmd/Makefile | 1 + cmd/acpi.c | 179 +++++++++++++++++++++++++ lib/acpi/acpi_table.c | 1 + test/dm/acpi.c | 73 ++++++++++ 7 files changed, 270 insertions(+) create mode 100644 cmd/acpi.c
diff --git a/arch/sandbox/include/asm/global_data.h b/arch/sandbox/include/asm/global_data.h index f4ce72d5660..f95ddb058a2 100644 --- a/arch/sandbox/include/asm/global_data.h +++ b/arch/sandbox/include/asm/global_data.h @@ -13,6 +13,7 @@ struct arch_global_data { uint8_t *ram_buf; /* emulated RAM buffer */ void *text_base; /* pointer to base of text region */
- ulong acpi_start; /* Start address of ACPI tables */
};
#include <asm-generic/global_data.h> diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index f4c1839104e..4aee2f3e8c4 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -123,6 +123,7 @@ struct arch_global_data { #ifdef CONFIG_FSP_VERSION2 struct fsp_header *fsp_s_hdr; /* Pointer to FSP-S header */ #endif
- ulong acpi_start; /* Start address of ACPI tables */
};
#endif diff --git a/cmd/Kconfig b/cmd/Kconfig index 6403bc45a5e..2d3bfe0ab91 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -190,6 +190,20 @@ comment "Commands"
menu "Info commands"
+config CMD_ACPI
- bool "acpi"
- default y if ACPIGEN
- help
List and dump ACPI tables. ACPI (Advanced Configuration and Power
Interface) is used mostly on x86 for providing information to the
Operating System about devices in the system. The tables are set up
by the firmware, typically U-Boot but possibly an earlier firmware
module, if U-Boot is chain-loaded from something else. ACPI tables
can also include code, to perform hardware-specific tasks required
by the Operating Systems. This allows some amount of separation
between the firmware and OS, and is particularly useful when you
want to make hardware changes without the OS needing to be adjusted.
config CMD_BDI bool "bdinfo" default y diff --git a/cmd/Makefile b/cmd/Makefile index f1dd513a4b4..15a9693ed0e 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -11,6 +11,7 @@ obj-y += help.o obj-y += version.o
# command +obj-$(CONFIG_CMD_ACPI) += acpi.o obj-$(CONFIG_CMD_AES) += aes.o obj-$(CONFIG_CMD_AB_SELECT) += ab_select.o obj-$(CONFIG_CMD_ADC) += adc.o diff --git a/cmd/acpi.c b/cmd/acpi.c new file mode 100644 index 00000000000..8a320435736 --- /dev/null +++ b/cmd/acpi.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright 2019 Google LLC
- Written by Simon Glass sjg@chromium.org
- */
+#include <common.h> +#include <command.h> +#include <mapmem.h> +#include <acpi/acpi_table.h> +#include <asm/acpi_table.h> +#include <dm/acpi.h>
+DECLARE_GLOBAL_DATA_PTR;
+static void dump_hdr(struct acpi_table_header *hdr) +{
- bool has_hdr = memcmp(hdr->signature, "FACS", ACPI_NAME_LEN);
- printf("%.*s %08lx %06x", ACPI_NAME_LEN, hdr->signature,
(ulong)map_to_sysmem(hdr), hdr->length);
- if (has_hdr) {
printf(" (v%02d %.6s %.8s %u %.4s %d)\n", hdr->revision,
hdr->oem_id, hdr->oem_table_id, hdr->oem_revision,
hdr->aslc_id, hdr->aslc_revision);
- } else {
printf("\n");
- }
+}
+/**
- find_table() - Look up an ACPI table
- @sig: Signature of table (4 characters, upper case)
- @return pointer to table header, or NULL if not found
- */
+struct acpi_table_header *find_table(const char *sig) +{
- struct acpi_rsdp *rsdp;
- struct acpi_rsdt *rsdt;
- int len, i, count;
- rsdp = map_sysmem(gd->arch.acpi_start, 0);
- if (!rsdp)
return NULL;
- rsdt = map_sysmem(rsdp->rsdt_address, 0);
- len = rsdt->header.length - sizeof(rsdt->header);
- count = len / sizeof(u32);
- for (i = 0; i < count; i++) {
struct acpi_table_header *hdr;
hdr = map_sysmem(rsdt->entry[i], 0);
if (!memcmp(hdr->signature, sig, ACPI_NAME_LEN))
return hdr;
if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN)) {
struct acpi_fadt *fadt = (struct acpi_fadt *)hdr;
if (!memcmp(sig, "DSDT", ACPI_NAME_LEN) && fadt->dsdt)
return map_sysmem(fadt->dsdt, 0);
if (!memcmp(sig, "FACS", ACPI_NAME_LEN) &&
fadt->firmware_ctrl)
return map_sysmem(fadt->firmware_ctrl, 0);
}
- }
- return NULL;
+}
+static int dump_table_name(const char *sig) +{
- struct acpi_table_header *hdr;
- hdr = find_table(sig);
- if (!hdr)
return -ENOENT;
- printf("%.*s @ %08lx\n", ACPI_NAME_LEN, hdr->signature,
(ulong)map_to_sysmem(hdr));
- print_buffer(0, hdr, 1, hdr->length, 0);
- return 0;
+}
+static void list_fact(struct acpi_fadt *fadt)
Hmm, should this function be called list_facp or list_fadt? (The wonder that is the table called FADT with the marker FACP.)
/ Leif
+{
- if (fadt->dsdt)
dump_hdr(map_sysmem(fadt->dsdt, 0));
- if (fadt->firmware_ctrl)
dump_hdr(map_sysmem(fadt->firmware_ctrl, 0));
+}
+static int list_rsdt(struct acpi_rsdt *rsdt, struct acpi_xsdt *xsdt) +{
- int len, i, count;
- dump_hdr(&rsdt->header);
- if (xsdt)
dump_hdr(&xsdt->header);
- len = rsdt->header.length - sizeof(rsdt->header);
- count = len / sizeof(u32);
- for (i = 0; i < count; i++) {
struct acpi_table_header *hdr;
if (!rsdt->entry[i])
break;
hdr = map_sysmem(rsdt->entry[i], 0);
dump_hdr(hdr);
if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN))
list_fact((struct acpi_fadt *)hdr);
if (xsdt) {
if (xsdt->entry[i] != rsdt->entry[i]) {
printf(" (xsdt mismatch %llx)\n",
xsdt->entry[i]);
}
}
- }
- return 0;
+}
+static int list_rsdp(struct acpi_rsdp *rsdp) +{
- struct acpi_rsdt *rsdt;
- struct acpi_xsdt *xsdt;
- printf("RSDP %08lx %06x (v%02d %.6s)\n", (ulong)map_to_sysmem(rsdp),
rsdp->length, rsdp->revision, rsdp->oem_id);
- rsdt = map_sysmem(rsdp->rsdt_address, 0);
- xsdt = map_sysmem(rsdp->xsdt_address, 0);
- list_rsdt(rsdt, xsdt);
- return 0;
+}
+static int do_acpi_list(cmd_tbl_t *cmdtp, int flag, int argc,
char *const argv[])
+{
- struct acpi_rsdp *rsdp;
- rsdp = map_sysmem(gd->arch.acpi_start, 0);
- if (!rsdp) {
printf("No ACPI tables present\n");
return 0;
- }
- printf("ACPI tables start at %lx\n", gd->arch.acpi_start);
- list_rsdp(rsdp);
- return 0;
+}
+static int do_acpi_dump(cmd_tbl_t *cmdtp, int flag, int argc,
char *const argv[])
+{
- const char *name;
- char sig[ACPI_NAME_LEN];
- int ret;
- if (argc < 2)
return CMD_RET_USAGE;
- name = argv[1];
- if (strlen(name) != ACPI_NAME_LEN) {
printf("Table name '%s' must be four characters\n", name);
return CMD_RET_FAILURE;
- }
- str_to_upper(name, sig, -1);
- ret = dump_table_name(sig);
- if (ret) {
printf("Table '%.*s' not found\n", ACPI_NAME_LEN, sig);
return CMD_RET_FAILURE;
- }
- return 0;
+}
+static char acpi_help_text[] =
- "list - list ACPI tables\n"
- "acpi dump <name> - Dump ACPI table";
+U_BOOT_CMD_WITH_SUBCMDS(acpi, "ACPI tables", acpi_help_text,
- U_BOOT_SUBCMD_MKENT(list, 1, 1, do_acpi_list),
- U_BOOT_SUBCMD_MKENT(dump, 2, 1, do_acpi_dump));
diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c index 28003dc8f46..3b5479eb85b 100644 --- a/lib/acpi/acpi_table.c +++ b/lib/acpi/acpi_table.c @@ -238,6 +238,7 @@ void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start)
/* Align ACPI tables to 16 byte */ acpi_align(ctx);
gd->arch.acpi_start = map_to_sysmem(ctx->current);
/* We need at least an RSDP and an RSDT Table */ ctx->rsdp = ctx->current;
diff --git a/test/dm/acpi.c b/test/dm/acpi.c index 8e160d2cf4e..4eabf53128a 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -7,9 +7,11 @@ */
#include <common.h> +#include <console.h> #include <dm.h> #include <malloc.h> #include <mapmem.h> +#include <version.h> #include <tables_csum.h> #include <version.h> #include <acpi/acpi_table.h> @@ -212,6 +214,7 @@ static int dm_test_acpi_setup_base_tables(struct unit_test_state *uts) buf = memalign(64, BUF_SIZE); ut_assertnonnull(buf); acpi_setup_base_tables(&ctx, buf + 4);
ut_asserteq(map_to_sysmem(PTR_ALIGN(buf + 4, 16)), gd->arch.acpi_start);
rsdp = buf + 16; ut_asserteq_ptr(rsdp, ctx.rsdp);
@@ -242,3 +245,73 @@ static int dm_test_acpi_setup_base_tables(struct unit_test_state *uts) } DM_TEST(dm_test_acpi_setup_base_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+/* Test 'acpi list' command */ +static int dm_test_acpi_cmd_list(struct unit_test_state *uts) +{
- struct acpi_ctx ctx;
- ulong addr;
- void *buf;
- buf = memalign(16, BUF_SIZE);
- ut_assertnonnull(buf);
- acpi_setup_base_tables(&ctx, buf);
- ut_assertok(acpi_write_dev_tables(&ctx));
- console_record_reset();
- run_command("acpi list", 0);
- addr = (ulong)map_to_sysmem(buf);
- ut_assert_nextline("ACPI tables start at %lx", addr);
- ut_assert_nextline("RSDP %08lx %06lx (v02 U-BOOT)", addr,
sizeof(struct acpi_rsdp));
- addr = ALIGN(addr + sizeof(struct acpi_rsdp), 16);
- ut_assert_nextline("RSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
addr, sizeof(struct acpi_table_header) +
2 * sizeof(u32), U_BOOT_BUILD_DATE);
- addr = ALIGN(addr + sizeof(struct acpi_rsdt), 16);
- ut_assert_nextline("XSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
addr, sizeof(struct acpi_table_header) +
2 * sizeof(u64), U_BOOT_BUILD_DATE);
- addr = ALIGN(addr + sizeof(struct acpi_xsdt), 64);
- ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
- addr = ALIGN(addr + sizeof(struct acpi_dmar), 16);
- ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
- ut_assert_console_end();
- return 0;
+} +DM_TEST(dm_test_acpi_cmd_list, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+/* Test 'acpi dump' command */ +static int dm_test_acpi_cmd_dump(struct unit_test_state *uts) +{
- struct acpi_ctx ctx;
- ulong addr;
- void *buf;
- buf = memalign(16, BUF_SIZE);
- ut_assertnonnull(buf);
- acpi_setup_base_tables(&ctx, buf);
- ut_assertok(acpi_write_dev_tables(&ctx));
- /* First search for a non-existent table */
- console_record_reset();
- run_command("acpi dump rdst", 0);
- ut_assert_nextline("Table 'RDST' not found");
- ut_assert_console_end();
- /* Now a real table */
- console_record_reset();
- run_command("acpi dump dmar", 0);
- addr = ALIGN(map_to_sysmem(ctx.xsdt) + sizeof(struct acpi_xsdt), 64);
- ut_assert_nextline("DMAR @ %08lx", addr);
- ut_assert_nextlines_are_dump(0x30);
- ut_assert_console_end();
- return 0;
+}
+DM_TEST(dm_test_acpi_cmd_dump, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
2.26.0.rc2.310.g2932bb562d-goog