Changeset View
Changeset View
Standalone View
Standalone View
sys/arm64/arm64/pmap.c
Show First 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | |||||
#include <sys/rwlock.h> | #include <sys/rwlock.h> | ||||
#include <sys/sx.h> | #include <sys/sx.h> | ||||
#include <sys/vmem.h> | #include <sys/vmem.h> | ||||
#include <sys/vmmeter.h> | #include <sys/vmmeter.h> | ||||
#include <sys/sched.h> | #include <sys/sched.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/_unrhdr.h> | #include <sys/_unrhdr.h> | ||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <sys/efi.h> | |||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/vm_param.h> | #include <vm/vm_param.h> | ||||
#include <vm/vm_kern.h> | #include <vm/vm_kern.h> | ||||
#include <vm/vm_page.h> | #include <vm/vm_page.h> | ||||
#include <vm/vm_map.h> | #include <vm/vm_map.h> | ||||
#include <vm/vm_object.h> | #include <vm/vm_object.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
▲ Show 20 Lines • Show All 1,009 Lines • ▼ Show 20 Lines | pmap_kextract(vm_offset_t va) | ||||
} | } | ||||
return (pa); | return (pa); | ||||
} | } | ||||
/*************************************************** | /*************************************************** | ||||
* Low level mapping routines..... | * Low level mapping routines..... | ||||
***************************************************/ | ***************************************************/ | ||||
static inline int | |||||
pmap_correct_attr(vm_paddr_t pa, int mode_req) | |||||
{ | |||||
uint64_t attr; | |||||
int mode; | |||||
/* From UEFI spec 2.8 table 7 in 2.3.6.1 */ | |||||
attr = efi_memory_attribute(pa); | |||||
kib: How large is typical map on arm64 ? How many linear walks per page mapping do we add this way ? | |||||
manuAuthorUnsubmitted Done Inline ActionsOn the Ampere eMAG it's 25 while on the Pine64 it's 4 and Overdrive 1000 3 it seems. manu: On the Ampere eMAG it's 25 while on the Pine64 it's 4 and Overdrive 1000 3 it seems. | |||||
kibUnsubmitted Not Done Inline ActionsFor me, 25 sounds same as 'a lot'. Since each pmap_kenter() would typically walk some part of the list, depending on the ordering of the elements, I believe it is a good reason to pre-process the map into something more optimal. If you do that, the derived data structure might allow to enter additional items not presented in the raw EFI map, which is good for e.g. purpose of using similar approach on amd64 with non-EFI boot. You might consider using pctrie keyed on the start address of the map element, see sys/pctrie.h. Although the tree will be quite sparse, so may be you can propose something even more optimal. kib: For me, 25 sounds same as 'a lot'. Since each pmap_kenter() would typically walk some part of… | |||||
if ((attr & EFI_MD_ATTR_WB) != 0) | |||||
mode = VM_MEMATTR_WRITE_BACK; | |||||
else if ((attr & EFI_MD_ATTR_WT) != 0) | |||||
mode = VM_MEMATTR_WRITE_THROUGH; | |||||
else if ((attr & EFI_MD_ATTR_WC) != 0) | |||||
mode = VM_MEMATTR_WRITE_COMBINING; | |||||
else | |||||
mode = VM_MEMATTR_DEVICE; | |||||
if (mode_req < mode) | |||||
mode = mode_req; | |||||
return (mode); | |||||
} | |||||
void | void | ||||
pmap_kenter(vm_offset_t sva, vm_size_t size, vm_paddr_t pa, int mode) | pmap_kenter(vm_offset_t sva, vm_size_t size, vm_paddr_t pa, int mode) | ||||
{ | { | ||||
pd_entry_t *pde; | pd_entry_t *pde; | ||||
pt_entry_t *pte, attr; | pt_entry_t *pte, attr; | ||||
vm_offset_t va; | vm_offset_t va; | ||||
int lvl; | int lvl; | ||||
KASSERT((pa & L3_OFFSET) == 0, | KASSERT((pa & L3_OFFSET) == 0, | ||||
("pmap_kenter: Invalid physical address")); | ("pmap_kenter: Invalid physical address")); | ||||
KASSERT((sva & L3_OFFSET) == 0, | KASSERT((sva & L3_OFFSET) == 0, | ||||
("pmap_kenter: Invalid virtual address")); | ("pmap_kenter: Invalid virtual address")); | ||||
KASSERT((size & PAGE_MASK) == 0, | KASSERT((size & PAGE_MASK) == 0, | ||||
("pmap_kenter: Mapping is not page-sized")); | ("pmap_kenter: Mapping is not page-sized")); | ||||
mode = pmap_correct_attr(pa, mode); | |||||
attr = ATTR_DEFAULT | ATTR_IDX(mode) | L3_PAGE; | attr = ATTR_DEFAULT | ATTR_IDX(mode) | L3_PAGE; | ||||
if (mode == DEVICE_MEMORY) | if (mode == DEVICE_MEMORY) | ||||
attr |= ATTR_XN; | attr |= ATTR_XN; | ||||
va = sva; | va = sva; | ||||
while (size != 0) { | while (size != 0) { | ||||
pde = pmap_pde(kernel_pmap, va, &lvl); | pde = pmap_pde(kernel_pmap, va, &lvl); | ||||
KASSERT(pde != NULL, | KASSERT(pde != NULL, | ||||
▲ Show 20 Lines • Show All 3,540 Lines • ▼ Show 20 Lines | if (va == 0) | ||||
panic("%s: Couldn't allocate KVA", __func__); | panic("%s: Couldn't allocate KVA", __func__); | ||||
pde = pmap_pde(kernel_pmap, va, &lvl); | pde = pmap_pde(kernel_pmap, va, &lvl); | ||||
KASSERT(lvl == 2, ("pmap_mapbios: Invalid level %d", lvl)); | KASSERT(lvl == 2, ("pmap_mapbios: Invalid level %d", lvl)); | ||||
/* L3 table is linked */ | /* L3 table is linked */ | ||||
va = trunc_page(va); | va = trunc_page(va); | ||||
pa = trunc_page(pa); | pa = trunc_page(pa); | ||||
pmap_kenter(va, size, pa, CACHED_MEMORY); | |||||
/* | |||||
* Call pmap_kenter with the highest mode | |||||
* it will call pmap_correct_attr to get the | |||||
* correct one based on the EFI map | |||||
*/ | |||||
pmap_kenter(va, size, pa, VM_MEMATTR_WRITE_BACK); | |||||
} | } | ||||
return ((void *)(va + offset)); | return ((void *)(va + offset)); | ||||
} | } | ||||
void | void | ||||
pmap_unmapbios(vm_offset_t va, vm_size_t size) | pmap_unmapbios(vm_offset_t va, vm_size_t size) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 684 Lines • Show Last 20 Lines |
How large is typical map on arm64 ? How many linear walks per page mapping do we add this way ?