svn commit: r278944 - in user/nwhitehorn/ppc64-pmap-rework: conf pseries

Nathan Whitehorn nwhitehorn at FreeBSD.org
Wed Feb 18 06:55:13 UTC 2015


Author: nwhitehorn
Date: Wed Feb 18 06:55:11 2015
New Revision: 278944
URL: https://svnweb.freebsd.org/changeset/base/278944

Log:
  Work around a bug in Linux KVM: the ability to unset referenced and changed
  bits in the page table doesn't exist despite these hypervisor calls being
  mandatory.
  
  To "fix" this, when asked to clear the bits, don't clear them and don't
  return the reference bit. This makes swap work at the expense of performance.
  It also results in pmap_ts_referenced() sometimes returning zero when the
  page has in fact been referenced. It is not clear to me whether this creates
  a problem beyond performance.
  
  In addition to adding a large warning banner if this issue is detected,
  I've sent a bug report to the PowerPC KVM list.

Modified:
  user/nwhitehorn/ppc64-pmap-rework/conf/GENERIC64
  user/nwhitehorn/ppc64-pmap-rework/pseries/mmu_phyp.c

Modified: user/nwhitehorn/ppc64-pmap-rework/conf/GENERIC64
==============================================================================
--- user/nwhitehorn/ppc64-pmap-rework/conf/GENERIC64	Wed Feb 18 06:53:40 2015	(r278943)
+++ user/nwhitehorn/ppc64-pmap-rework/conf/GENERIC64	Wed Feb 18 06:55:11 2015	(r278944)
@@ -28,7 +28,7 @@ makeoptions	WITH_CTF=1
 
 # Platform support
 options 	POWERMAC		#NewWorld Apple PowerMacs
-options 	PS3			#Sony Playstation 3
+#options 	PS3			#Sony Playstation 3
 options 	MAMBO			#IBM Mambo Full System Simulator
 options 	PSERIES			#PAPR-compliant systems (e.g. IBM p)
 

Modified: user/nwhitehorn/ppc64-pmap-rework/pseries/mmu_phyp.c
==============================================================================
--- user/nwhitehorn/ppc64-pmap-rework/pseries/mmu_phyp.c	Wed Feb 18 06:53:40 2015	(r278943)
+++ user/nwhitehorn/ppc64-pmap-rework/pseries/mmu_phyp.c	Wed Feb 18 06:55:11 2015	(r278944)
@@ -91,6 +91,23 @@ static mmu_method_t mphyp_methods[] = {
 
 MMU_DEF_INHERIT(pseries_mmu, "mmu_phyp", mphyp_methods, 0, oea64_mmu);
 
+static int brokenkvm = 0;
+
+static void
+print_kvm_bug_warning(void *data)
+{
+
+	if (brokenkvm)
+		printf("WARNING: Running on a broken hypervisor that does "
+		    "not support mandatory H_CLEAR_MOD and H_CLEAR_REF "
+		    "hypercalls. Performance will be suboptimal.\n");
+}
+
+SYSINIT(kvmbugwarn1, SI_SUB_COPYRIGHT, SI_ORDER_THIRD + 1,
+    print_kvm_bug_warning, NULL);
+SYSINIT(kvmbugwarn2, SI_SUB_LAST, SI_ORDER_THIRD + 1, print_kvm_bug_warning,
+    NULL);
+
 static void
 mphyp_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend)
 {
@@ -183,6 +200,10 @@ mphyp_bootstrap(mmu_t mmup, vm_offset_t 
 
 	moea64_mid_bootstrap(mmup, kernelstart, kernelend);
 	moea64_late_bootstrap(mmup, kernelstart, kernelend);
+
+	/* Test for broken versions of KVM that don't conform to the spec */
+	if (phyp_hcall(H_CLEAR_MOD, 0, 0) == H_FUNCTION)
+		brokenkvm = 1;
 }
 
 static void
@@ -231,6 +252,7 @@ mphyp_pte_clear(mmu_t mmu, struct pvo_en
 {
 	int64_t refchg;
 	uint64_t ptelo, junk;
+	int err;
 
 	/*
 	 * This involves two steps (synch and clear) so we need the entry
@@ -248,14 +270,28 @@ mphyp_pte_clear(mmu_t mmu, struct pvo_en
 		return (refchg);
 	}
 
+	if (brokenkvm) {
+		/*
+		 * No way to clear either bit, which is total madness.
+		 * Pessimistically claim that, once modified, it stays so
+		 * forever and that it is never referenced.
+		 */
+		rw_runlock(&mphyp_eviction_lock);
+		return (refchg & ~LPTE_REF);
+	}
+
 	if (ptebit & LPTE_CHG) {
-		phyp_pft_hcall(H_CLEAR_MOD, 0, pvo->pvo_pte.slot, 0, 0, &ptelo,
-		    &junk, &junk);
+		err = phyp_pft_hcall(H_CLEAR_MOD, 0, pvo->pvo_pte.slot, 0, 0,
+		    &ptelo, &junk, &junk);
+		KASSERT(err == H_SUCCESS,
+		    ("Error clearing page change bit: %d", err));
 		refchg |= (ptelo & LPTE_CHG);
 	}
 	if (ptebit & LPTE_REF) {
-		phyp_pft_hcall(H_CLEAR_REF, 0, pvo->pvo_pte.slot, 0, 0, &ptelo,
-		    &junk, &junk);
+		err = phyp_pft_hcall(H_CLEAR_REF, 0, pvo->pvo_pte.slot, 0, 0,
+		    &ptelo, &junk, &junk);
+		KASSERT(err == H_SUCCESS,
+		    ("Error clearing page reference bit: %d", err));
 		refchg |= (ptelo & LPTE_REF);
 	}
 


More information about the svn-src-user mailing list