From e9c2f3206d1163e43a2320134a0a82e080e27002 Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Sat, 20 Mar 2010 15:19:57 +0000 Subject: [PATCH] MFC r204268: Close a race involving the OEA64 scratchpage. When the scratch page's physical address is changed, there is a brief window during which its PTE is invalid. Since moea64_set_scratchpage_pa() does not and cannot hold the page table lock, it was possible for another CPU to insert a new PTE into the scratch page's PTEG slot during this interval, corrupting both mappings. Solve this by creating a new flag, LPTE_LOCKED, such that moea64_pte_insert will avoid claiming locked PTEG slots even if they are invalid. This change also incorporates some additional paranoia added to solve things I thought might be this bug. Reported by: linimon git-svn-id: svn://svn.freebsd.org/base/stable/8@205379 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/powerpc/aim/mmu_oea64.c | 24 ++++++++++++++---------- sys/powerpc/include/pte.h | 1 + 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/sys/powerpc/aim/mmu_oea64.c b/sys/powerpc/aim/mmu_oea64.c index be1545471..23e5950c7 100644 --- a/sys/powerpc/aim/mmu_oea64.c +++ b/sys/powerpc/aim/mmu_oea64.c @@ -227,6 +227,7 @@ TLBIE(pmap_t pmap, vm_offset_t va) { #define VSID_MAKE(sr, hash) ((sr) | (((hash) & 0xfffff) << 4)) #define VSID_TO_SR(vsid) ((vsid) & 0xf) #define VSID_TO_HASH(vsid) (((vsid) >> 4) & 0xfffff) +#define VSID_HASH_MASK 0x0000007fffffffffULL #define PVO_PTEGIDX_MASK 0x007UL /* which PTEG slot */ #define PVO_PTEGIDX_VALID 0x008UL /* slot is valid */ @@ -458,9 +459,9 @@ MMU_DEF(oea64_bridge_mmu); static __inline u_int va_to_pteg(uint64_t vsid, vm_offset_t addr) { - u_int hash; + uint64_t hash; - hash = vsid ^ (((uint64_t)addr & ADDR_PIDX) >> + hash = (vsid & VSID_HASH_MASK) ^ (((uint64_t)addr & ADDR_PIDX) >> ADDR_PIDX_SHFT); return (hash & moea64_pteg_mask); } @@ -979,6 +980,7 @@ moea64_bridge_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernele moea64_scratchpage_va[i],&j); moea64_scratchpage_pte[i] = moea64_pvo_to_pte( moea64_scratchpage_pvo[i],j); + moea64_scratchpage_pte[i]->pte_hi |= LPTE_LOCKED; UNLOCK_TABLE(); } @@ -1090,8 +1092,10 @@ moea64_zero_page(mmu_t mmu, vm_page_t m) static __inline void moea64_set_scratchpage_pa(int which, vm_offset_t pa) { + mtx_assert(&moea64_scratchpage_mtx, MA_OWNED); + moea64_scratchpage_pvo[which]->pvo_pte.lpte.pte_lo &= - (~LPTE_WIMG & ~LPTE_RPGN); + ~(LPTE_WIMG | LPTE_RPGN); moea64_scratchpage_pvo[which]->pvo_pte.lpte.pte_lo |= moea64_calc_wimg(pa) | (uint64_t)pa; @@ -2149,18 +2153,16 @@ moea64_pvo_remove(struct pvo_entry *pvo, int pteidx) static __inline int moea64_pvo_pte_index(const struct pvo_entry *pvo, int ptegidx) { - int pteidx; /* * We can find the actual pte entry without searching by grabbing - * the PTEG index from 3 unused bits in pte_lo[11:9] and by + * the PTEG index from 3 unused bits in pvo_vaddr and by * noticing the HID bit. */ - pteidx = ptegidx * 8 + PVO_PTEGIDX_GET(pvo); if (pvo->pvo_pte.lpte.pte_hi & LPTE_HID) - pteidx ^= moea64_pteg_mask * 8; + ptegidx ^= moea64_pteg_mask; - return (pteidx); + return ((ptegidx << 3) | PVO_PTEGIDX_GET(pvo)); } static struct pvo_entry * @@ -2257,7 +2259,8 @@ moea64_pte_insert(u_int ptegidx, struct lpte *pvo_pt) * First try primary hash. */ for (pt = moea64_pteg_table[ptegidx].pt, i = 0; i < 8; i++, pt++) { - if ((pt->pte_hi & LPTE_VALID) == 0) { + if ((pt->pte_hi & LPTE_VALID) == 0 && + (pt->pte_hi & LPTE_LOCKED) == 0) { pvo_pt->pte_hi &= ~LPTE_HID; moea64_pte_set(pt, pvo_pt); return (i); @@ -2270,7 +2273,8 @@ moea64_pte_insert(u_int ptegidx, struct lpte *pvo_pt) ptegidx ^= moea64_pteg_mask; for (pt = moea64_pteg_table[ptegidx].pt, i = 0; i < 8; i++, pt++) { - if ((pt->pte_hi & LPTE_VALID) == 0) { + if ((pt->pte_hi & LPTE_VALID) == 0 && + (pt->pte_hi & LPTE_LOCKED) == 0) { pvo_pt->pte_hi |= LPTE_HID; moea64_pte_set(pt, pvo_pt); return (i); diff --git a/sys/powerpc/include/pte.h b/sys/powerpc/include/pte.h index f1e5319a5..b7f5fd971 100644 --- a/sys/powerpc/include/pte.h +++ b/sys/powerpc/include/pte.h @@ -95,6 +95,7 @@ struct lpteg { /* High quadword: */ #define LPTE_VSID_SHIFT 12 #define LPTE_API 0x0000000000000F80ULL +#define LPTE_LOCKED 0x0000000000000008ULL #define LPTE_BIG 0x0000000000000004ULL /* 4kb/16Mb page */ #define LPTE_HID 0x0000000000000002ULL #define LPTE_VALID 0x0000000000000001ULL -- 2.45.0