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: