acpi: Support checking checksums

When the ACPI tables come from an earlier bootloader it is helpful to
see whether the checksums are correct or not. Add a -c flag to the
'acpi list' command to support that.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass
2025-03-15 14:26:05 +00:00
committed by Tom Rini
parent 9e98664cdb
commit 59001e758a
3 changed files with 102 additions and 21 deletions

View File

@@ -7,6 +7,7 @@
#include <display_options.h> #include <display_options.h>
#include <log.h> #include <log.h>
#include <mapmem.h> #include <mapmem.h>
#include <tables_csum.h>
#include <acpi/acpi_table.h> #include <acpi/acpi_table.h>
#include <asm/acpi_table.h> #include <asm/acpi_table.h>
#include <asm/global_data.h> #include <asm/global_data.h>
@@ -15,6 +16,17 @@
DECLARE_GLOBAL_DATA_PTR; DECLARE_GLOBAL_DATA_PTR;
static const char *show_checksum(void *ptr, uint size, bool chksums)
{
uint checksum;
if (!chksums)
return "";
checksum = table_compute_checksum(ptr, size);
return checksum ? " bad" : " OK";
}
/** /**
* dump_hdr() - Dump an ACPI header * dump_hdr() - Dump an ACPI header
* *
@@ -23,16 +35,17 @@ DECLARE_GLOBAL_DATA_PTR;
* *
* @hdr: ACPI header to dump * @hdr: ACPI header to dump
*/ */
static void dump_hdr(struct acpi_table_header *hdr) static void dump_hdr(struct acpi_table_header *hdr, bool chksums)
{ {
bool has_hdr = memcmp(hdr->signature, "FACS", ACPI_NAME_LEN); bool has_hdr = memcmp(hdr->signature, "FACS", ACPI_NAME_LEN);
printf("%.*s %16lx %5x", ACPI_NAME_LEN, hdr->signature, printf("%.*s %16lx %5x", ACPI_NAME_LEN, hdr->signature,
(ulong)map_to_sysmem(hdr), hdr->length); (ulong)map_to_sysmem(hdr), hdr->length);
if (has_hdr) { if (has_hdr) {
printf(" v%02d %.6s %.8s %x %.4s %x\n", hdr->revision, printf(" v%02d %.6s %.8s %x %.4s %x%s\n", hdr->revision,
hdr->oem_id, hdr->oem_table_id, hdr->oem_revision, hdr->oem_id, hdr->oem_table_id, hdr->oem_revision,
hdr->creator_id, hdr->creator_revision); hdr->creator_id, hdr->creator_revision,
show_checksum(hdr, hdr->length, chksums));
} else { } else {
printf("\n"); printf("\n");
} }
@@ -52,22 +65,22 @@ static int dump_table_name(const char *sig)
return 0; return 0;
} }
static void list_fadt(struct acpi_fadt *fadt) static void list_fadt(struct acpi_fadt *fadt, bool chksums)
{ {
if (fadt->header.revision >= 3 && fadt->x_dsdt) if (fadt->header.revision >= 3 && fadt->x_dsdt)
dump_hdr(nomap_sysmem(fadt->x_dsdt, 0)); dump_hdr(nomap_sysmem(fadt->x_dsdt, 0), chksums);
else if (fadt->dsdt) else if (fadt->dsdt)
dump_hdr(nomap_sysmem(fadt->dsdt, 0)); dump_hdr(nomap_sysmem(fadt->dsdt, 0), chksums);
if (!IS_ENABLED(CONFIG_X86) && !IS_ENABLED(CONFIG_SANDBOX) && if (!IS_ENABLED(CONFIG_X86) && !IS_ENABLED(CONFIG_SANDBOX) &&
!(fadt->flags & ACPI_FADT_HW_REDUCED_ACPI)) !(fadt->flags & ACPI_FADT_HW_REDUCED_ACPI))
log_err("FADT not ACPI-hardware-reduced-compliant\n"); log_err("FADT not ACPI-hardware-reduced-compliant\n");
if (fadt->header.revision >= 3 && fadt->x_firmware_ctrl) if (fadt->header.revision >= 3 && fadt->x_firmware_ctrl)
dump_hdr(nomap_sysmem(fadt->x_firmware_ctrl, 0)); dump_hdr(nomap_sysmem(fadt->x_firmware_ctrl, 0), chksums);
else if (fadt->firmware_ctrl) else if (fadt->firmware_ctrl)
dump_hdr(nomap_sysmem(fadt->firmware_ctrl, 0)); dump_hdr(nomap_sysmem(fadt->firmware_ctrl, 0), chksums);
} }
static void list_rsdt(struct acpi_rsdp *rsdp) static void list_rsdt(struct acpi_rsdp *rsdp, bool chksums)
{ {
int len, i, count; int len, i, count;
struct acpi_rsdt *rsdt; struct acpi_rsdt *rsdt;
@@ -75,11 +88,11 @@ static void list_rsdt(struct acpi_rsdp *rsdp)
if (rsdp->rsdt_address) { if (rsdp->rsdt_address) {
rsdt = nomap_sysmem(rsdp->rsdt_address, 0); rsdt = nomap_sysmem(rsdp->rsdt_address, 0);
dump_hdr(&rsdt->header); dump_hdr(&rsdt->header, chksums);
} }
if (rsdp->xsdt_address) { if (rsdp->xsdt_address) {
xsdt = nomap_sysmem(rsdp->xsdt_address, 0); xsdt = nomap_sysmem(rsdp->xsdt_address, 0);
dump_hdr(&xsdt->header); dump_hdr(&xsdt->header, chksums);
len = xsdt->header.length - sizeof(xsdt->header); len = xsdt->header.length - sizeof(xsdt->header);
count = len / sizeof(u64); count = len / sizeof(u64);
} else if (rsdp->rsdt_address) { } else if (rsdp->rsdt_address) {
@@ -100,24 +113,28 @@ static void list_rsdt(struct acpi_rsdp *rsdp)
if (!entry) if (!entry)
break; break;
hdr = nomap_sysmem(entry, 0); hdr = nomap_sysmem(entry, 0);
dump_hdr(hdr); dump_hdr(hdr, chksums);
if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN)) if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN))
list_fadt((struct acpi_fadt *)hdr); list_fadt((struct acpi_fadt *)hdr, chksums);
} }
} }
static void list_rsdp(struct acpi_rsdp *rsdp) static void list_rsdp(struct acpi_rsdp *rsdp, bool chksums)
{ {
printf("RSDP %16lx %5x v%02d %.6s\n", (ulong)map_to_sysmem(rsdp), printf("RSDP %16lx %5x v%02d %.6s%s%s\n",
rsdp->length, rsdp->revision, rsdp->oem_id); (ulong)map_to_sysmem(rsdp), rsdp->length, rsdp->revision,
list_rsdt(rsdp); rsdp->oem_id, show_checksum(rsdp, 0x14, chksums),
show_checksum(rsdp, rsdp->length, chksums));
list_rsdt(rsdp, chksums);
} }
static int do_acpi_list(struct cmd_tbl *cmdtp, int flag, int argc, static int do_acpi_list(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]) char *const argv[])
{ {
struct acpi_rsdp *rsdp; struct acpi_rsdp *rsdp;
bool chksums;
chksums = argc >= 2 && !strcmp("-c", argv[1]);
rsdp = map_sysmem(gd_acpi_start(), 0); rsdp = map_sysmem(gd_acpi_start(), 0);
if (!rsdp) { if (!rsdp) {
printf("No ACPI tables present\n"); printf("No ACPI tables present\n");
@@ -125,7 +142,7 @@ static int do_acpi_list(struct cmd_tbl *cmdtp, int flag, int argc,
} }
printf("Name Base Size Detail\n" printf("Name Base Size Detail\n"
"---- ---------------- ----- ----------------------------\n"); "---- ---------------- ----- ----------------------------\n");
list_rsdp(rsdp); list_rsdp(rsdp, chksums);
return 0; return 0;
} }
@@ -187,13 +204,13 @@ static int do_acpi_dump(struct cmd_tbl *cmdtp, int flag, int argc,
} }
U_BOOT_LONGHELP(acpi, U_BOOT_LONGHELP(acpi,
"list - list ACPI tables\n" "list [-c] - list ACPI tables [check checksums]\n"
"acpi items [-d] - List/dump each piece of ACPI data from devices\n" "acpi items [-d] - List/dump each piece of ACPI data from devices\n"
"acpi set [<addr>] - Set or show address of ACPI tables\n" "acpi set [<addr>] - Set or show address of ACPI tables\n"
"acpi dump <name> - Dump ACPI table"); "acpi dump <name> - Dump ACPI table");
U_BOOT_CMD_WITH_SUBCMDS(acpi, "ACPI tables", acpi_help_text, 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(list, 2, 1, do_acpi_list),
U_BOOT_SUBCMD_MKENT(items, 2, 1, do_acpi_items), U_BOOT_SUBCMD_MKENT(items, 2, 1, do_acpi_items),
U_BOOT_SUBCMD_MKENT(set, 2, 1, do_acpi_set), U_BOOT_SUBCMD_MKENT(set, 2, 1, do_acpi_set),
U_BOOT_SUBCMD_MKENT(dump, 2, 1, do_acpi_dump)); U_BOOT_SUBCMD_MKENT(dump, 2, 1, do_acpi_dump));

