[Android-virt] [PATCH] ARM: KVM: Trap and propagate cache maintainance by set/way

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The ARM ARM says in bold (B1.14.4):
"Virtualizing a uniprocessor system within an MP system, permitting a
 virtual machine to move between different physical processors, makes
 cache maintenance by set/way difficult. This is because a set/way
 operation might be interrupted part way through its operation, and
 therefore the hypervisor must reproduce the effect of the maintenance
 on both physical processors."

The direct consequence of this is that we have to trap all set/way
operations and make sure the other CPUs get the memo. In order to
avoid performance degradation, we maintain a per vcpu cpumask that
tracks the physcal CPUs on which the cache operation must be performed.
The remote operation is only executed when migrating the vcpu.

On the receiving end, we simply clean+invalidate the whole data cache
to avoid queuiing up individual set/way operations.

Reported-by: Peter Maydell <peter.maydell at linaro.org>
Cc: Will Deacon <will.deacon at arm.com>
Cc: Rusty Russell <rusty.russell at linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier at arm.com>
---
 arch/arm/include/asm/kvm_arm.h  |    3 ++-
 arch/arm/include/asm/kvm_host.h |    3 +++
 arch/arm/kvm/arm.c              |   15 +++++++++++++++
 arch/arm/kvm/emulate.c          |   39 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 59 insertions(+), 1 deletions(-)

diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
index a28b5f0..5bdbe61 100644
--- a/arch/arm/include/asm/kvm_arm.h
+++ b/arch/arm/include/asm/kvm_arm.h
@@ -53,6 +53,7 @@
  * The bits we set in HCR:
  * TAC:		Trap ACTLR
  * TSC:		Trap SMC
+ * TSW:		Trap cache operations by set/way
  * TWI:		Trap WFI
  * BSU_IS:	Upgrade barriers to the inner shareable domain
  * FB:		Force broadcast of all maintainance operations
@@ -61,7 +62,7 @@
  * FMO:		Override CPSR.F and enable signaling with VF
  * SWIO:	Turn set/way invalidates into set/way clean+invalidate
  */
-#define HCR_GUEST_MASK (HCR_TSC | HCR_TWI | HCR_VM | HCR_BSU_IS | HCR_FB | \
+#define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | HCR_FB | \
 			HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | HCR_SWIO)
 #define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
 
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 734a107..69ee513 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -113,6 +113,9 @@ struct kvm_vcpu_arch {
 	u32 hpfar;		/* Hyp IPA Fault Address Register */
 	u64 pc_ipa;		/* IPA for the current PC (VA to PA result) */
 
+	/* dcache set/way operation pending */
+	cpumask_t require_dcache_flush;
+
 	/* IO related fields */
 	bool mmio_sign_extend;	/* for byte/halfword loads */
 	u32 mmio_rd;
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index bf3e5f5..803d945 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -33,6 +33,7 @@
 #include <asm/ptrace.h>
 #include <asm/mman.h>
 #include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
 #include <asm/cputype.h>
 #include <asm/kvm_arm.h>
 #include <asm/kvm_asm.h>
@@ -462,6 +463,17 @@ static inline int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 	return arm_exit_handlers[hsr_ec](vcpu, run);
 }
 
+/*
+ * Check whether this vcpu requires the cache to be flushed on this
+ * physical CPU. This is a consequence of doing dcache operations by
+ * set/way on this vcpu.
+ */
+static bool kvm_needs_dcache_flush(struct kvm_vcpu *vcpu)
+{
+	return cpumask_test_and_clear_cpu(smp_processor_id(),
+					  &vcpu->arch.require_dcache_flush);
+}
+
 /**
  * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code
  * @vcpu:	The VCPU pointer
@@ -487,6 +499,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	if (vcpu->sigset_active)
 		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
 
+	if (kvm_needs_dcache_flush(vcpu))
+		flush_cache_all(); /* We'd really want v7_flush_dcache_all()... */
+
 	run->exit_reason = KVM_EXIT_UNKNOWN;
 	while (run->exit_reason == KVM_EXIT_UNKNOWN) {
 		/*
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index 3ceab47..55b4726 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -255,6 +255,36 @@ static bool read_actlr(struct kvm_vcpu *vcpu,
 	return true;
 }
 
+static bool write_dcsw(struct kvm_vcpu *vcpu,
+		       const struct coproc_params *p,
+		       unsigned long cp15_reg)
+{
+	cpumask_var_t tmpmask;
+
+	if (!alloc_cpumask_var(&tmpmask, GFP_KERNEL))
+		return false;
+
+	switch(p->CRm) {
+	case 6:			/* Upgrade DCISW to DCCISW, as per HCR.SWIO */
+	case 14:		/* DCCISW */
+		asm volatile("mcr p15, 0, %0, c7, c14, 2" : : "r" (p->Rt1));
+		break;
+
+	case 10:		/* DCCSW */
+		asm volatile("mcr p15, 0, %0, c7, c10, 2" : : "r" (p->Rt1));
+		break;
+	}
+
+	cpumask_complement(tmpmask, cpumask_of(smp_processor_id()));
+	cpumask_or(&vcpu->arch.require_dcache_flush,
+		   &vcpu->arch.require_dcache_flush,
+		   tmpmask);
+
+	free_cpumask_var(tmpmask);
+
+	return true;
+}
+
 static bool access_cp15_reg(struct kvm_vcpu *vcpu,
 			    const struct coproc_params *p,
 			    unsigned long cp15_reg)
@@ -302,6 +332,15 @@ static const struct coproc_emulate coproc_emulate[] = {
 	{ CRn( 1), CRm( 0), Op1( 0), Op2( 1), is32, WRITE, ignore_write},
 	{ CRn( 1), CRm( 0), Op1( 0), Op2( 1), is32, READ,  read_actlr},
 	/*
+	 * DC{C,I,CI}SW operations:
+	 */
+	{ CRn( 7), CRm( 6), Op1( 0), Op2( 2), is32,  WRITE, write_dcsw},	
+	{ CRn( 7), CRm( 6), Op1( 0), Op2( 2), is32,  READ,  read_zero},	
+	{ CRn( 7), CRm(10), Op1( 0), Op2( 2), is32,  WRITE, write_dcsw},	
+	{ CRn( 7), CRm(10), Op1( 0), Op2( 2), is32,  READ,  read_zero},	
+	{ CRn( 7), CRm(14), Op1( 0), Op2( 2), is32,  WRITE, write_dcsw},	
+	{ CRn( 7), CRm(14), Op1( 0), Op2( 2), is32,  READ,  read_zero},	
+	/*
 	 * L2CTLR access:
 	 *
 	 * Ignore writes completely.
-- 
1.7.3.4



[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux