Changeset View
Standalone View
sys/arm64/arm64/pmap.c
Show First 20 Lines • Show All 1,359 Lines • ▼ Show 20 Lines | if (use) { | ||||
if (m != NULL && !vm_page_wire_mapped(m)) | if (m != NULL && !vm_page_wire_mapped(m)) | ||||
m = NULL; | m = NULL; | ||||
} | } | ||||
} | } | ||||
PMAP_UNLOCK(pmap); | PMAP_UNLOCK(pmap); | ||||
return (m); | return (m); | ||||
} | } | ||||
vm_paddr_t | |||||
pmap_kextract(vm_offset_t va) | /* | ||||
* Walks the page tables to translate a kernel virtual address to a | |||||
* physical address. Returns true if the kva is valid and stores the | |||||
* physical address in pa if it is not NULL. | |||||
*/ | |||||
bool | |||||
pmap_kva_to_pa(vm_offset_t va, vm_paddr_t *pa) | |||||
markj: Extra newline. | |||||
{ | { | ||||
pt_entry_t *pte, tpte; | pt_entry_t *pte, tpte; | ||||
register_t intr; | |||||
uint64_t par; | |||||
if (va >= DMAP_MIN_ADDRESS && va < DMAP_MAX_ADDRESS) | /* | ||||
Not Done Inline ActionsWhy do we need to disable interrupts around AT ? kib: Why do we need to disable interrupts around AT ? | |||||
Done Inline ActionsIt's two instructions. The at instruction stores the result in par_el1 so we then need the following to get the result in x1: at s1e1r, x0 mrs x1, par_el1 If a interrupt happens after the at, but before the mrs we may have an invalid value in par_el, e.g. if the thread is moved to a new CPU. We could handle this by restarting the instruction, however disabling interrupts on arm64 is cheap so there is no need. andrew: It's two instructions. The at instruction stores the result in par_el1 so we then need the… | |||||
Not Done Inline ActionsMay be add a comment there noting that operation is not atomic? kib: May be add a comment there noting that operation is not atomic? | |||||
Not Done Inline ActionsOr perhaps disable interrupts in the implementation rather than the caller. markj: Or perhaps disable interrupts in the implementation rather than the caller. | |||||
return (DMAP_TO_PHYS(va)); | * Disable interrupts so we don't get interrupted between asking | ||||
* for address translation, and getting the result back. | |||||
*/ | |||||
intr = intr_disable(); | |||||
par = arm64_address_translate_s1e1r(va); | |||||
intr_restore(intr); | |||||
if (PAR_SUCCESS(par)) { | |||||
if (pa != NULL) | |||||
*pa = (par & PAR_PA_MASK) | (va & PAR_LOW_MASK); | |||||
return (true); | |||||
} | |||||
/* | |||||
* Fall back to walking the page table. The address translation | |||||
* instruction may fail when the page is in a break-before-make | |||||
* sequence. As we only clear the valid bit in said sequence we | |||||
* can walk the page table to find the physical address. | |||||
*/ | |||||
pte = pmap_l1(kernel_pmap, va); | pte = pmap_l1(kernel_pmap, va); | ||||
if (pte == NULL) | if (pte == NULL) | ||||
return (0); | return (false); | ||||
/* | /* | ||||
* A concurrent pmap_update_entry() will clear the entry's valid bit | * A concurrent pmap_update_entry() will clear the entry's valid bit | ||||
* but leave the rest of the entry unchanged. Therefore, we treat a | * but leave the rest of the entry unchanged. Therefore, we treat a | ||||
* non-zero entry as being valid, and we ignore the valid bit when | * non-zero entry as being valid, and we ignore the valid bit when | ||||
* determining whether the entry maps a block, page, or table. | * determining whether the entry maps a block, page, or table. | ||||
*/ | */ | ||||
tpte = pmap_load(pte); | tpte = pmap_load(pte); | ||||
if (tpte == 0) | if (tpte == 0) | ||||
return (0); | return (false); | ||||
if ((tpte & ATTR_DESCR_TYPE_MASK) == ATTR_DESCR_TYPE_BLOCK) | if ((tpte & ATTR_DESCR_TYPE_MASK) == ATTR_DESCR_TYPE_BLOCK) { | ||||
return ((tpte & ~ATTR_MASK) | (va & L1_OFFSET)); | if (pa != NULL) | ||||
*pa = (tpte & ~ATTR_MASK) | (va & L1_OFFSET); | |||||
return (true); | |||||
} | |||||
pte = pmap_l1_to_l2(&tpte, va); | pte = pmap_l1_to_l2(&tpte, va); | ||||
tpte = pmap_load(pte); | tpte = pmap_load(pte); | ||||
if (tpte == 0) | if (tpte == 0) | ||||
return (0); | return (false); | ||||
if ((tpte & ATTR_DESCR_TYPE_MASK) == ATTR_DESCR_TYPE_BLOCK) | if ((tpte & ATTR_DESCR_TYPE_MASK) == ATTR_DESCR_TYPE_BLOCK) { | ||||
return ((tpte & ~ATTR_MASK) | (va & L2_OFFSET)); | if (pa != NULL) | ||||
*pa = (tpte & ~ATTR_MASK) | (va & L2_OFFSET); | |||||
return (true); | |||||
} | |||||
pte = pmap_l2_to_l3(&tpte, va); | pte = pmap_l2_to_l3(&tpte, va); | ||||
tpte = pmap_load(pte); | tpte = pmap_load(pte); | ||||
if (tpte == 0) | if (tpte == 0) | ||||
return (false); | |||||
if (pa != NULL) | |||||
*pa = (tpte & ~ATTR_MASK) | (va & L3_OFFSET); | |||||
return (true); | |||||
} | |||||
vm_paddr_t | |||||
pmap_kextract(vm_offset_t va) | |||||
{ | |||||
vm_paddr_t pa; | |||||
if (va >= DMAP_MIN_ADDRESS && va < DMAP_MAX_ADDRESS) | |||||
return (DMAP_TO_PHYS(va)); | |||||
if (pmap_kva_to_pa(va, &pa) == false) | |||||
return (0); | return (0); | ||||
return ((tpte & ~ATTR_MASK) | (va & L3_OFFSET)); | return (pa); | ||||
} | } | ||||
/*************************************************** | /*************************************************** | ||||
* Low level mapping routines..... | * Low level mapping routines..... | ||||
***************************************************/ | ***************************************************/ | ||||
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) | ||||
▲ Show 20 Lines • Show All 5,419 Lines • ▼ Show 20 Lines | case ISS_DATA_DFSC_TF_L3: | ||||
* produce a transient fault. | * produce a transient fault. | ||||
*/ | */ | ||||
if (pmap == kernel_pmap) { | if (pmap == kernel_pmap) { | ||||
/* | /* | ||||
* The translation fault may have occurred within a | * The translation fault may have occurred within a | ||||
* critical section. Therefore, we must check the | * critical section. Therefore, we must check the | ||||
* address without acquiring the kernel pmap's lock. | * address without acquiring the kernel pmap's lock. | ||||
*/ | */ | ||||
if (pmap_kextract(far) != 0) | if (pmap_kva_to_pa(far, NULL)) | ||||
Not Done Inline ActionsI think pmap_klookup() might be a better name. kva_to_pa is a bit confusing since 1) translating KVAs to PAs is ostensibly pmap_kextract()'s job, and 2) the function is used here only to see if the address is valid. markj: I think pmap_klookup() might be a better name. kva_to_pa is a bit confusing since 1)… | |||||
rv = KERN_SUCCESS; | rv = KERN_SUCCESS; | ||||
} else { | } else { | ||||
PMAP_LOCK(pmap); | PMAP_LOCK(pmap); | ||||
/* Ask the MMU to check the address. */ | /* Ask the MMU to check the address. */ | ||||
intr = intr_disable(); | intr = intr_disable(); | ||||
par = arm64_address_translate_s1e0r(far); | par = arm64_address_translate_s1e0r(far); | ||||
intr_restore(intr); | intr_restore(intr); | ||||
PMAP_UNLOCK(pmap); | PMAP_UNLOCK(pmap); | ||||
▲ Show 20 Lines • Show All 329 Lines • Show Last 20 Lines |
Extra newline.