svn commit: r342769 - head/sys/i386/include

Konstantin Belousov kib at FreeBSD.org
Fri Jan 4 17:33:08 UTC 2019


Author: kib
Date: Fri Jan  4 17:33:07 2019
New Revision: 342769
URL: https://svnweb.freebsd.org/changeset/base/342769

Log:
  i386: Use atomic 64bit load to read PDE value from PAE pagetables in
  pmap_kextract().
  
  pmap_kextract() can race with promotion/demotion on the kernel page
  table, in which case current non-atomic 64bit read would see torn
  value, breaking pmap_kextract().  pmap_kextract() would correctly
  handle either promoted or demoted PDE, but not a mix where one word
  is from a different state.
  
  It requires PAE and > 4G memory to reproduce.  We observed this in
  real loads, both for intensive use of malloc(9)/free(9) where
  vtoslab() returned invalid pointer to the slab, and with the use of
  busdma_bounce, where incorrect page was bounced.
  
  In collaboration with:	pho
  Reviewed by:	markj
  Sponsored by:	The FreeBSD Foundation
  MFC after:	1 week
  Differential revision:	https://reviews.freebsd.org/D18714

Modified:
  head/sys/i386/include/pmap.h

Modified: head/sys/i386/include/pmap.h
==============================================================================
--- head/sys/i386/include/pmap.h	Fri Jan  4 17:31:50 2019	(r342768)
+++ head/sys/i386/include/pmap.h	Fri Jan  4 17:33:07 2019	(r342769)
@@ -234,6 +234,32 @@ extern pd_entry_t *IdlePTD;	/* physical address of "Id
  */
 extern pt_entry_t *KPTmap;
 
+#if (defined(PAE) || defined(PAE_TABLES))
+
+#define	pde_cmpset(pdep, old, new)	atomic_cmpset_64_i586(pdep, old, new)
+#define	pte_load_store(ptep, pte)	atomic_swap_64_i586(ptep, pte)
+#define	pte_load_clear(ptep)		atomic_swap_64_i586(ptep, 0)
+#define	pte_store(ptep, pte)		atomic_store_rel_64_i586(ptep, pte)
+#define	pte_load(ptep)			atomic_load_acq_64_i586(ptep)
+
+extern pt_entry_t pg_nx;
+
+#else /* !(PAE || PAE_TABLES) */
+
+#define	pde_cmpset(pdep, old, new)	atomic_cmpset_int(pdep, old, new)
+#define	pte_load_store(ptep, pte)	atomic_swap_int(ptep, pte)
+#define	pte_load_clear(ptep)		atomic_swap_int(ptep, 0)
+#define	pte_store(ptep, pte) do { \
+	*(u_int *)(ptep) = (u_int)(pte); \
+} while (0)
+#define	pte_load(ptep)			atomic_load_acq_int(ptep)
+
+#endif /* !(PAE || PAE_TABLES) */
+
+#define	pte_clear(ptep)			pte_store(ptep, 0)
+
+#define	pde_store(pdep, pde)		pte_store(pdep, pde)
+
 /*
  * Extract from the kernel page table the physical address that is mapped by
  * the given virtual address "va".
@@ -245,7 +271,7 @@ pmap_kextract(vm_offset_t va)
 {
 	vm_paddr_t pa;
 
-	if ((pa = PTD[va >> PDRSHIFT]) & PG_PS) {
+	if ((pa = pte_load(&PTD[va >> PDRSHIFT])) & PG_PS) {
 		pa = (pa & PG_PS_FRAME) | (va & PDRMASK);
 	} else {
 		/*
@@ -260,30 +286,6 @@ pmap_kextract(vm_offset_t va)
 	}
 	return (pa);
 }
-
-#if (defined(PAE) || defined(PAE_TABLES))
-
-#define	pde_cmpset(pdep, old, new)	atomic_cmpset_64_i586(pdep, old, new)
-#define	pte_load_store(ptep, pte)	atomic_swap_64_i586(ptep, pte)
-#define	pte_load_clear(ptep)		atomic_swap_64_i586(ptep, 0)
-#define	pte_store(ptep, pte)		atomic_store_rel_64_i586(ptep, pte)
-
-extern pt_entry_t pg_nx;
-
-#else /* !(PAE || PAE_TABLES) */
-
-#define	pde_cmpset(pdep, old, new)	atomic_cmpset_int(pdep, old, new)
-#define	pte_load_store(ptep, pte)	atomic_swap_int(ptep, pte)
-#define	pte_load_clear(ptep)		atomic_swap_int(ptep, 0)
-#define	pte_store(ptep, pte) do { \
-	*(u_int *)(ptep) = (u_int)(pte); \
-} while (0)
-
-#endif /* !(PAE || PAE_TABLES) */
-
-#define	pte_clear(ptep)			pte_store(ptep, 0)
-
-#define	pde_store(pdep, pde)		pte_store(pdep, pde)
 
 #endif /* _KERNEL */
 


More information about the svn-src-all mailing list