|
@@ -1970,6 +1970,41 @@ enum emulation_result kvm_mips_emulate_bp_exc(unsigned long cause,
|
|
|
return er;
|
|
|
}
|
|
|
|
|
|
+enum emulation_result kvm_mips_emulate_trap_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 TRAP @ pc %#lx\n", arch->pc);
|
|
|
+
|
|
|
+ kvm_change_c0_guest_cause(cop0, (0xff),
|
|
|
+ (T_TRAP << CAUSEB_EXCCODE));
|
|
|
+
|
|
|
+ /* Set PC to the exception entry point */
|
|
|
+ arch->pc = KVM_GUEST_KSEG0 + 0x180;
|
|
|
+
|
|
|
+ } else {
|
|
|
+ kvm_err("Trying to deliver TRAP when EXL is already set\n");
|
|
|
+ er = EMULATE_FAIL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return er;
|
|
|
+}
|
|
|
+
|
|
|
/* ll/sc, rdhwr, sync emulation */
|
|
|
|
|
|
#define OPCODE 0xfc000000
|
|
@@ -2176,6 +2211,7 @@ enum emulation_result kvm_mips_check_privilege(unsigned long cause,
|
|
|
case T_SYSCALL:
|
|
|
case T_BREAK:
|
|
|
case T_RES_INST:
|
|
|
+ case T_TRAP:
|
|
|
case T_MSADIS:
|
|
|
break;
|
|
|
|