The branch main has been updated by bnovkov:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=7a5ef20a977c2d1ae5b94e6e6e927ac7a566ff10

commit 7a5ef20a977c2d1ae5b94e6e6e927ac7a566ff10
Author:     Bojan Novković <[email protected]>
AuthorDate: 2026-06-10 19:13:03 +0000
Commit:     Bojan Novković <[email protected]>
CommitDate: 2026-07-10 15:56:57 +0000

    riscv/pmap.c: Handle spurious kernel page faults in critical sections
    
    The Privileged ISA specification permits caching of invalid PTEs
    12.2.1. Supervisor Memory-Management Fence Instruction), which may
    result in a spurious page fault. Such faults are handled by 'pmap_fault'
    which locks the kernel pmap before inspecting and possibly updating the
    offending L2 entry.
    Unfortunately, spurious faults may also occur when we're already holding
    the kernel_pmap lock or running in a critical section, where any attempt
    to grab the pmap lock will result in a kernel panic.
    
    Fix this avoidable panic by performing a lockless lookup to determine
    whether a valid kernel mapping exits and flushing appropriate TLB entry.
    
    Differential Revision:  https://reviews.freebsd.org/D56925
    Reviewed by:    jrtc27, mhorne, markj
---
 sys/riscv/riscv/pmap.c | 46 +++++++++++++++++++++++++++++++++++-----------
 1 file changed, 35 insertions(+), 11 deletions(-)

diff --git a/sys/riscv/riscv/pmap.c b/sys/riscv/riscv/pmap.c
index 35194ebd7c28..67123f9bfcc8 100644
--- a/sys/riscv/riscv/pmap.c
+++ b/sys/riscv/riscv/pmap.c
@@ -2911,28 +2911,52 @@ retryl3:
        PMAP_UNLOCK(pmap);
 }
 
+static pt_entry_t *
+pmap_fault_lookup(pmap_t pmap, vm_offset_t va)
+{
+       pd_entry_t *l2, l2e;
+
+       l2 = pmap_l2(pmap, va);
+       if (l2 == NULL || ((l2e = pmap_load(l2)) & PTE_V) == 0)
+               return (NULL);
+       if ((l2e & PTE_RWX) == 0)
+               return (pmap_l2_to_l3(l2, va));
+       return (l2);
+}
+
 int
 pmap_fault(pmap_t pmap, vm_offset_t va, vm_prot_t ftype)
 {
-       pd_entry_t *l2, l2e;
        pt_entry_t bits, *pte, oldpte;
        int rv;
 
        KASSERT(VIRT_IS_VALID(va), ("pmap_fault: invalid va %#lx", va));
 
+       if (pmap == kernel_pmap) {
+               /*
+                * Locking the kernel pmap while processing spurious faults
+                * may lead to a panic since we might be running a critical 
section
+                * or already holding the kernel pmap lock.
+                * We deal with this by taking advantage of the fact that
+                * kernel PTPs are never freed and performing a lockless lookup
+                * to determine whether a valid mapping exits.
+                */
+               pte = pmap_fault_lookup(pmap, va);
+               if (pte != NULL && (pmap_load(pte) & PTE_KERN) == PTE_KERN) {
+                       sfence_vma_page(va);
+                       return (1);
+               }
+               /*
+                * The entry is either not present or missing some bits.
+                * Fall back to the locked lookup below to handle the fault.
+                */
+       }
+
        rv = 0;
        PMAP_LOCK(pmap);
-       l2 = pmap_l2(pmap, va);
-       if (l2 == NULL || ((l2e = pmap_load(l2)) & PTE_V) == 0)
+       pte = pmap_fault_lookup(pmap, va);
+       if (pte == NULL || ((oldpte = pmap_load(pte)) & PTE_V) == 0)
                goto done;
-       if ((l2e & PTE_RWX) == 0) {
-               pte = pmap_l2_to_l3(l2, va);
-               if (((oldpte = pmap_load(pte)) & PTE_V) == 0)
-                       goto done;
-       } else {
-               pte = l2;
-               oldpte = l2e;
-       }
 
        if ((pmap != kernel_pmap && (oldpte & PTE_U) == 0) ||
            (ftype == VM_PROT_WRITE && (oldpte & PTE_W) == 0) ||

Reply via email to