git: 15a163794539 - stable/13 - riscv: Fix a race in pmap_pinit()

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Tue, 01 Mar 2022 15:17:51 UTC
The branch stable/13 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=15a16379453983788fdcb030006b59ff4807f61f

commit 15a16379453983788fdcb030006b59ff4807f61f
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2022-02-08 18:15:54 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2022-03-01 15:17:33 +0000

    riscv: Fix a race in pmap_pinit()
    
    All pmaps share the top half of the address space.  With 3-level page
    tables, the top-level kernel map entries are not static: they might
    change if the kernel map is extended (via pmap_growkernel()) or a 1GB
    mapping in the direct map is demoted (not implemented yet).  Thus the
    riscv pmap maintains the allpmaps list to synchronize updates to
    top-level entries.
    
    When a pmap is created, it is inserted into this list after copying
    top-level entries from the kernel pmap.  The copying is done without
    holding the allpmaps lock, and it is possible for pmap_pinit() to race
    with kernel map updates.  In particular, if a thread is modifying L1
    entries, and a concurrent pmap_pinit() copies the old version of the
    entries, it might not receive the update.
    
    Fix the problem by copying the kernel map entries after inserting the
    pmap into the list.  This ensures that the nascent pmap always receives
    updates, though pmap_distribute_l1() may race with the page copy.
    
    Reviewed by:    mhorne, jhb
    Sponsored by:   The FreeBSD Foundation
    
    (cherry picked from commit c862d5f2a789925efe70fc64247caa5148e98a54)
---
 sys/riscv/riscv/pmap.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/sys/riscv/riscv/pmap.c b/sys/riscv/riscv/pmap.c
index 589628d0e350..97f96ebdf99e 100644
--- a/sys/riscv/riscv/pmap.c
+++ b/sys/riscv/riscv/pmap.c
@@ -1231,14 +1231,12 @@ pmap_pinit(pmap_t pmap)
 
 	CPU_ZERO(&pmap->pm_active);
 
-	/* Install kernel pagetables */
-	memcpy(pmap->pm_l1, kernel_pmap->pm_l1, PAGE_SIZE);
-
-	/* Add to the list of all user pmaps */
 	mtx_lock(&allpmaps_lock);
 	LIST_INSERT_HEAD(&allpmaps, pmap, pm_list);
 	mtx_unlock(&allpmaps_lock);
 
+	memcpy(pmap->pm_l1, kernel_pmap->pm_l1, PAGE_SIZE);
+
 	vm_radix_init(&pmap->pm_root);
 
 	return (1);