[PATCH] KVM: ARM: Cleanup and fix load/store instruction decoding

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

 



Split the kvm_emulate_mmio_ls into a separate decoding function
and also supports emulated mmio writes now.

Signed-off-by: Christoffer Dall <c.dall@xxxxxxxxxxxxxxxxxxxxxx>
---
 arch/arm/include/asm/kvm_host.h |    6 ++-
 arch/arm/kvm/emulate.c          |   84 ++++++++++++++++++++++++++-------------
 arch/arm/kvm/mmu.c              |   15 ++-----
 3 files changed, 65 insertions(+), 40 deletions(-)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 10b6e04..fd93d37 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -156,8 +156,10 @@ struct kvm_vcpu_arch {
 	bool pause;
 
 	/* IO related fields */
-	bool mmio_sign_extend;	/* for byte/halfword loads */
-	u32 mmio_rd;
+	struct {
+		bool sign_extend;	/* for byte/halfword loads */
+		u32  rd;
+	} mmio;
 
 	/* Interrupt related fields */
 	u32 irq_lines;		/* IRQ and FIQ levels */
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index 1b3f18f..6044c02 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -364,6 +364,44 @@ static int kvm_ls_length(struct kvm_vcpu *vcpu, u32 instr)
 	BUG();
 }
 
+static bool kvm_decode_arm_ls(struct kvm_vcpu *vcpu, unsigned long instr,
+			      struct kvm_exit_mmio *mmio)
+{
+	int index;
+	bool is_write;
+	unsigned long rd, rn, offset, len;
+
+	index = get_arm_ls_instr_index(instr);
+	if (index == INSTR_NONE)
+		return false;
+
+	is_write = (index < NUM_LD_INSTR) ? false : true;
+	rd = (instr & INSTR_LS_RD_MASK) >> INSTR_LS_RD_SHIFT;
+	len = kvm_ls_length(vcpu, instr);
+
+	mmio->is_write = is_write;
+	mmio->len = len;
+
+	vcpu->arch.mmio.sign_extend = false;
+	vcpu->arch.mmio.rd = rd;
+
+	/* Handle base register writeback */
+	if (!(instr & (1U << INSTR_LS_BIT_P)) ||
+	     (instr & (1U << INSTR_LS_BIT_W))) {
+		rn = (instr & INSTR_LS_RN_MASK) >> INSTR_LS_RN_SHIFT;
+		offset = ls_word_calc_offset(vcpu, instr);
+		*vcpu_reg(vcpu, rn) += offset;
+	}
+
+	return true;
+}
+
+static bool kvm_decode_thumb_ls(struct kvm_vcpu *vcpu, unsigned long instr,
+			      struct kvm_exit_mmio *mmio)
+{
+	return false;
+}
+
 /**
  * kvm_emulate_mmio_ls - emulates load/store instructions made to I/O memory
  * @vcpu:	The vcpu pointer
@@ -378,39 +416,31 @@ static int kvm_ls_length(struct kvm_vcpu *vcpu, u32 instr)
 int kvm_emulate_mmio_ls(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 			unsigned long instr)
 {
-	unsigned long rd, rn, offset, len;
-	int index;
-	bool is_write;
+	bool is_thumb;
+	struct kvm_exit_mmio mmio;
 
 	trace_kvm_mmio_emulate(vcpu->arch.regs.pc, instr, vcpu->arch.regs.cpsr);
 
-	index = get_arm_ls_instr_index(instr);
-	if (index == INSTR_NONE) {
-		kvm_err("Unknown load/store instruction\n");
-		return -EINVAL;
+	mmio.phys_addr = fault_ipa;
+	is_thumb = !!(*vcpu_cpsr(vcpu) & PSR_T_BIT);
+	if (!is_thumb && !kvm_decode_arm_ls(vcpu, instr, &mmio)) {
+		kvm_err("Unable to decode instr.: %#08lx (cpsr: %#08x (T=0))\n",
+			instr, *vcpu_cpsr(vcpu));
+		return -ENXIO;
+	} else if (is_thumb && !kvm_decode_thumb_ls(vcpu, instr, &mmio)) {
+		kvm_err("Unable to decode instr.: %#08lx (cpsr: %#08x (T=1))\n",
+			instr, *vcpu_cpsr(vcpu));
+		return -ENXIO;
 	}
 
-	is_write = (index < NUM_LD_INSTR) ? false : true;
-	rd = (instr & INSTR_LS_RD_MASK) >> INSTR_LS_RD_SHIFT;
-	len = kvm_ls_length(vcpu, instr);
-
-	vcpu->run->mmio.is_write = is_write;
-	vcpu->run->mmio.phys_addr = fault_ipa;
-	vcpu->run->mmio.len = len;
-	vcpu->arch.mmio_sign_extend = false;
-	vcpu->arch.mmio_rd = rd;
+	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((is_write) ? KVM_TRACE_MMIO_WRITE :
-				    KVM_TRACE_MMIO_READ_UNSATISFIED,
-			len, fault_ipa, (is_write) ? *vcpu_reg(vcpu, rd) : 0);
-
-	/* Handle base register writeback */
-	if (!(instr & (1U << INSTR_LS_BIT_P)) ||
-	     (instr & (1U << INSTR_LS_BIT_W))) {
-		rn = (instr & INSTR_LS_RN_MASK) >> INSTR_LS_RN_SHIFT;
-		offset = ls_word_calc_offset(vcpu, instr);
-		*vcpu_reg(vcpu, rn) += offset;
-	}
+	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
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 61766a6..91377a7 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -559,7 +559,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	int mask;
 
 	if (!run->mmio.is_write) {
-		dest = vcpu_reg(vcpu, vcpu->arch.mmio_rd);
+		dest = vcpu_reg(vcpu, vcpu->arch.mmio.rd);
 		memset(dest, 0, sizeof(int));
 
 		len = run->mmio.len;
@@ -571,7 +571,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
 				*((u64 *)run->mmio.data));
 
-		if (vcpu->arch.mmio_sign_extend && len < 4) {
+		if (vcpu->arch.mmio.sign_extend && len < 4) {
 			mask = 1U << ((len * 8) - 1);
 			*dest = (*dest ^ mask) - mask;
 		}
@@ -711,13 +711,6 @@ static int invalid_io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
 {
 	unsigned long instr = 0;
 
-	if (vcpu->arch.regs.cpsr & PSR_T_BIT) {
-		/* TODO: Check validity of PC IPA and IPA2!!! */
-		/* Need to decode thumb instructions as well */
-		kvm_err("Thumb guest support not there yet :(\n");
-		return -EINVAL;
-	}
-
 	/* If it fails (SMP race?), we reenter guest for it to retry. */
 	if (!copy_current_insn(vcpu, &instr))
 		return 1;
@@ -781,8 +774,8 @@ static int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 	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;
+	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,
-- 
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