svn commit: r253582 - head/sys/amd64/amd64

Neel Natu neel at FreeBSD.org
Tue Jul 23 22:17:01 UTC 2013


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: gperez at 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);


More information about the svn-src-head mailing list