Author: nwhitehorn
Date: Thu Feb 18 15:00:43 2010
New Revision: 204042
URL: http://svn.freebsd.org/changeset/base/204042

Log:
  Fix a bug where pages being removed from memory entirely no longer have
  PVOs, and so the modified state of the page can no longer be communicated
  to the VM layer, causing pages not to be flushed to swap when needed, in
  turn causing memory corruption. Also make several correctness adjustments
  to I-Cache synchronization and TLB invalidation for 64-bit Book-S CPUs.
  
  Obtained from:        projects/ppc64
  Discussed with:       grehan
  MFC after:    2 weeks

Modified:
  head/sys/powerpc/aim/mmu_oea.c
  head/sys/powerpc/aim/mmu_oea64.c

Modified: head/sys/powerpc/aim/mmu_oea.c
==============================================================================
--- head/sys/powerpc/aim/mmu_oea.c      Thu Feb 18 14:28:38 2010        
(r204041)
+++ head/sys/powerpc/aim/mmu_oea.c      Thu Feb 18 15:00:43 2010        
(r204042)
@@ -1729,6 +1729,10 @@ moea_remove_all(mmu_t mmu, vm_page_t m)
                moea_pvo_remove(pvo, -1);
                PMAP_UNLOCK(pmap);
        }
+       if ((m->flags & PG_WRITEABLE) && moea_is_modified(mmu, m)) {
+               moea_attr_clear(m, LPTE_CHG);
+               vm_page_dirty(m);
+       }
        vm_page_flag_clear(m, PG_WRITEABLE);
 }
 
@@ -2203,10 +2207,8 @@ moea_query_bit(vm_page_t m, int ptebit)
        struct  pvo_entry *pvo;
        struct  pte *pt;
 
-#if 0
        if (moea_attr_fetch(m) & ptebit)
                return (TRUE);
-#endif
 
        LIST_FOREACH(pvo, vm_page_to_pvoh(m), pvo_vlink) {
                MOEA_PVO_CHECK(pvo);    /* sanity check */

Modified: head/sys/powerpc/aim/mmu_oea64.c
==============================================================================
--- head/sys/powerpc/aim/mmu_oea64.c    Thu Feb 18 14:28:38 2010        
(r204041)
+++ head/sys/powerpc/aim/mmu_oea64.c    Thu Feb 18 15:00:43 2010        
(r204042)
@@ -172,6 +172,7 @@ va_to_vsid(pmap_t pm, vm_offset_t va)
        return ((pm->pm_sr[(uintptr_t)va >> ADDR_SR_SHFT]) & SR_VSID_MASK);
 }
 
+#define        PTESYNC()       __asm __volatile("ptesync");
 #define        TLBSYNC()       __asm __volatile("tlbsync; ptesync");
 #define        SYNC()          __asm __volatile("sync");
 #define        EIEIO()         __asm __volatile("eieio");
@@ -194,6 +195,7 @@ TLBIE(pmap_t pmap, vm_offset_t va) {
        vpn = (uint64_t)(va & ADDR_PIDX);
        if (pmap != NULL)
                vpn |= (va_to_vsid(pmap,va) << 28);
+       vpn &= ~(0xffffULL << 48);
 
        vpn_hi = (uint32_t)(vpn >> 32);
        vpn_lo = (uint32_t)vpn;
@@ -201,8 +203,7 @@ TLBIE(pmap_t pmap, vm_offset_t va) {
        mtx_lock_spin(&tlbie_mutex);
        __asm __volatile("\
            mfmsr %0; \
-           clrldi %1,%0,49; \
-           mtmsr %1; \
+           mr %1, %0; \
            insrdi %1,%5,1,0; \
            mtmsrd %1; \
            ptesync; \
@@ -215,7 +216,8 @@ TLBIE(pmap_t pmap, vm_offset_t va) {
            eieio; \
            tlbsync; \
            ptesync;" 
-       : "=r"(msr), "=r"(scratch) : "r"(vpn_hi), "r"(vpn_lo), "r"(32), "r"(1));
+       : "=r"(msr), "=r"(scratch) : "r"(vpn_hi), "r"(vpn_lo), "r"(32), "r"(1)
+           : "memory");
        mtx_unlock_spin(&tlbie_mutex);
 }
 
