aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPali Rohár <pali@kernel.org>2024-02-28 00:32:08 +0100
committerMartin Mares <mj@ucw.cz>2024-04-05 13:14:01 +0200
commit1836a2d4c62a3adbad269e8177528c42daf40f42 (patch)
tree1f14d8c925e084b1d73fd4c8d5f04bd858ca49c5
parenta34006f8e9c1f80e1446d1007bfff3ffefef4d23 (diff)
downloadpciutils-1836a2d4c62a3adbad269e8177528c42daf40f42.tar.gz
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.
-rw-r--r--lib/ecam.c36
1 files 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;