tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

NVMM missing opcode REPE CMPS implementation



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



Home | Main Index | Thread Index | Old Index