Module Name:    src
Committed By:   maxv
Date:           Sat Feb 23 10:43:37 UTC 2019

Modified Files:
        src/sys/arch/x86/x86: pmap.c
        src/sys/dev/nvmm/x86: nvmm_x86_vmx.c

Log Message:
Add support for CPUs that don't have the EPT_{A,D} bits.

On such CPUs, these bits are ignored by the hardware. We don't care about
setting them, however, we must always assume they are set. Modify the pmap
code to do that.

While here, in pmap_ept_remove_pte, don't flush the TLB when it's not
needed.

Tested on an old Intel Celeron.


To generate a diff of this commit:
cvs rdiff -u -r1.325 -r1.326 src/sys/arch/x86/x86/pmap.c
cvs rdiff -u -r1.12 -r1.13 src/sys/dev/nvmm/x86/nvmm_x86_vmx.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/x86/x86/pmap.c
diff -u src/sys/arch/x86/x86/pmap.c:1.325 src/sys/arch/x86/x86/pmap.c:1.326
--- src/sys/arch/x86/x86/pmap.c:1.325	Thu Feb 21 14:31:54 2019
+++ src/sys/arch/x86/x86/pmap.c	Sat Feb 23 10:43:37 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: pmap.c,v 1.325 2019/02/21 14:31:54 maxv Exp $	*/
+/*	$NetBSD: pmap.c,v 1.326 2019/02/23 10:43:37 maxv Exp $	*/
 
 /*
  * Copyright (c) 2008, 2010, 2016, 2017 The NetBSD Foundation, Inc.
@@ -130,7 +130,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.325 2019/02/21 14:31:54 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.326 2019/02/23 10:43:37 maxv Exp $");
 
 #include "opt_user_ldt.h"
 #include "opt_lockdebug.h"
@@ -4857,6 +4857,8 @@ x86_mmap_flags(paddr_t mdpgno)
 
 #define pmap_ept_valid_entry(pte)	(pte & EPT_R)
 
+bool pmap_ept_has_ad __read_mostly;
+
 static inline void
 pmap_ept_stats_update_bypte(struct pmap *pmap, pt_entry_t npte, pt_entry_t opte)
 {
@@ -4912,10 +4914,14 @@ static inline uint8_t
 pmap_ept_to_pp_attrs(pt_entry_t ept)
 {
 	uint8_t ret = 0;
-	if (ept & EPT_D)
-		ret |= PP_ATTRS_M;
-	if (ept & EPT_A)
-		ret |= PP_ATTRS_U;
+	if (pmap_ept_has_ad) {
+		if (ept & EPT_D)
+			ret |= PP_ATTRS_M;
+		if (ept & EPT_A)
+			ret |= PP_ATTRS_U;
+	} else {
+		ret |= (PP_ATTRS_M|PP_ATTRS_U);
+	}
 	if (ept & EPT_W)
 		ret |= PP_ATTRS_W;
 	return ret;
@@ -5098,6 +5104,7 @@ pmap_ept_enter(struct pmap *pmap, vaddr_
 	struct pv_entry *new_pve;
 	struct pv_entry *new_sparepve;
 	bool wired = (flags & PMAP_WIRED) != 0;
+	bool accessed;
 	int error;
 
 	KASSERT(pmap_initialized);
@@ -5238,8 +5245,12 @@ pmap_ept_enter(struct pmap *pmap, vaddr_
 same_pa:
 	mutex_exit(pmap->pm_lock);
 
-	if ((~opte & (EPT_R | EPT_A)) == 0 &&
-	    ((opte ^ npte) & (PG_FRAME | EPT_W)) != 0) {
+	if (pmap_ept_has_ad) {
+		accessed = (~opte & (EPT_R | EPT_A)) == 0;
+	} else {
+		accessed = (opte & EPT_R) != 0;
+	}
+	if (accessed && ((opte ^ npte) & (PG_FRAME | EPT_W)) != 0) {
 		pmap_tlb_shootdown(pmap, va, 0, TLBSHOOT_ENTER);
 	}
 
@@ -5334,6 +5345,7 @@ pmap_ept_remove_pte(struct pmap *pmap, s
 	struct vm_page *pg;
 	struct pmap_page *pp;
 	pt_entry_t opte;
+	bool accessed;
 
 	KASSERT(pmap != pmap_kernel());
 	KASSERT(mutex_owned(pmap->pm_lock));
@@ -5362,7 +5374,14 @@ pmap_ept_remove_pte(struct pmap *pmap, s
 		}
 	}
 
-	pmap_tlb_shootdown(pmap, va, 0, TLBSHOOT_REMOVE_PTE);
+	if (pmap_ept_has_ad) {
+		accessed = (opte & EPT_A) != 0;
+	} else {
+		accessed = true;
+	}
+	if (accessed) {
+		pmap_tlb_shootdown(pmap, va, 0, TLBSHOOT_REMOVE_PTE);
+	}
 
 	/*
 	 * If we are not on a pv_head list - we are done.
@@ -5530,8 +5549,12 @@ pmap_ept_sync_pv(struct vm_page *ptp, va
 		 * ... Unless we are clearing only the PG_RW bit and
 		 * it isn't cached as RW (PG_M).
 		 */
