1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <linux/kvm.h>
20#include <linux/kvm_host.h>
21#include <asm/kvm_emulate.h>
22#include <asm/kvm_coproc.h>
23#include <asm/kvm_mmu.h>
24#include <asm/kvm_psci.h>
25#include <trace/events/kvm.h>
26
27#include "trace.h"
28
29typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *);
30
31static int handle_svc_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
32{
33
34 kvm_debug("SVC called from Hyp mode shouldn't go here\n");
35 BUG();
36 return -EINVAL;
37}
38
39static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
40{
41 int ret;
42
43 trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0),
44 kvm_vcpu_hvc_get_imm(vcpu));
45
46 ret = kvm_psci_call(vcpu);
47 if (ret < 0) {
48 kvm_inject_undefined(vcpu);
49 return 1;
50 }
51
52 return ret;
53}
54
55static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
56{
57 kvm_inject_undefined(vcpu);
58 return 1;
59}
60
61static int handle_pabt_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
62{
63
64 kvm_err("Prefetch Abort taken from Hyp mode at %#08lx (HSR: %#08x)\n",
65 kvm_vcpu_get_hfar(vcpu), kvm_vcpu_get_hsr(vcpu));
66 return -EFAULT;
67}
68
69static int handle_dabt_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
70{
71
72 kvm_err("Data Abort taken from Hyp mode at %#08lx (HSR: %#08x)\n",
73 kvm_vcpu_get_hfar(vcpu), kvm_vcpu_get_hsr(vcpu));
74 return -EFAULT;
75}
76
77
78
79
80
81
82
83
84
85
86
87
88static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run)
89{
90 if (kvm_vcpu_get_hsr(vcpu) & HSR_WFI_IS_WFE) {
91 trace_kvm_wfx(*vcpu_pc(vcpu), true);
92 kvm_vcpu_on_spin(vcpu);
93 } else {
94 trace_kvm_wfx(*vcpu_pc(vcpu), false);
95 kvm_vcpu_block(vcpu);
96 }
97
98 kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
99
100 return 1;
101}
102
103static exit_handle_fn arm_exit_handlers[] = {
104 [HSR_EC_WFI] = kvm_handle_wfx,
105 [HSR_EC_CP15_32] = kvm_handle_cp15_32,
106 [HSR_EC_CP15_64] = kvm_handle_cp15_64,
107 [HSR_EC_CP14_MR] = kvm_handle_cp14_access,
108 [HSR_EC_CP14_LS] = kvm_handle_cp14_load_store,
109 [HSR_EC_CP14_64] = kvm_handle_cp14_access,
110 [HSR_EC_CP_0_13] = kvm_handle_cp_0_13_access,
111 [HSR_EC_CP10_ID] = kvm_handle_cp10_id,
112 [HSR_EC_SVC_HYP] = handle_svc_hyp,
113 [HSR_EC_HVC] = handle_hvc,
114 [HSR_EC_SMC] = handle_smc,
115 [HSR_EC_IABT] = kvm_handle_guest_abort,
116 [HSR_EC_IABT_HYP] = handle_pabt_hyp,
117 [HSR_EC_DABT] = kvm_handle_guest_abort,
118 [HSR_EC_DABT_HYP] = handle_dabt_hyp,
119};
120
121static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
122{
123 u8 hsr_ec = kvm_vcpu_trap_get_class(vcpu);
124
125 if (hsr_ec >= ARRAY_SIZE(arm_exit_handlers) ||
126 !arm_exit_handlers[hsr_ec]) {
127 kvm_err("Unknown exception class: hsr: %#08x\n",
128 (unsigned int)kvm_vcpu_get_hsr(vcpu));
129 BUG();
130 }
131
132 return arm_exit_handlers[hsr_ec];
133}
134
135
136
137
138
139int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
140 int exception_index)
141{
142 exit_handle_fn exit_handler;
143
144 switch (exception_index) {
145 case ARM_EXCEPTION_IRQ:
146 return 1;
147 case ARM_EXCEPTION_UNDEFINED:
148 kvm_err("Undefined exception in Hyp mode at: %#08lx\n",
149 kvm_vcpu_get_hyp_pc(vcpu));
150 BUG();
151 panic("KVM: Hypervisor undefined exception!\n");
152 case ARM_EXCEPTION_DATA_ABORT:
153 case ARM_EXCEPTION_PREF_ABORT:
154 case ARM_EXCEPTION_HVC:
155
156
157
158
159 if (!kvm_condition_valid(vcpu)) {
160 kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
161 return 1;
162 }
163
164 exit_handler = kvm_get_exit_handler(vcpu);
165
166 return exit_handler(vcpu, run);
167 default:
168 kvm_pr_unimpl("Unsupported exception type: %d",
169 exception_index);
170 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
171 return 0;
172 }
173}
174