Dear folks, i stumbled on an instruction that NVMM couldn't code and thus couldn't emulate either. It was as stated the REPE CMPS (0xF3A7) instruction as stated in https://c9x.me/x86/html/file_module_x86_id_279.html and confirmed by disassembly by ndisasm (from nasm). Appended is the implementation of imentioned instruction together with its byte sized sibling 0xF3A6. When installing the modified libnvmm, qemu behaves like NVMM is not used. I think the implementation does the right thing but feel free to double check! Tested and found by NetBSD/amd64 9.99.74 (19 oct) on an Intel Celeron 2957U by executing: qemu-system-x86_64 -accel nvmm -nographic -netdev \ user,id=n0,tftp=/usr/mdec,bootfile=pxeboot_ia32.bin -device \ e1000,netdev=n0 -boot n With regards, Reinoud
Index: lib/libnvmm/libnvmm_x86.c =================================================================== RCS file: /cvsroot/src/lib/libnvmm/libnvmm_x86.c,v retrieving revision 1.40 diff -u -p -r1.40 libnvmm_x86.c --- lib/libnvmm/libnvmm_x86.c 5 Sep 2020 07:22:25 -0000 1.40 +++ lib/libnvmm/libnvmm_x86.c 29 Oct 2020 20:39:24 -0000 @@ -1051,6 +1051,7 @@ struct x86_opcode { bool movs:1; bool stos:1; bool lods:1; + bool cmps:1; bool szoverride:1; bool group1:1; bool group3:1; @@ -1463,6 +1464,26 @@ static const struct x86_opcode primary_o }, /* + * CMPS + */ + [0xA6] = { + /* Yb, Xb */ + .valid = true, + .cmps = true, + .szoverride = false, + .defsize = OPSIZE_BYTE, + .emul = &x86_emul_cmp + }, + [0xA7] = { + /* Yv, Xv */ + .valid = true, + .cmps = true, + .szoverride = true, + .defsize = -1, + .emul = &x86_emul_cmp + }, + + /* * STOS */ [0xAA] = { @@ -1871,6 +1892,35 @@ node_movs(struct x86_decode_fsm *fsm, st } /* + * Special node, for CMPS. Fake two displacements of zero on the source and + * destination registers. + * XXX coded as clone of movs as its similar in register usage + * XXX might be merged with node_movs() + */ +static int +node_cmps(struct x86_decode_fsm *fsm, struct x86_instr *instr) +{ + size_t adrsize; + + adrsize = instr->address_size; + + /* DS:RSI */ + instr->src.type = STORE_REG; + instr->src.u.reg = &gpr_map__special[1][2][adrsize-1]; + instr->src.disp.type = DISP_0; + + /* ES:RDI, force ES */ + instr->dst.type = STORE_REG; + instr->dst.u.reg = &gpr_map__special[1][3][adrsize-1]; + instr->dst.disp.type = DISP_0; + instr->dst.hardseg = NVMM_X64_SEG_ES; + + fsm_advance(fsm, 0, NULL); + + return 0; +} + +/* * Special node, for STOS and LODS. Fake a displacement of zero on the * destination register. */ @@ -2448,6 +2498,8 @@ node_primary_opcode(struct x86_decode_fs opcode = &primary_opcode_table[byte]; if (__predict_false(!opcode->valid)) { + printf("%s: opcode %02x is not marked valid in " \ + "primary_opcode_table[]\n", __func__, byte); return -1; } @@ -2470,6 +2522,8 @@ node_primary_opcode(struct x86_decode_fs fsm_advance(fsm, 1, node_stlo); } else if (opcode->movs) { fsm_advance(fsm, 1, node_movs); + } else if (opcode->cmps) { + fsm_advance(fsm, 1, node_cmps); } else { return -1; } @@ -2646,8 +2700,15 @@ x86_decode(uint8_t *inst_bytes, size_t i while (fsm.fn != NULL) { ret = (*fsm.fn)(&fsm, instr); - if (ret == -1) + if (ret == -1) { + printf("\n%s debug: unrecognized instruction found " \ + "with max length %ld : [ ", __func__, inst_len); + for (uint i = 0; i < inst_len; i++) + printf("%02x ", inst_bytes[i]); + printf("]\n"); + fflush(stdout); return -1; + } } instr->len = fsm.buf - inst_bytes;
Attachment:
signature.asc
Description: PGP signature