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:
57
cmd/acpi.c
57
cmd/acpi.c
@@ -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));
|
||||||
|
@@ -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
|
||||||
|
@@ -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)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user