u-boot/cmd/acpi.c
Heinrich Schuchardt 36e3a1e91a cmd: acpi: fix acpi list command
ACPI tables may comprise either RSDT, XSDT, or both. The current code fails
to check the presence of the RSDT table before accessing it. This leads to
an exception if the RSDT table is not provided.

The XSDT table takes precedence over the RSDT table.

The return values of list_rsdt() and list_rsdp() are always zero and not
checked. Remove the return values.

Addresses in the XSDT table are 64-bit. Adjust the output accordingly.

As the RSDT table has to be ignored if the XSDT command is present there is
no need to compare the tables in a display command. Anyway the
specification does not require that the sequence of addresses in the RSDT
and XSDT table are the same.

The FACS table header does not provide revision information. Correct the
description of dump_hdr().

Adjust the ACPI test to match the changed output format of the 'acpi list'
command.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
2023-12-13 18:39:06 -05:00

188 lines
4.4 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2019 Google LLC
* Written by Simon Glass <sjg@chromium.org>
*/
#include <common.h>
#include <command.h>
#include <display_options.h>
#include <mapmem.h>
#include <acpi/acpi_table.h>
#include <asm/acpi_table.h>
#include <asm/global_data.h>
#include <dm/acpi.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* dump_hdr() - Dump an ACPI header
*
* Except for the Firmware ACPI Control Structure (FACS)
* additionally show the revision information.
*
* @hdr: ACPI header to dump
*/
static void dump_hdr(struct acpi_table_header *hdr)
{
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,
hdr->oem_id, hdr->oem_table_id, hdr->oem_revision,
hdr->aslc_id, hdr->aslc_revision);
} else {
printf("\n");
}
}
static int dump_table_name(const char *sig)
{
struct acpi_table_header *hdr;
hdr = acpi_find_table(sig);
if (!hdr)
return -ENOENT;
printf("%.*s @ %16lx\n", ACPI_NAME_LEN, hdr->signature,
(ulong)map_to_sysmem(hdr));
print_buffer(0, hdr, 1, hdr->length, 0);
return 0;
}
static void list_fadt(struct acpi_fadt *fadt)
{
if (fadt->dsdt)
dump_hdr(map_sysmem(fadt->dsdt, 0));
if (fadt->firmware_ctrl)
dump_hdr(map_sysmem(fadt->firmware_ctrl, 0));
}
static void list_rsdt(struct acpi_rsdp *rsdp)
{
int len, i, count;
struct acpi_rsdt *rsdt;
struct acpi_xsdt *xsdt;
if (rsdp->rsdt_address) {
rsdt = map_sysmem(rsdp->rsdt_address, 0);
dump_hdr(&rsdt->header);
}
if (rsdp->xsdt_address) {
xsdt = map_sysmem(rsdp->xsdt_address, 0);
dump_hdr(&xsdt->header);
len = xsdt->header.length - sizeof(xsdt->header);
count = len / sizeof(u64);
} else if (rsdp->rsdt_address) {
len = rsdt->header.length - sizeof(rsdt->header);
count = len / sizeof(u32);
} else {
return;
}
for (i = 0; i < count; i++) {
struct acpi_table_header *hdr;
u64 entry;
if (rsdp->xsdt_address)
entry = xsdt->entry[i];
else
entry = rsdt->entry[i];
if (!entry)
break;
hdr = map_sysmem(entry, 0);
dump_hdr(hdr);
if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN))
list_fadt((struct acpi_fadt *)hdr);
}
}
static void list_rsdp(struct acpi_rsdp *rsdp)
{
printf("RSDP %16lx %5x v%02d %.6s\n", (ulong)map_to_sysmem(rsdp),
rsdp->length, rsdp->revision, rsdp->oem_id);
list_rsdt(rsdp);
}
static int do_acpi_list(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
struct acpi_rsdp *rsdp;
rsdp = map_sysmem(gd_acpi_start(), 0);
if (!rsdp) {
printf("No ACPI tables present\n");
return 0;
}
printf("Name Base Size Detail\n"
"---- ---------------- ----- ----------------------------\n");
list_rsdp(rsdp);
return 0;
}
static int do_acpi_set(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
ulong val;
if (argc < 2) {
printf("ACPI pointer: %lx\n", gd_acpi_start());
} else {
val = hextoul(argv[1], NULL);
printf("Setting ACPI pointer to %lx\n", val);
gd_set_acpi_start(val);
}
return 0;
}
static int do_acpi_items(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
bool dump_contents;
dump_contents = argc >= 2 && !strcmp("-d", argv[1]);
if (!IS_ENABLED(CONFIG_ACPIGEN)) {
printf("Not supported (enable ACPIGEN)\n");
return CMD_RET_FAILURE;
}
acpi_dump_items(dump_contents ? ACPI_DUMP_CONTENTS : ACPI_DUMP_LIST);
return 0;
}
static int do_acpi_dump(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
const char *name;
char sig[ACPI_NAME_LEN];
int ret;
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, ACPI_NAME_LEN);
ret = dump_table_name(sig);
if (ret) {
printf("Table '%.*s' not found\n", ACPI_NAME_LEN, sig);
return CMD_RET_FAILURE;
}
return 0;
}
U_BOOT_LONGHELP(acpi,
"list - list ACPI tables\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(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));