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 <log.h>
#include <mapmem.h>
#include <tables_csum.h>
#include <acpi/acpi_table.h>
#include <asm/acpi_table.h>
#include <asm/global_data.h>
@@ -15,6 +16,17 @@
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
*
@@ -23,16 +35,17 @@ DECLARE_GLOBAL_DATA_PTR;
*
* @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);
printf("%.*s %16lx %5x", ACPI_NAME_LEN, hdr->signature,
(ulong)map_to_sysmem(hdr), hdr->length);
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->creator_id, hdr->creator_revision);
hdr->creator_id, hdr->creator_revision,
show_checksum(hdr, hdr->length, chksums));
} else {
printf("\n");
}
@@ -52,22 +65,22 @@ static int dump_table_name(const char *sig)
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)
dump_hdr(nomap_sysmem(fadt->x_dsdt, 0));
dump_hdr(nomap_sysmem(fadt->x_dsdt, 0), chksums);
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) &&
!(fadt->flags & ACPI_FADT_HW_REDUCED_ACPI))
log_err("FADT not ACPI-hardware-reduced-compliant\n");
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)
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;
struct acpi_rsdt *rsdt;
@@ -75,11 +88,11 @@ static void list_rsdt(struct acpi_rsdp *rsdp)
if (rsdp->rsdt_address) {
rsdt = nomap_sysmem(rsdp->rsdt_address, 0);
dump_hdr(&rsdt->header);
dump_hdr(&rsdt->header, chksums);
}
if (rsdp->xsdt_address) {
xsdt = nomap_sysmem(rsdp->xsdt_address, 0);
dump_hdr(&xsdt->header);
dump_hdr(&xsdt->header, chksums);
len = xsdt->header.length - sizeof(xsdt->header);
count = len / sizeof(u64);
} else if (rsdp->rsdt_address) {
@@ -100,24 +113,28 @@ static void list_rsdt(struct acpi_rsdp *rsdp)
if (!entry)
break;
hdr = nomap_sysmem(entry, 0);
dump_hdr(hdr);
dump_hdr(hdr, chksums);
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),
rsdp->length, rsdp->revision, rsdp->oem_id);
list_rsdt(rsdp);
printf("RSDP %16lx %5x v%02d %.6s%s%s\n",
(ulong)map_to_sysmem(rsdp), rsdp->length, rsdp->revision,
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,
char *const argv[])
{
struct acpi_rsdp *rsdp;
bool chksums;
chksums = argc >= 2 && !strcmp("-c", argv[1]);
rsdp = map_sysmem(gd_acpi_start(), 0);
if (!rsdp) {
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"
"---- ---------------- ----- ----------------------------\n");
list_rsdp(rsdp);
list_rsdp(rsdp, chksums);
return 0;
}
@@ -187,13 +204,13 @@ static int do_acpi_dump(struct cmd_tbl *cmdtp, int flag, int argc,
}
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 set [<addr>] - Set or show address of 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(list, 2, 1, do_acpi_list),
U_BOOT_SUBCMD_MKENT(items, 2, 1, do_acpi_items),
U_BOOT_SUBCMD_MKENT(set, 2, 1, do_acpi_set),
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 dump <name>
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
`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
tables have no regular schema and also some include bytecode, so decoding the
tables requires a lot of code.
@@ -259,5 +262,20 @@ pointer::
WAET bff76a3b 28 v01 BOCHS BXPC 1 BXPC 1
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

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);
/* 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 */
static int dm_test_acpi_cmd_dump(struct unit_test_state *uts)
{