tech-kern archive

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

NVMM missing opcode REPE CMPS implementation, version 2



Dear folks,

I've reworked the patch using the feedback I got from Maxime and had to
refactor some minor parts in the other code. I'm in the process of writing the
test-cases now but would like feedback for this solution in the meantime. It
ought now give a proper REPE memory assist implementation. It could use some
minor enhancements still though.

With regards,
Reinoud
Index: libnvmm_x86.c
===================================================================
RCS file: /cvsroot/src/lib/libnvmm/libnvmm_x86.c,v
retrieving revision 1.42
diff -u -p -r1.42 libnvmm_x86.c
--- libnvmm_x86.c	31 Oct 2020 15:44:01 -0000	1.42
+++ libnvmm_x86.c	31 Oct 2020 22:55:45 -0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: libnvmm_x86.c,v 1.42 2020/10/31 15:44:01 reinoud Exp $	*/
+/*	$NetBSD: libnvmm_x86.c,v 1.41 2020/10/30 21:06:13 reinoud Exp $	*/
 
 /*
  * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net
@@ -869,7 +869,6 @@ static void x86_func_test(struct nvmm_vc
 static void x86_func_mov(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *);
 static void x86_func_stos(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *);
 static void x86_func_lods(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *);
-static void x86_func_movs(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *);
 
 static const struct x86_emul x86_emul_or = {
 	.readreg = true,
@@ -919,10 +918,6 @@ static const struct x86_emul x86_emul_lo
 	.func = x86_func_lods
 };
 
-static const struct x86_emul x86_emul_movs = {
-	.func = x86_func_movs
-};
-
 /* Legacy prefixes. */
 #define LEG_LOCK	0xF0
 #define LEG_REPN	0xF2
@@ -1051,6 +1046,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;
@@ -1451,7 +1447,7 @@ static const struct x86_opcode primary_o
 		.movs = true,
 		.szoverride = false,
 		.defsize = OPSIZE_BYTE,
-		.emul = &x86_emul_movs
+		.emul = NULL
 	},
 	[0xA5] = {
 		/* Yv, Xv */
@@ -1459,7 +1455,27 @@ static const struct x86_opcode primary_o
 		.movs = true,
 		.szoverride = true,
 		.defsize = -1,
-		.emul = &x86_emul_movs
+		.emul = NULL
+	},
+
+	/*
+	 * CMPS
+	 */
+	[0xA6] = {
+		/* Yb, Xb */
+		.valid = true,
+		.cmps = true,
+		.szoverride = false,
+		.defsize = OPSIZE_BYTE,
+		.emul = NULL
+	},
+	[0xA7] = {
+		/* Yv, Xv */
+		.valid = true,
+		.cmps = true,
+		.szoverride = true,
+		.defsize = -1,
+		.emul = NULL
 	},
 
 	/*
@@ -1871,6 +1887,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.
  */
@@ -2470,6 +2515,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;
 	}
@@ -2966,23 +3013,6 @@ x86_func_lods(struct nvmm_vcpu *vcpu, st
 	}
 }
 
-static void
-x86_func_movs(struct nvmm_vcpu *vcpu, struct nvmm_mem *mem, uint64_t *gprs)
-{
-	/*
-	 * Special instruction: double memory operand. Don't call the cb,
-	 * because the storage has already been performed earlier.
-	 */
-
-	if (gprs[NVMM_X64_GPR_RFLAGS] & PSL_D) {
-		gprs[NVMM_X64_GPR_RSI] -= mem->size;
-		gprs[NVMM_X64_GPR_RDI] -= mem->size;
-	} else {
-		gprs[NVMM_X64_GPR_RSI] += mem->size;
-		gprs[NVMM_X64_GPR_RDI] += mem->size;
-	}
-}
-
 /* -------------------------------------------------------------------------- */
 
 static inline uint64_t
@@ -3145,17 +3175,18 @@ fetch_instruction(struct nvmm_machine *m
 }
 
 static int
