summaryrefslogtreecommitdiff
path: root/arch/mips/kvm/emulate.c
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2015-02-06 10:56:27 (GMT)
committerJames Hogan <james.hogan@imgtec.com>2015-03-27 21:25:16 (GMT)
commit1c0cd66adbac8aa339b9521eceb18b00d1b0699e (patch)
tree62a893856435ad26ac8724cb23c3e47b63d177bd /arch/mips/kvm/emulate.c
parent6cdc65e31d4f70561d71eeaf34a2a70ab68bf146 (diff)
downloadlinux-1c0cd66adbac8aa339b9521eceb18b00d1b0699e.tar.xz
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/emulate.c')
-rw-r--r--arch/mips/kvm/emulate.c36
1 files changed, 36 insertions, 0 deletions
diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c
index 3511bb2..fbf169f 100644
--- a/arch/mips/kvm/emulate.c
+++ b/arch/mips/kvm/emulate.c
@@ -2146,6 +2146,41 @@ enum emulation_result kvm_mips_emulate_trap_exc(unsigned long cause,
return er;
}
+enum emulation_result kvm_mips_emulate_fpe_exc(unsigned long cause,
+ uint32_t *opc,
+ struct kvm_run *run,
+ struct kvm_vcpu *vcpu)
+{
+ struct mips_coproc *cop0 = vcpu->arch.cop0;
+ struct kvm_vcpu_arch *arch = &vcpu->arch;
+ enum emulation_result er = EMULATE_DONE;
+
+ if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) {
+ /* save old pc */
+ kvm_write_c0_guest_epc(cop0, arch->pc);
+ kvm_set_c0_guest_status(cop0, ST0_EXL);
+
+ if (cause & CAUSEF_BD)
+ kvm_set_c0_guest_cause(cop0, CAUSEF_BD);
+ else
+ kvm_clear_c0_guest_cause(cop0, CAUSEF_BD);
+
+ kvm_debug("Delivering FPE @ pc %#lx\n", arch->pc);
+
+ kvm_change_c0_guest_cause(cop0, (0xff),
+ (T_FPE << CAUSEB_EXCCODE));
+
+ /* Set PC to the exception entry point */
+ arch->pc = KVM_GUEST_KSEG0 + 0x180;
+
+ } else {
+ kvm_err("Trying to deliver FPE when EXL is already set\n");
+ er = EMULATE_FAIL;
+ }
+
+ return er;
+}
+
/* ll/sc, rdhwr, sync emulation */
#define OPCODE 0xfc000000
@@ -2353,6 +2388,7 @@ enum emulation_result kvm_mips_check_privilege(unsigned long cause,
case T_BREAK:
case T_RES_INST:
case T_TRAP:
+ case T_FPE:
case T_MSADIS:
break;