[PATCH] KVM: ARM: Allow non hsr.isv mmio to go through vgic

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

 



When the guest uses mmio operations that do not have decode information
in the HSR, we decode these instructions manually, but the instruction
may be used to access the vgic distributor interface emulated inside the
kernel so we have to go through that path for both values of HSR.ISV.

Signed-off-by: Christoffer Dall <c.dall@xxxxxxxxxxxxxxxxxxxxxx>
---
 arch/arm/include/asm/kvm_emulate.h |    2 +-
 arch/arm/kvm/emulate.c             |   19 +++-------
 arch/arm/kvm/mmu.c                 |   68 +++++++++++++++++++++++-------------
 3 files changed, 49 insertions(+), 40 deletions(-)

diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
index 96b9f81..68489f2 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -74,7 +74,7 @@ static inline enum vcpu_mode vcpu_mode(struct kvm_vcpu *vcpu)
 
 int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run);
 int kvm_emulate_mmio_ls(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
-			unsigned long instr);
+			unsigned long instr, struct kvm_exit_mmio *mmio);
 void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr);
 void kvm_inject_undefined(struct kvm_vcpu *vcpu);
 void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index 8ece96d..b4429de 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -566,22 +566,21 @@ static bool kvm_decode_thumb_ls(struct kvm_vcpu *vcpu, unsigned long instr,
  * required operands.
  */
 int kvm_emulate_mmio_ls(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
-			unsigned long instr)
+			unsigned long instr, struct kvm_exit_mmio *mmio)
 {
 	bool is_thumb;
-	struct kvm_exit_mmio mmio;
 
 	trace_kvm_mmio_emulate(vcpu->arch.regs.pc, instr, vcpu->arch.regs.cpsr);
 
-	mmio.phys_addr = fault_ipa;
+	mmio->phys_addr = fault_ipa;
 	is_thumb = !!(*vcpu_cpsr(vcpu) & PSR_T_BIT);
-	if (!is_thumb && !kvm_decode_arm_ls(vcpu, instr, &mmio)) {
+	if (!is_thumb && !kvm_decode_arm_ls(vcpu, instr, mmio)) {
 		kvm_debug("Unable to decode inst: %#08lx (cpsr: %#08x (T=0)"
 			  "pc: %#08x)\n",
 			  instr, *vcpu_cpsr(vcpu), *vcpu_pc(vcpu));
 		kvm_inject_dabt(vcpu, vcpu->arch.hdfar);
 		return 1;
-	} else if (is_thumb && !kvm_decode_thumb_ls(vcpu, instr, &mmio)) {
+	} else if (is_thumb && !kvm_decode_thumb_ls(vcpu, instr, mmio)) {
 		kvm_debug("Unable to decode inst: %#08lx (cpsr: %#08x (T=1)"
 			  "pc: %#08x)\n",
 			  instr, *vcpu_cpsr(vcpu), *vcpu_pc(vcpu));
@@ -589,21 +588,11 @@ int kvm_emulate_mmio_ls(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 		return 1;
 	}
 
-	if (mmio.is_write)
-		memcpy(mmio.data, vcpu_reg(vcpu, vcpu->arch.mmio.rd), mmio.len);
-	kvm_prepare_mmio(vcpu->run, &mmio);
-
-	trace_kvm_mmio((mmio.is_write) ? KVM_TRACE_MMIO_WRITE :
-					 KVM_TRACE_MMIO_READ_UNSATISFIED,
-		mmio.len, fault_ipa,
-		(mmio.is_write) ? *vcpu_reg(vcpu, vcpu->arch.mmio.rd) : 0);
-
 	/*
 	 * The MMIO instruction is emulated and should not be re-executed
 	 * in the guest.
 	 */
 	kvm_skip_instr(vcpu, is_wide_instruction(instr));
-	vcpu->run->exit_reason = KVM_EXIT_MMIO;
 	return 0;
 }
 
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 53d1dc5..c22b18e 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -613,6 +613,7 @@ static bool copy_from_guest_va(struct kvm_vcpu *vcpu,
 	pc_ipa = par & PAGE_MASK & ((1ULL << 32) - 1);
 	pc_ipa += gva & ~PAGE_MASK;
 
+
 	err = kvm_read_guest(vcpu->kvm, pc_ipa, dest, len);
 	if (unlikely(err))
 		return false;
@@ -694,13 +695,15 @@ out:
  *
  * @vcpu:      The vcpu pointer
  * @fault_ipa: The IPA that caused the 2nd stage fault
+ * @mmio:      Pointer to struct to hold decode information
  *
  * Some load/store instructions cannot be emulated using the information
  * presented in the HSR, for instance, register write-back instructions are not
  * supported. We therefore need to fetch the instruction, decode it, and then
  * emulate its behavior.
  */
-static int invalid_io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
+static int invalid_io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+				struct kvm_exit_mmio *mmio)
 {
 	unsigned long instr = 0;
 
@@ -708,20 +711,16 @@ static int invalid_io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
 	if (!copy_current_insn(vcpu, &instr))
 		return 1;
 
-	return kvm_emulate_mmio_ls(vcpu, fault_ipa, instr);
+	return kvm_emulate_mmio_ls(vcpu, fault_ipa, instr, mmio);
 }
 
-static int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
-			phys_addr_t fault_ipa, struct kvm_memory_slot *memslot)
+static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+		      struct kvm_exit_mmio *mmio)
 {
 	unsigned long rd, len;
 	bool is_write, sign_extend;
-	struct kvm_exit_mmio mmio;
 
-	if (!(vcpu->arch.hsr & HSR_ISV))
-		return invalid_io_mem_abort(vcpu, fault_ipa);
-
-	if (((vcpu->arch.hsr >> 8) & 1)) {
+	if ((vcpu->arch.hsr >> 8) & 1) {
 		/* cache operation on I/O addr, tell guest unsupported */
 		kvm_inject_dabt(vcpu, vcpu->arch.hdfar);
 		return 1;
@@ -758,34 +757,55 @@ static int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 		return 1;
 	}
 
+	mmio->is_write = is_write;
+	mmio->phys_addr = fault_ipa;
+	mmio->len = len;
+	vcpu->arch.mmio.sign_extend = sign_extend;
+	vcpu->arch.mmio.rd = rd;
+
+	/*
+	 * The MMIO instruction is emulated and should not be re-executed
+	 * in the guest.
+	 */
+	kvm_skip_instr(vcpu, (vcpu->arch.hsr >> 25) & 1);
+	return 0;
+}
+
+static int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
+			phys_addr_t fault_ipa, struct kvm_memory_slot *memslot)
+{
+	struct kvm_exit_mmio mmio;
+	unsigned long rd;
+	int ret;
+
 	/*
 	 * Prepare MMIO operation. First stash it in a private
 	 * structure that we can use for in-kernel emulation. If the
 	 * kernel can't handle it, copy it into run->mmio and let user
 	 * space do its magic.
 	 */
-	mmio.is_write = is_write;
-	mmio.phys_addr = fault_ipa;
-	mmio.len = len;
-	vcpu->arch.mmio.sign_extend = sign_extend;
-	vcpu->arch.mmio.rd = rd;
 
-	trace_kvm_mmio((is_write) ? KVM_TRACE_MMIO_WRITE :
-				    KVM_TRACE_MMIO_READ_UNSATISFIED,
-			len, fault_ipa, (is_write) ? *vcpu_reg(vcpu, rd) : 0);
+	if (vcpu->arch.hsr & HSR_ISV)
+		ret = decode_hsr(vcpu, fault_ipa, &mmio);
+	else
+		ret = invalid_io_mem_abort(vcpu, fault_ipa, &mmio);
 
-	if (is_write)
-		memcpy(mmio.data, vcpu_reg(vcpu, rd), len);
+	if (ret != 0)
+		return ret;
 
-	/*
-	 * The MMIO instruction is emulated and should not be re-executed
-	 * in the guest.
-	 */
-	kvm_skip_instr(vcpu, (vcpu->arch.hsr >> 25) & 1);
+	rd = vcpu->arch.mmio.rd;
+	trace_kvm_mmio((mmio.is_write) ? KVM_TRACE_MMIO_WRITE :
+					 KVM_TRACE_MMIO_READ_UNSATISFIED,
+			mmio.len, fault_ipa,
+			(mmio.is_write) ? *vcpu_reg(vcpu, rd) : 0);
+
+	if (mmio.is_write)
+		memcpy(mmio.data, vcpu_reg(vcpu, rd), mmio.len);
 
 	if (vgic_handle_mmio(vcpu, run, &mmio))
 		return 1;
 
+	run->exit_reason = KVM_EXIT_MMIO;
 	kvm_prepare_mmio(run, &mmio);
 	return 0;
 }
-- 
1.7.9.5

_______________________________________________
kvmarm mailing list
kvmarm@xxxxxxxxxxxxxxxxxxxxx
https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm


[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