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: