1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2019 Western Digital Corporation or its affiliates.
4 * Copyright (c) 2022 Ventana Micro Systems Inc.
5 */
6
7 #include <linux/bitops.h>
8 #include <linux/kvm_host.h>
9
10 #include <asm/cpufeature.h>
11 #include <asm/insn.h>
12
13 struct insn_func {
14 unsigned long mask;
15 unsigned long match;
16 /*
17 * Possible return values are as follows:
18 * 1) Returns < 0 for error case
19 * 2) Returns 0 for exit to user-space
20 * 3) Returns 1 to continue with next sepc
21 * 4) Returns 2 to continue with same sepc
22 * 5) Returns 3 to inject illegal instruction trap and continue
23 * 6) Returns 4 to inject virtual instruction trap and continue
24 *
25 * Use enum kvm_insn_return for return values
26 */
27 int (*func)(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn);
28 };
29
truly_illegal_insn(struct kvm_vcpu * vcpu,struct kvm_run * run,ulong insn)30 static int truly_illegal_insn(struct kvm_vcpu *vcpu, struct kvm_run *run,
31 ulong insn)
32 {
33 struct kvm_cpu_trap utrap = { 0 };
34
35 /* Redirect trap to Guest VCPU */
36 utrap.sepc = vcpu->arch.guest_context.sepc;
37 utrap.scause = EXC_INST_ILLEGAL;
38 utrap.stval = insn;
39 utrap.htval = 0;
40 utrap.htinst = 0;
41 kvm_riscv_vcpu_trap_redirect(vcpu, &utrap);
42
43 return 1;
44 }
45
truly_virtual_insn(struct kvm_vcpu * vcpu,struct kvm_run * run,ulong insn)46 static int truly_virtual_insn(struct kvm_vcpu *vcpu, struct kvm_run *run,
47 ulong insn)
48 {
49 struct kvm_cpu_trap utrap = { 0 };
50
51 /* Redirect trap to Guest VCPU */
52 utrap.sepc = vcpu->arch.guest_context.sepc;
53 utrap.scause = EXC_VIRTUAL_INST_FAULT;
54 utrap.stval = insn;
55 utrap.htval = 0;
56 utrap.htinst = 0;
57 kvm_riscv_vcpu_trap_redirect(vcpu, &utrap);
58
59 return 1;
60 }
61
62 /**
63 * kvm_riscv_vcpu_wfi -- Emulate wait for interrupt (WFI) behaviour
64 *
65 * @vcpu: The VCPU pointer
66 */
kvm_riscv_vcpu_wfi(struct kvm_vcpu * vcpu)67 void kvm_riscv_vcpu_wfi(struct kvm_vcpu *vcpu)
68 {
69 if (!kvm_arch_vcpu_runnable(vcpu)) {
70 kvm_vcpu_srcu_read_unlock(vcpu);
71 kvm_vcpu_halt(vcpu);
72 kvm_vcpu_srcu_read_lock(vcpu);
73 }
74 }
75
wfi_insn(struct kvm_vcpu * vcpu,struct kvm_run * run,ulong insn)76 static int wfi_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn)
77 {
78 vcpu->stat.wfi_exit_stat++;
79 kvm_riscv_vcpu_wfi(vcpu);
80 return KVM_INSN_CONTINUE_NEXT_SEPC;
81 }
82
wrs_insn(struct kvm_vcpu * vcpu,struct kvm_run * run,ulong insn)83 static int wrs_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn)
84 {
85 vcpu->stat.wrs_exit_stat++;
86 kvm_vcpu_on_spin(vcpu, vcpu->arch.guest_context.sstatus & SR_SPP);
87 return KVM_INSN_CONTINUE_NEXT_SEPC;
88 }
89
90 struct csr_func {
91 unsigned int base;
92 unsigned int count;
93 /*
94 * Possible return values are as same as "func" callback in
95 * "struct insn_func".
96 */
97 int (*func)(struct kvm_vcpu *vcpu, unsigned int csr_num,
98 unsigned long *val, unsigned long new_val,
99 unsigned long wr_mask);
100 };
101
seed_csr_rmw(struct kvm_vcpu * vcpu,unsigned int csr_num,unsigned long * val,unsigned long new_val,unsigned long wr_mask)102 static int seed_csr_rmw(struct kvm_vcpu *vcpu, unsigned int csr_num,
103 unsigned long *val, unsigned long new_val,
104 unsigned long wr_mask)
105 {
106 if (!riscv_isa_extension_available(vcpu->arch.isa, ZKR))
107 return KVM_INSN_ILLEGAL_TRAP;
108
109 return KVM_INSN_EXIT_TO_USER_SPACE;
110 }
111
112 static const struct csr_func csr_funcs[] = {
113 KVM_RISCV_VCPU_AIA_CSR_FUNCS
114 KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS
115 { .base = CSR_SEED, .count = 1, .func = seed_csr_rmw },
116 };
117
118 /**
119 * kvm_riscv_vcpu_csr_return -- Handle CSR read/write after user space
120 * emulation or in-kernel emulation
121 *
122 * @vcpu: The VCPU pointer
123 * @run: The VCPU run struct containing the CSR data
124 *
125 * Returns > 0 upon failure and 0 upon success
126 */
kvm_riscv_vcpu_csr_return(struct kvm_vcpu * vcpu,struct kvm_run * run)127 int kvm_riscv_vcpu_csr_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
128 {
129 ulong insn;
130
131 if (vcpu->arch.csr_decode.return_handled)
132 return 0;
133 vcpu->arch.csr_decode.return_handled = 1;
134
135 /* Update destination register for CSR reads */
136 insn = vcpu->arch.csr_decode.insn;
137 if ((insn >> SH_RD) & MASK_RX)
138 SET_RD(insn, &vcpu->arch.guest_context,
139 run->riscv_csr.ret_value);
140
141 /* Move to next instruction */
142 vcpu->arch.guest_context.sepc += INSN_LEN(insn);
143
144 return 0;
145 }
146
csr_insn(struct kvm_vcpu * vcpu,struct kvm_run * run,ulong insn)147 static int csr_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn)
148 {
149 int i, rc = KVM_INSN_ILLEGAL_TRAP;
150 unsigned int csr_num = insn >> SH_RS2;
151 unsigned int rs1_num = (insn >> SH_RS1) & MASK_RX;
152 ulong rs1_val = GET_RS1(insn, &vcpu->arch.guest_context);
153 const struct csr_func *tcfn, *cfn = NULL;
154 ulong val = 0, wr_mask = 0, new_val = 0;
155
156 /* Decode the CSR instruction */
157 switch (GET_FUNCT3(insn)) {
158 case GET_FUNCT3(INSN_MATCH_CSRRW):
159 wr_mask = -1UL;
160 new_val = rs1_val;
161 break;
162 case GET_FUNCT3(INSN_MATCH_CSRRS):
163 wr_mask = rs1_val;
164 new_val = -1UL;
165 break;
166 case GET_FUNCT3(INSN_MATCH_CSRRC):
167 wr_mask = rs1_val;
168 new_val = 0;
169 break;
170 case GET_FUNCT3(INSN_MATCH_CSRRWI):
171 wr_mask = -1UL;
172 new_val = rs1_num;
173 break;
174 case GET_FUNCT3(INSN_MATCH_CSRRSI):
175 wr_mask = rs1_num;
176 new_val = -1UL;
177 break;
178 case GET_FUNCT3(INSN_MATCH_CSRRCI):
179 wr_mask = rs1_num;
180 new_val = 0;
181 break;
182 default:
183 return rc;
184 }
185
186 /* Save instruction decode info */
187 vcpu->arch.csr_decode.insn = insn;
188 vcpu->arch.csr_decode.return_handled = 0;
189
190 /* Update CSR details in kvm_run struct */
191 run->riscv_csr.csr_num = csr_num;
192 run->riscv_csr.new_value = new_val;
193 run->riscv_csr.write_mask = wr_mask;
194 run->riscv_csr.ret_value = 0;
195
196 /* Find in-kernel CSR function */
197 for (i = 0; i < ARRAY_SIZE(csr_funcs); i++) {
198 tcfn = &csr_funcs[i];
199 if ((tcfn->base <= csr_num) &&
200 (csr_num < (tcfn->base + tcfn->count))) {
201 cfn = tcfn;
202 break;
203 }
204 }
205
206 /* First try in-kernel CSR emulation */
207 if (cfn && cfn->func) {
208 rc = cfn->func(vcpu, csr_num, &val, new_val, wr_mask);
209 if (rc > KVM_INSN_EXIT_TO_USER_SPACE) {
210 if (rc == KVM_INSN_CONTINUE_NEXT_SEPC) {
211 run->riscv_csr.ret_value = val;
212 vcpu->stat.csr_exit_kernel++;
213 kvm_riscv_vcpu_csr_return(vcpu, run);
214 rc = KVM_INSN_CONTINUE_SAME_SEPC;
215 }
216 return rc;
217 }
218 }
219
220 /* Exit to user-space for CSR emulation */
221 if (rc <= KVM_INSN_EXIT_TO_USER_SPACE) {
222 vcpu->stat.csr_exit_user++;
223 run->exit_reason = KVM_EXIT_RISCV_CSR;
224 }
225
226 return rc;
227 }
228
229 static const struct insn_func system_opcode_funcs[] = {
230 {
231 .mask = INSN_MASK_CSRRW,
232 .match = INSN_MATCH_CSRRW,
233 .func = csr_insn,
234 },
235 {
236 .mask = INSN_MASK_CSRRS,
237 .match = INSN_MATCH_CSRRS,
238 .func = csr_insn,
239 },
240 {
241 .mask = INSN_MASK_CSRRC,
242 .match = INSN_MATCH_CSRRC,
243 .func = csr_insn,
244 },
245 {
246 .mask = INSN_MASK_CSRRWI,
247 .match = INSN_MATCH_CSRRWI,
248 .func = csr_insn,
249 },
250 {
251 .mask = INSN_MASK_CSRRSI,
252 .match = INSN_MATCH_CSRRSI,
253 .func = csr_insn,
254 },
255 {
256 .mask = INSN_MASK_CSRRCI,
257 .match = INSN_MATCH_CSRRCI,
258 .func = csr_insn,
259 },
260 {
261 .mask = INSN_MASK_WFI,
262 .match = INSN_MATCH_WFI,
263 .func = wfi_insn,
264 },
265 {
266 .mask = INSN_MASK_WRS,
267 .match = INSN_MATCH_WRS,
268 .func = wrs_insn,
269 },
270 };
271
system_opcode_insn(struct kvm_vcpu * vcpu,struct kvm_run * run,ulong insn)272 static int system_opcode_insn(struct kvm_vcpu *vcpu, struct kvm_run *run,
273 ulong insn)
274 {
275 int i, rc = KVM_INSN_ILLEGAL_TRAP;
276 const struct insn_func *ifn;
277
278 for (i = 0; i < ARRAY_SIZE(system_opcode_funcs); i++) {
279 ifn = &system_opcode_funcs[i];
280 if ((insn & ifn->mask) == ifn->match) {
281 rc = ifn->func(vcpu, run, insn);
282 break;
283 }
284 }
285
286 switch (rc) {
287 case KVM_INSN_ILLEGAL_TRAP:
288 return truly_illegal_insn(vcpu, run, insn);
289 case KVM_INSN_VIRTUAL_TRAP:
290 return truly_virtual_insn(vcpu, run, insn);
291 case KVM_INSN_CONTINUE_NEXT_SEPC:
292 vcpu->arch.guest_context.sepc += INSN_LEN(insn);
293 break;
294 default:
295 break;
296 }
297
298 return (rc <= 0) ? rc : 1;
299 }
300
301 /**
302 * kvm_riscv_vcpu_virtual_insn -- Handle virtual instruction trap
303 *
304 * @vcpu: The VCPU pointer
305 * @run: The VCPU run struct containing the mmio data
306 * @trap: Trap details
307 *
308 * Returns > 0 to continue run-loop
309 * Returns 0 to exit run-loop and handle in user-space.
310 * Returns < 0 to report failure and exit run-loop
311 */
kvm_riscv_vcpu_virtual_insn(struct kvm_vcpu * vcpu,struct kvm_run * run,struct kvm_cpu_trap * trap)312 int kvm_riscv_vcpu_virtual_insn(struct kvm_vcpu *vcpu, struct kvm_run *run,
313 struct kvm_cpu_trap *trap)
314 {
315 unsigned long insn = trap->stval;
316 struct kvm_cpu_trap utrap = { 0 };
317 struct kvm_cpu_context *ct;
318
319 if (unlikely(INSN_IS_16BIT(insn))) {
320 if (insn == 0) {
321 ct = &vcpu->arch.guest_context;
322 insn = kvm_riscv_vcpu_unpriv_read(vcpu, true,
323 ct->sepc,
324 &utrap);
325 if (utrap.scause) {
326 utrap.sepc = ct->sepc;
327 kvm_riscv_vcpu_trap_redirect(vcpu, &utrap);
328 return 1;
329 }
330 }
331 if (INSN_IS_16BIT(insn))
332 return truly_illegal_insn(vcpu, run, insn);
333 }
334
335 switch ((insn & INSN_OPCODE_MASK) >> INSN_OPCODE_SHIFT) {
336 case INSN_OPCODE_SYSTEM:
337 return system_opcode_insn(vcpu, run, insn);
338 default:
339 return truly_illegal_insn(vcpu, run, insn);
340 }
341 }
342
343 /**
344 * kvm_riscv_vcpu_mmio_load -- Emulate MMIO load instruction
345 *
346 * @vcpu: The VCPU pointer
347 * @run: The VCPU run struct containing the mmio data
348 * @fault_addr: Guest physical address to load
349 * @htinst: Transformed encoding of the load instruction
350 *
351 * Returns > 0 to continue run-loop
352 * Returns 0 to exit run-loop and handle in user-space.
353 * Returns < 0 to report failure and exit run-loop
354 */
kvm_riscv_vcpu_mmio_load(struct kvm_vcpu * vcpu,struct kvm_run * run,unsigned long fault_addr,unsigned long htinst)355 int kvm_riscv_vcpu_mmio_load(struct kvm_vcpu *vcpu, struct kvm_run *run,
356 unsigned long fault_addr,
357 unsigned long htinst)
358 {
359 u8 data_buf[8];
360 unsigned long insn;
361 int shift = 0, len = 0, insn_len = 0;
362 struct kvm_cpu_trap utrap = { 0 };
363 struct kvm_cpu_context *ct = &vcpu->arch.guest_context;
364
365 /* Determine trapped instruction */
366 if (htinst & 0x1) {
367 /*
368 * Bit[0] == 1 implies trapped instruction value is
369 * transformed instruction or custom instruction.
370 */
371 insn = htinst | INSN_16BIT_MASK;
372 insn_len = (htinst & BIT(1)) ? INSN_LEN(insn) : 2;
373 } else {
374 /*
375 * Bit[0] == 0 implies trapped instruction value is
376 * zero or special value.
377 */
378 insn = kvm_riscv_vcpu_unpriv_read(vcpu, true, ct->sepc,
379 &utrap);
380 if (utrap.scause) {
381 /* Redirect trap if we failed to read instruction */
382 utrap.sepc = ct->sepc;
383 kvm_riscv_vcpu_trap_redirect(vcpu, &utrap);
384 return 1;
385 }
386 insn_len = INSN_LEN(insn);
387 }
388
389 /* Decode length of MMIO and shift */
390 if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
391 len = 4;
392 shift = 8 * (sizeof(ulong) - len);
393 } else if ((insn & INSN_MASK_LB) == INSN_MATCH_LB) {
394 len = 1;
395 shift = 8 * (sizeof(ulong) - len);
396 } else if ((insn & INSN_MASK_LBU) == INSN_MATCH_LBU) {
397 len = 1;
398 shift = 8 * (sizeof(ulong) - len);
399 #ifdef CONFIG_64BIT
400 } else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) {
401 len = 8;
402 shift = 8 * (sizeof(ulong) - len);
403 } else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) {
404 len = 4;
405 #endif
406 } else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) {
407 len = 2;
408 shift = 8 * (sizeof(ulong) - len);
409 } else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) {
410 len = 2;
411 #ifdef CONFIG_64BIT
412 } else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) {
413 len = 8;
414 shift = 8 * (sizeof(ulong) - len);
415 insn = RVC_RS2S(insn) << SH_RD;
416 } else if ((insn & INSN_MASK_C_LDSP) == INSN_MATCH_C_LDSP &&
417 ((insn >> SH_RD) & 0x1f)) {
418 len = 8;
419 shift = 8 * (sizeof(ulong) - len);
420 #endif
421 } else if ((insn & INSN_MASK_C_LW) == INSN_MATCH_C_LW) {
422 len = 4;
423 shift = 8 * (sizeof(ulong) - len);
424 insn = RVC_RS2S(insn) << SH_RD;
425 } else if ((insn & INSN_MASK_C_LWSP) == INSN_MATCH_C_LWSP &&
426 ((insn >> SH_RD) & 0x1f)) {
427 len = 4;
428 shift = 8 * (sizeof(ulong) - len);
429 } else {
430 return -EOPNOTSUPP;
431 }
432
433 /* Fault address should be aligned to length of MMIO */
434 if (fault_addr & (len - 1))
435 return -EIO;
436
437 /* Save instruction decode info */
438 vcpu->arch.mmio_decode.insn = insn;
439 vcpu->arch.mmio_decode.insn_len = insn_len;
440 vcpu->arch.mmio_decode.shift = shift;
441 vcpu->arch.mmio_decode.len = len;
442 vcpu->arch.mmio_decode.return_handled = 0;
443
444 /* Update MMIO details in kvm_run struct */
445 run->mmio.is_write = false;
446 run->mmio.phys_addr = fault_addr;
447 run->mmio.len = len;
448
449 /* Try to handle MMIO access in the kernel */
450 if (!kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_addr, len, data_buf)) {
451 /* Successfully handled MMIO access in the kernel so resume */
452 memcpy(run->mmio.data, data_buf, len);
453 vcpu->stat.mmio_exit_kernel++;
454 kvm_riscv_vcpu_mmio_return(vcpu, run);
455 return 1;
456 }
457
458 /* Exit to userspace for MMIO emulation */
459 vcpu->stat.mmio_exit_user++;
460 run->exit_reason = KVM_EXIT_MMIO;
461
462 return 0;
463 }
464
465 /**
466 * kvm_riscv_vcpu_mmio_store -- Emulate MMIO store instruction
467 *
468 * @vcpu: The VCPU pointer
469 * @run: The VCPU run struct containing the mmio data
470 * @fault_addr: Guest physical address to store
471 * @htinst: Transformed encoding of the store instruction
472 *
473 * Returns > 0 to continue run-loop
474 * Returns 0 to exit run-loop and handle in user-space.
475 * Returns < 0 to report failure and exit run-loop
476 */
kvm_riscv_vcpu_mmio_store(struct kvm_vcpu * vcpu,struct kvm_run * run,unsigned long fault_addr,unsigned long htinst)477 int kvm_riscv_vcpu_mmio_store(struct kvm_vcpu *vcpu, struct kvm_run *run,
478 unsigned long fault_addr,
479 unsigned long htinst)
480 {
481 u8 data8;
482 u16 data16;
483 u32 data32;
484 u64 data64;
485 ulong data;
486 unsigned long insn;
487 int len = 0, insn_len = 0;
488 struct kvm_cpu_trap utrap = { 0 };
489 struct kvm_cpu_context *ct = &vcpu->arch.guest_context;
490
491 /* Determine trapped instruction */
492 if (htinst & 0x1) {
493 /*
494 * Bit[0] == 1 implies trapped instruction value is
495 * transformed instruction or custom instruction.
496 */
497 insn = htinst | INSN_16BIT_MASK;
498 insn_len = (htinst & BIT(1)) ? INSN_LEN(insn) : 2;
499 } else {
500 /*
501 * Bit[0] == 0 implies trapped instruction value is
502 * zero or special value.
503 */
504 insn = kvm_riscv_vcpu_unpriv_read(vcpu, true, ct->sepc,
505 &utrap);
506 if (utrap.scause) {
507 /* Redirect trap if we failed to read instruction */
508 utrap.sepc = ct->sepc;
509 kvm_riscv_vcpu_trap_redirect(vcpu, &utrap);
510 return 1;
511 }
512 insn_len = INSN_LEN(insn);
513 }
514
515 data = GET_RS2(insn, &vcpu->arch.guest_context);
516 data8 = data16 = data32 = data64 = data;
517
518 if ((insn & INSN_MASK_SW) == INSN_MATCH_SW) {
519 len = 4;
520 } else if ((insn & INSN_MASK_SB) == INSN_MATCH_SB) {
521 len = 1;
522 #ifdef CONFIG_64BIT
523 } else if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) {
524 len = 8;
525 #endif
526 } else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) {
527 len = 2;
528 #ifdef CONFIG_64BIT
529 } else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
530 len = 8;
531 data64 = GET_RS2S(insn, &vcpu->arch.guest_context);
532 } else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP &&
533 ((insn >> SH_RD) & 0x1f)) {
534 len = 8;
535 data64 = GET_RS2C(insn, &vcpu->arch.guest_context);
536 #endif
537 } else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) {
538 len = 4;
539 data32 = GET_RS2S(insn, &vcpu->arch.guest_context);
540 } else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP &&
541 ((insn >> SH_RD) & 0x1f)) {
542 len = 4;
543 data32 = GET_RS2C(insn, &vcpu->arch.guest_context);
544 } else {
545 return -EOPNOTSUPP;
546 }
547
548 /* Fault address should be aligned to length of MMIO */
549 if (fault_addr & (len - 1))
550 return -EIO;
551
552 /* Save instruction decode info */
553 vcpu->arch.mmio_decode.insn = insn;
554 vcpu->arch.mmio_decode.insn_len = insn_len;
555 vcpu->arch.mmio_decode.shift = 0;
556 vcpu->arch.mmio_decode.len = len;
557 vcpu->arch.mmio_decode.return_handled = 0;
558
559 /* Copy data to kvm_run instance */
560 switch (len) {
561 case 1:
562 *((u8 *)run->mmio.data) = data8;
563 break;
564 case 2:
565 *((u16 *)run->mmio.data) = data16;
566 break;
567 case 4:
568 *((u32 *)run->mmio.data) = data32;
569 break;
570 case 8:
571 *((u64 *)run->mmio.data) = data64;
572 break;
573 default:
574 return -EOPNOTSUPP;
575 }
576
577 /* Update MMIO details in kvm_run struct */
578 run->mmio.is_write = true;
579 run->mmio.phys_addr = fault_addr;
580 run->mmio.len = len;
581
582 /* Try to handle MMIO access in the kernel */
583 if (!kvm_io_bus_write(vcpu, KVM_MMIO_BUS,
584 fault_addr, len, run->mmio.data)) {
585 /* Successfully handled MMIO access in the kernel so resume */
586 vcpu->stat.mmio_exit_kernel++;
587 kvm_riscv_vcpu_mmio_return(vcpu, run);
588 return 1;
589 }
590
591 /* Exit to userspace for MMIO emulation */
592 vcpu->stat.mmio_exit_user++;
593 run->exit_reason = KVM_EXIT_MMIO;
594
595 return 0;
596 }
597
598 /**
599 * kvm_riscv_vcpu_mmio_return -- Handle MMIO loads after user space emulation
600 * or in-kernel IO emulation
601 *
602 * @vcpu: The VCPU pointer
603 * @run: The VCPU run struct containing the mmio data
604 */
kvm_riscv_vcpu_mmio_return(struct kvm_vcpu * vcpu,struct kvm_run * run)605 int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
606 {
607 u8 data8;
608 u16 data16;
609 u32 data32;
610 u64 data64;
611 ulong insn;
612 int len, shift;
613
614 if (vcpu->arch.mmio_decode.return_handled)
615 return 0;
616
617 vcpu->arch.mmio_decode.return_handled = 1;
618 insn = vcpu->arch.mmio_decode.insn;
619
620 if (run->mmio.is_write)
621 goto done;
622
623 len = vcpu->arch.mmio_decode.len;
624 shift = vcpu->arch.mmio_decode.shift;
625
626 switch (len) {
627 case 1:
628 data8 = *((u8 *)run->mmio.data);
629 SET_RD(insn, &vcpu->arch.guest_context,
630 (ulong)data8 << shift >> shift);
631 break;
632 case 2:
633 data16 = *((u16 *)run->mmio.data);
634 SET_RD(insn, &vcpu->arch.guest_context,
635 (ulong)data16 << shift >> shift);
636 break;
637 case 4:
638 data32 = *((u32 *)run->mmio.data);
639 SET_RD(insn, &vcpu->arch.guest_context,
640 (ulong)data32 << shift >> shift);
641 break;
642 case 8:
643 data64 = *((u64 *)run->mmio.data);
644 SET_RD(insn, &vcpu->arch.guest_context,
645 (ulong)data64 << shift >> shift);
646 break;
647 default:
648 return -EOPNOTSUPP;
649 }
650
651 done:
652 /* Move to next instruction */
653 vcpu->arch.guest_context.sepc += vcpu->arch.mmio_decode.insn_len;
654
655 return 0;
656 }
657