Module Name:    src
Committed By:   maxv
Date:           Mon Oct 14 10:39:24 UTC 2019

Modified Files:
        src/lib/libnvmm: libnvmm_x86.c
        src/tests/lib/libnvmm: h_mem_assist.c h_mem_assist_asm.S

Log Message:
Implement XCHG, add associated tests, and add comments to explain. With
this in place the Windows 95 installer completes successfuly.

Part of PR/54611.


To generate a diff of this commit:
cvs rdiff -u -r1.32 -r1.33 src/lib/libnvmm/libnvmm_x86.c
cvs rdiff -u -r1.13 -r1.14 src/tests/lib/libnvmm/h_mem_assist.c
cvs rdiff -u -r1.7 -r1.8 src/tests/lib/libnvmm/h_mem_assist_asm.S

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libnvmm/libnvmm_x86.c
diff -u src/lib/libnvmm/libnvmm_x86.c:1.32 src/lib/libnvmm/libnvmm_x86.c:1.33
--- src/lib/libnvmm/libnvmm_x86.c:1.32	Sun Oct 13 17:32:15 2019
+++ src/lib/libnvmm/libnvmm_x86.c	Mon Oct 14 10:39:24 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: libnvmm_x86.c,v 1.32 2019/10/13 17:32:15 maxv Exp $	*/
+/*	$NetBSD: libnvmm_x86.c,v 1.33 2019/10/14 10:39:24 maxv Exp $	*/
 
 /*
  * Copyright (c) 2018-2019 The NetBSD Foundation, Inc.
@@ -838,13 +838,15 @@ out:
 /* -------------------------------------------------------------------------- */
 
 struct x86_emul {
-	bool read;
+	bool readreg;
+	bool backprop;
 	bool notouch;
 	void (*func)(struct nvmm_machine *, struct nvmm_mem *, uint64_t *);
 };
 
 static void x86_func_or(struct nvmm_machine *, struct nvmm_mem *, uint64_t *);
 static void x86_func_and(struct nvmm_machine *, struct nvmm_mem *, uint64_t *);
+static void x86_func_xchg(struct nvmm_machine *, struct nvmm_mem *, uint64_t *);
 static void x86_func_sub(struct nvmm_machine *, struct nvmm_mem *, uint64_t *);
 static void x86_func_xor(struct nvmm_machine *, struct nvmm_mem *, uint64_t *);
 static void x86_func_cmp(struct nvmm_machine *, struct nvmm_mem *, uint64_t *);
