aarch64: fix SMBIOS parsing crash when loaded via shim

map startup-only regions as Normal memory
This commit is contained in:
Sam Demeulemeester
2026-08-10 16:51:47 +02:00
parent 5b28992a7a
commit 386ba63cec
+14 -8
View File
@@ -8,7 +8,8 @@
// regions described by the BIOS/EFI memory map, so all mapping functions
// simply return the physical address unchanged. RAM is mapped as Normal
// write-back cacheable memory, the frame buffer as Normal non-cacheable
// memory, and anything else mapped on demand (MMIO) as Device-nGnRnE.
// memory, and anything else mapped on demand either as Normal write-back
// (RAM-resident firmware tables) or as Device-nGnRnE (MMIO).
//
// The tables use the 4KB granule with a 48-bit input address range and
// are built from 1GB and 2MB block descriptors only. paging_init() is
@@ -66,6 +67,7 @@
typedef struct {
uint64_t start;
uint64_t end;
uint64_t attrs;
} device_region_t;
//------------------------------------------------------------------------------
@@ -287,13 +289,13 @@ void paging_init(void)
paging_incomplete |= !map_range(cmd_line_start, cmd_line_end, PTE_ATTR_NORMAL);
}
// Replay the device mappings made via map_region.
// Replay the mappings made via map_region.
for (int i = 0; i < num_device_regions; i++) {
paging_incomplete |= !map_range(device_regions[i].start, device_regions[i].end, PTE_ATTR_DEVICE);
paging_incomplete |= !map_range(device_regions[i].start, device_regions[i].end, device_regions[i].attrs);
}
}
uintptr_t map_region(uintptr_t base_addr, size_t size, bool only_for_startup __attribute__((unused)))
uintptr_t map_region(uintptr_t base_addr, size_t size, bool only_for_startup)
{
if (size == 0) {
size = 1;
@@ -304,6 +306,12 @@ uintptr_t map_region(uintptr_t base_addr, size_t size, bool only_for_startup __a
return 0;
}
// Startup-only regions are RAM-resident firmware tables (ACPI, SMBIOS,
// ...) and must be mapped as Normal memory: their parsers do unaligned
// accesses, which fault on Device memory. Everything else is assumed
// to be MMIO. Regions mapped earlier keep their original attributes.
uint64_t attrs = only_for_startup ? (PTE_ATTR_NORMAL | PTE_PXN) : PTE_ATTR_DEVICE;
// Record the region (at block granularity) so the mapping can be
// replayed when the page tables are rebuilt after relocation.
uint64_t start = base_addr & ~(BLOCK_2M - 1);
@@ -320,13 +328,11 @@ uintptr_t map_region(uintptr_t base_addr, size_t size, bool only_for_startup __a
}
device_regions[num_device_regions].start = start;
device_regions[num_device_regions].end = end;
device_regions[num_device_regions].attrs = attrs;
num_device_regions++;
}
// Anything not already mapped is assumed to be MMIO and gets a Device
// mapping. Regions mapped earlier (e.g. RAM, the frame buffer) keep
// their original attributes.
if (!map_range(base_addr, base_addr + size, PTE_ATTR_DEVICE)) {
if (!map_range(base_addr, base_addr + size, attrs)) {
return 0;
}