-		need_shootdown = (opte & EPT_A) != 0 &&
-		    !(clearbits == EPT_W && (opte & EPT_D) == 0);
+		if (pmap_ept_has_ad) {
+			need_shootdown = (opte & EPT_A) != 0 &&
+			    !(clearbits == EPT_W && (opte & EPT_D) == 0);
+		} else {
+			need_shootdown = true;
+		}
 
 		npte = opte & ~clearbits;
 
@@ -5579,6 +5602,7 @@ pmap_ept_write_protect(struct pmap *pmap
 	pd_entry_t pde;
 	paddr_t ptppa;
 	vaddr_t va;
+	bool modified;
 
 	bit_rem = 0;
 	if (!(prot & VM_PROT_WRITE))
@@ -5609,7 +5633,12 @@ pmap_ept_write_protect(struct pmap *pmap
 			npte = (opte & ~bit_rem);
 		} while (pmap_pte_cas(spte, opte, npte) != opte);
 
-		if ((opte & EPT_D) != 0) {
+		if (pmap_ept_has_ad) {
+			modified = (opte & EPT_D) != 0;
+		} else {
+			modified = true;
+		}
+		if (modified) {
 			vaddr_t tva = x86_ptob(spte - ptes);
 			pmap_tlb_shootdown(pmap, tva, 0,
 			    TLBSHOOT_WRITE_PROTECT);

Index: src/sys/dev/nvmm/x86/nvmm_x86_vmx.c
diff -u src/sys/dev/nvmm/x86/nvmm_x86_vmx.c:1.12 src/sys/dev/nvmm/x86/nvmm_x86_vmx.c:1.13
--- src/sys/dev/nvmm/x86/nvmm_x86_vmx.c:1.12	Sat Feb 23 08:19:16 2019
+++ src/sys/dev/nvmm/x86/nvmm_x86_vmx.c	Sat Feb 23 10:43:36 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvmm_x86_vmx.c,v 1.12 2019/02/23 08:19:16 maxv Exp $	*/
+/*	$NetBSD: nvmm_x86_vmx.c,v 1.13 2019/02/23 10:43:36 maxv Exp $	*/
 
 /*
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_vmx.c,v 1.12 2019/02/23 08:19:16 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_vmx.c,v 1.13 2019/02/23 10:43:36 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -551,6 +551,8 @@ static uint64_t vmx_cr0_fixed1 __read_mo
 static uint64_t vmx_cr4_fixed0 __read_mostly;
 static uint64_t vmx_cr4_fixed1 __read_mostly;
 
+extern bool pmap_ept_has_ad;
+
 #define VMX_PINBASED_CTLS_ONE	\
 	(PIN_CTLS_INT_EXITING| \
 	 PIN_CTLS_NMI_EXITING| \
@@ -2396,7 +2398,7 @@ vmx_vcpu_init(struct nvmm_machine *mach,
 	eptp =
 	    __SHIFTIN(vmx_eptp_type, EPTP_TYPE) |
 	    __SHIFTIN(4-1, EPTP_WALKLEN) |
-	    EPTP_FLAGS_AD |
+	    (pmap_ept_has_ad ? EPTP_FLAGS_AD : 0) |
 	    mach->vm->vm_map.pmap->pm_pdirpa[0];
 	vmx_vmwrite(VMCS_EPTP, eptp);
 
@@ -2725,8 +2727,10 @@ vmx_ident(void)
 	if ((msr & IA32_VMX_EPT_VPID_INVVPID) == 0) {
 		return false;
 	}
-	if ((msr & IA32_VMX_EPT_VPID_FLAGS_AD) == 0) {
-		return false;
+	if ((msr & IA32_VMX_EPT_VPID_FLAGS_AD) != 0) {
+		pmap_ept_has_ad = true;
+	} else {
+		pmap_ept_has_ad = false;
 	}
 	if (!(msr & IA32_VMX_EPT_VPID_UC) && !(msr & IA32_VMX_EPT_VPID_WB)) {
 		return false;

Reply via email to