From: Rusty Russell <rusty at rustcorp.com.au> The hardware has separate traps for the two cases, so don't prematurely unify them. Signed-off-by: Rusty Russell <rusty at rustcorp.com.au> --- arch/arm/include/asm/kvm_emulate.h | 3 + arch/arm/kvm/arm.c | 4 + arch/arm/kvm/emulate.c | 97 +++++++++++++++++++++--------------- 3 files changed, 60 insertions(+), 44 deletions(-) diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h index 029f45f..fa54247 100644 --- a/arch/arm/include/asm/kvm_emulate.h +++ b/arch/arm/include/asm/kvm_emulate.h @@ -44,7 +44,8 @@ int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_handle_cp_0_13_access(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run); -int kvm_handle_cp15_access(struct kvm_vcpu *vcpu, struct kvm_run *run); +int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run); +int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run); 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); diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index f27a96b..a6cf02b 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -377,8 +377,8 @@ static int handle_dabt_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run) static int (*arm_exit_handlers[])(struct kvm_vcpu *vcpu, struct kvm_run *r) = { [HSR_EC_WFI] = kvm_handle_wfi, - [HSR_EC_CP15_32] = kvm_handle_cp15_access, - [HSR_EC_CP15_64] = kvm_handle_cp15_access, + [HSR_EC_CP15_32] = kvm_handle_cp15_32, + [HSR_EC_CP15_64] = kvm_handle_cp15_64, [HSR_EC_CP14_MR] = kvm_handle_cp14_access, [HSR_EC_CP14_LS] = kvm_handle_cp14_load_store, [HSR_EC_CP14_64] = kvm_handle_cp14_access, diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c index 87a1141..11ab0a9 100644 --- a/arch/arm/kvm/emulate.c +++ b/arch/arm/kvm/emulate.c @@ -304,55 +304,25 @@ static int emulate_cp15_c15_access(struct kvm_vcpu *vcpu, return 0; } -/** - * kvm_handle_cp15_access -- handles a trap on a guest CP15 access - * @vcpu: The VCPU pointer - * @run: The kvm_run struct - * - * Investigates the CRn/CRm and wether this was mcr/mrc or mcrr/mrrc and either - * simply errors out if the operation was not supported (should maybe raise - * undefined to guest instead?) and otherwise emulated access. - */ -int kvm_handle_cp15_access(struct kvm_vcpu *vcpu, struct kvm_run *run) +static int emulate_cp15(struct kvm_vcpu *vcpu, + const struct coproc_params *params) { - unsigned long hsr_ec, instr_len; - struct coproc_params params; - int ret = 0; - - hsr_ec = vcpu->arch.hsr >> HSR_EC_SHIFT; - params.CRm = (vcpu->arch.hsr >> 1) & 0xf; - params.Rt1 = (vcpu->arch.hsr >> 5) & 0xf; - BUG_ON(params.Rt1 >= 15); - params.is_write = ((vcpu->arch.hsr & 1) == 0); - params.is_64bit = (hsr_ec == HSR_EC_CP15_64); - - if (params.is_64bit) { - /* mrrc, mccr operation */ - params.Op1 = (vcpu->arch.hsr >> 16) & 0xf; - params.Op2 = 0; - params.Rt2 = (vcpu->arch.hsr >> 10) & 0xf; - BUG_ON(params.Rt2 >= 15); - params.CRn = 0; - } else { - params.CRn = (vcpu->arch.hsr >> 10) & 0xf; - params.Op1 = (vcpu->arch.hsr >> 14) & 0x7; - params.Op2 = (vcpu->arch.hsr >> 17) & 0x7; - params.Rt2 = 0; - } + unsigned long instr_len; + int ret; /* So far no mrrc/mcrr accesses are emulated */ - if (params.is_64bit) + if (params->is_64bit) goto unsupp_err_out; - switch (params.CRn) { + switch (params->CRn) { case 9: - ret = emulate_cp15_c9_access(vcpu, ¶ms); + ret = emulate_cp15_c9_access(vcpu, params); break; case 10: - ret = emulate_cp15_c10_access(vcpu, ¶ms); + ret = emulate_cp15_c10_access(vcpu, params); break; case 15: - ret = emulate_cp15_c15_access(vcpu, ¶ms); + ret = emulate_cp15_c15_access(vcpu, params); break; default: ret = -EINVAL; @@ -367,10 +337,55 @@ int kvm_handle_cp15_access(struct kvm_vcpu *vcpu, struct kvm_run *run) *vcpu_reg(vcpu, 15) += instr_len; return ret; + unsupp_err_out: kvm_err("Unsupported guest CP15 access at: %08x\n", vcpu->arch.regs.pc); - print_cp_instr(¶ms); - return -EINVAL; + print_cp_instr(params); + return ret; +} + +/** + * kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access + * @vcpu: The VCPU pointer + * @run: The kvm_run struct + */ +int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + struct coproc_params params; + + params.CRm = (vcpu->arch.hsr >> 1) & 0xf; + params.Rt1 = (vcpu->arch.hsr >> 5) & 0xf; + params.is_write = ((vcpu->arch.hsr & 1) == 0); + params.is_64bit = true; + + params.Op1 = (vcpu->arch.hsr >> 16) & 0xf; + params.Op2 = 0; + params.Rt2 = (vcpu->arch.hsr >> 10) & 0xf; + params.CRn = 0; + + return emulate_cp15(vcpu, ¶ms); +} + +/** + * kvm_handle_cp15_32 -- handles a mrc/mcr trap on a guest CP15 access + * @vcpu: The VCPU pointer + * @run: The kvm_run struct + */ +int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + struct coproc_params params; + + params.CRm = (vcpu->arch.hsr >> 1) & 0xf; + params.Rt1 = (vcpu->arch.hsr >> 5) & 0xf; + params.is_write = ((vcpu->arch.hsr & 1) == 0); + params.is_64bit = false; + + params.CRn = (vcpu->arch.hsr >> 10) & 0xf; + params.Op1 = (vcpu->arch.hsr >> 14) & 0x7; + params.Op2 = (vcpu->arch.hsr >> 17) & 0x7; + params.Rt2 = 0; + + return emulate_cp15(vcpu, ¶ms); } /**