1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include <linux/kvm.h>
23#include <linux/kvm_host.h>
24
25#include <kvm/arm_psci.h>
26
27#include <asm/esr.h>
28#include <asm/exception.h>
29#include <asm/kvm_asm.h>
30#include <asm/kvm_coproc.h>
31#include <asm/kvm_emulate.h>
32#include <asm/kvm_mmu.h>
33#include <asm/debug-monitors.h>
34#include <asm/traps.h>
35
36#define CREATE_TRACE_POINTS
37#include "trace.h"
38
39typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *);
40
41static void kvm_handle_guest_serror(struct kvm_vcpu *vcpu, u32 esr)
42{
43 if (!arm64_is_ras_serror(esr) || arm64_is_fatal_ras_serror(NULL, esr))
44 kvm_inject_vabt(vcpu);
45}
46
47static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
48{
49 int ret;
50
51 trace_kvm_hvc_arm64(*vcpu_pc(vcpu), vcpu_get_reg(vcpu, 0),
52 kvm_vcpu_hvc_get_imm(vcpu));
53 vcpu->stat.hvc_exit_stat++;
54
55 ret = kvm_hvc_call_handler(vcpu);
56 if (ret < 0) {
57 vcpu_set_reg(vcpu, 0, ~0UL);
58 return 1;
59 }
60
61 return ret;
62}
63
64static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
65{
66
67
68
69
70
71
72
73
74 vcpu_set_reg(vcpu, 0, ~0UL);
75 kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
76 return 1;
77}
78
79
80
81
82
83static int handle_no_fpsimd(struct kvm_vcpu *vcpu, struct kvm_run *run)
84{
85 kvm_inject_undefined(vcpu);
86 return 1;
87}
88
89
90
91
92
93
94
95
96
97
98
99
100
101static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run)
102{
103 if (kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WFx_ISS_WFE) {
104 trace_kvm_wfx_arm64(*vcpu_pc(vcpu), true);
105 vcpu->stat.wfe_exit_stat++;
106 kvm_vcpu_on_spin(vcpu, vcpu_mode_priv(vcpu));
107 } else {
108 trace_kvm_wfx_arm64(*vcpu_pc(vcpu), false);
109 vcpu->stat.wfi_exit_stat++;
110 kvm_vcpu_block(vcpu);
111 kvm_clear_request(KVM_REQ_UNHALT, vcpu);
112 }
113
114 kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
115
116 return 1;
117}
118
119
120
121
122
123
124
125
126
127
128
129
130
131static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu, struct kvm_run *run)
132{
133 u32 hsr = kvm_vcpu_get_hsr(vcpu);
134 int ret = 0;
135
136 run->exit_reason = KVM_EXIT_DEBUG;
137 run->debug.arch.hsr = hsr;
138
139 switch (ESR_ELx_EC(hsr)) {
140 case ESR_ELx_EC_WATCHPT_LOW:
141 run->debug.arch.far = vcpu->arch.fault.far_el2;
142
143 case ESR_ELx_EC_SOFTSTP_LOW:
144 case ESR_ELx_EC_BREAKPT_LOW:
145 case ESR_ELx_EC_BKPT32:
146 case ESR_ELx_EC_BRK64:
147 break;
148 default:
149 kvm_err("%s: un-handled case hsr: %#08x\n",
150 __func__, (unsigned int) hsr);
151 ret = -1;
152 break;
153 }
154
155 return ret;
156}
157
158static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu, struct kvm_run *run)
159{
160 u32 hsr = kvm_vcpu_get_hsr(vcpu);
161
162 kvm_pr_unimpl("Unknown exception class: hsr: %#08x -- %s\n",
163 hsr, esr_get_class_string(hsr));
164
165 kvm_inject_undefined(vcpu);
166 return 1;
167}
168
169static int handle_sve(struct kvm_vcpu *vcpu, struct kvm_run *run)
170{
171
172 kvm_inject_undefined(vcpu);
173 return 1;
174}
175
176
177
178
179
180static int kvm_handle_ptrauth(struct kvm_vcpu *vcpu, struct kvm_run *run)
181{
182
183
184
185
186
187
188
189 kvm_inject_undefined(vcpu);
190 return 1;
191}
192
193static exit_handle_fn arm_exit_handlers[] = {
194 [0 ... ESR_ELx_EC_MAX] = kvm_handle_unknown_ec,
195 [ESR_ELx_EC_WFx] = kvm_handle_wfx,
196 [ESR_ELx_EC_CP15_32] = kvm_handle_cp15_32,
197 [ESR_ELx_EC_CP15_64] = kvm_handle_cp15_64,
198 [ESR_ELx_EC_CP14_MR] = kvm_handle_cp14_32,
199 [ESR_ELx_EC_CP14_LS] = kvm_handle_cp14_load_store,
200 [ESR_ELx_EC_CP14_64] = kvm_handle_cp14_64,
201 [ESR_ELx_EC_HVC32] = handle_hvc,
202 [ESR_ELx_EC_SMC32] = handle_smc,
203 [ESR_ELx_EC_HVC64] = handle_hvc,
204 [ESR_ELx_EC_SMC64] = handle_smc,
205 [ESR_ELx_EC_SYS64] = kvm_handle_sys_reg,
206 [ESR_ELx_EC_SVE] = handle_sve,
207 [ESR_ELx_EC_IABT_LOW] = kvm_handle_guest_abort,
208 [ESR_ELx_EC_DABT_LOW] = kvm_handle_guest_abort,
209 [ESR_ELx_EC_SOFTSTP_LOW]= kvm_handle_guest_debug,
210 [ESR_ELx_EC_WATCHPT_LOW]= kvm_handle_guest_debug,
211 [ESR_ELx_EC_BREAKPT_LOW]= kvm_handle_guest_debug,
212 [ESR_ELx_EC_BKPT32] = kvm_handle_guest_debug,
213 [ESR_ELx_EC_BRK64] = kvm_handle_guest_debug,
214 [ESR_ELx_EC_FP_ASIMD] = handle_no_fpsimd,
215 [ESR_ELx_EC_PAC] = kvm_handle_ptrauth,
216};
217
218static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
219{
220 u32 hsr = kvm_vcpu_get_hsr(vcpu);
221 u8 hsr_ec = ESR_ELx_EC(hsr);
222
223 return arm_exit_handlers[hsr_ec];
224}
225
226
227
228
229
230
231
232static int handle_trap_exceptions(struct kvm_vcpu *vcpu, struct kvm_run *run)
233{
234 int handled;
235
236
237
238
239
240 if (!kvm_condition_valid(vcpu)) {
241 kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
242 handled = 1;
243 } else {
244 exit_handle_fn exit_handler;
245
246 exit_handler = kvm_get_exit_handler(vcpu);
247 handled = exit_handler(vcpu, run);
248 }
249
250 return handled;
251}
252
253
254
255
256
257int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
258 int exception_index)
259{
260 if (ARM_SERROR_PENDING(exception_index)) {
261 u8 hsr_ec = ESR_ELx_EC(kvm_vcpu_get_hsr(vcpu));
262
263
264
265
266
267
268 if (hsr_ec == ESR_ELx_EC_HVC32 || hsr_ec == ESR_ELx_EC_HVC64 ||
269 hsr_ec == ESR_ELx_EC_SMC32 || hsr_ec == ESR_ELx_EC_SMC64) {
270 u32 adj = kvm_vcpu_trap_il_is32bit(vcpu) ? 4 : 2;
271 *vcpu_pc(vcpu) -= adj;
272 }
273
274 return 1;
275 }
276
277 exception_index = ARM_EXCEPTION_CODE(exception_index);
278
279 switch (exception_index) {
280 case ARM_EXCEPTION_IRQ:
281 return 1;
282 case ARM_EXCEPTION_EL1_SERROR:
283 return 1;
284 case ARM_EXCEPTION_TRAP:
285 return handle_trap_exceptions(vcpu, run);
286 case ARM_EXCEPTION_HYP_GONE:
287
288
289
290
291 run->exit_reason = KVM_EXIT_FAIL_ENTRY;
292 return 0;
293 case ARM_EXCEPTION_IL:
294
295
296
297
298 run->exit_reason = KVM_EXIT_FAIL_ENTRY;
299 return -EINVAL;
300 default:
301 kvm_pr_unimpl("Unsupported exception type: %d",
302 exception_index);
303 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
304 return 0;
305 }
306}
307
308
309void handle_exit_early(struct kvm_vcpu *vcpu, struct kvm_run *run,
310 int exception_index)
311{
312 if (ARM_SERROR_PENDING(exception_index)) {
313 if (this_cpu_has_cap(ARM64_HAS_RAS_EXTN)) {
314 u64 disr = kvm_vcpu_get_disr(vcpu);
315
316 kvm_handle_guest_serror(vcpu, disr_to_esr(disr));
317 } else {
318 kvm_inject_vabt(vcpu);
319 }
320
321 return;
322 }
323
324 exception_index = ARM_EXCEPTION_CODE(exception_index);
325
326 if (exception_index == ARM_EXCEPTION_EL1_SERROR)
327 kvm_handle_guest_serror(vcpu, kvm_vcpu_get_hsr(vcpu));
328}
329