View File

@@ -11,7 +11,7 @@ Synopsis
:: ::
acpi list acpi list [-c]
acpi items [-d] acpi items [-d]
acpi dump <name> acpi dump <name>
acpi set <address> acpi set <address>
@@ -38,6 +38,9 @@ List the ACPI tables that have been generated. Each table has a 4-character
table name (e.g. SSDT, FACS) and has a format defined by the table name (e.g. SSDT, FACS) and has a format defined by the
`ACPI specification`_. `ACPI specification`_.
The `-c` flag tells U-Boot to verify the checksums and print 'OK' or 'BAD' next
to each table.
U-Boot does not currently support decoding the tables. Unlike devicetree, ACPI U-Boot does not currently support decoding the tables. Unlike devicetree, ACPI
tables have no regular schema and also some include bytecode, so decoding the tables have no regular schema and also some include bytecode, so decoding the
tables requires a lot of code. tables requires a lot of code.
@@ -259,5 +262,20 @@ pointer::
WAET bff76a3b 28 v01 BOCHS BXPC 1 BXPC 1 WAET bff76a3b 28 v01 BOCHS BXPC 1 BXPC 1
SSDT bff95040 c5 v02 COREv4 COREBOOT 2a CORE 20221020 SSDT bff95040 c5 v02 COREv4 COREBOOT 2a CORE 20221020
This shows checking that the checksums are correct for each table::
=> acpi list -c
Name Base Size Detail
---- ---------------- ----- ----------------------------
RSDP bec9a000 24 v00 BOCHS OK OK
RSDT bec9bd4a 38 v01 BOCHS BXPC 1 BXPC 1 OK
FACP bec9bb46 74 v01 BOCHS BXPC 1 BXPC 1 OK
DSDT bec9a080 1ac6 v01 BOCHS BXPC 1 BXPC 1 OK
FACS bec9a040 40
APIC bec9bbba 78 v03 BOCHS BXPC 1 BXPC 1 OK
HPET bec9bc32 38 v01 BOCHS BXPC 1 BXPC 1 OK
SRAT bec9bc6a b8 v01 BOCHS BXPC 1 BXPC 1 OK
WAET bec9bd22 28 v01 BOCHS BXPC 1 BXPC 1 OK
.. _`ACPI specification`: https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf .. _`ACPI specification`: https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf

