--- sys/platform/pc64/acpica/OsdEnvironment.c +++ sys/platform/pc64/acpica/OsdEnvironment.c @@ -33,12 +33,17 @@ #include #include +#include #include +#include #include #include "acpi.h" +static int acpi_rsdp_checksum(const uint8_t *, int); +static int acpi_validate_rsdp_paddr(u_long); + static u_long acpi_root_phys; SYSCTL_ULONG(_machdep, OID_AUTO, acpi_root, CTLFLAG_RD, &acpi_root_phys, 0, @@ -56,6 +61,51 @@ return (AE_OK); } +/* + * Sum a region modulo 256; a valid ACPI checksum region sums to 0. + */ +static int +acpi_rsdp_checksum(const uint8_t *cp, int len) +{ + int sum = 0; + + while (len-- > 0) + sum += *cp++; + return (sum & 0xFF); +} + +/* + * The RSDP address passed in via hint.acpi.0.rsdp must refer to actual + * physical memory (mapping an address with reserved PTE bits faults the + * moment it is read) and the bytes it points at must actually look like + * an RSDP (signature, a revision we understand, checksums) before it is + * handed to ACPICA as the table root. Otherwise fall back to the + * firmware scan. + */ +static int +acpi_validate_rsdp_paddr(u_long paddr) +{ + const ACPI_TABLE_RSDP *rsdp; + void *map; + int ok = 0; + + if (paddr == 0 || paddr >= ptoa(Maxmem)) + return (0); + map = pmap_mapdev(paddr, PAGE_SIZE); + rsdp = (const ACPI_TABLE_RSDP *)map; + if (memcmp(rsdp->Signature, ACPI_SIG_RSDP, + sizeof(rsdp->Signature)) == 0 && + rsdp->Revision <= 2 && + acpi_rsdp_checksum((const uint8_t *)rsdp, + ACPI_RSDP_CHECKSUM_LENGTH) == 0 && + (rsdp->Revision < 2 || + acpi_rsdp_checksum((const uint8_t *)rsdp, + ACPI_RSDP_XCHECKSUM_LENGTH) == 0)) + ok = 1; + pmap_unmapdev((vm_offset_t)map, PAGE_SIZE); + return (ok); +} + ACPI_PHYSICAL_ADDRESS AcpiOsGetRootPointer(void) { @@ -70,8 +120,14 @@ * manually here. */ if (kgetenv_ulong("hint.acpi.0.rsdp", &acpi_root) == 1) { - acpi_root_phys = acpi_root; - } else { + if (acpi_validate_rsdp_paddr(acpi_root)) { + acpi_root_phys = acpi_root; + } else { + kprintf("AcpiOsGetRootPointer: kenv RSDP failed " + "validation, falling back to firmware scan\n"); + } + } + if (acpi_root_phys == 0) { status = AcpiFindRootPointer(&ptr); if (ACPI_SUCCESS(status)) acpi_root_phys = ptr; --- sys/contrib/dev/acpica/source/components/tables/tbxfload.c +++ sys/contrib/dev/acpica/source/components/tables/tbxfload.c @@ -272,10 +272,16 @@ * Load the namespace. The DSDT is required, but any SSDT and * PSDT tables are optional. Verify the DSDT. */ + if (!AcpiGbl_RootTableList.CurrentTableCount || + AcpiGbl_DsdtIndex == ACPI_INVALID_TABLE_INDEX) + { + Status = AE_NO_ACPI_TABLES; + goto UnlockAndExit; + } + Table = &AcpiGbl_RootTableList.Tables[AcpiGbl_DsdtIndex]; - if (!AcpiGbl_RootTableList.CurrentTableCount || - !ACPI_COMPARE_NAMESEG (Table->Signature.Ascii, ACPI_SIG_DSDT) || + if (!ACPI_COMPARE_NAMESEG (Table->Signature.Ascii, ACPI_SIG_DSDT) || ACPI_FAILURE (AcpiTbValidateTable (Table))) { Status = AE_NO_ACPI_TABLES;