aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips/include/asm/kvm_host.h8
-rw-r--r--arch/mips/kvm/emulate.c36
-rw-r--r--arch/mips/kvm/mips.c7
-rw-r--r--arch/mips/kvm/stats.c1
-rw-r--r--arch/mips/kvm/trap_emul.c19
5 files changed, 71 insertions, 0 deletions
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
index f722b0528c25..8fc3ba2872f0 100644
--- a/arch/mips/include/asm/kvm_host.h
+++ b/arch/mips/include/asm/kvm_host.h
@@ -119,6 +119,7 @@ struct kvm_vcpu_stat {
119 u32 syscall_exits; 119 u32 syscall_exits;
120 u32 resvd_inst_exits; 120 u32 resvd_inst_exits;
121 u32 break_inst_exits; 121 u32 break_inst_exits;
122 u32 trap_inst_exits;
122 u32 flush_dcache_exits; 123 u32 flush_dcache_exits;
123 u32 halt_successful_poll; 124 u32 halt_successful_poll;
124 u32 halt_wakeup; 125 u32 halt_wakeup;
@@ -138,6 +139,7 @@ enum kvm_mips_exit_types {
138 SYSCALL_EXITS, 139 SYSCALL_EXITS,
139 RESVD_INST_EXITS, 140 RESVD_INST_EXITS,
140 BREAK_INST_EXITS, 141 BREAK_INST_EXITS,
142 TRAP_INST_EXITS,
141 FLUSH_DCACHE_EXITS, 143 FLUSH_DCACHE_EXITS,
142 MAX_KVM_MIPS_EXIT_TYPES 144 MAX_KVM_MIPS_EXIT_TYPES
143}; 145};
@@ -579,6 +581,7 @@ struct kvm_mips_callbacks {
579 int (*handle_syscall)(struct kvm_vcpu *vcpu); 581 int (*handle_syscall)(struct kvm_vcpu *vcpu);
580 int (*handle_res_inst)(struct kvm_vcpu *vcpu); 582 int (*handle_res_inst)(struct kvm_vcpu *vcpu);
581 int (*handle_break)(struct kvm_vcpu *vcpu); 583 int (*handle_break)(struct kvm_vcpu *vcpu);
584 int (*handle_trap)(struct kvm_vcpu *vcpu);
582 int (*handle_msa_disabled)(struct kvm_vcpu *vcpu); 585 int (*handle_msa_disabled)(struct kvm_vcpu *vcpu);
583 int (*vm_init)(struct kvm *kvm); 586 int (*vm_init)(struct kvm *kvm);
584 int (*vcpu_init)(struct kvm_vcpu *vcpu); 587 int (*vcpu_init)(struct kvm_vcpu *vcpu);
@@ -713,6 +716,11 @@ extern enum emulation_result kvm_mips_emulate_bp_exc(unsigned long cause,
713 struct kvm_run *run, 716 struct kvm_run *run,
714 struct kvm_vcpu *vcpu); 717 struct kvm_vcpu *vcpu);
715 718
719extern enum emulation_result kvm_mips_emulate_trap_exc(unsigned long cause,
720 uint32_t *opc,
721 struct kvm_run *run,
722 struct kvm_vcpu *vcpu);
723
716extern enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu, 724extern enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu,
717 struct kvm_run *run); 725 struct kvm_run *run);
718 726
diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c
index 838d3a6a5b7d..33e132dc7de8 100644
--- a/arch/mips/kvm/emulate.c
+++ b/arch/mips/kvm/emulate.c
@@ -1970,6 +1970,41 @@ enum emulation_result kvm_mips_emulate_bp_exc(unsigned long cause,
1970 return er; 1970 return er;
1971} 1971}
1972 1972
1973enum emulation_result kvm_mips_emulate_trap_exc(unsigned long cause,
1974 uint32_t *opc,
1975 struct kvm_run *run,
1976 struct kvm_vcpu *vcpu)
1977{
1978 struct mips_coproc *cop0 = vcpu->arch.cop0;
1979 struct kvm_vcpu_arch *arch = &vcpu->arch;
1980 enum emulation_result er = EMULATE_DONE;
1981
1982 if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) {
1983 /* save old pc */
1984 kvm_write_c0_guest_epc(cop0, arch->pc);
1985 kvm_set_c0_guest_status(cop0, ST0_EXL);
1986
1987 if (cause & CAUSEF_BD)
1988 kvm_set_c0_guest_cause(cop0, CAUSEF_BD);
1989 else
1990 kvm_clear_c0_guest_cause(cop0, CAUSEF_BD);
1991
1992 kvm_debug("Delivering TRAP @ pc %#lx\n", arch->pc);
1993
1994 kvm_change_c0_guest_cause(cop0, (0xff),
1995 (T_TRAP << CAUSEB_EXCCODE));
1996
1997 /* Set PC to the exception entry point */
1998 arch->pc = KVM_GUEST_KSEG0 + 0x180;
1999
2000 } else {
2001 kvm_err("Trying to deliver TRAP when EXL is already set\n");
2002 er = EMULATE_FAIL;
2003 }
2004
2005 return er;
2006}
2007
1973/* ll/sc, rdhwr, sync emulation */ 2008/* ll/sc, rdhwr, sync emulation */
1974 2009
1975#define OPCODE 0xfc000000 2010#define OPCODE 0xfc000000
@@ -2176,6 +2211,7 @@ enum emulation_result kvm_mips_check_privilege(unsigned long cause,
2176 case T_SYSCALL: 2211 case T_SYSCALL:
2177 case T_BREAK: 2212 case T_BREAK:
2178 case T_RES_INST: 2213 case T_RES_INST:
2214 case T_TRAP:
2179 case T_MSADIS: 2215 case T_MSADIS:
2180 break; 2216 break;
2181 2217
diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c
index f5e7ddab02f7..399b5517ecb8 100644
--- a/arch/mips/kvm/mips.c
+++ b/arch/mips/kvm/mips.c
@@ -48,6 +48,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
48 { "syscall", VCPU_STAT(syscall_exits), KVM_STAT_VCPU }, 48 { "syscall", VCPU_STAT(syscall_exits), KVM_STAT_VCPU },
49 { "resvd_inst", VCPU_STAT(resvd_inst_exits), KVM_STAT_VCPU }, 49 { "resvd_inst", VCPU_STAT(resvd_inst_exits), KVM_STAT_VCPU },
50 { "break_inst", VCPU_STAT(break_inst_exits), KVM_STAT_VCPU }, 50 { "break_inst", VCPU_STAT(break_inst_exits), KVM_STAT_VCPU },
51 { "trap_inst", VCPU_STAT(trap_inst_exits), KVM_STAT_VCPU },
51 { "flush_dcache", VCPU_STAT(flush_dcache_exits), KVM_STAT_VCPU }, 52 { "flush_dcache", VCPU_STAT(flush_dcache_exits), KVM_STAT_VCPU },
52 { "halt_successful_poll", VCPU_STAT(halt_successful_poll), KVM_STAT_VCPU }, 53 { "halt_successful_poll", VCPU_STAT(halt_successful_poll), KVM_STAT_VCPU },
53 { "halt_wakeup", VCPU_STAT(halt_wakeup), KVM_STAT_VCPU }, 54 { "halt_wakeup", VCPU_STAT(halt_wakeup), KVM_STAT_VCPU },
@@ -1119,6 +1120,12 @@ int kvm_mips_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
1119 ret = kvm_mips_callbacks->handle_break(vcpu); 1120 ret = kvm_mips_callbacks->handle_break(vcpu);
1120 break; 1121 break;
1121 1122
1123 case T_TRAP:
1124 ++vcpu->stat.trap_inst_exits;
1125 trace_kvm_exit(vcpu, TRAP_INST_EXITS);
1126 ret = kvm_mips_callbacks->handle_trap(vcpu);
1127 break;
1128
1122 case T_MSADIS: 1129 case T_MSADIS:
1123 ret = kvm_mips_callbacks->handle_msa_disabled(vcpu); 1130 ret = kvm_mips_callbacks->handle_msa_disabled(vcpu);
1124 break; 1131 break;
diff --git a/arch/mips/kvm/stats.c b/arch/mips/kvm/stats.c
index a74d6024c5ad..dd90b0a92181 100644
--- a/arch/mips/kvm/stats.c
+++ b/arch/mips/kvm/stats.c
@@ -25,6 +25,7 @@ char *kvm_mips_exit_types_str[MAX_KVM_MIPS_EXIT_TYPES] = {
25 "System Call", 25 "System Call",
26 "Reserved Inst", 26 "Reserved Inst",
27 "Break Inst", 27 "Break Inst",
28 "Trap Inst",
28 "D-Cache Flushes", 29 "D-Cache Flushes",
29}; 30};
30 31
diff --git a/arch/mips/kvm/trap_emul.c b/arch/mips/kvm/trap_emul.c
index 4372cc86650c..dc019950e243 100644
--- a/arch/mips/kvm/trap_emul.c
+++ b/arch/mips/kvm/trap_emul.c
@@ -330,6 +330,24 @@ static int kvm_trap_emul_handle_break(struct kvm_vcpu *vcpu)
330 return ret; 330 return ret;
331} 331}
332 332
333static int kvm_trap_emul_handle_trap(struct kvm_vcpu *vcpu)
334{
335 struct kvm_run *run = vcpu->run;
336 uint32_t __user *opc = (uint32_t __user *)vcpu->arch.pc;
337 unsigned long cause = vcpu->arch.host_cp0_cause;
338 enum emulation_result er = EMULATE_DONE;
339 int ret = RESUME_GUEST;
340
341 er = kvm_mips_emulate_trap_exc(cause, opc, run, vcpu);
342 if (er == EMULATE_DONE) {
343 ret = RESUME_GUEST;
344 } else {
345 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
346 ret = RESUME_HOST;
347 }
348 return ret;
349}
350
333static int kvm_trap_emul_handle_msa_disabled(struct kvm_vcpu *vcpu) 351static int kvm_trap_emul_handle_msa_disabled(struct kvm_vcpu *vcpu)
334{ 352{
335 struct kvm_run *run = vcpu->run; 353 struct kvm_run *run = vcpu->run;
@@ -497,6 +515,7 @@ static struct kvm_mips_callbacks kvm_trap_emul_callbacks = {
497 .handle_syscall = kvm_trap_emul_handle_syscall, 515 .handle_syscall = kvm_trap_emul_handle_syscall,
498 .handle_res_inst = kvm_trap_emul_handle_res_inst, 516 .handle_res_inst = kvm_trap_emul_handle_res_inst,
499 .handle_break = kvm_trap_emul_handle_break, 517 .handle_break = kvm_trap_emul_handle_break,
518 .handle_trap = kvm_trap_emul_handle_trap,
500 .handle_msa_disabled = kvm_trap_emul_handle_msa_disabled, 519 .handle_msa_disabled = kvm_trap_emul_handle_msa_disabled,
501 520
502 .vm_init = kvm_trap_emul_vm_init, 521 .vm_init = kvm_trap_emul_vm_init,