From 1836a2d4c62a3adbad269e8177528c42daf40f42 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Wed, 28 Feb 2024 00:32:08 +0100 Subject: libpci: ecam: Fix scanning of Extended BIOS Data Area for ACPI RSDP At physical address 0x40E (part of BDA) is stored indirect 16-bit paragraph offset to the EBDA, and not the EBDA itself. Fix it. ACPI code in linux kernel checks if the EBDA offset in BDA is above physical address 0x400. Do the same check here. It is for detection if EBDA is present as it does not have to be on the old computers or in some virtualised environments. --- lib/ecam.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/lib/ecam.c b/lib/ecam.c index 7f73d51..fdeec07 100644 --- a/lib/ecam.c +++ b/lib/ecam.c @@ -221,9 +221,11 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE #if defined(__amd64__) || defined(__i386__) struct ecam_access *eacc = a->backend_data; struct physmem *physmem = eacc->physmem; + long pagesize = eacc->pagesize; u64 rsdp_addr; u64 addr; void *map; + u64 ebda; #endif size_t len; FILE *f; @@ -305,23 +307,39 @@ find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSE rsdp_addr = 0; /* Scan first kB of Extended BIOS Data Area */ - a->debug("scanning first kB of EBDA..."); - map = physmem_map(physmem, 0, 0x40E + 1024, 0); + a->debug("reading EBDA location from BDA..."); + map = physmem_map(physmem, 0, 0x40E + 2, 0); if (map != (void *)-1) { - for (addr = 0x40E; addr < 0x40E + 1024; addr += 16) + ebda = (u64)physmem_readw((unsigned char *)map + 0x40E) << 4; + if (physmem_unmap(physmem, map, 0x40E + 2) != 0) + a->debug("unmapping of BDA failed: %s...", strerror(errno)); + if (ebda >= 0x400) { - if (check_rsdp((struct acpi_rsdp *)((unsigned char *)map + addr))) + a->debug("scanning first kB of EBDA at 0x%" PCI_U64_FMT_X "...", ebda); + map = physmem_map(physmem, ebda & ~(pagesize-1), 1024 + (ebda & (pagesize-1)), 0); + if (map != (void *)-1) { - rsdp_addr = addr; - break; + for (addr = ebda & (pagesize-1); addr < (ebda & (pagesize-1)) + 1024; addr += 16) + { + if (check_rsdp((struct acpi_rsdp *)((unsigned char *)map + addr))) + { + rsdp_addr = (ebda & ~(pagesize-1)) + addr; + break; + } + } + if (physmem_unmap(physmem, map, 1024 + (ebda & (pagesize-1))) != 0) + a->debug("unmapping of EBDA failed: %s...", strerror(errno)); } + else + a->debug("mapping of EBDA failed: %s...", strerror(errno)); } - if (physmem_unmap(physmem, map, 0x40E + 1024) != 0) - a->debug("unmapping of EBDA failed: %s...", strerror(errno)); + else + a->debug("EBDA location 0x%" PCI_U64_FMT_X " is insane...", ebda); } else - a->debug("mapping of EBDA failed: %s...", strerror(errno)); + a->debug("mapping of BDA failed: %s...", strerror(errno)); + if (rsdp_addr) return rsdp_addr; -- cgit 1.2.3-korg