-assist_mem_double(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
+assist_mem_movs(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
     struct x86_instr *instr)
 {
 	struct nvmm_x64_state *state = vcpu->state;
-	struct nvmm_mem mem;
+	uint64_t *gprs;
 	uint8_t data[8];
 	gvaddr_t gva;
 	size_t size;
 	int ret;
 
 	size = instr->operand_size;
+	gprs = state->gprs;
 
 	/* Source. */
 	ret = store_to_gva(state, instr, &instr->src, &gva, size);
@@ -3173,8 +3204,72 @@ assist_mem_double(struct nvmm_machine *m
 	if (ret == -1)
 		return -1;
 
-	mem.size = size;
-	(*instr->emul->func)(vcpu, &mem, state->gprs);
+	/*
+	 * Inlined x86_func_movs() call
+	 * 	(*instr->emul->func)(vcpu, &mem, state->gprs);
+	 */
+
+	if (gprs[NVMM_X64_GPR_RFLAGS] & PSL_D) {
+		gprs[NVMM_X64_GPR_RSI] -= size;
+		gprs[NVMM_X64_GPR_RDI] -= size;
+	} else {
+		gprs[NVMM_X64_GPR_RSI] += size;
+		gprs[NVMM_X64_GPR_RDI] += size;
+	}
+
+	return 0;
+}
+
+static int
+assist_mem_cmps(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
+    struct x86_instr *instr)
+{
+	struct nvmm_x64_state *state = vcpu->state;
+	uint64_t *gprs, op1, op2, fl;
+	uint8_t data1[8], data2[8];
+	gvaddr_t gva;
+	size_t size;
+	int ret;
+
+	size = instr->operand_size;
+	gprs = state->gprs;
+
+	/* Source 1. */
+	ret = store_to_gva(state, instr, &instr->src, &gva, size);
+	if (ret == -1)
+		return -1;
+	ret = read_guest_memory(mach, vcpu, gva, data1, size);
+	if (ret == -1)
+		return -1;
+
+	/* Source 2. */
+	ret = store_to_gva(state, instr, &instr->dst, &gva, size);
+	if (ret == -1)
+		return -1;
+	ret = read_guest_memory(mach, vcpu, gva, data2, size);
+	if (ret == -1)
+		return -1;
+
+	/*
+	 * Inlined x86_func_cmps() call
+	 * 	(*instr->emul->func)(vcpu, &mem, state->gprs);
+	 */
+
+	/* Perform the CMP. */
+	op1 = *((uint64_t *) data1);
+	op2 = *((uint64_t *) data2);
+	exec_sub(op1, op2, &fl, size);
+
+	gprs[NVMM_X64_GPR_RFLAGS] &= ~PSL_SUB_MASK;
+	gprs[NVMM_X64_GPR_RFLAGS] |= (fl & PSL_SUB_MASK);
+
+	if (gprs[NVMM_X64_GPR_RFLAGS] & PSL_D) {
+		gprs[NVMM_X64_GPR_RSI] -= size;
+		gprs[NVMM_X64_GPR_RDI] -= size;
+	} else {
+		gprs[NVMM_X64_GPR_RSI] += size;
+		gprs[NVMM_X64_GPR_RDI] += size;
+	}
 
 	return 0;
 }
@@ -3349,7 +3444,9 @@ nvmm_assist_mem(struct nvmm_machine *mac
 	}
 
 	if (instr.opcode->movs) {
-		ret = assist_mem_double(mach, vcpu, &instr);
+		ret = assist_mem_movs(mach, vcpu, &instr);
+	} else if (instr.opcode->cmps) {
+		ret = assist_mem_cmps(mach, vcpu, &instr);
 	} else {
 		ret = assist_mem_single(mach, vcpu, &instr);
 	}

Attachment: signature.asc
Description: PGP signature



Home | Main Index | Thread Index | Old Index