aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kvm
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2016-06-15 14:29:47 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2016-06-15 17:58:17 -0400
commit258f3a2ea93ff7e322006c716cedc4fa3d861453 (patch)
tree06792df7de3f877db5af2850c454f36a18d11cec /arch/mips/kvm
parentd5cd26bcfc881f5443d510e3acd40b30d7b7d0df (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.c74
-rw-r--r--arch/mips/kvm/emulate.c109
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 */
37static int kvm_mips_trans_replace(struct kvm_vcpu *vcpu, u32 *opc, u32 replace) 29static 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
61int kvm_mips_trans_cache_index(u32 inst, u32 *opc, 54int 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 */
72int kvm_mips_trans_cache_va(u32 inst, u32 *opc, 67int 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
85int kvm_mips_trans_mfc0(u32 inst, u32 *opc, struct kvm_vcpu *vcpu) 80int 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
107int kvm_mips_trans_mtc0(u32 inst, u32 *opc, struct kvm_vcpu *vcpu) 103int 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
975enum emulation_result kvm_mips_emulate_CP0(u32 inst, u32 *opc, u32 cause, 975enum 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
1314enum emulation_result kvm_mips_emulate_store(u32 inst, u32 cause, 1310enum 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
1428enum emulation_result kvm_mips_emulate_load(u32 inst, u32 cause, 1421enum 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
1535enum emulation_result kvm_mips_emulate_cache(u32 inst, u32 *opc, 1525enum 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
2280enum emulation_result kvm_mips_handle_ri(u32 cause, u32 *opc, 2255enum 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