@@ -855,22 +857,28 @@ static void x86_func_lods(struct nvmm_ma
 static void x86_func_movs(struct nvmm_machine *, struct nvmm_mem *, uint64_t *);
 
 static const struct x86_emul x86_emul_or = {
-	.read = true,
+	.readreg = true,
 	.func = x86_func_or
 };
 
 static const struct x86_emul x86_emul_and = {
-	.read = true,
+	.readreg = true,
 	.func = x86_func_and
 };
 
+static const struct x86_emul x86_emul_xchg = {
+	.readreg = true,
+	.backprop = true,
+	.func = x86_func_xchg
+};
+
 static const struct x86_emul x86_emul_sub = {
-	.read = true,
+	.readreg = true,
 	.func = x86_func_sub
 };
 
 static const struct x86_emul x86_emul_xor = {
-	.read = true,
+	.readreg = true,
 	.func = x86_func_xor
 };
 
@@ -1322,6 +1330,28 @@ static const struct x86_opcode primary_o
 	},
 
 	/*
+	 * XCHG
+	 */
+	[0x86] = {
+		/* Eb, Gb */
+		.valid = true,
+		.regmodrm = true,
+		.regtorm = true,
+		.szoverride = false,
+		.defsize = OPSIZE_BYTE,
+		.emul = &x86_emul_xchg
+	},
+	[0x87] = {
+		/* Ev, Gv */
+		.valid = true,
+		.regmodrm = true,
+		.regtorm = true,
+		.szoverride = true,
+		.defsize = -1,
+		.emul = &x86_emul_xchg
+	},
+
+	/*
 	 * MOV
 	 */
 	[0x88] = {
@@ -2616,10 +2646,10 @@ exec_##instr##sz(uint##sz##_t op1, uint#
 {									\
 	uint##sz##_t res;						\
 	__asm __volatile (						\
-		#instr " %2, %3;"					\
-		"mov %3, %1;"						\
+		#instr"	%2, %3;"					\
+		"mov	%3, %1;"					\
 		"pushfq;"						\
-		"popq %0"						\
+		"popq	%0"						\
 	    : "=r" (*rflags), "=r" (res)				\
 	    : "r" (op1), "r" (op2));					\
 	return res;							\
@@ -2677,7 +2707,7 @@ EXEC_DISPATCHER(xor)
 
 /*
  * Emulation functions. We don't care about the order of the operands, except
- * for SUB, CMP and TEST. For these ones we look at mem->write todetermine who
+ * for SUB, CMP and TEST. For these ones we look at mem->write to determine who
  * is op1 and who is op2.
  */
 
@@ -2746,6 +2776,28 @@ x86_func_and(struct nvmm_machine *mach, 
 }
 
 static void
+x86_func_xchg(struct nvmm_machine *mach, struct nvmm_mem *mem, uint64_t *gprs)
+{
+	uint64_t *op1, op2;
+
+	op1 = (uint64_t *)mem->data;
+	op2 = 0;
+
+	/* Fetch op2. */
+	mem->data = (uint8_t *)&op2;
+	mem->write = false;
+	(*mach->cbs.mem)(mem);
+
+	/* Write op1 in op2. */
+	mem->data = (uint8_t *)op1;
+	mem->write = true;
+	(*mach->cbs.mem)(mem);
+
+	/* Write op2 in op1. */
+	*op1 = op2;
+}
+
+static void
 x86_func_sub(struct nvmm_machine *mach, struct nvmm_mem *mem, uint64_t *gprs)
 {
 	uint64_t *retval = (uint64_t *)mem->data;
@@ -3154,7 +3206,9 @@ assist_mem_single(struct nvmm_machine *m
 	if (mem.write) {
 		switch (instr->src.type) {
 		case STORE_REG:
-			if (instr->src.disp.type != DISP_NONE) {
+			/* The instruction was "reg -> mem". Fetch the register
+			 * in membuf. */
+			if (__predict_false(instr->src.disp.type != DISP_NONE)) {
 				DISASSEMBLER_BUG();
 			}
 			val = state->gprs[instr->src.u.reg->num];
@@ -3162,16 +3216,20 @@ assist_mem_single(struct nvmm_machine *m
 			memcpy(mem.data, &val, mem.size);
 			break;
 		case STORE_IMM:
+			/* The instruction was "imm -> mem". Fetch the immediate
+			 * in membuf. */
 			memcpy(mem.data, &instr->src.u.imm.data, mem.size);
 			break;
 		default:
 			DISASSEMBLER_BUG();
 		}
-	} else if (instr->emul->read) {
-		if (instr->dst.type != STORE_REG) {
+	} else if (instr->emul->readreg) {
+		/* The instruction was "mem -> reg", but the value of the
+		 * register matters for the emul func. Fetch it in membuf. */
+		if (__predict_false(instr->dst.type != STORE_REG)) {
 			DISASSEMBLER_BUG();
 		}
-		if (instr->dst.disp.type != DISP_NONE) {
+		if (__predict_false(instr->dst.disp.type != DISP_NONE)) {
 			DISASSEMBLER_BUG();
 		}
 		val = state->gprs[instr->dst.u.reg->num];
@@ -3181,8 +3239,19 @@ assist_mem_single(struct nvmm_machine *m
 
 	(*instr->emul->func)(mach, &mem, state->gprs);
 
-	if (!instr->emul->notouch && !mem.write) {
-		if (instr->dst.type != STORE_REG) {
+	if (instr->emul->notouch) {
+		/* We're done. */
+		return 0;
+	}
+
+	if (!mem.write) {
+		/* The instruction was "mem -> reg". The emul func has filled
+		 * membuf with the memory content. Install membuf in the
+		 * register. */
+		if (__predict_false(instr->dst.type != STORE_REG)) {
+			DISASSEMBLER_BUG();
+		}
+		if (__predict_false(instr->dst.disp.type != DISP_NONE)) {
 			DISASSEMBLER_BUG();
 		}
 		memcpy(&val, membuf, sizeof(uint64_t));
@@ -3190,6 +3259,21 @@ assist_mem_single(struct nvmm_machine *m
 		state->gprs[instr->dst.u.reg->num] &= ~instr->dst.u.reg->mask;
 		state->gprs[instr->dst.u.reg->num] |= val;
 		state->gprs[instr->dst.u.reg->num] &= ~instr->zeroextend_mask;
+	} else if (instr->emul->backprop) {
+		/* The instruction was "reg -> mem", but the memory must be
+		 * back-propagated to the register. Install membuf in the
+		 * register. */
+		if (__predict_false(instr->src.type != STORE_REG)) {
+			DISASSEMBLER_BUG();
+		}
+		if (__predict_false(instr->src.disp.type != DISP_NONE)) {
+			DISASSEMBLER_BUG();
+		}
+		memcpy(&val, membuf, sizeof(uint64_t));
+		val = __SHIFTIN(val, instr->src.u.reg->mask);
+		state->gprs[instr->src.u.reg->num] &= ~instr->src.u.reg->mask;
+		state->gprs[instr->src.u.reg->num] |= val;
+		state->gprs[instr->src.u.reg->num] &= ~instr->zeroextend_mask;
 	}
 
 	return 0;

Index: src/tests/lib/libnvmm/h_mem_assist.c
diff -u src/tests/lib/libnvmm/h_mem_assist.c:1.13 src/tests/lib/libnvmm/h_mem_assist.c:1.14
--- src/tests/lib/libnvmm/h_mem_assist.c:1.13	Mon Oct 14 01:15:32 2019
+++ src/tests/lib/libnvmm/h_mem_assist.c	Mon Oct 14 10:39:24 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: h_mem_assist.c,v 1.13 2019/10/14 01:15:32 christos Exp $	*/
+/*	$NetBSD: h_mem_assist.c,v 1.14 2019/10/14 10:39:24 maxv Exp $	*/
 
 /*
  * Copyright (c) 2018-2019 The NetBSD Foundation, Inc.
@@ -173,6 +173,8 @@ extern uint8_t test11_begin, test11_end;
 extern uint8_t test12_begin, test12_end;
 extern uint8_t test13_begin, test13_end;
 extern uint8_t test14_begin, test14_end;
+extern uint8_t test_64bit_15_begin, test_64bit_15_end;
+extern uint8_t test_64bit_16_begin, test_64bit_16_end;
 
 static const struct test tests64[] = {
 	{ "test1 - MOV", &test1_begin, &test1_end, 0x3004, 0 },
@@ -189,6 +191,9 @@ static const struct test tests64[] = {
 	{ "test12 - CMP", &test12_begin, &test12_end, 0x00000001, 0 },
 	{ "test13 - SUB", &test13_begin, &test13_end, 0x0000000F0000A0FF, 0 },
 	{ "test14 - TEST", &test14_begin, &test14_end, 0x00000001, 0 },
+	{ "test15 - XCHG", &test_64bit_15_begin, &test_64bit_15_end, 0x123456, 0 },
+	{ "test16 - XCHG", &test_64bit_16_begin, &test_64bit_16_end,
+	  0x123456, 0 },
 	{ NULL, NULL, NULL, -1, 0 }
 };
 
@@ -371,6 +376,7 @@ extern uint8_t test_16bit_2_begin, test_
 extern uint8_t test_16bit_3_begin, test_16bit_3_end;
 extern uint8_t test_16bit_4_begin, test_16bit_4_end;
 extern uint8_t test_16bit_5_begin, test_16bit_5_end;
+extern uint8_t test_16bit_6_begin, test_16bit_6_end;
 
 static const struct test tests16[] = {
 	{ "16bit test1 - MOV single", &test_16bit_1_begin, &test_16bit_1_end,
@@ -383,6 +389,8 @@ static const struct test tests16[] = {
 	  0x1011, 0x10f6 - 0x1000 },
 	{ "16bit test5 - disp16-only", &test_16bit_5_begin, &test_16bit_5_end,
 	  0x12, 0x1234 - 0x1000 },
+	{ "16bit test6 - XCHG", &test_16bit_6_begin, &test_16bit_6_end,
+	  0x1234, 0x1234 - 0x1000 },
 	{ NULL, NULL, NULL, -1, -1 }
 };
 

Index: src/tests/lib/libnvmm/h_mem_assist_asm.S
diff -u src/tests/lib/libnvmm/h_mem_assist_asm.S:1.7 src/tests/lib/libnvmm/h_mem_assist_asm.S:1.8
--- src/tests/lib/libnvmm/h_mem_assist_asm.S:1.7	Sun Oct 13 17:32:15 2019
+++ src/tests/lib/libnvmm/h_mem_assist_asm.S	Mon Oct 14 10:39:24 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: h_mem_assist_asm.S,v 1.7 2019/10/13 17:32:15 maxv Exp $	*/
+/*	$NetBSD: h_mem_assist_asm.S,v 1.8 2019/10/14 10:39:24 maxv Exp $	*/
 
 /*
  * Copyright (c) 2018-2019 The NetBSD Foundation, Inc.
@@ -43,6 +43,8 @@
 	.globl	test12_begin, test12_end
 	.globl	test13_begin, test13_end
 	.globl	test14_begin, test14_end
+	.globl	test_64bit_15_begin, test_64bit_15_end
+	.globl	test_64bit_16_begin, test_64bit_16_end
 	.text
 	.code64
 
@@ -294,6 +296,35 @@ test14_begin:
 	TEST_END
 test14_end:
 
+	.align	64
+test_64bit_15_begin:
+	movq	$0x1000,%rax
+	movq	$0x120000,%rbx
+	movq	$0x003400,%rcx
+	movq	$0x000056,%rdx
+
+	xchgq	%rbx,(%rax)
+	xchgw	(%rax),%cx
+	xchgb	%dl,(%rax)
+
+	TEST_END
+test_64bit_15_end:
+
+	.align	64
+test_64bit_16_begin:
+	movq	$0x1000,%rax
+	movq	$0x000000,%rbx
+	movq	$0x000000,%rcx
+	movq	$0x000000,%rdx
+
+	movq	$0x123456,(%rax)
+	xchgq	%rbx,(%eax)
+	movq	$0,(%rax)
+	xchgq	%rbx,(%eax)
+
+	TEST_END
+test_64bit_16_end:
+
 /* -------------------------------------------------------------------------- */
 
 	.globl	test_16bit_1_begin, test_16bit_1_end
@@ -301,6 +332,7 @@ test14_end:
 	.globl	test_16bit_3_begin, test_16bit_3_end
 	.globl	test_16bit_4_begin, test_16bit_4_end
 	.globl	test_16bit_5_begin, test_16bit_5_end
+	.globl	test_16bit_6_begin, test_16bit_6_end
 
 #define TEST16_END	\
 	rdmsr
@@ -363,3 +395,16 @@ test_16bit_5_begin:
 
 	TEST16_END
 test_16bit_5_end:
+
+	.align	64
+test_16bit_6_begin:
+	movw	$0x1234,%bp
+	movw	$4,%di
+	movw	$0x1200,%bx
+	movw	$0x0034,%cx
+
+	xchgw	%bx,(%bp)
+	xchgb	-4(%bp,%di),%cl
+
+	TEST16_END
+test_16bit_6_end:

Reply via email to