@@ -226,13 +228,13 @@ TLBIE(pmap_t pmap, vm_offset_t va) {
 #define        VSID_TO_SR(vsid)        ((vsid) & 0xf)
 #define        VSID_TO_HASH(vsid)      (((vsid) >> 4) & 0xfffff)
 
-#define        PVO_PTEGIDX_MASK        0x007           /* which PTEG slot */
-#define        PVO_PTEGIDX_VALID       0x008           /* slot is valid */
-#define        PVO_WIRED               0x010           /* PVO entry is wired */
-#define        PVO_MANAGED             0x020           /* PVO entry is managed 
*/
-#define        PVO_BOOTSTRAP           0x080           /* PVO entry allocated 
during
+#define        PVO_PTEGIDX_MASK        0x007UL         /* which PTEG slot */
+#define        PVO_PTEGIDX_VALID       0x008UL         /* slot is valid */
+#define        PVO_WIRED               0x010UL         /* PVO entry is wired */
+#define        PVO_MANAGED             0x020UL         /* PVO entry is managed 
*/
+#define        PVO_BOOTSTRAP           0x080UL         /* PVO entry allocated 
during
                                                   bootstrap */
-#define PVO_FAKE               0x100           /* fictitious phys page */
+#define PVO_FAKE               0x100UL         /* fictitious phys page */
 #define        PVO_VADDR(pvo)          ((pvo)->pvo_vaddr & ~ADDR_POFF)
 #define PVO_ISFAKE(pvo)                ((pvo)->pvo_vaddr & PVO_FAKE)
 #define        PVO_PTEGIDX_GET(pvo)    ((pvo)->pvo_vaddr & PVO_PTEGIDX_MASK)
@@ -512,23 +514,6 @@ moea64_attr_save(vm_page_t m, u_int64_t 
        m->md.mdpg_attrs |= ptebit;
 }
 
-static __inline int
-moea64_pte_compare(const struct lpte *pt, const struct lpte *pvo_pt)
-{
-       if (pt->pte_hi == pvo_pt->pte_hi)
-               return (1);
-
-       return (0);
-}
-
-static __inline int
-moea64_pte_match(struct lpte *pt, uint64_t vsid, vm_offset_t va, int which)
-{
-       return (pt->pte_hi & ~LPTE_VALID) ==
-           ((vsid << LPTE_VSID_SHIFT) |
-           ((uint64_t)(va >> ADDR_API_SHFT64) & LPTE_API) | which);
-}
-
 static __inline void
 moea64_pte_create(struct lpte *pt, uint64_t vsid, vm_offset_t va, 
     uint64_t pte_lo)
@@ -583,7 +568,7 @@ moea64_pte_set(struct lpte *pt, struct l
        pt->pte_lo = pvo_pt->pte_lo;
        EIEIO();
        pt->pte_hi = pvo_pt->pte_hi;
-       SYNC();
+       PTESYNC();
        moea64_pte_valid++;
 }
 
@@ -602,7 +587,6 @@ moea64_pte_unset(struct lpte *pt, struct
         * Invalidate the pte.
         */
        pt->pte_hi &= ~LPTE_VALID;
-
        TLBIE(pmap,va);
 
        /*
@@ -621,6 +605,8 @@ moea64_pte_change(struct lpte *pt, struc
         */
        moea64_pte_unset(pt, pvo_pt, pmap, va);
        moea64_pte_set(pt, pvo_pt);
+       if (pmap == kernel_pmap)
+               isync();
 }
 
 static __inline uint64_t
@@ -701,7 +687,7 @@ moea64_bridge_cpu_bootstrap(mmu_t mmup, 
        for (i = 0; i < 16; i++) {
                mtsrin(i << ADDR_SR_SHFT, kernel_pmap->pm_sr[i]);
        }
-       __asm __volatile ("sync; mtsdr1 %0; isync"
+       __asm __volatile ("ptesync; mtsdr1 %0; isync"
            :: "r"((u_int)moea64_pteg_table 
                     | (32 - cntlzw(moea64_pteg_mask >> 11))));
        tlbia();
@@ -1135,7 +1121,7 @@ void moea64_set_scratchpage_pa(int which
        EIEIO();
 
        moea64_scratchpage_pte[which]->pte_hi |= LPTE_VALID;
-       TLBIE(kernel_pmap, moea64_scratchpage_va[which]);
+       PTESYNC(); isync();
 }
 
 void
@@ -1155,8 +1141,6 @@ moea64_copy_page(mmu_t mmu, vm_page_t ms
        kcopy((void *)moea64_scratchpage_va[0], 
            (void *)moea64_scratchpage_va[1], PAGE_SIZE);
 
-       __syncicache((void *)moea64_scratchpage_va[1],PAGE_SIZE);
-
        mtx_unlock(&moea64_scratchpage_mtx);
 }
 
@@ -1174,8 +1158,6 @@ moea64_zero_page_area(mmu_t mmu, vm_page
 
        moea64_set_scratchpage_pa(0,pa);
        bzero((caddr_t)moea64_scratchpage_va[0] + off, size);
-       __syncicache((void *)moea64_scratchpage_va[0],PAGE_SIZE);
-
        mtx_unlock(&moea64_scratchpage_mtx);
 }
 
@@ -1266,9 +1248,6 @@ moea64_enter_locked(pmap_t pmap, vm_offs
        error = moea64_pvo_enter(pmap, zone, pvo_head, va, VM_PAGE_TO_PHYS(m),
            pte_lo, pvo_flags);
 
-       if (pmap == kernel_pmap)
-               TLBIE(pmap, va);
-
        /*
         * Flush the page from the instruction cache if this page is
         * mapped executable and cacheable.
@@ -1281,6 +1260,7 @@ moea64_enter_locked(pmap_t pmap, vm_offs
 static void
 moea64_syncicache(pmap_t pmap, vm_offset_t va, vm_offset_t pa, vm_size_t sz)
 {
+
        /*
         * This is much trickier than on older systems because
         * we can't sync the icache on physical addresses directly
@@ -1303,8 +1283,9 @@ moea64_syncicache(pmap_t pmap, vm_offset
 
                mtx_lock(&moea64_scratchpage_mtx);
 
-               moea64_set_scratchpage_pa(1,pa);
-               __syncicache((void *)moea64_scratchpage_va[1], sz);
+               moea64_set_scratchpage_pa(1,pa & ~ADDR_POFF);
+               __syncicache((void *)(moea64_scratchpage_va[1] + 
+                   (va & ADDR_POFF)), sz);
 
                mtx_unlock(&moea64_scratchpage_mtx);
        }
@@ -1441,8 +1422,6 @@ moea64_uma_page_alloc(uma_zone_t zone, i
            &moea64_pvo_kunmanaged, va,  VM_PAGE_TO_PHYS(m), LPTE_M, 
            PVO_WIRED | PVO_BOOTSTRAP);
 
-       TLBIE(kernel_pmap, va);
-
        if (needed_lock)
                PMAP_UNLOCK(kernel_pmap);
        
@@ -1531,7 +1510,7 @@ moea64_remove_write(mmu_t mmu, vm_page_t
                                lo |= pvo->pvo_pte.lpte.pte_lo;
                                pvo->pvo_pte.lpte.pte_lo &= ~LPTE_CHG;
                                moea64_pte_change(pt, &pvo->pvo_pte.lpte,
-                                   pvo->pvo_pmap, pvo->pvo_vaddr);
+                                   pvo->pvo_pmap, PVO_VADDR(pvo));
                        }
                        UNLOCK_TABLE();
                }
@@ -1590,8 +1569,6 @@ moea64_kenter(mmu_t mmu, vm_offset_t va,
            &moea64_pvo_kunmanaged, va, pa, pte_lo, 
            PVO_WIRED | VM_PROT_EXECUTE);
 
-       TLBIE(kernel_pmap, va);
-
        if (error != 0 && error != ENOENT)
                panic("moea64_kenter: failed to enter va %#x pa %#x: %d", va,
                    pa, error);
@@ -1823,7 +1800,7 @@ moea64_protect(mmu_t mmu, pmap_t pm, vm_
                 */
                if (pt != NULL) {
                        moea64_pte_change(pt, &pvo->pvo_pte.lpte, 
-                           pvo->pvo_pmap, pvo->pvo_vaddr);
+                           pvo->pvo_pmap, PVO_VADDR(pvo));
                        if ((pvo->pvo_pte.lpte.pte_lo & 
                            (LPTE_I | LPTE_G | LPTE_NOEXEC)) == 0) {
                                moea64_syncicache(pm, sva,
@@ -1927,6 +1904,10 @@ moea64_remove_all(mmu_t mmu, vm_page_t m
                moea64_pvo_remove(pvo, -1);
                PMAP_UNLOCK(pmap);
        }
+       if ((m->flags & PG_WRITEABLE) && moea64_is_modified(mmu, m)) {
+               moea64_attr_clear(m, LPTE_CHG);
+               vm_page_dirty(m);
+       }
        vm_page_flag_clear(m, PG_WRITEABLE);
 }
 
@@ -2107,7 +2088,7 @@ moea64_pvo_enter(pmap_t pm, uma_zone_t z
                first = 1;
        LIST_INSERT_HEAD(pvo_head, pvo, pvo_vlink);
 
-       if (pvo->pvo_pte.lpte.pte_lo & PVO_WIRED)
+       if (pvo->pvo_vaddr & PVO_WIRED)
                pm->pm_stats.wired_count++;
        pm->pm_stats.resident_count++;
 
@@ -2122,6 +2103,9 @@ moea64_pvo_enter(pmap_t pm, uma_zone_t z
                moea64_pte_overflow++;
        }
 
+       if (pm == kernel_pmap)
+               isync();
+
        UNLOCK_TABLE();
 
        return (first ? ENOENT : 0);
@@ -2140,7 +2124,7 @@ moea64_pvo_remove(struct pvo_entry *pvo,
        pt = moea64_pvo_to_pte(pvo, pteidx);
        if (pt != NULL) {
                moea64_pte_unset(pt, &pvo->pvo_pte.lpte, pvo->pvo_pmap,
-                   pvo->pvo_vaddr);
+                   PVO_VADDR(pvo));
                PVO_PTEGIDX_CLR(pvo);
        } else {
                moea64_pte_overflow--;
@@ -2151,7 +2135,7 @@ moea64_pvo_remove(struct pvo_entry *pvo,
         * Update our statistics.
         */
        pvo->pvo_pmap->pm_stats.resident_count--;
-       if (pvo->pvo_pte.lpte.pte_lo & PVO_WIRED)
+       if (pvo->pvo_vaddr & PVO_WIRED)
                pvo->pvo_pmap->pm_stats.wired_count--;
 
        /*
@@ -2178,7 +2162,7 @@ moea64_pvo_remove(struct pvo_entry *pvo,
         */
        LIST_REMOVE(pvo, pvo_olink);
        if (!(pvo->pvo_vaddr & PVO_BOOTSTRAP))
-               uma_zfree(pvo->pvo_vaddr & PVO_MANAGED ? moea64_mpvo_zone :
+               uma_zfree((pvo->pvo_vaddr & PVO_MANAGED) ? moea64_mpvo_zone :
                    moea64_upvo_zone, pvo);
        moea64_pvo_entries--;
        moea64_pvo_remove_calls++;
@@ -2237,8 +2221,8 @@ moea64_pvo_to_pte(const struct pvo_entry
                int             ptegidx;
                uint64_t        vsid;
 
-               vsid = va_to_vsid(pvo->pvo_pmap, pvo->pvo_vaddr);
-               ptegidx = va_to_pteg(vsid, pvo->pvo_vaddr);
+               vsid = va_to_vsid(pvo->pvo_pmap, PVO_VADDR(pvo));
+               ptegidx = va_to_pteg(vsid, PVO_VADDR(pvo));
                pteidx = moea64_pvo_pte_index(pvo, ptegidx);
        }
 
@@ -2325,10 +2309,8 @@ moea64_query_bit(vm_page_t m, u_int64_t 
        struct  pvo_entry *pvo;
        struct  lpte *pt;
 
-#if 0
        if (moea64_attr_fetch(m) & ptebit)
                return (TRUE);
-#endif
 
        LIST_FOREACH(pvo, vm_page_to_pvoh(m), pvo_vlink) {
                MOEA_PVO_CHECK(pvo);    /* sanity check */
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to