The new unit test checks if ACPI tables are available. If yes, it checks if the RSDP correctly points to the RSDT or XSDT.
Signed-off-by: Heinrich Schuchardt <[email protected]> --- v2: Correct commit message %s/RSDT/RSDP/. Check checksums. Add a 'skipped' message. --- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_acpi.c | 138 +++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_acpi.c diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 67102648703..c6cc2430bbf 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -17,6 +17,7 @@ CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) obj-y += \ efi_selftest.o \ +efi_selftest_acpi.o \ efi_selftest_bitblt.o \ efi_selftest_config_table.o \ efi_selftest_controllers.o \ diff --git a/lib/efi_selftest/efi_selftest_acpi.c b/lib/efi_selftest/efi_selftest_acpi.c new file mode 100644 index 00000000000..94cf5c00484 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_acpi.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * efi_selftest_acpi + * + * Copyright 2026, Heinrich Schuchardt <[email protected]> + * + * Check ACPI configuration table availability and root table presence. + */ + +#include <efi_selftest.h> +#include <acpi/acpi_table.h> + +static const efi_guid_t acpi2_guid = EFI_ACPI_TABLE_GUID; +static const efi_guid_t acpi1_guid = EFI_GUID_EFI_ACPI1; + +/** + * checksum_ok() - check if byte-sum of buffer is zero + * + * @buf: buffer to check + * @len: buffer length + * Return: true if checksum is valid + */ +static bool checksum_ok(const void *buf, efi_uintn_t len) +{ + const u8 *pos = buf; + u8 sum = 0; + + for (; len; --len, ++pos) + sum += *pos; + + return !sum; +} + +/** + * check_rsdp() - validate RSDP signature, checksum and root table pointer + * + * @rsdp: RSDP to validate + * Return: EFI_ST_SUCCESS or EFI_ST_FAILURE + */ +static int check_rsdp(struct acpi_rsdp *rsdp) +{ + struct acpi_table_header *table; + u32 rsdt_addr32; + u64 xsdt_addr64; + uintptr_t rsdt_addr; + uintptr_t xsdt_addr; + u32 rsdp_len; + + if (memcmp(rsdp->signature, RSDP_SIG, sizeof(rsdp->signature))) { + efi_st_error("Wrong RSDP signature\n"); + return EFI_ST_FAILURE; + } + + if (!checksum_ok(rsdp, 20)) { + efi_st_error("Invalid RSDP checksum\n"); + return EFI_ST_FAILURE; + } + + if (rsdp->revision >= ACPI_RSDP_REV_ACPI_2_0) { + rsdp_len = rsdp->length; + if (rsdp_len < sizeof(*rsdp)) { + efi_st_error("Invalid ACPI 2.0 RSDP length\n"); + return EFI_ST_FAILURE; + } + if (!checksum_ok(rsdp, rsdp_len)) { + efi_st_error("Invalid RSDP extended checksum\n"); + return EFI_ST_FAILURE; + } + } + + memcpy(&rsdt_addr32, &rsdp->rsdt_address, sizeof(rsdt_addr32)); + rsdt_addr = rsdt_addr32; + + xsdt_addr64 = 0; + if (rsdp->revision >= ACPI_RSDP_REV_ACPI_2_0) + memcpy(&xsdt_addr64, &rsdp->xsdt_address, sizeof(xsdt_addr64)); + xsdt_addr = xsdt_addr64; + + if (!rsdt_addr && !xsdt_addr) { + efi_st_error("Neither RSDT nor XSDT address is set\n"); + return EFI_ST_FAILURE; + } + + if (xsdt_addr) { + table = (struct acpi_table_header *)xsdt_addr; + if (!memcmp(table->signature, "XSDT", 4)) + return EFI_ST_SUCCESS; + efi_st_error("XSDT address does not point to XSDT\n"); + } + + if (rsdt_addr) { + table = (struct acpi_table_header *)rsdt_addr; + if (!memcmp(table->signature, "RSDT", 4)) + return EFI_ST_SUCCESS; + efi_st_error("RSDT address does not point to RSDT\n"); + } + + return EFI_ST_FAILURE; +} + +/** + * efi_st_acpi_execute() - execute ACPI selftest + * + * Return: status code + */ +static int efi_st_acpi_execute(void) +{ + struct acpi_rsdp *rsdp2, *rsdp1; + int ret; + + rsdp2 = efi_st_get_config_table(&acpi2_guid); + rsdp1 = efi_st_get_config_table(&acpi1_guid); + + if (!rsdp2 && !rsdp1) { + efi_st_printf("No ACPI configuration table, test skipped\n"); + return EFI_ST_SUCCESS; + } + + if (rsdp2) { + ret = check_rsdp(rsdp2); + if (ret != EFI_ST_SUCCESS) + return ret; + } + + if (rsdp1) { + ret = check_rsdp(rsdp1); + if (ret != EFI_ST_SUCCESS) + return ret; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(acpi) = { + .name = "acpi", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .execute = efi_st_acpi_execute, +}; -- 2.53.0

