Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/riscv/kvm/vcpu_insn.c
51480 views
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
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
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
*/
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
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
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
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
*/
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
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
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
static bool is_load_guest_page_fault(unsigned long scause)
302
{
303
/**
304
* If a g-stage page fault occurs, the direct approach
305
* is to let the g-stage page fault handler handle it
306
* naturally, however, calling the g-stage page fault
307
* handler here seems rather strange.
308
* Considering this is a corner case, we can directly
309
* return to the guest and re-execute the same PC, this
310
* will trigger a g-stage page fault again and then the
311
* regular g-stage page fault handler will populate
312
* g-stage page table.
313
*/
314
return (scause == EXC_LOAD_GUEST_PAGE_FAULT);
315
}
316
317
/**
318
* kvm_riscv_vcpu_virtual_insn -- Handle virtual instruction trap
319
*
320
* @vcpu: The VCPU pointer
321
* @run: The VCPU run struct containing the mmio data
322
* @trap: Trap details
323
*
324
* Returns > 0 to continue run-loop
325
* Returns 0 to exit run-loop and handle in user-space.
326
* Returns < 0 to report failure and exit run-loop
327
*/
328
int kvm_riscv_vcpu_virtual_insn(struct kvm_vcpu *vcpu, struct kvm_run *run,
329
struct kvm_cpu_trap *trap)
330
{
331
unsigned long insn = trap->stval;
332
struct kvm_cpu_trap utrap = { 0 };
333
struct kvm_cpu_context *ct;
334
335
if (unlikely(INSN_IS_16BIT(insn))) {
336
if (insn == 0) {
337
ct = &vcpu->arch.guest_context;
338
insn = kvm_riscv_vcpu_unpriv_read(vcpu, true,
339
ct->sepc,
340
&utrap);
341
if (utrap.scause) {
342
if (is_load_guest_page_fault(utrap.scause))
343
return 1;
344
utrap.sepc = ct->sepc;
345
kvm_riscv_vcpu_trap_redirect(vcpu, &utrap);
346
return 1;
347
}
348
}
349
if (INSN_IS_16BIT(insn))
350
return truly_illegal_insn(vcpu, run, insn);
351
}
352
353
switch ((insn & INSN_OPCODE_MASK) >> INSN_OPCODE_SHIFT) {
354
case INSN_OPCODE_SYSTEM:
355
return system_opcode_insn(vcpu, run, insn);
356
default:
357
return truly_illegal_insn(vcpu, run, insn);
358
}
359
}
360
361
/**
362
* kvm_riscv_vcpu_mmio_load -- Emulate MMIO load instruction
363
*
364
* @vcpu: The VCPU pointer
365
* @run: The VCPU run struct containing the mmio data
366
* @fault_addr: Guest physical address to load
367
* @htinst: Transformed encoding of the load instruction
368
*
369
* Returns > 0 to continue run-loop
370
* Returns 0 to exit run-loop and handle in user-space.
371
* Returns < 0 to report failure and exit run-loop
372
*/
373
int kvm_riscv_vcpu_mmio_load(struct kvm_vcpu *vcpu, struct kvm_run *run,
374
unsigned long fault_addr,
375
unsigned long htinst)
376
{
377
u8 data_buf[8];
378
unsigned long insn;
379
int shift = 0, len = 0, insn_len = 0;
380
struct kvm_cpu_trap utrap = { 0 };
381
struct kvm_cpu_context *ct = &vcpu->arch.guest_context;
382
383
/* Determine trapped instruction */
384
if (htinst & 0x1) {
385
/*
386
* Bit[0] == 1 implies trapped instruction value is
387
* transformed instruction or custom instruction.
388
*/
389
insn = htinst | INSN_16BIT_MASK;
390
insn_len = (htinst & BIT(1)) ? INSN_LEN(insn) : 2;
391
} else {
392
/*
393
* Bit[0] == 0 implies trapped instruction value is
394
* zero or special value.
395
*/
396
insn = kvm_riscv_vcpu_unpriv_read(vcpu, true, ct->sepc,
397
&utrap);
398
if (utrap.scause) {
399
if (is_load_guest_page_fault(utrap.scause))
400
return 1;
401
/* Redirect trap if we failed to read instruction */
402
utrap.sepc = ct->sepc;
403
kvm_riscv_vcpu_trap_redirect(vcpu, &utrap);
404
return 1;
405
}
406
insn_len = INSN_LEN(insn);
407
}
408
409
/* Decode length of MMIO and shift */
410
if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
411
len = 4;
412
shift = 8 * (sizeof(ulong) - len);
413
} else if ((insn & INSN_MASK_LB) == INSN_MATCH_LB) {
414
len = 1;
415
shift = 8 * (sizeof(ulong) - len);
416
} else if ((insn & INSN_MASK_LBU) == INSN_MATCH_LBU) {
417
len = 1;
418
shift = 8 * (sizeof(ulong) - len);
419
#ifdef CONFIG_64BIT
420
} else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) {
421
len = 8;
422
shift = 8 * (sizeof(ulong) - len);
423
} else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) {
424
len = 4;
425
#endif
426
} else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) {
427
len = 2;
428
shift = 8 * (sizeof(ulong) - len);
429
} else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) {
430
len = 2;
431
#ifdef CONFIG_64BIT
432
} else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) {
433
len = 8;
434
shift = 8 * (sizeof(ulong) - len);
435
insn = RVC_RS2S(insn) << SH_RD;
436
} else if ((insn & INSN_MASK_C_LDSP) == INSN_MATCH_C_LDSP &&
437
((insn >> SH_RD) & 0x1f)) {
438
len = 8;
439
shift = 8 * (sizeof(ulong) - len);
440
#endif
441
} else if ((insn & INSN_MASK_C_LW) == INSN_MATCH_C_LW) {
442
len = 4;
443
shift = 8 * (sizeof(ulong) - len);
444
insn = RVC_RS2S(insn) << SH_RD;
445
} else if ((insn & INSN_MASK_C_LWSP) == INSN_MATCH_C_LWSP &&
446
((insn >> SH_RD) & 0x1f)) {
447
len = 4;
448
shift = 8 * (sizeof(ulong) - len);
449
} else {
450
return -EOPNOTSUPP;
451
}
452
453
/* Fault address should be aligned to length of MMIO */
454
if (fault_addr & (len - 1))
455
return -EIO;
456
457
/* Save instruction decode info */
458
vcpu->arch.mmio_decode.insn = insn;
459
vcpu->arch.mmio_decode.insn_len = insn_len;
460
vcpu->arch.mmio_decode.shift = shift;
461
vcpu->arch.mmio_decode.len = len;
462
vcpu->arch.mmio_decode.return_handled = 0;
463
464
/* Update MMIO details in kvm_run struct */
465
run->mmio.is_write = false;
466
run->mmio.phys_addr = fault_addr;
467
run->mmio.len = len;
468
469
/* Try to handle MMIO access in the kernel */
470
if (!kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_addr, len, data_buf)) {
471
/* Successfully handled MMIO access in the kernel so resume */
472
memcpy(run->mmio.data, data_buf, len);
473
vcpu->stat.mmio_exit_kernel++;
474
kvm_riscv_vcpu_mmio_return(vcpu, run);
475
return 1;
476
}
477
478
/* Exit to userspace for MMIO emulation */
479
vcpu->stat.mmio_exit_user++;
480
run->exit_reason = KVM_EXIT_MMIO;
481
482
return 0;
483
}
484
485
/**
486
* kvm_riscv_vcpu_mmio_store -- Emulate MMIO store instruction
487
*
488
* @vcpu: The VCPU pointer
489
* @run: The VCPU run struct containing the mmio data
490
* @fault_addr: Guest physical address to store
491
* @htinst: Transformed encoding of the store instruction
492
*
493
* Returns > 0 to continue run-loop
494
* Returns 0 to exit run-loop and handle in user-space.
495
* Returns < 0 to report failure and exit run-loop
496
*/
497
int kvm_riscv_vcpu_mmio_store(struct kvm_vcpu *vcpu, struct kvm_run *run,
498
unsigned long fault_addr,
499
unsigned long htinst)
500
{
501
u8 data8;
502
u16 data16;
503
u32 data32;
504
u64 data64;
505
ulong data;
506
unsigned long insn;
507
int len = 0, insn_len = 0;
508
struct kvm_cpu_trap utrap = { 0 };
509
struct kvm_cpu_context *ct = &vcpu->arch.guest_context;
510
511
/* Determine trapped instruction */
512
if (htinst & 0x1) {
513
/*
514
* Bit[0] == 1 implies trapped instruction value is
515
* transformed instruction or custom instruction.
516
*/
517
insn = htinst | INSN_16BIT_MASK;
518
insn_len = (htinst & BIT(1)) ? INSN_LEN(insn) : 2;
519
} else {
520
/*
521
* Bit[0] == 0 implies trapped instruction value is
522
* zero or special value.
523
*/
524
insn = kvm_riscv_vcpu_unpriv_read(vcpu, true, ct->sepc,
525
&utrap);
526
if (utrap.scause) {
527
if (is_load_guest_page_fault(utrap.scause))
528
return 1;
529
/* Redirect trap if we failed to read instruction */
530
utrap.sepc = ct->sepc;
531
kvm_riscv_vcpu_trap_redirect(vcpu, &utrap);
532
return 1;
533
}
534
insn_len = INSN_LEN(insn);
535
}
536
537
data = GET_RS2(insn, &vcpu->arch.guest_context);
538
data8 = data16 = data32 = data64 = data;
539
540
if ((insn & INSN_MASK_SW) == INSN_MATCH_SW) {
541
len = 4;
542
} else if ((insn & INSN_MASK_SB) == INSN_MATCH_SB) {
543
len = 1;
544
#ifdef CONFIG_64BIT
545
} else if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) {
546
len = 8;
547
#endif
548
} else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) {
549
len = 2;
550
#ifdef CONFIG_64BIT
551
} else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
552
len = 8;
553
data64 = GET_RS2S(insn, &vcpu->arch.guest_context);
554
} else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP &&
555
((insn >> SH_RD) & 0x1f)) {
556
len = 8;
557
data64 = GET_RS2C(insn, &vcpu->arch.guest_context);
558
#endif
559
} else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) {
560
len = 4;
561
data32 = GET_RS2S(insn, &vcpu->arch.guest_context);
562
} else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP &&
563
((insn >> SH_RD) & 0x1f)) {
564
len = 4;
565
data32 = GET_RS2C(insn, &vcpu->arch.guest_context);
566
} else {
567
return -EOPNOTSUPP;
568
}
569
570
/* Fault address should be aligned to length of MMIO */
571
if (fault_addr & (len - 1))
572
return -EIO;
573
574
/* Save instruction decode info */
575
vcpu->arch.mmio_decode.insn = insn;
576
vcpu->arch.mmio_decode.insn_len = insn_len;
577
vcpu->arch.mmio_decode.shift = 0;
578
vcpu->arch.mmio_decode.len = len;
579
vcpu->arch.mmio_decode.return_handled = 0;
580
581
/* Copy data to kvm_run instance */
582
switch (len) {
583
case 1:
584
*((u8 *)run->mmio.data) = data8;
585
break;
586
case 2:
587
*((u16 *)run->mmio.data) = data16;
588
break;
589
case 4:
590
*((u32 *)run->mmio.data) = data32;
591
break;
592
case 8:
593
*((u64 *)run->mmio.data) = data64;
594
break;
595
default:
596
return -EOPNOTSUPP;
597
}
598
599
/* Update MMIO details in kvm_run struct */
600
run->mmio.is_write = true;
601
run->mmio.phys_addr = fault_addr;
602
run->mmio.len = len;
603
604
/* Try to handle MMIO access in the kernel */
605
if (!kvm_io_bus_write(vcpu, KVM_MMIO_BUS,
606
fault_addr, len, run->mmio.data)) {
607
/* Successfully handled MMIO access in the kernel so resume */
608
vcpu->stat.mmio_exit_kernel++;
609
kvm_riscv_vcpu_mmio_return(vcpu, run);
610
return 1;
611
}
612
613
/* Exit to userspace for MMIO emulation */
614
vcpu->stat.mmio_exit_user++;
615
run->exit_reason = KVM_EXIT_MMIO;
616
617
return 0;
618
}
619
620
/**
621
* kvm_riscv_vcpu_mmio_return -- Handle MMIO loads after user space emulation
622
* or in-kernel IO emulation
623
*
624
* @vcpu: The VCPU pointer
625
* @run: The VCPU run struct containing the mmio data
626
*/
627
int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
628
{
629
u8 data8;
630
u16 data16;
631
u32 data32;
632
u64 data64;
633
ulong insn;
634
int len, shift;
635
636
if (vcpu->arch.mmio_decode.return_handled)
637
return 0;
638
639
vcpu->arch.mmio_decode.return_handled = 1;
640
insn = vcpu->arch.mmio_decode.insn;
641
642
if (run->mmio.is_write)
643
goto done;
644
645
len = vcpu->arch.mmio_decode.len;
646
shift = vcpu->arch.mmio_decode.shift;
647
648
switch (len) {
649
case 1:
650
data8 = *((u8 *)run->mmio.data);
651
SET_RD(insn, &vcpu->arch.guest_context,
652
(ulong)data8 << shift >> shift);
653
break;
654
case 2:
655
data16 = *((u16 *)run->mmio.data);
656
SET_RD(insn, &vcpu->arch.guest_context,
657
(ulong)data16 << shift >> shift);
658
break;
659
case 4:
660
data32 = *((u32 *)run->mmio.data);
661
SET_RD(insn, &vcpu->arch.guest_context,
662
(ulong)data32 << shift >> shift);
663
break;
664
case 8:
665
data64 = *((u64 *)run->mmio.data);
666
SET_RD(insn, &vcpu->arch.guest_context,
667
(ulong)data64 << shift >> shift);
668
break;
669
default:
670
return -EOPNOTSUPP;
671
}
672
673
done:
674
/* Move to next instruction */
675
vcpu->arch.guest_context.sepc += vcpu->arch.mmio_decode.insn_len;
676
677
return 0;
678
}
679
680