View File

@@ -439,6 +439,52 @@ static int dm_test_acpi_cmd_list(struct unit_test_state *uts)
} }
DM_TEST(dm_test_acpi_cmd_list, UTF_SCAN_PDATA | UTF_SCAN_FDT | UTF_CONSOLE); DM_TEST(dm_test_acpi_cmd_list, UTF_SCAN_PDATA | UTF_SCAN_FDT | UTF_CONSOLE);
/* Test 'acpi list -c' command */
static int dm_test_acpi_cmd_list_chksum(struct unit_test_state *uts)
{
struct acpi_ctx ctx;
ulong addr;
void *buf;
buf = memalign(16, BUF_SIZE);
ut_assertnonnull(buf);
addr = map_to_sysmem(buf);
ut_assertok(setup_ctx_and_base_tables(uts, &ctx, addr));
ut_assertok(acpi_write_dev_tables(&ctx));
run_command("acpi list -c", 0);
ut_assert_nextline("Name Base Size Detail");
ut_assert_nextline("---- ---------------- ----- ----------------------------");
ut_assert_nextline("RSDP %16lx %5zx v02 U-BOOT OK OK", addr,
sizeof(struct acpi_rsdp));
addr = ALIGN(addr + sizeof(struct acpi_rsdp), 16);
ut_assert_nextline("RSDT %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0 OK",
addr, sizeof(struct acpi_table_header) +
3 * sizeof(u32), OEM_REVISION);
addr = ALIGN(addr + sizeof(struct acpi_rsdt), 16);
ut_assert_nextline("XSDT %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0 OK",
addr, sizeof(struct acpi_table_header) +
3 * sizeof(u64), OEM_REVISION);
addr = ALIGN(addr + sizeof(struct acpi_xsdt), 64);
ut_assert_nextline("DMAR %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0 OK",
addr, sizeof(struct acpi_dmar), OEM_REVISION);
addr = ALIGN(addr + sizeof(struct acpi_dmar), 16);
ut_assert_nextline("DMAR %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0 OK",
addr, sizeof(struct acpi_dmar), OEM_REVISION);
addr = ALIGN(addr + sizeof(struct acpi_dmar), 16);
ut_assert_nextline("DMAR %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0 OK",
addr, sizeof(struct acpi_dmar), OEM_REVISION);
ut_assert_console_end();
ut_assert_console_end();
unmap_sysmem(buf);
free(buf);
return 0;
}
DM_TEST(dm_test_acpi_cmd_list_chksum,
UTF_SCAN_PDATA | UTF_SCAN_FDT | UTF_CONSOLE);
/* Test 'acpi dump' command */ /* Test 'acpi dump' command */
static int dm_test_acpi_cmd_dump(struct unit_test_state *uts) static int dm_test_acpi_cmd_dump(struct unit_test_state *uts)
{ {