Index: sys/arm64/arm64/pmap.c =================================================================== --- sys/arm64/arm64/pmap.c +++ sys/arm64/arm64/pmap.c @@ -110,10 +110,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -145,6 +147,8 @@ #include #include +#include +#include #include #include #include @@ -355,6 +359,7 @@ static void pmap_abort_ptp(pmap_t pmap, vm_offset_t va, vm_page_t mpte); static bool pmap_activate_int(pmap_t pmap); static void pmap_alloc_asid(pmap_t pmap); +static int efi_find_mode(vm_paddr_t pa); static int pmap_change_attr_locked(vm_offset_t va, vm_size_t size, int mode); static pt_entry_t *pmap_demote_l1(pmap_t pmap, pt_entry_t *l1, vm_offset_t va); static pt_entry_t *pmap_demote_l2_locked(pmap_t pmap, pt_entry_t *l2, @@ -5439,12 +5444,53 @@ /* L3 table is linked */ va = trunc_page(va); pa = trunc_page(pa); - pmap_kenter(va, size, pa, VM_MEMATTR_WRITE_BACK); + pmap_kenter(va, size, pa, efi_find_mode(pa)); } return ((void *)(va + offset)); } +static int efi_find_mode(vm_paddr_t pa) +{ + int i, ndesc, mode = VM_MEMATTR_DEVICE; + size_t efisz; + struct efi_map_header *efihdr; + struct efi_md *map, *p; + caddr_t kmdp; + + /* TODO: don't search preload etc. on every call */ + kmdp = preload_search_by_type("elf kernel"); + + efihdr = (struct efi_map_header *)preload_search_info(kmdp, + MODINFO_METADATA | MODINFOMD_EFI_MAP); + + if (efihdr == NULL) { + printf("pmap: EFI header not found\n"); + return VM_MEMATTR_WRITE_BACK; + } + + efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf; + map = (struct efi_md *)((uint8_t *)efihdr + efisz); + ndesc = efihdr->memory_size / efihdr->descriptor_size; + + for (i = 0, p = map; i < ndesc; i++, p = efi_next_descriptor(p, + efihdr->descriptor_size)) { + if (pa < p->md_phys || pa >= p->md_phys + p->md_pages * EFI_PAGE_SIZE) + continue; + if (p->md_type == EFI_MD_TYPE_IOMEM || p->md_type == EFI_MD_TYPE_IOPORT) + mode = VM_MEMATTR_DEVICE; + else if ((p->md_attr & EFI_MD_ATTR_WB) != 0 || p->md_type == EFI_MD_TYPE_RECLAIM) + mode = VM_MEMATTR_WRITE_BACK; + else if ((p->md_attr & EFI_MD_ATTR_WT) != 0) + mode = VM_MEMATTR_WRITE_THROUGH; + else if ((p->md_attr & EFI_MD_ATTR_WC) != 0) + mode = VM_MEMATTR_WRITE_COMBINING; + break; + } + + return mode; +} + void pmap_unmapbios(vm_offset_t va, vm_size_t size) {