diff options
author | James Hogan <james.hogan@imgtec.com> | 2016-06-15 14:29:47 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2016-06-15 17:58:17 -0400 |
commit | 258f3a2ea93ff7e322006c716cedc4fa3d861453 (patch) | |
tree | 06792df7de3f877db5af2850c454f36a18d11cec /arch/mips/kvm | |
parent | d5cd26bcfc881f5443d510e3acd40b30d7b7d0df (diff) |
MIPS: KVM: Convert emulation to use asm/inst.h
Convert various MIPS KVM guest instruction emulation functions to decode
instructions (and encode translations) using the union mips_instruction
and related enumerations in asm/inst.h rather than #defines and
hardcoded values.
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Acked-by: Ralf Baechle <ralf@linux-mips.org>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Radim Krčmář <rkrcmar@redhat.com>
Cc: linux-mips@linux-mips.org
Cc: kvm@vger.kernel.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/mips/kvm')
-rw-r--r-- | arch/mips/kvm/dyntrans.c | 74 | ||||
-rw-r--r-- | arch/mips/kvm/emulate.c | 109 |
2 files changed, 79 insertions, 104 deletions
diff --git a/arch/mips/kvm/dyntrans.c b/arch/mips/kvm/dyntrans.c index eb6e0d17a668..a3031dae8d1b 100644 --- a/arch/mips/kvm/dyntrans.c +++ b/arch/mips/kvm/dyntrans.c | |||
@@ -20,21 +20,14 @@ | |||
20 | 20 | ||
21 | #include "commpage.h" | 21 | #include "commpage.h" |
22 | 22 | ||
23 | #define SYNCI_TEMPLATE 0x041f0000 | ||
24 | #define SYNCI_BASE(x) (((x) >> 21) & 0x1f) | ||
25 | #define SYNCI_OFFSET ((x) & 0xffff) | ||
26 | |||
27 | #define LW_TEMPLATE 0x8c000000 | ||
28 | #define CLEAR_TEMPLATE 0x00000020 | ||
29 | #define SW_TEMPLATE 0xac000000 | ||
30 | |||
31 | /** | 23 | /** |
32 | * kvm_mips_trans_replace() - Replace trapping instruction in guest memory. | 24 | * kvm_mips_trans_replace() - Replace trapping instruction in guest memory. |
33 | * @vcpu: Virtual CPU. | 25 | * @vcpu: Virtual CPU. |
34 | * @opc: PC of instruction to replace. | 26 | * @opc: PC of instruction to replace. |
35 | * @replace: Instruction to write | 27 | * @replace: Instruction to write |
36 | */ | 28 | */ |
37 | static int kvm_mips_trans_replace(struct kvm_vcpu *vcpu, u32 *opc, u32 replace) | 29 | static int kvm_mips_trans_replace(struct kvm_vcpu *vcpu, u32 *opc, |
30 | union mips_instruction replace) | ||
38 | { | 31 | { |
39 | unsigned long kseg0_opc, flags; | 32 | unsigned long kseg0_opc, flags; |
40 | 33 | ||
@@ -58,63 +51,68 @@ static int kvm_mips_trans_replace(struct kvm_vcpu *vcpu, u32 *opc, u32 replace) | |||
58 | return 0; | 51 | return 0; |
59 | } | 52 | } |
60 | 53 | ||
61 | int kvm_mips_trans_cache_index(u32 inst, u32 *opc, | 54 | int kvm_mips_trans_cache_index(union mips_instruction inst, u32 *opc, |
62 | struct kvm_vcpu *vcpu) | 55 | struct kvm_vcpu *vcpu) |
63 | { | 56 | { |
57 | union mips_instruction nop_inst = { 0 }; | ||
58 | |||
64 | /* Replace the CACHE instruction, with a NOP */ | 59 | /* Replace the CACHE instruction, with a NOP */ |
65 | return kvm_mips_trans_replace(vcpu, opc, 0x00000000); | 60 | return kvm_mips_trans_replace(vcpu, opc, nop_inst); |
66 | } | 61 | } |
67 | 62 | ||
68 | /* | 63 | /* |
69 | * Address based CACHE instructions are transformed into synci(s). A little | 64 | * Address based CACHE instructions are transformed into synci(s). A little |
70 | * heavy for just D-cache invalidates, but avoids an expensive trap | 65 | * heavy for just D-cache invalidates, but avoids an expensive trap |
71 | */ | 66 | */ |
72 | int kvm_mips_trans_cache_va(u32 inst, u32 *opc, | 67 | int kvm_mips_trans_cache_va(union mips_instruction inst, u32 *opc, |
73 | struct kvm_vcpu *vcpu) | 68 | struct kvm_vcpu *vcpu) |
74 | { | 69 | { |
75 | u32 synci_inst = SYNCI_TEMPLATE, base, offset; | 70 | union mips_instruction synci_inst = { 0 }; |
76 | 71 | ||
77 | base = (inst >> 21) & 0x1f; | 72 | synci_inst.i_format.opcode = bcond_op; |
78 | offset = inst & 0xffff; | 73 | synci_inst.i_format.rs = inst.i_format.rs; |
79 | synci_inst |= (base << 21); | 74 | synci_inst.i_format.rt = synci_op; |
80 | synci_inst |= offset; | 75 | synci_inst.i_format.simmediate = inst.i_format.simmediate; |
81 | 76 | ||
82 | return kvm_mips_trans_replace(vcpu, opc, synci_inst); | 77 | return kvm_mips_trans_replace(vcpu, opc, synci_inst); |
83 | } | 78 | } |
84 | 79 | ||
85 | int kvm_mips_trans_mfc0(u32 inst, u32 *opc, struct kvm_vcpu *vcpu) | 80 | int kvm_mips_trans_mfc0(union mips_instruction inst, u32 *opc, |
81 | struct kvm_vcpu *vcpu) | ||
86 | { | 82 | { |
87 | u32 rt, rd, sel; | 83 | union mips_instruction mfc0_inst = { 0 }; |
88 | u32 mfc0_inst; | 84 | u32 rd, sel; |
89 | 85 | ||
90 | rt = (inst >> 16) & 0x1f; | 86 | rd = inst.c0r_format.rd; |
91 | rd = (inst >> 11) & 0x1f; | 87 | sel = inst.c0r_format.sel; |
92 | sel = inst & 0x7; | ||
93 | 88 | ||
94 | if ((rd == MIPS_CP0_ERRCTL) && (sel == 0)) { | 89 | if (rd == MIPS_CP0_ERRCTL && sel == 0) { |
95 | mfc0_inst = CLEAR_TEMPLATE; | 90 | mfc0_inst.r_format.opcode = spec_op; |
96 | mfc0_inst |= ((rt & 0x1f) << 11); | 91 | mfc0_inst.r_format.rd = inst.c0r_format.rt; |
92 | mfc0_inst.r_format.func = add_op; | ||
97 | } else { | 93 | } else { |
98 | mfc0_inst = LW_TEMPLATE; | 94 | mfc0_inst.i_format.opcode = lw_op; |
99 | mfc0_inst |= ((rt & 0x1f) << 16); | 95 | mfc0_inst.i_format.rt = inst.c0r_format.rt; |
100 | mfc0_inst |= offsetof(struct kvm_mips_commpage, | 96 | mfc0_inst.i_format.simmediate = |
101 | cop0.reg[rd][sel]); | 97 | offsetof(struct kvm_mips_commpage, cop0.reg[rd][sel]); |
102 | } | 98 | } |
103 | 99 | ||
104 | return kvm_mips_trans_replace(vcpu, opc, mfc0_inst); | 100 | return kvm_mips_trans_replace(vcpu, opc, mfc0_inst); |
105 | } | 101 | } |
106 | 102 | ||
107 | int kvm_mips_trans_mtc0(u32 inst, u32 *opc, struct kvm_vcpu *vcpu) | 103 | int kvm_mips_trans_mtc0(union mips_instruction inst, u32 *opc, |
104 | struct kvm_vcpu *vcpu) | ||
108 | { | 105 | { |
109 | u32 rt, rd, sel; | 106 | union mips_instruction mtc0_inst = { 0 }; |
110 | u32 mtc0_inst = SW_TEMPLATE; | 107 | u32 rd, sel; |
111 | 108 | ||
112 | rt = (inst >> 16) & 0x1f; | 109 | rd = inst.c0r_format.rd; |
113 | rd = (inst >> 11) & 0x1f; | 110 | sel = inst.c0r_format.sel; |
114 | sel = inst & 0x7; | ||
115 | 111 | ||
116 | mtc0_inst |= ((rt & 0x1f) << 16); | 112 | mtc0_inst.i_format.opcode = sw_op; |
117 | mtc0_inst |= offsetof(struct kvm_mips_commpage, cop0.reg[rd][sel]); | 113 | mtc0_inst.i_format.rt = inst.c0r_format.rt; |
114 | mtc0_inst.i_format.simmediate = | ||
115 | offsetof(struct kvm_mips_commpage, cop0.reg[rd][sel]); | ||
118 | 116 | ||
119 | return kvm_mips_trans_replace(vcpu, opc, mtc0_inst); | 117 | return kvm_mips_trans_replace(vcpu, opc, mtc0_inst); |
120 | } | 118 | } |
diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c index ff4072c2b25e..80bb6212a067 100644 --- a/arch/mips/kvm/emulate.c +++ b/arch/mips/kvm/emulate.c | |||
@@ -972,13 +972,14 @@ unsigned int kvm_mips_config5_wrmask(struct kvm_vcpu *vcpu) | |||
972 | return mask; | 972 | return mask; |
973 | } | 973 | } |
974 | 974 | ||
975 | enum emulation_result kvm_mips_emulate_CP0(u32 inst, u32 *opc, u32 cause, | 975 | enum emulation_result kvm_mips_emulate_CP0(union mips_instruction inst, |
976 | u32 *opc, u32 cause, | ||
976 | struct kvm_run *run, | 977 | struct kvm_run *run, |
977 | struct kvm_vcpu *vcpu) | 978 | struct kvm_vcpu *vcpu) |
978 | { | 979 | { |
979 | struct mips_coproc *cop0 = vcpu->arch.cop0; | 980 | struct mips_coproc *cop0 = vcpu->arch.cop0; |
980 | enum emulation_result er = EMULATE_DONE; | 981 | enum emulation_result er = EMULATE_DONE; |
981 | u32 rt, rd, copz, sel, co_bit, op; | 982 | u32 rt, rd, sel; |
982 | unsigned long curr_pc; | 983 | unsigned long curr_pc; |
983 | 984 | ||
984 | /* | 985 | /* |
@@ -990,16 +991,8 @@ enum emulation_result kvm_mips_emulate_CP0(u32 inst, u32 *opc, u32 cause, | |||
990 | if (er == EMULATE_FAIL) | 991 | if (er == EMULATE_FAIL) |
991 | return er; | 992 | return er; |
992 | 993 | ||
993 | copz = (inst >> 21) & 0x1f; | 994 | if (inst.co_format.co) { |
994 | rt = (inst >> 16) & 0x1f; | 995 | switch (inst.co_format.func) { |
995 | rd = (inst >> 11) & 0x1f; | ||
996 | sel = inst & 0x7; | ||
997 | co_bit = (inst >> 25) & 1; | ||
998 | |||
999 | if (co_bit) { | ||
1000 | op = (inst) & 0xff; | ||
1001 | |||
1002 | switch (op) { | ||
1003 | case tlbr_op: /* Read indexed TLB entry */ | 996 | case tlbr_op: /* Read indexed TLB entry */ |
1004 | er = kvm_mips_emul_tlbr(vcpu); | 997 | er = kvm_mips_emul_tlbr(vcpu); |
1005 | break; | 998 | break; |
@@ -1018,13 +1011,16 @@ enum emulation_result kvm_mips_emulate_CP0(u32 inst, u32 *opc, u32 cause, | |||
1018 | case eret_op: | 1011 | case eret_op: |
1019 | er = kvm_mips_emul_eret(vcpu); | 1012 | er = kvm_mips_emul_eret(vcpu); |
1020 | goto dont_update_pc; | 1013 | goto dont_update_pc; |
1021 | break; | ||
1022 | case wait_op: | 1014 | case wait_op: |
1023 | er = kvm_mips_emul_wait(vcpu); | 1015 | er = kvm_mips_emul_wait(vcpu); |
1024 | break; | 1016 | break; |
1025 | } | 1017 | } |
1026 | } else { | 1018 | } else { |
1027 | switch (copz) { | 1019 | rt = inst.c0r_format.rt; |
1020 | rd = inst.c0r_format.rd; | ||
1021 | sel = inst.c0r_format.sel; | ||
1022 | |||
1023 | switch (inst.c0r_format.rs) { | ||
1028 | case mfc_op: | 1024 | case mfc_op: |
1029 | #ifdef CONFIG_KVM_MIPS_DEBUG_COP0_COUNTERS | 1025 | #ifdef CONFIG_KVM_MIPS_DEBUG_COP0_COUNTERS |
1030 | cop0->stat[rd][sel]++; | 1026 | cop0->stat[rd][sel]++; |
@@ -1258,7 +1254,7 @@ enum emulation_result kvm_mips_emulate_CP0(u32 inst, u32 *opc, u32 cause, | |||
1258 | vcpu->arch.gprs[rt] = | 1254 | vcpu->arch.gprs[rt] = |
1259 | kvm_read_c0_guest_status(cop0); | 1255 | kvm_read_c0_guest_status(cop0); |
1260 | /* EI */ | 1256 | /* EI */ |
1261 | if (inst & 0x20) { | 1257 | if (inst.mfmc0_format.sc) { |
1262 | kvm_debug("[%#lx] mfmc0_op: EI\n", | 1258 | kvm_debug("[%#lx] mfmc0_op: EI\n", |
1263 | vcpu->arch.pc); | 1259 | vcpu->arch.pc); |
1264 | kvm_set_c0_guest_status(cop0, ST0_IE); | 1260 | kvm_set_c0_guest_status(cop0, ST0_IE); |
@@ -1290,7 +1286,7 @@ enum emulation_result kvm_mips_emulate_CP0(u32 inst, u32 *opc, u32 cause, | |||
1290 | break; | 1286 | break; |
1291 | default: | 1287 | default: |
1292 | kvm_err("[%#lx]MachEmulateCP0: unsupported COP0, copz: 0x%x\n", | 1288 | kvm_err("[%#lx]MachEmulateCP0: unsupported COP0, copz: 0x%x\n", |
1293 | vcpu->arch.pc, copz); | 1289 | vcpu->arch.pc, inst.c0r_format.rs); |
1294 | er = EMULATE_FAIL; | 1290 | er = EMULATE_FAIL; |
1295 | break; | 1291 | break; |
1296 | } | 1292 | } |
@@ -1311,13 +1307,13 @@ dont_update_pc: | |||
1311 | return er; | 1307 | return er; |
1312 | } | 1308 | } |
1313 | 1309 | ||
1314 | enum emulation_result kvm_mips_emulate_store(u32 inst, u32 cause, | 1310 | enum emulation_result kvm_mips_emulate_store(union mips_instruction inst, |
1311 | u32 cause, | ||
1315 | struct kvm_run *run, | 1312 | struct kvm_run *run, |
1316 | struct kvm_vcpu *vcpu) | 1313 | struct kvm_vcpu *vcpu) |
1317 | { | 1314 | { |
1318 | enum emulation_result er = EMULATE_DO_MMIO; | 1315 | enum emulation_result er = EMULATE_DO_MMIO; |
1319 | u32 op, base, rt; | 1316 | u32 rt; |
1320 | s16 offset; | ||
1321 | u32 bytes; | 1317 | u32 bytes; |
1322 | void *data = run->mmio.data; | 1318 | void *data = run->mmio.data; |
1323 | unsigned long curr_pc; | 1319 | unsigned long curr_pc; |
@@ -1331,12 +1327,9 @@ enum emulation_result kvm_mips_emulate_store(u32 inst, u32 cause, | |||
1331 | if (er == EMULATE_FAIL) | 1327 | if (er == EMULATE_FAIL) |
1332 | return er; | 1328 | return er; |
1333 | 1329 | ||
1334 | rt = (inst >> 16) & 0x1f; | 1330 | rt = inst.i_format.rt; |
1335 | base = (inst >> 21) & 0x1f; | ||
1336 | offset = (s16)inst; | ||
1337 | op = (inst >> 26) & 0x3f; | ||
1338 | 1331 | ||
1339 | switch (op) { | 1332 | switch (inst.i_format.opcode) { |
1340 | case sb_op: | 1333 | case sb_op: |
1341 | bytes = 1; | 1334 | bytes = 1; |
1342 | if (bytes > sizeof(run->mmio.data)) { | 1335 | if (bytes > sizeof(run->mmio.data)) { |
@@ -1413,7 +1406,7 @@ enum emulation_result kvm_mips_emulate_store(u32 inst, u32 cause, | |||
1413 | 1406 | ||
1414 | default: | 1407 | default: |
1415 | kvm_err("Store not yet supported (inst=0x%08x)\n", | 1408 | kvm_err("Store not yet supported (inst=0x%08x)\n", |
1416 | inst); | 1409 | inst.word); |
1417 | er = EMULATE_FAIL; | 1410 | er = EMULATE_FAIL; |
1418 | break; | 1411 | break; |
1419 | } | 1412 | } |
@@ -1425,19 +1418,16 @@ enum emulation_result kvm_mips_emulate_store(u32 inst, u32 cause, | |||
1425 | return er; | 1418 | return er; |
1426 | } | 1419 | } |
1427 | 1420 | ||
1428 | enum emulation_result kvm_mips_emulate_load(u32 inst, u32 cause, | 1421 | enum emulation_result kvm_mips_emulate_load(union mips_instruction inst, |
1429 | struct kvm_run *run, | 1422 | u32 cause, struct kvm_run *run, |
1430 | struct kvm_vcpu *vcpu) | 1423 | struct kvm_vcpu *vcpu) |
1431 | { | 1424 | { |
1432 | enum emulation_result er = EMULATE_DO_MMIO; | 1425 | enum emulation_result er = EMULATE_DO_MMIO; |
1433 | u32 op, base, rt; | 1426 | u32 op, rt; |
1434 | s16 offset; | ||
1435 | u32 bytes; | 1427 | u32 bytes; |
1436 | 1428 | ||
1437 | rt = (inst >> 16) & 0x1f; | 1429 | rt = inst.i_format.rt; |
1438 | base = (inst >> 21) & 0x1f; | 1430 | op = inst.i_format.opcode; |
1439 | offset = (s16)inst; | ||
1440 | op = (inst >> 26) & 0x3f; | ||
1441 | 1431 | ||
1442 | vcpu->arch.pending_load_cause = cause; | 1432 | vcpu->arch.pending_load_cause = cause; |
1443 | vcpu->arch.io_gpr = rt; | 1433 | vcpu->arch.io_gpr = rt; |
@@ -1524,7 +1514,7 @@ enum emulation_result kvm_mips_emulate_load(u32 inst, u32 cause, | |||
1524 | 1514 | ||
1525 | default: | 1515 | default: |
1526 | kvm_err("Load not yet supported (inst=0x%08x)\n", | 1516 | kvm_err("Load not yet supported (inst=0x%08x)\n", |
1527 | inst); | 1517 | inst.word); |
1528 | er = EMULATE_FAIL; | 1518 | er = EMULATE_FAIL; |
1529 | break; | 1519 | break; |
1530 | } | 1520 | } |
@@ -1532,8 +1522,8 @@ enum emulation_result kvm_mips_emulate_load(u32 inst, u32 cause, | |||
1532 | return er; | 1522 | return er; |
1533 | } | 1523 | } |
1534 | 1524 | ||
1535 | enum emulation_result kvm_mips_emulate_cache(u32 inst, u32 *opc, | 1525 | enum emulation_result kvm_mips_emulate_cache(union mips_instruction inst, |
1536 | u32 cause, | 1526 | u32 *opc, u32 cause, |
1537 | struct kvm_run *run, | 1527 | struct kvm_run *run, |
1538 | struct kvm_vcpu *vcpu) | 1528 | struct kvm_vcpu *vcpu) |
1539 | { | 1529 | { |
@@ -1554,9 +1544,9 @@ enum emulation_result kvm_mips_emulate_cache(u32 inst, u32 *opc, | |||
1554 | if (er == EMULATE_FAIL) | 1544 | if (er == EMULATE_FAIL) |
1555 | return er; | 1545 | return er; |
1556 | 1546 | ||
1557 | base = (inst >> 21) & 0x1f; | 1547 | base = inst.i_format.rs; |
1558 | op_inst = (inst >> 16) & 0x1f; | 1548 | op_inst = inst.i_format.rt; |
1559 | offset = (s16)inst; | 1549 | offset = inst.i_format.simmediate; |
1560 | cache = op_inst & CacheOp_Cache; | 1550 | cache = op_inst & CacheOp_Cache; |
1561 | op = op_inst & CacheOp_Op; | 1551 | op = op_inst & CacheOp_Op; |
1562 | 1552 | ||
@@ -1693,16 +1683,16 @@ enum emulation_result kvm_mips_emulate_inst(u32 cause, u32 *opc, | |||
1693 | struct kvm_run *run, | 1683 | struct kvm_run *run, |
1694 | struct kvm_vcpu *vcpu) | 1684 | struct kvm_vcpu *vcpu) |
1695 | { | 1685 | { |
1686 | union mips_instruction inst; | ||
1696 | enum emulation_result er = EMULATE_DONE; | 1687 | enum emulation_result er = EMULATE_DONE; |
1697 | u32 inst; | ||
1698 | 1688 | ||
1699 | /* Fetch the instruction. */ | 1689 | /* Fetch the instruction. */ |
1700 | if (cause & CAUSEF_BD) | 1690 | if (cause & CAUSEF_BD) |
1701 | opc += 1; | 1691 | opc += 1; |
1702 | 1692 | ||
1703 | inst = kvm_get_inst(opc, vcpu); | 1693 | inst.word = kvm_get_inst(opc, vcpu); |
1704 | 1694 | ||
1705 | switch (((union mips_instruction)inst).r_format.opcode) { | 1695 | switch (inst.r_format.opcode) { |
1706 | case cop0_op: | 1696 | case cop0_op: |
1707 | er = kvm_mips_emulate_CP0(inst, opc, cause, run, vcpu); | 1697 | er = kvm_mips_emulate_CP0(inst, opc, cause, run, vcpu); |
1708 | break; | 1698 | break; |
@@ -1727,7 +1717,7 @@ enum emulation_result kvm_mips_emulate_inst(u32 cause, u32 *opc, | |||
1727 | 1717 | ||
1728 | default: | 1718 | default: |
1729 | kvm_err("Instruction emulation not supported (%p/%#x)\n", opc, | 1719 | kvm_err("Instruction emulation not supported (%p/%#x)\n", opc, |
1730 | inst); | 1720 | inst.word); |
1731 | kvm_arch_vcpu_dump_regs(vcpu); | 1721 | kvm_arch_vcpu_dump_regs(vcpu); |
1732 | er = EMULATE_FAIL; | 1722 | er = EMULATE_FAIL; |
1733 | break; | 1723 | break; |
@@ -2262,21 +2252,6 @@ enum emulation_result kvm_mips_emulate_msadis_exc(u32 cause, | |||
2262 | return er; | 2252 | return er; |
2263 | } | 2253 | } |
2264 | 2254 | ||
2265 | /* ll/sc, rdhwr, sync emulation */ | ||
2266 | |||
2267 | #define OPCODE 0xfc000000 | ||
2268 | #define BASE 0x03e00000 | ||
2269 | #define RT 0x001f0000 | ||
2270 | #define OFFSET 0x0000ffff | ||
2271 | #define LL 0xc0000000 | ||
2272 | #define SC 0xe0000000 | ||
2273 | #define SPEC0 0x00000000 | ||
2274 | #define SPEC3 0x7c000000 | ||
2275 | #define RD 0x0000f800 | ||
2276 | #define FUNC 0x0000003f | ||
2277 | #define SYNC 0x0000000f | ||
2278 | #define RDHWR 0x0000003b | ||
2279 | |||
2280 | enum emulation_result kvm_mips_handle_ri(u32 cause, u32 *opc, | 2255 | enum emulation_result kvm_mips_handle_ri(u32 cause, u32 *opc, |
2281 | struct kvm_run *run, | 2256 | struct kvm_run *run, |
2282 | struct kvm_vcpu *vcpu) | 2257 | struct kvm_vcpu *vcpu) |
@@ -2285,7 +2260,7 @@ enum emulation_result kvm_mips_handle_ri(u32 cause, u32 *opc, | |||
2285 | struct kvm_vcpu_arch *arch = &vcpu->arch; | 2260 | struct kvm_vcpu_arch *arch = &vcpu->arch; |
2286 | enum emulation_result er = EMULATE_DONE; | 2261 | enum emulation_result er = EMULATE_DONE; |
2287 | unsigned long curr_pc; | 2262 | unsigned long curr_pc; |
2288 | u32 inst; | 2263 | union mips_instruction inst; |
2289 | 2264 | ||
2290 | /* | 2265 | /* |
2291 | * Update PC and hold onto current PC in case there is | 2266 | * Update PC and hold onto current PC in case there is |
@@ -2300,18 +2275,19 @@ enum emulation_result kvm_mips_handle_ri(u32 cause, u32 *opc, | |||
2300 | if (cause & CAUSEF_BD) | 2275 | if (cause & CAUSEF_BD) |
2301 | opc += 1; | 2276 | opc += 1; |
2302 | 2277 | ||
2303 | inst = kvm_get_inst(opc, vcpu); | 2278 | inst.word = kvm_get_inst(opc, vcpu); |
2304 | 2279 | ||
2305 | if (inst == KVM_INVALID_INST) { | 2280 | if (inst.word == KVM_INVALID_INST) { |
2306 | kvm_err("%s: Cannot get inst @ %p\n", __func__, opc); | 2281 | kvm_err("%s: Cannot get inst @ %p\n", __func__, opc); |
2307 | return EMULATE_FAIL; | 2282 | return EMULATE_FAIL; |
2308 | } | 2283 | } |
2309 | 2284 | ||
2310 | if ((inst & OPCODE) == SPEC3 && (inst & FUNC) == RDHWR) { | 2285 | if (inst.r_format.opcode == spec3_op && |
2286 | inst.r_format.func == rdhwr_op) { | ||
2311 | int usermode = !KVM_GUEST_KERNEL_MODE(vcpu); | 2287 | int usermode = !KVM_GUEST_KERNEL_MODE(vcpu); |
2312 | int rd = (inst & RD) >> 11; | 2288 | int rd = inst.r_format.rd; |
2313 | int rt = (inst & RT) >> 16; | 2289 | int rt = inst.r_format.rt; |
2314 | int sel = (inst >> 6) & 0x7; | 2290 | int sel = inst.r_format.re & 0x7; |
2315 | 2291 | ||
2316 | /* If usermode, check RDHWR rd is allowed by guest HWREna */ | 2292 | /* If usermode, check RDHWR rd is allowed by guest HWREna */ |
2317 | if (usermode && !(kvm_read_c0_guest_hwrena(cop0) & BIT(rd))) { | 2293 | if (usermode && !(kvm_read_c0_guest_hwrena(cop0) & BIT(rd))) { |
@@ -2352,7 +2328,8 @@ enum emulation_result kvm_mips_handle_ri(u32 cause, u32 *opc, | |||
2352 | trace_kvm_hwr(vcpu, KVM_TRACE_RDHWR, KVM_TRACE_HWR(rd, sel), | 2328 | trace_kvm_hwr(vcpu, KVM_TRACE_RDHWR, KVM_TRACE_HWR(rd, sel), |
2353 | vcpu->arch.gprs[rt]); | 2329 | vcpu->arch.gprs[rt]); |
2354 | } else { | 2330 | } else { |
2355 | kvm_debug("Emulate RI not supported @ %p: %#x\n", opc, inst); | 2331 | kvm_debug("Emulate RI not supported @ %p: %#x\n", |
2332 | opc, inst.word); | ||
2356 | goto emulate_ri; | 2333 | goto emulate_ri; |
2357 | } | 2334 | } |
2358 | 2335 | ||