In case a translation fault on the kernel address space occurs from

within a critical section, we must perform a lock-free check on the
faulting address.

Reported by:	andrew
Reviewed by:	andrew, markj
X-MFC with:	r350579
Differential Revision:	https://reviews.freebsd.org/D21685
This commit is contained in:
alc 2019-09-21 19:51:57 +00:00
parent 7c14989404
commit 1629aaf0f7

View File

@ -5810,23 +5810,33 @@ pmap_fault(pmap_t pmap, uint64_t esr, uint64_t far)
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.
* Retry the translation. A break-before-make sequence can
* produce a transient fault.
*/
if (PAR_SUCCESS(par))
rv = KERN_SUCCESS;
if (pmap == kernel_pmap) {
/*
* The translation fault may have occurred within a
* critical section. Therefore, we must check the
* address without acquiring the kernel pmap's lock.
*/
if (pmap_kextract(far) != 0)
rv = KERN_SUCCESS;
} else {
PMAP_LOCK(pmap);
/* Ask the MMU to check the address. */
intr = intr_disable();
par = arm64_address_translate_s1e0r(far);
intr_restore(intr);
PMAP_UNLOCK(pmap);
/*
* If the translation was successful, then we can
* return success to the trap handler.
*/
if (PAR_SUCCESS(par))
rv = KERN_SUCCESS;
}
break;
}