git: ef7d7011ce2f - main - arm64: Fix EFI runtime mappings with 16K pages
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 20 Oct 2026 18:55:53 UTC
The branch main has been updated by gallatin:
URL: https://cgit.FreeBSD.org/src/commit/?id=ef7d7011ce2fa48ab072c5e802ac00ccb25c4c48
commit ef7d7011ce2fa48ab072c5e802ac00ccb25c4c48
Author: Andrew Gallatin <gallatin@FreeBSD.org>
AuthorDate: 2026-10-20 18:54:01 +0000
Commit: Andrew Gallatin <gallatin@FreeBSD.org>
CommitDate: 2026-10-20 18:54:01 +0000
arm64: Fix EFI runtime mappings with 16K pages
Map complete EFI descriptor ranges at the kernel page granularity
and merge compatible entries when 4K EFI regions share a kernel page.
Preserve execution when any sharing region requires it and reject
conflicting mapping attributes without panicing.
This gets my small N1 booting with 16K pages.
Reviewed by: chs, imp
Sponsored by: Netflix
Differential Revision: https://reviews.freebsd.org/D60749
---
sys/arm64/arm64/efirt_machdep.c | 31 +++++++++++++++++++++++--------
1 file changed, 23 insertions(+), 8 deletions(-)
diff --git a/sys/arm64/arm64/efirt_machdep.c b/sys/arm64/arm64/efirt_machdep.c
index 07946a2bdb82..5e6a58295e36 100644
--- a/sys/arm64/arm64/efirt_machdep.c
+++ b/sys/arm64/arm64/efirt_machdep.c
@@ -139,8 +139,6 @@ efi_1t1_l3(vm_offset_t va)
l3 = PHYS_TO_DMAP(mphys);
l3 += pmap_l3_index(va);
- KASSERT(*l3 == 0, ("%s: Already mapped: va %#jx *pt %#jx", __func__,
- va, *l3));
return (l3);
}
@@ -167,10 +165,9 @@ bool
efi_create_1t1_map(struct efi_md *map, int ndesc, int descsz)
{
struct efi_md *p;
- pt_entry_t *l3, l3_attr;
- vm_offset_t va;
+ pt_entry_t *l3, l3_attr, l3_entry;
+ vm_offset_t va, end;
vm_page_t efi_l0_page;
- uint64_t idx;
int i, mode;
uint64_t pa;
@@ -230,8 +227,9 @@ efi_create_1t1_map(struct efi_md *map, int ndesc, int descsz)
l3_attr |= ATTR_S1_XN;
VM_OBJECT_WLOCK(obj_1t1_pt);
- for (va = p->md_phys, idx = 0; idx < p->md_pages;
- idx += (PAGE_SIZE / EFI_PAGE_SIZE), va += PAGE_SIZE) {
+ /* EFI regions can start and end within a kernel page. */
+ end = p->md_phys + p->md_pages * EFI_PAGE_SIZE;
+ for (va = trunc_page(p->md_phys); va < end; va += PAGE_SIZE) {
l3 = efi_1t1_l3(va);
if (mode == VM_MEMATTR_DEVICE && in_realm())
@@ -239,7 +237,24 @@ efi_create_1t1_map(struct efi_md *map, int ndesc, int descsz)
else
pa = va;
- *l3 = PHYS_TO_PTE(pa) | l3_attr;
+ l3_entry = PHYS_TO_PTE(pa) | l3_attr;
+ if (*l3 != 0) {
+ /*
+ * Multiple EFI regions can share a kernel page.
+ * Their memory attributes must agree, but the
+ * page must be executable if any region needs it.
+ */
+ if (((*l3 ^ l3_entry) & ~ATTR_S1_PXN) != 0) {
+ VM_OBJECT_WUNLOCK(obj_1t1_pt);
+ printf("EFI Runtime entry %d has conflicting "
+ "mapping at %#jx: %#jx != %#jx\n", i,
+ (uintmax_t)va, (uintmax_t)*l3,
+ (uintmax_t)l3_entry);
+ goto fail;
+ }
+ l3_entry &= *l3 | ~ATTR_S1_PXN;
+ }
+ *l3 = l3_entry;
}
VM_OBJECT_WUNLOCK(obj_1t1_pt);
}