mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-03 21:48:15 +00:00 
			
		
		
		
	acpi: Add an acpi command
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>
This commit is contained in:
		
							parent
							
								
									b38309b737
								
							
						
					
					
						commit
						0b885bcfd9
					
				@ -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>
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								cmd/Kconfig
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								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
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										186
									
								
								cmd/acpi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								cmd/acpi.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,186 @@
 | 
			
		||||
// 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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * dump_hdr() - Dump an ACPI header
 | 
			
		||||
 *
 | 
			
		||||
 * If the header is for FACS then it shows the revision information as well
 | 
			
		||||
 *
 | 
			
		||||
 * @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 %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_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 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_fadt((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));
 | 
			
		||||
@ -240,6 +240,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;
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user