Module Name: src Committed By: nonaka Date: Mon Jan 26 04:47:53 UTC 2015
Modified Files: src/sys/arch/powerpc/booke: booke_pmap.c genassym.cf trap_subr.S src/sys/arch/powerpc/include/booke: pmap.h src/sys/uvm/pmap: pmap.c Log Message: Avoid race condition between PTE update and TLB miss walk. To generate a diff of this commit: cvs rdiff -u -r1.21 -r1.22 src/sys/arch/powerpc/booke/booke_pmap.c cvs rdiff -u -r1.10 -r1.11 src/sys/arch/powerpc/booke/genassym.cf cvs rdiff -u -r1.11 -r1.12 src/sys/arch/powerpc/booke/trap_subr.S cvs rdiff -u -r1.14 -r1.15 src/sys/arch/powerpc/include/booke/pmap.h cvs rdiff -u -r1.9 -r1.10 src/sys/uvm/pmap/pmap.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/powerpc/booke/booke_pmap.c diff -u src/sys/arch/powerpc/booke/booke_pmap.c:1.21 src/sys/arch/powerpc/booke/booke_pmap.c:1.22 --- src/sys/arch/powerpc/booke/booke_pmap.c:1.21 Fri Jan 23 06:39:41 2015 +++ src/sys/arch/powerpc/booke/booke_pmap.c Mon Jan 26 04:47:53 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: booke_pmap.c,v 1.21 2015/01/23 06:39:41 nonaka Exp $ */ +/* $NetBSD: booke_pmap.c,v 1.22 2015/01/26 04:47:53 nonaka Exp $ */ /*- * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. * All rights reserved. @@ -38,16 +38,21 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: booke_pmap.c,v 1.21 2015/01/23 06:39:41 nonaka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: booke_pmap.c,v 1.22 2015/01/26 04:47:53 nonaka Exp $"); #include <sys/param.h> #include <sys/kcore.h> #include <sys/buf.h> +#include <sys/mutex.h> #include <uvm/uvm.h> #include <machine/pmap.h> +#if defined(MULTIPROCESSOR) +kmutex_t pmap_tlb_miss_lock; +#endif + /* * Initialize the kernel pmap. */ @@ -166,6 +171,10 @@ pmap_bootstrap(vaddr_t startkernel, vadd /* init the lock */ pmap_tlb_info_init(&pmap_tlb0_info); +#if defined(MULTIPROCESSOR) + mutex_init(&pmap_tlb_miss_lock, MUTEX_SPIN, IPL_HIGH); +#endif + /* * Compute the number of pages kmem_arena will have. */ @@ -427,4 +436,18 @@ pmap_md_tlb_info_attach(struct pmap_tlb_ { /* nothing */ } + +void +pmap_md_tlb_miss_lock_enter(void) +{ + + mutex_spin_enter(&pmap_tlb_miss_lock); +} + +void +pmap_md_tlb_miss_lock_exit(void) +{ + + mutex_spin_exit(&pmap_tlb_miss_lock); +} #endif /* MULTIPROCESSOR */ Index: src/sys/arch/powerpc/booke/genassym.cf diff -u src/sys/arch/powerpc/booke/genassym.cf:1.10 src/sys/arch/powerpc/booke/genassym.cf:1.11 --- src/sys/arch/powerpc/booke/genassym.cf:1.10 Tue Nov 27 19:24:46 2012 +++ src/sys/arch/powerpc/booke/genassym.cf Mon Jan 26 04:47:53 2015 @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.10 2012/11/27 19:24:46 matt Exp $ +# $NetBSD: genassym.cf,v 1.11 2015/01/26 04:47:53 nonaka Exp $ #- # Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. @@ -111,4 +111,7 @@ define HATCH_SP offsetof(struct cpu_hat define HATCH_TBU offsetof(struct cpu_hatch_data, hatch_tbu) define HATCH_TBL offsetof(struct cpu_hatch_data, hatch_tbl) define HATCH_TLBIDX offsetof(struct cpu_hatch_data, hatch_tlbidx) + +define __SIMPLELOCK_LOCKED __SIMPLELOCK_LOCKED +define __SIMPLELOCK_UNLOCKED __SIMPLELOCK_UNLOCKED endif Index: src/sys/arch/powerpc/booke/trap_subr.S diff -u src/sys/arch/powerpc/booke/trap_subr.S:1.11 src/sys/arch/powerpc/booke/trap_subr.S:1.12 --- src/sys/arch/powerpc/booke/trap_subr.S:1.11 Thu Sep 18 23:37:51 2014 +++ src/sys/arch/powerpc/booke/trap_subr.S Mon Jan 26 04:47:53 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: trap_subr.S,v 1.11 2014/09/18 23:37:51 joerg Exp $ */ +/* $NetBSD: trap_subr.S,v 1.12 2015/01/26 04:47:53 nonaka Exp $ */ /*- * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. * All rights reserved. @@ -34,7 +34,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -RCSID("$NetBSD: trap_subr.S,v 1.11 2014/09/18 23:37:51 joerg Exp $") +RCSID("$NetBSD: trap_subr.S,v 1.12 2015/01/26 04:47:53 nonaka Exp $") .globl _C_LABEL(sctrapexit), _C_LABEL(trapexit), _C_LABEL(intrcall) @@ -346,6 +346,50 @@ RCSID("$NetBSD: trap_subr.S,v 1.11 2014/ RESTORE_SPRG1(%r6); \ FRAME_INTR_XEXIT(rfci, CSRR) +#if defined(MULTIPROCESSOR) +#define FRAME_TLBMISSLOCK \ + GET_CPUINFO(%r23); \ + ldint %r22, CI_MTX_COUNT(%r23); \ + subi %r22, %r22, 1; \ + stint %r22, CI_MTX_COUNT(%r23); \ + isync; \ + cmpwi %r22, 0; \ + bne 1f; \ + ldint %r22, CI_CPL(%r23); \ + stint %r22, CI_MTX_OLDSPL(%r23); \ +1: lis %r23, _C_LABEL(pmap_tlb_miss_lock)@h; \ + ori %r23, %r23, _C_LABEL(pmap_tlb_miss_lock)@l; \ + li %r20, MTX_LOCK; \ +2: lwarx %r22, %r20, %r23; \ + cmpwi %r22, __SIMPLELOCK_UNLOCKED; \ + beq+ 4f; \ +3: lwzx %r22, %r20, %r23; \ + cmpwi %r22, __SIMPLELOCK_UNLOCKED; \ + beq+ 2b; \ + b 3b; \ +4: li %r21, __SIMPLELOCK_LOCKED; \ + stwcx. %r21, %r20, %r23; \ + bne- 2b; \ + isync; \ + msync; +#define FRAME_TLBMISSUNLOCK \ + sync; \ + lis %r23, _C_LABEL(pmap_tlb_miss_lock)@h; \ + ori %r23, %r23, _C_LABEL(pmap_tlb_miss_lock)@l; \ + li %r22, __SIMPLELOCK_UNLOCKED; \ + stw %r22, MTX_LOCK(%r23); \ + isync; \ + msync; \ + GET_CPUINFO(%r23); \ + ldint %r22, CI_MTX_COUNT(%r23); \ + addi %r22, %r22, 1; \ + stint %r22, CI_MTX_COUNT(%r23); \ + isync; +#else /* !MULTIPROCESSOR */ +#define FRAME_TLBMISSLOCK +#define FRAME_TLBMISSUNLOCK +#endif /* MULTIPROCESSOR */ + .text .p2align 4 _C_LABEL(critical_input_vector): @@ -535,6 +579,7 @@ _C_LABEL(watchdog_timer_vector): _C_LABEL(data_tlb_error_vector): /* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */ FRAME_TLBPROLOGUE + FRAME_TLBMISSLOCK /* * Registers as this point: * @@ -577,6 +622,7 @@ _C_LABEL(data_tlb_error_vector): 31-PTR_SCALESHIFT, \ 31-PTR_SCALESHIFT /* move PSL_DS[27] to bit 29 */ bl pte_load + FRAME_TLBMISSUNLOCK mtlr %r29 /* restore LR */ /* * If we returned, pte load failed so let trap deal with it but @@ -590,6 +636,7 @@ _C_LABEL(data_tlb_error_vector): _C_LABEL(instruction_tlb_error_vector): /* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */ FRAME_TLBPROLOGUE + FRAME_TLBMISSLOCK /* * Attempt to update the TLB from the page table. */ @@ -600,6 +647,7 @@ _C_LABEL(instruction_tlb_error_vector): 31-PTR_SCALESHIFT, \ 31-PTR_SCALESHIFT /* move PSL_IS[26] to bit 29 */ bl pte_load + FRAME_TLBMISSUNLOCK mtlr %r29 /* restore LR */ /* * If we returned, pte load failed so let trap deal with it but @@ -764,6 +812,9 @@ e500_pte_load: addic %r31, %r31, 1 addze %r30, %r30 stmw %r30, CI_EV_TLBMISS_SOFT(%r2) + + FRAME_TLBMISSUNLOCK + /* * Cleanup and leave. We know any higher priority exception will * save and restore SPRG1 and %r2 thereby preserving their values. Index: src/sys/arch/powerpc/include/booke/pmap.h diff -u src/sys/arch/powerpc/include/booke/pmap.h:1.14 src/sys/arch/powerpc/include/booke/pmap.h:1.15 --- src/sys/arch/powerpc/include/booke/pmap.h:1.14 Thu Apr 3 13:55:34 2014 +++ src/sys/arch/powerpc/include/booke/pmap.h Mon Jan 26 04:47:53 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.h,v 1.14 2014/04/03 13:55:34 matt Exp $ */ +/* $NetBSD: pmap.h,v 1.15 2015/01/26 04:47:53 nonaka Exp $ */ /*- * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. * All rights reserved. @@ -92,6 +92,12 @@ void pmap_md_init(void); bool pmap_md_tlb_check_entry(void *, vaddr_t, tlb_asid_t, pt_entry_t); +#ifdef MULTIPROCESSOR +#define PMAP_MD_NEED_TLB_MISS_LOCK +void pmap_md_tlb_miss_lock_enter(void); +void pmap_md_tlb_miss_lock_exit(void); +#endif /* MULTIPROCESSOR */ + #ifdef PMAP_MINIMALTLB vaddr_t pmap_kvptefill(vaddr_t, vaddr_t, pt_entry_t); #endif Index: src/sys/uvm/pmap/pmap.c diff -u src/sys/uvm/pmap/pmap.c:1.9 src/sys/uvm/pmap/pmap.c:1.10 --- src/sys/uvm/pmap/pmap.c:1.9 Mon Jan 5 05:35:18 2015 +++ src/sys/uvm/pmap/pmap.c Mon Jan 26 04:47:53 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.c,v 1.9 2015/01/05 05:35:18 nonaka Exp $ */ +/* $NetBSD: pmap.c,v 1.10 2015/01/26 04:47:53 nonaka Exp $ */ /*- * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. @@ -67,7 +67,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.9 2015/01/05 05:35:18 nonaka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.10 2015/01/26 04:47:53 nonaka Exp $"); /* * Manages physical address maps. @@ -263,6 +263,11 @@ struct pool_allocator pmap_pv_page_alloc #define pmap_pv_alloc() pool_get(&pmap_pv_pool, PR_NOWAIT) #define pmap_pv_free(pv) pool_put(&pmap_pv_pool, (pv)) +#if !defined(MULTIPROCESSOR) || !defined(PMAP_MD_NEED_TLB_MISS_LOCK) +#define pmap_md_tlb_miss_lock_enter() do { } while(/*CONSTCOND*/0) +#define pmap_md_tlb_miss_lock_exit() do { } while(/*CONSTCOND*/0) +#endif /* !MULTIPROCESSOR || !PMAP_MD_NEED_TLB_MISS_LOCK */ + /* * Misc. functions. */ @@ -541,8 +546,10 @@ pmap_destroy(pmap_t pmap) KASSERT(pmap->pm_count == 0); PMAP_COUNT(destroy); kpreempt_disable(); + pmap_md_tlb_miss_lock_enter(); pmap_tlb_asid_release_all(pmap); pmap_segtab_destroy(pmap, NULL, 0); + pmap_md_tlb_miss_lock_exit(); #ifdef MULTIPROCESSOR kcpuset_destroy(pmap->pm_active); @@ -586,10 +593,12 @@ pmap_activate(struct lwp *l) PMAP_COUNT(activate); kpreempt_disable(); + pmap_md_tlb_miss_lock_enter(); pmap_tlb_asid_acquire(pmap, l); if (l == curlwp) { pmap_segtab_activate(pmap, l); } + pmap_md_tlb_miss_lock_exit(); kpreempt_enable(); UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); @@ -608,8 +617,10 @@ pmap_deactivate(struct lwp *l) PMAP_COUNT(deactivate); kpreempt_disable(); + pmap_md_tlb_miss_lock_enter(); curcpu()->ci_pmap_user_segtab = PMAP_INVALID_SEGTAB_ADDRESS; pmap_tlb_asid_deactivate(pmap); + pmap_md_tlb_miss_lock_exit(); kpreempt_enable(); UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); @@ -629,6 +640,7 @@ pmap_update(struct pmap *pmap) if (pending && pmap_tlb_shootdown_bystanders(pmap)) PMAP_COUNT(shootdown_ipis); #endif + pmap_md_tlb_miss_lock_enter(); #ifdef DEBUG pmap_tlb_check(pmap, pmap_md_tlb_check_entry); #endif /* DEBUG */ @@ -642,6 +654,7 @@ pmap_update(struct pmap *pmap) pmap_tlb_asid_acquire(pmap, curlwp); pmap_segtab_activate(pmap, curlwp); } + pmap_md_tlb_miss_lock_exit(); kpreempt_enable(); UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); @@ -685,11 +698,13 @@ pmap_pte_remove(pmap_t pmap, vaddr_t sva pmap_remove_pv(pmap, sva, pg, pte_modified_p(pt_entry)); } + pmap_md_tlb_miss_lock_enter(); *ptep = npte; /* * Flush the TLB for the given address. */ pmap_tlb_invalidate_addr(pmap, sva); + pmap_md_tlb_miss_lock_exit(); } return false; } @@ -843,12 +858,14 @@ pmap_pte_protect(pmap_t pmap, vaddr_t sv } pt_entry = pte_prot_downgrade(pt_entry, prot); if (*ptep != pt_entry) { + pmap_md_tlb_miss_lock_enter(); *ptep = pt_entry; /* * Update the TLB if needed. */ pmap_tlb_update_addr(pmap, sva, pt_entry, PMAP_TLB_NEED_IPI); + pmap_md_tlb_miss_lock_exit(); } } return false; @@ -937,9 +954,11 @@ pmap_page_cache(struct vm_page *pg, bool pt_entry_t pt_entry = *ptep; if (pte_valid_p(pt_entry)) { pt_entry = pte_cached_change(pt_entry, cached); + pmap_md_tlb_miss_lock_enter(); *ptep = pt_entry; pmap_tlb_update_addr(pmap, va, pt_entry, PMAP_TLB_NEED_IPI); + pmap_md_tlb_miss_lock_exit(); } } UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); @@ -1060,11 +1079,13 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd bool resident = pte_valid_p(opte); if (!resident) pmap->pm_stats.resident_count++; + pmap_md_tlb_miss_lock_enter(); *ptep = npte; pmap_tlb_update_addr(pmap, va, npte, ((flags & VM_PROT_ALL) ? PMAP_TLB_INSERT : 0) | (resident ? PMAP_TLB_NEED_IPI : 0)); + pmap_md_tlb_miss_lock_exit(); kpreempt_enable(); if (pg != NULL && (prot == (VM_PROT_READ | VM_PROT_EXECUTE))) { @@ -1138,12 +1159,14 @@ pmap_kenter_pa(vaddr_t va, paddr_t pa, v pt_entry_t * const ptep = pmap_pte_reserve(pmap_kernel(), va, 0); KASSERT(ptep != NULL); KASSERT(!pte_valid_p(*ptep)); + pmap_md_tlb_miss_lock_enter(); *ptep = npte; /* * We have the option to force this mapping into the TLB but we * don't. Instead let the next reference to the page do it. */ pmap_tlb_update_addr(pmap_kernel(), va, npte, 0); + pmap_md_tlb_miss_lock_exit(); kpreempt_enable(); #if DEBUG > 1 for (u_int i = 0; i < PAGE_SIZE / sizeof(long); i++) { @@ -1179,8 +1202,10 @@ pmap_pte_kremove(pmap_t pmap, vaddr_t sv if (pg != NULL) pmap_md_vca_clean(pg, sva, PMAP_WBINV); + pmap_md_tlb_miss_lock_enter(); *ptep = new_pt_entry; pmap_tlb_invalidate_addr(pmap_kernel(), sva); + pmap_md_tlb_miss_lock_exit(); } return false; @@ -1213,8 +1238,10 @@ pmap_remove_all(struct pmap *pmap) * Free all of our ASIDs which means we can skip doing all the * tlb_invalidate_addrs(). */ + pmap_md_tlb_miss_lock_enter(); pmap_tlb_asid_deactivate(pmap); pmap_tlb_asid_release_all(pmap); + pmap_md_tlb_miss_lock_exit(); pmap->pm_flags |= PMAP_DEFERRED_ACTIVATE; kpreempt_enable(); @@ -1258,7 +1285,9 @@ pmap_unwire(pmap_t pmap, vaddr_t va) #endif if (pte_wired_p(pt_entry)) { + pmap_md_tlb_miss_lock_enter(); *ptep = pte_unwire_entry(*ptep); + pmap_md_tlb_miss_lock_exit(); pmap->pm_stats.wired_count--; } #ifdef DIAGNOSTIC @@ -1421,9 +1450,11 @@ pmap_clear_modify(struct vm_page *pg) continue; } pmap_md_vca_clean(pg, va, PMAP_WBINV); + pmap_md_tlb_miss_lock_enter(); *ptep = pt_entry; VM_PAGEMD_PVLIST_UNLOCK(mdpg); pmap_tlb_invalidate_addr(pmap, va); + pmap_md_tlb_miss_lock_exit(); pmap_update(pmap); if (__predict_false(gen != VM_PAGEMD_PVLIST_LOCK(mdpg, false))) { /*