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