aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kvm/trap_emul.c
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2015-02-06 05:56:27 -0500
committerJames Hogan <james.hogan@imgtec.com>2015-03-27 17:25:16 -0400
commit1c0cd66adbac8aa339b9521eceb18b00d1b0699e (patch)
tree62a893856435ad26ac8724cb23c3e47b63d177bd /arch/mips/kvm/trap_emul.c
parent6cdc65e31d4f70561d71eeaf34a2a70ab68bf146 (diff)
MIPS: KVM: Add FP exception handling
Add guest exception handling for floating point exceptions and coprocessor 1 unusable exceptions. Floating point exceptions from the guest need passing to the guest kernel, so for these a guest FPE is emulated. Also, coprocessor 1 unusable exceptions are normally passed straight through to the guest (because no guest FPU was supported), but the hypervisor can now handle them if the guest has its FPU enabled by restoring the guest FPU context and enabling the FPU. Signed-off-by: James Hogan <james.hogan@imgtec.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Paul Burton <paul.burton@imgtec.com> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Gleb Natapov <gleb@kernel.org> Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org
Diffstat (limited to 'arch/mips/kvm/trap_emul.c')
-rw-r--r--arch/mips/kvm/trap_emul.c39
1 files changed, 36 insertions, 3 deletions
diff --git a/arch/mips/kvm/trap_emul.c b/arch/mips/kvm/trap_emul.c
index 408af244aed2..421d5b815f24 100644
--- a/arch/mips/kvm/trap_emul.c
+++ b/arch/mips/kvm/trap_emul.c
@@ -39,16 +39,30 @@ static gpa_t kvm_trap_emul_gva_to_gpa_cb(gva_t gva)
39 39
40static int kvm_trap_emul_handle_cop_unusable(struct kvm_vcpu *vcpu) 40static int kvm_trap_emul_handle_cop_unusable(struct kvm_vcpu *vcpu)
41{ 41{
42 struct mips_coproc *cop0 = vcpu->arch.cop0;
42 struct kvm_run *run = vcpu->run; 43 struct kvm_run *run = vcpu->run;
43 uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc; 44 uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
44 unsigned long cause = vcpu->arch.host_cp0_cause; 45 unsigned long cause = vcpu->arch.host_cp0_cause;
45 enum emulation_result er = EMULATE_DONE; 46 enum emulation_result er = EMULATE_DONE;
46 int ret = RESUME_GUEST; 47 int ret = RESUME_GUEST;
47 48
48 if (((cause & CAUSEF_CE) >> CAUSEB_CE) == 1) 49 if (((cause & CAUSEF_CE) >> CAUSEB_CE) == 1) {
49 er = kvm_mips_emulate_fpu_exc(cause, opc, run, vcpu); 50 /* FPU Unusable */
50 else 51 if (!kvm_mips_guest_has_fpu(&vcpu->arch) ||
52 (kvm_read_c0_guest_status(cop0) & ST0_CU1) == 0) {
53 /*
54 * Unusable/no FPU in guest:
55 * deliver guest COP1 Unusable Exception
56 */
57 er = kvm_mips_emulate_fpu_exc(cause, opc, run, vcpu);
58 } else {
59 /* Restore FPU state */
60 kvm_own_fpu(vcpu);
61 er = EMULATE_DONE;
62 }
63 } else {
51 er = kvm_mips_emulate_inst(cause, opc, run, vcpu); 64 er = kvm_mips_emulate_inst(cause, opc, run, vcpu);
65 }
52 66
53 switch (er) { 67 switch (er) {
54 case EMULATE_DONE: 68 case EMULATE_DONE:
@@ -348,6 +362,24 @@ static int kvm_trap_emul_handle_trap(struct kvm_vcpu *vcpu)
348 return ret; 362 return ret;
349} 363}
350 364
365static int kvm_trap_emul_handle_fpe(struct kvm_vcpu *vcpu)
366{
367 struct kvm_run *run = vcpu->run;
368 uint32_t __user *opc = (uint32_t __user *)vcpu->arch.pc;
369 unsigned long cause = vcpu->arch.host_cp0_cause;
370 enum emulation_result er = EMULATE_DONE;
371 int ret = RESUME_GUEST;
372
373 er = kvm_mips_emulate_fpe_exc(cause, opc, run, vcpu);
374 if (er == EMULATE_DONE) {
375 ret = RESUME_GUEST;
376 } else {
377 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
378 ret = RESUME_HOST;
379 }
380 return ret;
381}
382
351static int kvm_trap_emul_handle_msa_disabled(struct kvm_vcpu *vcpu) 383static int kvm_trap_emul_handle_msa_disabled(struct kvm_vcpu *vcpu)
352{ 384{
353 struct kvm_run *run = vcpu->run; 385 struct kvm_run *run = vcpu->run;
@@ -576,6 +608,7 @@ static struct kvm_mips_callbacks kvm_trap_emul_callbacks = {
576 .handle_res_inst = kvm_trap_emul_handle_res_inst, 608 .handle_res_inst = kvm_trap_emul_handle_res_inst,
577 .handle_break = kvm_trap_emul_handle_break, 609 .handle_break = kvm_trap_emul_handle_break,
578 .handle_trap = kvm_trap_emul_handle_trap, 610 .handle_trap = kvm_trap_emul_handle_trap,
611 .handle_fpe = kvm_trap_emul_handle_fpe,
579 .handle_msa_disabled = kvm_trap_emul_handle_msa_disabled, 612 .handle_msa_disabled = kvm_trap_emul_handle_msa_disabled,
580 613
581 .vm_init = kvm_trap_emul_vm_init, 614 .vm_init = kvm_trap_emul_vm_init,