Author: neel
Date: Tue Jul 23 22:17:00 2013
New Revision: 253582
URL: http://svnweb.freebsd.org/changeset/base/253582

Log:
  Fix a bug introduced in r252646 that causes a page with the PG_PTE_PAT bit set
  to be interpreted as a superpage. This is because PG_PTE_PAT is at the same
  bit position in PTE as PG_PS is in a PDE.
  
  This caused a number of regressions on amd64 systems: panic when starting
  X applications, freeze during shutdown etc.
  
  Pointy hat to:        me
  Tested by: gpe...@entel.upc.edu, joel, dumbbell
  Reviewed by: kib

Modified:
  head/sys/amd64/amd64/pmap.c

Modified: head/sys/amd64/amd64/pmap.c
==============================================================================
--- head/sys/amd64/amd64/pmap.c Tue Jul 23 21:09:26 2013        (r253581)
+++ head/sys/amd64/amd64/pmap.c Tue Jul 23 22:17:00 2013        (r253582)
@@ -4401,6 +4401,7 @@ pmap_remove_pages(pmap_t pmap)
        int64_t bit;
        uint64_t inuse, bitmask;
        int allfree, field, freed, idx;
+       boolean_t superpage;
        vm_paddr_t pa;
 
        if (pmap != PCPU_GET(curpmap)) {
@@ -4427,12 +4428,26 @@ pmap_remove_pages(pmap_t pmap)
                                pte = pmap_pdpe_to_pde(pte, pv->pv_va);
                                tpte = *pte;
                                if ((tpte & (PG_PS | PG_V)) == PG_V) {
+                                       superpage = FALSE;
                                        ptepde = tpte;
                                        pte = (pt_entry_t *)PHYS_TO_DMAP(tpte &
                                            PG_FRAME);
                                        pte = &pte[pmap_pte_index(pv->pv_va)];
                                        tpte = *pte;
+                               } else {
+                                       /*
+                                        * Keep track whether 'tpte' is a
+                                        * superpage explicitly instead of
+                                        * relying on PG_PS being set.
+                                        *
+                                        * This is because PG_PS is numerically
+                                        * identical to PG_PTE_PAT and thus a
+                                        * regular page could be mistaken for
+                                        * a superpage.
+                                        */
+                                       superpage = TRUE;
                                }
+
                                if ((tpte & PG_V) == 0) {
                                        panic("bad pte va %lx pte %lx",
                                            pv->pv_va, tpte);
@@ -4446,7 +4461,7 @@ pmap_remove_pages(pmap_t pmap)
                                        continue;
                                }
 
-                               if (tpte & PG_PS)
+                               if (superpage)
                                        pa = tpte & PG_PS_FRAME;
                                else
                                        pa = tpte & PG_FRAME;
@@ -4468,7 +4483,7 @@ pmap_remove_pages(pmap_t pmap)
                                 * Update the vm_page_t clean/reference bits.
                                 */
                                if ((tpte & (PG_M | PG_RW)) == (PG_M | PG_RW)) {
-                                       if ((tpte & PG_PS) != 0) {
+                                       if (superpage) {
                                                for (mt = m; mt < &m[NBPDR / 
PAGE_SIZE]; mt++)
                                                        vm_page_dirty(mt);
                                        } else
@@ -4479,7 +4494,7 @@ pmap_remove_pages(pmap_t pmap)
 
                                /* Mark free */
                                pc->pc_map[field] |= bitmask;
-                               if ((tpte & PG_PS) != 0) {
+                               if (superpage) {
                                        pmap_resident_count_dec(pmap, NBPDR / 
PAGE_SIZE);
                                        pvh = pa_to_pvh(tpte & PG_PS_FRAME);
                                        TAILQ_REMOVE(&pvh->pv_list, pv, 
pv_next);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to