Index: sys/arm64/arm64/pmap.c =================================================================== --- sys/arm64/arm64/pmap.c +++ sys/arm64/arm64/pmap.c @@ -5764,11 +5764,27 @@ } } +static uint64_t +pmap_fault_translate(pmap_t pmap, uint64_t far) +{ + register_t intr; + uint64_t par; + + /* Ask the MMU to check the address */ + intr = intr_disable(); + if (pmap == kernel_pmap) + par = arm64_address_translate_s1e1r(far); + else + par = arm64_address_translate_s1e0r(far); + intr_restore(intr); + + return (par); +} + int pmap_fault(pmap_t pmap, uint64_t esr, uint64_t far) { pt_entry_t pte, *ptep; - register_t intr; uint64_t ec, par; int lvl, rv; @@ -5824,21 +5840,26 @@ case ISS_DATA_DFSC_TF_L1: case ISS_DATA_DFSC_TF_L2: case ISS_DATA_DFSC_TF_L3: - PMAP_LOCK(pmap); - /* Ask the MMU to check the address */ - intr = intr_disable(); - if (pmap == kernel_pmap) - par = arm64_address_translate_s1e1r(far); - else - par = arm64_address_translate_s1e0r(far); - intr_restore(intr); - PMAP_UNLOCK(pmap); - /* * If the translation was successful the address was invalid - * due to a break-before-make sequence. We can unlock and - * return success to the trap handler. + * due to a break-before-make sequence. Try first unlocked + * as the operatin is only a few instructions long and will + * have interrupts disabled to stop it being interrupted. */ + par = pmap_fault_translate(pmap, far); + if (PAR_SUCCESS(par)) { + rv = KERN_SUCCESS; + break; + } + + /* + * The translation failed, try afain with the pmap lock to + * ensure all page table updates have completed. + */ + PMAP_LOCK(pmap); + par = pmap_fault_translate(pmap, far); + PMAP_UNLOCK(pmap); + if (PAR_SUCCESS(par)) rv = KERN_SUCCESS; break;