Source-Changes-HG archive

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

[src/trunk]: src Implement XCHG, add associated tests, and add comments to ex...



details:   https://anonhg.NetBSD.org/src/rev/b01f15909c5c
branches:  trunk
changeset: 464615:b01f15909c5c
user:      maxv <maxv%NetBSD.org@localhost>
date:      Mon Oct 14 10:39:24 2019 +0000

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

Part of PR/54611.

diffstat:

 lib/libnvmm/libnvmm_x86.c            |  116 ++++++++++++++++++++++++++++++----
 tests/lib/libnvmm/h_mem_assist.c     |   10 ++-
 tests/lib/libnvmm/h_mem_assist_asm.S |   47 +++++++++++++-
 3 files changed, 155 insertions(+), 18 deletions(-)

diffs (truncated from 343 to 300 lines):

diff -r 84b40334c5da -r b01f15909c5c lib/libnvmm/libnvmm_x86.c
--- a/lib/libnvmm/libnvmm_x86.c Mon Oct 14 06:40:40 2019 +0000
+++ b/lib/libnvmm/libnvmm_x86.c Mon Oct 14 10:39:24 2019 +0000
@@ -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 @@
 /* -------------------------------------------------------------------------- */
 
 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_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 @@
        },
 
        /*
+        * 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 @@
 {                                                                      \
        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 @@
 
 /*
  * 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 @@
 }
 
 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 @@
        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 @@
                        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 @@
 
        (*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 @@
                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;
diff -r 84b40334c5da -r b01f15909c5c tests/lib/libnvmm/h_mem_assist.c
--- a/tests/lib/libnvmm/h_mem_assist.c  Mon Oct 14 06:40:40 2019 +0000
+++ b/tests/lib/libnvmm/h_mem_assist.c  Mon Oct 14 10:39:24 2019 +0000
@@ -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 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 @@
        { "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_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 @@
          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 }
 };
 
diff -r 84b40334c5da -r b01f15909c5c tests/lib/libnvmm/h_mem_assist_asm.S
--- a/tests/lib/libnvmm/h_mem_assist_asm.S      Mon Oct 14 06:40:40 2019 +0000
+++ b/tests/lib/libnvmm/h_mem_assist_asm.S      Mon Oct 14 10:39:24 2019 +0000
@@ -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 @@
        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:
+



Home | Main Index | Thread Index | Old Index