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