1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2020-2023 Loongson Technology Corporation Limited |
4 | */ |
5 | |
6 | #include <linux/err.h> |
7 | #include <linux/errno.h> |
8 | #include <linux/kvm_host.h> |
9 | #include <linux/module.h> |
10 | #include <linux/preempt.h> |
11 | #include <linux/vmalloc.h> |
12 | #include <asm/fpu.h> |
13 | #include <asm/inst.h> |
14 | #include <asm/loongarch.h> |
15 | #include <asm/mmzone.h> |
16 | #include <asm/numa.h> |
17 | #include <asm/time.h> |
18 | #include <asm/tlb.h> |
19 | #include <asm/kvm_csr.h> |
20 | #include <asm/kvm_vcpu.h> |
21 | #include "trace.h" |
22 | |
23 | static unsigned long kvm_emu_read_csr(struct kvm_vcpu *vcpu, int csrid) |
24 | { |
25 | unsigned long val = 0; |
26 | struct loongarch_csrs *csr = vcpu->arch.csr; |
27 | |
28 | /* |
29 | * From LoongArch Reference Manual Volume 1 Chapter 4.2.1 |
30 | * For undefined CSR id, return value is 0 |
31 | */ |
32 | if (get_gcsr_flag(csrid) & SW_GCSR) |
33 | val = kvm_read_sw_gcsr(csr, csrid); |
34 | else |
35 | pr_warn_once("Unsupported csrrd 0x%x with pc %lx\n" , csrid, vcpu->arch.pc); |
36 | |
37 | return val; |
38 | } |
39 | |
40 | static unsigned long kvm_emu_write_csr(struct kvm_vcpu *vcpu, int csrid, unsigned long val) |
41 | { |
42 | unsigned long old = 0; |
43 | struct loongarch_csrs *csr = vcpu->arch.csr; |
44 | |
45 | if (get_gcsr_flag(csrid) & SW_GCSR) { |
46 | old = kvm_read_sw_gcsr(csr, csrid); |
47 | kvm_write_sw_gcsr(csr, csrid, val); |
48 | } else |
49 | pr_warn_once("Unsupported csrwr 0x%x with pc %lx\n" , csrid, vcpu->arch.pc); |
50 | |
51 | return old; |
52 | } |
53 | |
54 | static unsigned long kvm_emu_xchg_csr(struct kvm_vcpu *vcpu, int csrid, |
55 | unsigned long csr_mask, unsigned long val) |
56 | { |
57 | unsigned long old = 0; |
58 | struct loongarch_csrs *csr = vcpu->arch.csr; |
59 | |
60 | if (get_gcsr_flag(csrid) & SW_GCSR) { |
61 | old = kvm_read_sw_gcsr(csr, csrid); |
62 | val = (old & ~csr_mask) | (val & csr_mask); |
63 | kvm_write_sw_gcsr(csr, csrid, val); |
64 | old = old & csr_mask; |
65 | } else |
66 | pr_warn_once("Unsupported csrxchg 0x%x with pc %lx\n" , csrid, vcpu->arch.pc); |
67 | |
68 | return old; |
69 | } |
70 | |
71 | static int kvm_handle_csr(struct kvm_vcpu *vcpu, larch_inst inst) |
72 | { |
73 | unsigned int rd, rj, csrid; |
74 | unsigned long csr_mask, val = 0; |
75 | |
76 | /* |
77 | * CSR value mask imm |
78 | * rj = 0 means csrrd |
79 | * rj = 1 means csrwr |
80 | * rj != 0,1 means csrxchg |
81 | */ |
82 | rd = inst.reg2csr_format.rd; |
83 | rj = inst.reg2csr_format.rj; |
84 | csrid = inst.reg2csr_format.csr; |
85 | |
86 | /* Process CSR ops */ |
87 | switch (rj) { |
88 | case 0: /* process csrrd */ |
89 | val = kvm_emu_read_csr(vcpu, csrid); |
90 | vcpu->arch.gprs[rd] = val; |
91 | break; |
92 | case 1: /* process csrwr */ |
93 | val = vcpu->arch.gprs[rd]; |
94 | val = kvm_emu_write_csr(vcpu, csrid, val); |
95 | vcpu->arch.gprs[rd] = val; |
96 | break; |
97 | default: /* process csrxchg */ |
98 | val = vcpu->arch.gprs[rd]; |
99 | csr_mask = vcpu->arch.gprs[rj]; |
100 | val = kvm_emu_xchg_csr(vcpu, csrid, csr_mask, val); |
101 | vcpu->arch.gprs[rd] = val; |
102 | } |
103 | |
104 | return EMULATE_DONE; |
105 | } |
106 | |
107 | int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu) |
108 | { |
109 | int ret; |
110 | unsigned long val; |
111 | u32 addr, rd, rj, opcode; |
112 | |
113 | /* |
114 | * Each IOCSR with different opcode |
115 | */ |
116 | rd = inst.reg2_format.rd; |
117 | rj = inst.reg2_format.rj; |
118 | opcode = inst.reg2_format.opcode; |
119 | addr = vcpu->arch.gprs[rj]; |
120 | ret = EMULATE_DO_IOCSR; |
121 | run->iocsr_io.phys_addr = addr; |
122 | run->iocsr_io.is_write = 0; |
123 | |
124 | /* LoongArch is Little endian */ |
125 | switch (opcode) { |
126 | case iocsrrdb_op: |
127 | run->iocsr_io.len = 1; |
128 | break; |
129 | case iocsrrdh_op: |
130 | run->iocsr_io.len = 2; |
131 | break; |
132 | case iocsrrdw_op: |
133 | run->iocsr_io.len = 4; |
134 | break; |
135 | case iocsrrdd_op: |
136 | run->iocsr_io.len = 8; |
137 | break; |
138 | case iocsrwrb_op: |
139 | run->iocsr_io.len = 1; |
140 | run->iocsr_io.is_write = 1; |
141 | break; |
142 | case iocsrwrh_op: |
143 | run->iocsr_io.len = 2; |
144 | run->iocsr_io.is_write = 1; |
145 | break; |
146 | case iocsrwrw_op: |
147 | run->iocsr_io.len = 4; |
148 | run->iocsr_io.is_write = 1; |
149 | break; |
150 | case iocsrwrd_op: |
151 | run->iocsr_io.len = 8; |
152 | run->iocsr_io.is_write = 1; |
153 | break; |
154 | default: |
155 | ret = EMULATE_FAIL; |
156 | break; |
157 | } |
158 | |
159 | if (ret == EMULATE_DO_IOCSR) { |
160 | if (run->iocsr_io.is_write) { |
161 | val = vcpu->arch.gprs[rd]; |
162 | memcpy(run->iocsr_io.data, &val, run->iocsr_io.len); |
163 | } |
164 | vcpu->arch.io_gpr = rd; |
165 | } |
166 | |
167 | return ret; |
168 | } |
169 | |
170 | int kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run) |
171 | { |
172 | enum emulation_result er = EMULATE_DONE; |
173 | unsigned long *gpr = &vcpu->arch.gprs[vcpu->arch.io_gpr]; |
174 | |
175 | switch (run->iocsr_io.len) { |
176 | case 1: |
177 | *gpr = *(s8 *)run->iocsr_io.data; |
178 | break; |
179 | case 2: |
180 | *gpr = *(s16 *)run->iocsr_io.data; |
181 | break; |
182 | case 4: |
183 | *gpr = *(s32 *)run->iocsr_io.data; |
184 | break; |
185 | case 8: |
186 | *gpr = *(s64 *)run->iocsr_io.data; |
187 | break; |
188 | default: |
189 | kvm_err("Bad IOCSR length: %d, addr is 0x%lx\n" , |
190 | run->iocsr_io.len, vcpu->arch.badv); |
191 | er = EMULATE_FAIL; |
192 | break; |
193 | } |
194 | |
195 | return er; |
196 | } |
197 | |
198 | int kvm_emu_idle(struct kvm_vcpu *vcpu) |
199 | { |
200 | ++vcpu->stat.idle_exits; |
201 | trace_kvm_exit_idle(vcpu, KVM_TRACE_EXIT_IDLE); |
202 | |
203 | if (!kvm_arch_vcpu_runnable(vcpu)) |
204 | kvm_vcpu_halt(vcpu); |
205 | |
206 | return EMULATE_DONE; |
207 | } |
208 | |
209 | static int kvm_trap_handle_gspr(struct kvm_vcpu *vcpu) |
210 | { |
211 | int rd, rj; |
212 | unsigned int index; |
213 | unsigned long curr_pc; |
214 | larch_inst inst; |
215 | enum emulation_result er = EMULATE_DONE; |
216 | struct kvm_run *run = vcpu->run; |
217 | |
218 | /* Fetch the instruction */ |
219 | inst.word = vcpu->arch.badi; |
220 | curr_pc = vcpu->arch.pc; |
221 | update_pc(&vcpu->arch); |
222 | |
223 | trace_kvm_exit_gspr(vcpu, inst.word); |
224 | er = EMULATE_FAIL; |
225 | switch (((inst.word >> 24) & 0xff)) { |
226 | case 0x0: /* CPUCFG GSPR */ |
227 | if (inst.reg2_format.opcode == 0x1B) { |
228 | rd = inst.reg2_format.rd; |
229 | rj = inst.reg2_format.rj; |
230 | ++vcpu->stat.cpucfg_exits; |
231 | index = vcpu->arch.gprs[rj]; |
232 | er = EMULATE_DONE; |
233 | /* |
234 | * By LoongArch Reference Manual 2.2.10.5 |
235 | * return value is 0 for undefined cpucfg index |
236 | */ |
237 | if (index < KVM_MAX_CPUCFG_REGS) |
238 | vcpu->arch.gprs[rd] = vcpu->arch.cpucfg[index]; |
239 | else |
240 | vcpu->arch.gprs[rd] = 0; |
241 | } |
242 | break; |
243 | case 0x4: /* CSR{RD,WR,XCHG} GSPR */ |
244 | er = kvm_handle_csr(vcpu, inst); |
245 | break; |
246 | case 0x6: /* Cache, Idle and IOCSR GSPR */ |
247 | switch (((inst.word >> 22) & 0x3ff)) { |
248 | case 0x18: /* Cache GSPR */ |
249 | er = EMULATE_DONE; |
250 | trace_kvm_exit_cache(vcpu, KVM_TRACE_EXIT_CACHE); |
251 | break; |
252 | case 0x19: /* Idle/IOCSR GSPR */ |
253 | switch (((inst.word >> 15) & 0x1ffff)) { |
254 | case 0xc90: /* IOCSR GSPR */ |
255 | er = kvm_emu_iocsr(inst, run, vcpu); |
256 | break; |
257 | case 0xc91: /* Idle GSPR */ |
258 | er = kvm_emu_idle(vcpu); |
259 | break; |
260 | default: |
261 | er = EMULATE_FAIL; |
262 | break; |
263 | } |
264 | break; |
265 | default: |
266 | er = EMULATE_FAIL; |
267 | break; |
268 | } |
269 | break; |
270 | default: |
271 | er = EMULATE_FAIL; |
272 | break; |
273 | } |
274 | |
275 | /* Rollback PC only if emulation was unsuccessful */ |
276 | if (er == EMULATE_FAIL) { |
277 | kvm_err("[%#lx]%s: unsupported gspr instruction 0x%08x\n" , |
278 | curr_pc, __func__, inst.word); |
279 | |
280 | kvm_arch_vcpu_dump_regs(vcpu); |
281 | vcpu->arch.pc = curr_pc; |
282 | } |
283 | |
284 | return er; |
285 | } |
286 | |
287 | /* |
288 | * Trigger GSPR: |
289 | * 1) Execute CPUCFG instruction; |
290 | * 2) Execute CACOP/IDLE instructions; |
291 | * 3) Access to unimplemented CSRs/IOCSRs. |
292 | */ |
293 | static int kvm_handle_gspr(struct kvm_vcpu *vcpu) |
294 | { |
295 | int ret = RESUME_GUEST; |
296 | enum emulation_result er = EMULATE_DONE; |
297 | |
298 | er = kvm_trap_handle_gspr(vcpu); |
299 | |
300 | if (er == EMULATE_DONE) { |
301 | ret = RESUME_GUEST; |
302 | } else if (er == EMULATE_DO_MMIO) { |
303 | vcpu->run->exit_reason = KVM_EXIT_MMIO; |
304 | ret = RESUME_HOST; |
305 | } else if (er == EMULATE_DO_IOCSR) { |
306 | vcpu->run->exit_reason = KVM_EXIT_LOONGARCH_IOCSR; |
307 | ret = RESUME_HOST; |
308 | } else { |
309 | kvm_queue_exception(vcpu, EXCCODE_INE, 0); |
310 | ret = RESUME_GUEST; |
311 | } |
312 | |
313 | return ret; |
314 | } |
315 | |
316 | int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst) |
317 | { |
318 | int ret; |
319 | unsigned int op8, opcode, rd; |
320 | struct kvm_run *run = vcpu->run; |
321 | |
322 | run->mmio.phys_addr = vcpu->arch.badv; |
323 | vcpu->mmio_needed = 2; /* signed */ |
324 | op8 = (inst.word >> 24) & 0xff; |
325 | ret = EMULATE_DO_MMIO; |
326 | |
327 | switch (op8) { |
328 | case 0x24 ... 0x27: /* ldptr.w/d process */ |
329 | rd = inst.reg2i14_format.rd; |
330 | opcode = inst.reg2i14_format.opcode; |
331 | |
332 | switch (opcode) { |
333 | case ldptrw_op: |
334 | run->mmio.len = 4; |
335 | break; |
336 | case ldptrd_op: |
337 | run->mmio.len = 8; |
338 | break; |
339 | default: |
340 | break; |
341 | } |
342 | break; |
343 | case 0x28 ... 0x2e: /* ld.b/h/w/d, ld.bu/hu/wu process */ |
344 | rd = inst.reg2i12_format.rd; |
345 | opcode = inst.reg2i12_format.opcode; |
346 | |
347 | switch (opcode) { |
348 | case ldb_op: |
349 | run->mmio.len = 1; |
350 | break; |
351 | case ldbu_op: |
352 | vcpu->mmio_needed = 1; /* unsigned */ |
353 | run->mmio.len = 1; |
354 | break; |
355 | case ldh_op: |
356 | run->mmio.len = 2; |
357 | break; |
358 | case ldhu_op: |
359 | vcpu->mmio_needed = 1; /* unsigned */ |
360 | run->mmio.len = 2; |
361 | break; |
362 | case ldw_op: |
363 | run->mmio.len = 4; |
364 | break; |
365 | case ldwu_op: |
366 | vcpu->mmio_needed = 1; /* unsigned */ |
367 | run->mmio.len = 4; |
368 | break; |
369 | case ldd_op: |
370 | run->mmio.len = 8; |
371 | break; |
372 | default: |
373 | ret = EMULATE_FAIL; |
374 | break; |
375 | } |
376 | break; |
377 | case 0x38: /* ldx.b/h/w/d, ldx.bu/hu/wu process */ |
378 | rd = inst.reg3_format.rd; |
379 | opcode = inst.reg3_format.opcode; |
380 | |
381 | switch (opcode) { |
382 | case ldxb_op: |
383 | run->mmio.len = 1; |
384 | break; |
385 | case ldxbu_op: |
386 | run->mmio.len = 1; |
387 | vcpu->mmio_needed = 1; /* unsigned */ |
388 | break; |
389 | case ldxh_op: |
390 | run->mmio.len = 2; |
391 | break; |
392 | case ldxhu_op: |
393 | run->mmio.len = 2; |
394 | vcpu->mmio_needed = 1; /* unsigned */ |
395 | break; |
396 | case ldxw_op: |
397 | run->mmio.len = 4; |
398 | break; |
399 | case ldxwu_op: |
400 | run->mmio.len = 4; |
401 | vcpu->mmio_needed = 1; /* unsigned */ |
402 | break; |
403 | case ldxd_op: |
404 | run->mmio.len = 8; |
405 | break; |
406 | default: |
407 | ret = EMULATE_FAIL; |
408 | break; |
409 | } |
410 | break; |
411 | default: |
412 | ret = EMULATE_FAIL; |
413 | } |
414 | |
415 | if (ret == EMULATE_DO_MMIO) { |
416 | /* Set for kvm_complete_mmio_read() use */ |
417 | vcpu->arch.io_gpr = rd; |
418 | run->mmio.is_write = 0; |
419 | vcpu->mmio_is_write = 0; |
420 | } else { |
421 | kvm_err("Read not supported Inst=0x%08x @%lx BadVaddr:%#lx\n" , |
422 | inst.word, vcpu->arch.pc, vcpu->arch.badv); |
423 | kvm_arch_vcpu_dump_regs(vcpu); |
424 | vcpu->mmio_needed = 0; |
425 | } |
426 | |
427 | return ret; |
428 | } |
429 | |
430 | int kvm_complete_mmio_read(struct kvm_vcpu *vcpu, struct kvm_run *run) |
431 | { |
432 | enum emulation_result er = EMULATE_DONE; |
433 | unsigned long *gpr = &vcpu->arch.gprs[vcpu->arch.io_gpr]; |
434 | |
435 | /* Update with new PC */ |
436 | update_pc(&vcpu->arch); |
437 | switch (run->mmio.len) { |
438 | case 1: |
439 | if (vcpu->mmio_needed == 2) |
440 | *gpr = *(s8 *)run->mmio.data; |
441 | else |
442 | *gpr = *(u8 *)run->mmio.data; |
443 | break; |
444 | case 2: |
445 | if (vcpu->mmio_needed == 2) |
446 | *gpr = *(s16 *)run->mmio.data; |
447 | else |
448 | *gpr = *(u16 *)run->mmio.data; |
449 | break; |
450 | case 4: |
451 | if (vcpu->mmio_needed == 2) |
452 | *gpr = *(s32 *)run->mmio.data; |
453 | else |
454 | *gpr = *(u32 *)run->mmio.data; |
455 | break; |
456 | case 8: |
457 | *gpr = *(s64 *)run->mmio.data; |
458 | break; |
459 | default: |
460 | kvm_err("Bad MMIO length: %d, addr is 0x%lx\n" , |
461 | run->mmio.len, vcpu->arch.badv); |
462 | er = EMULATE_FAIL; |
463 | break; |
464 | } |
465 | |
466 | return er; |
467 | } |
468 | |
469 | int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst) |
470 | { |
471 | int ret; |
472 | unsigned int rd, op8, opcode; |
473 | unsigned long curr_pc, rd_val = 0; |
474 | struct kvm_run *run = vcpu->run; |
475 | void *data = run->mmio.data; |
476 | |
477 | /* |
478 | * Update PC and hold onto current PC in case there is |
479 | * an error and we want to rollback the PC |
480 | */ |
481 | curr_pc = vcpu->arch.pc; |
482 | update_pc(&vcpu->arch); |
483 | |
484 | op8 = (inst.word >> 24) & 0xff; |
485 | run->mmio.phys_addr = vcpu->arch.badv; |
486 | ret = EMULATE_DO_MMIO; |
487 | switch (op8) { |
488 | case 0x24 ... 0x27: /* stptr.w/d process */ |
489 | rd = inst.reg2i14_format.rd; |
490 | opcode = inst.reg2i14_format.opcode; |
491 | |
492 | switch (opcode) { |
493 | case stptrw_op: |
494 | run->mmio.len = 4; |
495 | *(unsigned int *)data = vcpu->arch.gprs[rd]; |
496 | break; |
497 | case stptrd_op: |
498 | run->mmio.len = 8; |
499 | *(unsigned long *)data = vcpu->arch.gprs[rd]; |
500 | break; |
501 | default: |
502 | ret = EMULATE_FAIL; |
503 | break; |
504 | } |
505 | break; |
506 | case 0x28 ... 0x2e: /* st.b/h/w/d process */ |
507 | rd = inst.reg2i12_format.rd; |
508 | opcode = inst.reg2i12_format.opcode; |
509 | rd_val = vcpu->arch.gprs[rd]; |
510 | |
511 | switch (opcode) { |
512 | case stb_op: |
513 | run->mmio.len = 1; |
514 | *(unsigned char *)data = rd_val; |
515 | break; |
516 | case sth_op: |
517 | run->mmio.len = 2; |
518 | *(unsigned short *)data = rd_val; |
519 | break; |
520 | case stw_op: |
521 | run->mmio.len = 4; |
522 | *(unsigned int *)data = rd_val; |
523 | break; |
524 | case std_op: |
525 | run->mmio.len = 8; |
526 | *(unsigned long *)data = rd_val; |
527 | break; |
528 | default: |
529 | ret = EMULATE_FAIL; |
530 | break; |
531 | } |
532 | break; |
533 | case 0x38: /* stx.b/h/w/d process */ |
534 | rd = inst.reg3_format.rd; |
535 | opcode = inst.reg3_format.opcode; |
536 | |
537 | switch (opcode) { |
538 | case stxb_op: |
539 | run->mmio.len = 1; |
540 | *(unsigned char *)data = vcpu->arch.gprs[rd]; |
541 | break; |
542 | case stxh_op: |
543 | run->mmio.len = 2; |
544 | *(unsigned short *)data = vcpu->arch.gprs[rd]; |
545 | break; |
546 | case stxw_op: |
547 | run->mmio.len = 4; |
548 | *(unsigned int *)data = vcpu->arch.gprs[rd]; |
549 | break; |
550 | case stxd_op: |
551 | run->mmio.len = 8; |
552 | *(unsigned long *)data = vcpu->arch.gprs[rd]; |
553 | break; |
554 | default: |
555 | ret = EMULATE_FAIL; |
556 | break; |
557 | } |
558 | break; |
559 | default: |
560 | ret = EMULATE_FAIL; |
561 | } |
562 | |
563 | if (ret == EMULATE_DO_MMIO) { |
564 | run->mmio.is_write = 1; |
565 | vcpu->mmio_needed = 1; |
566 | vcpu->mmio_is_write = 1; |
567 | } else { |
568 | vcpu->arch.pc = curr_pc; |
569 | kvm_err("Write not supported Inst=0x%08x @%lx BadVaddr:%#lx\n" , |
570 | inst.word, vcpu->arch.pc, vcpu->arch.badv); |
571 | kvm_arch_vcpu_dump_regs(vcpu); |
572 | /* Rollback PC if emulation was unsuccessful */ |
573 | } |
574 | |
575 | return ret; |
576 | } |
577 | |
578 | static int kvm_handle_rdwr_fault(struct kvm_vcpu *vcpu, bool write) |
579 | { |
580 | int ret; |
581 | larch_inst inst; |
582 | enum emulation_result er = EMULATE_DONE; |
583 | struct kvm_run *run = vcpu->run; |
584 | unsigned long badv = vcpu->arch.badv; |
585 | |
586 | ret = kvm_handle_mm_fault(vcpu, badv, write); |
587 | if (ret) { |
588 | /* Treat as MMIO */ |
589 | inst.word = vcpu->arch.badi; |
590 | if (write) { |
591 | er = kvm_emu_mmio_write(vcpu, inst); |
592 | } else { |
593 | /* A code fetch fault doesn't count as an MMIO */ |
594 | if (kvm_is_ifetch_fault(&vcpu->arch)) { |
595 | kvm_queue_exception(vcpu, EXCCODE_ADE, EXSUBCODE_ADEF); |
596 | return RESUME_GUEST; |
597 | } |
598 | |
599 | er = kvm_emu_mmio_read(vcpu, inst); |
600 | } |
601 | } |
602 | |
603 | if (er == EMULATE_DONE) { |
604 | ret = RESUME_GUEST; |
605 | } else if (er == EMULATE_DO_MMIO) { |
606 | run->exit_reason = KVM_EXIT_MMIO; |
607 | ret = RESUME_HOST; |
608 | } else { |
609 | kvm_queue_exception(vcpu, EXCCODE_ADE, EXSUBCODE_ADEM); |
610 | ret = RESUME_GUEST; |
611 | } |
612 | |
613 | return ret; |
614 | } |
615 | |
616 | static int kvm_handle_read_fault(struct kvm_vcpu *vcpu) |
617 | { |
618 | return kvm_handle_rdwr_fault(vcpu, write: false); |
619 | } |
620 | |
621 | static int kvm_handle_write_fault(struct kvm_vcpu *vcpu) |
622 | { |
623 | return kvm_handle_rdwr_fault(vcpu, write: true); |
624 | } |
625 | |
626 | /** |
627 | * kvm_handle_fpu_disabled() - Guest used fpu however it is disabled at host |
628 | * @vcpu: Virtual CPU context. |
629 | * |
630 | * Handle when the guest attempts to use fpu which hasn't been allowed |
631 | * by the root context. |
632 | */ |
633 | static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu) |
634 | { |
635 | struct kvm_run *run = vcpu->run; |
636 | |
637 | if (!kvm_guest_has_fpu(&vcpu->arch)) { |
638 | kvm_queue_exception(vcpu, EXCCODE_INE, 0); |
639 | return RESUME_GUEST; |
640 | } |
641 | |
642 | /* |
643 | * If guest FPU not present, the FPU operation should have been |
644 | * treated as a reserved instruction! |
645 | * If FPU already in use, we shouldn't get this at all. |
646 | */ |
647 | if (WARN_ON(vcpu->arch.aux_inuse & KVM_LARCH_FPU)) { |
648 | kvm_err("%s internal error\n" , __func__); |
649 | run->exit_reason = KVM_EXIT_INTERNAL_ERROR; |
650 | return RESUME_HOST; |
651 | } |
652 | |
653 | kvm_own_fpu(vcpu); |
654 | |
655 | return RESUME_GUEST; |
656 | } |
657 | |
658 | /* |
659 | * kvm_handle_lsx_disabled() - Guest used LSX while disabled in root. |
660 | * @vcpu: Virtual CPU context. |
661 | * |
662 | * Handle when the guest attempts to use LSX when it is disabled in the root |
663 | * context. |
664 | */ |
665 | static int kvm_handle_lsx_disabled(struct kvm_vcpu *vcpu) |
666 | { |
667 | if (kvm_own_lsx(vcpu)) |
668 | kvm_queue_exception(vcpu, EXCCODE_INE, 0); |
669 | |
670 | return RESUME_GUEST; |
671 | } |
672 | |
673 | /* |
674 | * kvm_handle_lasx_disabled() - Guest used LASX while disabled in root. |
675 | * @vcpu: Virtual CPU context. |
676 | * |
677 | * Handle when the guest attempts to use LASX when it is disabled in the root |
678 | * context. |
679 | */ |
680 | static int kvm_handle_lasx_disabled(struct kvm_vcpu *vcpu) |
681 | { |
682 | if (kvm_own_lasx(vcpu)) |
683 | kvm_queue_exception(vcpu, EXCCODE_INE, 0); |
684 | |
685 | return RESUME_GUEST; |
686 | } |
687 | |
688 | /* |
689 | * LoongArch KVM callback handling for unimplemented guest exiting |
690 | */ |
691 | static int kvm_fault_ni(struct kvm_vcpu *vcpu) |
692 | { |
693 | unsigned int ecode, inst; |
694 | unsigned long estat, badv; |
695 | |
696 | /* Fetch the instruction */ |
697 | inst = vcpu->arch.badi; |
698 | badv = vcpu->arch.badv; |
699 | estat = vcpu->arch.host_estat; |
700 | ecode = (estat & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT; |
701 | kvm_err("ECode: %d PC=%#lx Inst=0x%08x BadVaddr=%#lx ESTAT=%#lx\n" , |
702 | ecode, vcpu->arch.pc, inst, badv, read_gcsr_estat()); |
703 | kvm_arch_vcpu_dump_regs(vcpu); |
704 | kvm_queue_exception(vcpu, EXCCODE_INE, 0); |
705 | |
706 | return RESUME_GUEST; |
707 | } |
708 | |
709 | static exit_handle_fn kvm_fault_tables[EXCCODE_INT_START] = { |
710 | [0 ... EXCCODE_INT_START - 1] = kvm_fault_ni, |
711 | [EXCCODE_TLBI] = kvm_handle_read_fault, |
712 | [EXCCODE_TLBL] = kvm_handle_read_fault, |
713 | [EXCCODE_TLBS] = kvm_handle_write_fault, |
714 | [EXCCODE_TLBM] = kvm_handle_write_fault, |
715 | [EXCCODE_FPDIS] = kvm_handle_fpu_disabled, |
716 | [EXCCODE_LSXDIS] = kvm_handle_lsx_disabled, |
717 | [EXCCODE_LASXDIS] = kvm_handle_lasx_disabled, |
718 | [EXCCODE_GSPR] = kvm_handle_gspr, |
719 | }; |
720 | |
721 | int kvm_handle_fault(struct kvm_vcpu *vcpu, int fault) |
722 | { |
723 | return kvm_fault_tables[fault](vcpu); |
724 | } |
725 | |