diff options
-rw-r--r-- | arch/mips/include/asm/kvm_host.h | 8 | ||||
-rw-r--r-- | arch/mips/kvm/emulate.c | 36 | ||||
-rw-r--r-- | arch/mips/kvm/mips.c | 7 | ||||
-rw-r--r-- | arch/mips/kvm/stats.c | 1 | ||||
-rw-r--r-- | arch/mips/kvm/trap_emul.c | 19 |
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 | ||
719 | extern 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 | |||
716 | extern enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu, | 724 | extern 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 | ||
1973 | enum 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 | ||
333 | static 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 | |||
333 | static int kvm_trap_emul_handle_msa_disabled(struct kvm_vcpu *vcpu) | 351 | static 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, |