Source-Changes-HG archive

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

[src/trunk]: src/lib/libnvmm Handle more corner cases, clean up a little, and...



details:   https://anonhg.NetBSD.org/src/rev/c7337371a6d2
branches:  trunk
changeset: 447487:c7337371a6d2
user:      maxv <maxv%NetBSD.org@localhost>
date:      Sun Jan 13 10:43:22 2019 +0000

description:
Handle more corner cases, clean up a little, and add a set of instructions
in Group1.

diffstat:

 lib/libnvmm/libnvmm_x86.c |  216 ++++++++++++++++++++++++---------------------
 1 files changed, 116 insertions(+), 100 deletions(-)

diffs (truncated from 455 to 300 lines):

diff -r 91411bfec329 -r c7337371a6d2 lib/libnvmm/libnvmm_x86.c
--- a/lib/libnvmm/libnvmm_x86.c Sun Jan 13 10:07:50 2019 +0000
+++ b/lib/libnvmm/libnvmm_x86.c Sun Jan 13 10:43:22 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: libnvmm_x86.c,v 1.14 2019/01/08 07:34:22 maxv Exp $    */
+/*     $NetBSD: libnvmm_x86.c,v 1.15 2019/01/13 10:43:22 maxv Exp $    */
 
 /*
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -77,13 +77,15 @@
        printf("| -> RAX=%p\n", (void *)state.gprs[NVMM_X64_GPR_RAX]);
        printf("| -> RBX=%p\n", (void *)state.gprs[NVMM_X64_GPR_RBX]);
        printf("| -> RCX=%p\n", (void *)state.gprs[NVMM_X64_GPR_RCX]);
+       printf("| -> RFLAGS=%p\n", (void *)state.gprs[NVMM_X64_GPR_RFLAGS]);
        for (i = 0; i < NVMM_X64_NSEG; i++) {
-               printf("| -> %s: sel=0x%lx base=%p, limit=%p, P=%d, D=%d\n",
+               printf("| -> %s: sel=0x%lx base=%p, limit=%p, P=%d, D=%d L=%d\n",
                    segnames[i],
                    state.segs[i].selector,
                    (void *)state.segs[i].base,
                    (void *)state.segs[i].limit,
-                   state.segs[i].attrib.p, state.segs[i].attrib.def32);
+                   state.segs[i].attrib.p, state.segs[i].attrib.def32,
+                   state.segs[i].attrib.lng);
        }
        printf("| -> MSR_EFER=%p\n", (void *)state.msrs[NVMM_X64_MSR_EFER]);
        printf("| -> CR0=%p\n", (void *)state.crs[NVMM_X64_CR_CR0]);
@@ -392,7 +394,7 @@
        gva &= ~PAGE_MASK;
 
        is_pae = (state->crs[NVMM_X64_CR_CR4] & CR4_PAE) != 0;
-       is_lng = (state->msrs[NVMM_X64_MSR_EFER] & EFER_LME) != 0;
+       is_lng = (state->msrs[NVMM_X64_MSR_EFER] & EFER_LMA) != 0;
        has_pse = (state->crs[NVMM_X64_CR_CR4] & CR4_PSE) != 0;
        cr3 = state->crs[NVMM_X64_CR_CR3];
 
@@ -437,6 +439,12 @@
 /* -------------------------------------------------------------------------- */
 
 static inline bool
+is_long_mode(struct nvmm_x64_state *state)
+{
+       return (state->msrs[NVMM_X64_MSR_EFER] & EFER_LMA) != 0;
+}
+
+static inline bool
 is_64bit(struct nvmm_x64_state *state)
 {
        return (state->segs[NVMM_X64_SEG_CS].attrib.lng != 0);
@@ -456,14 +464,8 @@
            (state->segs[NVMM_X64_SEG_CS].attrib.def32 == 0);
 }
 
-static inline bool
-is_long_mode(struct nvmm_x64_state *state)
-{
-       return (state->msrs[NVMM_X64_MSR_EFER] & EFER_LME) != 0;
-}
-
 static int
-segment_apply(struct nvmm_x64_state_seg *seg, gvaddr_t *gva, size_t size)
+segment_check(struct nvmm_x64_state_seg *seg, gvaddr_t gva, size_t size)
 {
        uint64_t limit;
 
@@ -480,11 +482,10 @@
                limit *= PAGE_SIZE;
        }
 
-       if (__predict_false(*gva + size > limit)) {
+       if (__predict_false(gva + size > limit)) {
                goto error;
        }
 
-       *gva += seg->base;
        return 0;
 
 error:
@@ -492,17 +493,25 @@
        return -1;
 }
 
-static uint64_t
-mask_from_adsize(size_t adsize)
+static inline void
+segment_apply(struct nvmm_x64_state_seg *seg, gvaddr_t *gva)
 {
-       switch (adsize) {
-       case 8:
-               return 0xFFFFFFFFFFFFFFFF;
+       *gva += seg->base;
+}
+
+static inline uint64_t
+size_to_mask(size_t size)
+{
+       switch (size) {
+       case 1:
+               return 0x00000000000000FF;
+       case 2:
+               return 0x000000000000FFFF;
        case 4:
                return 0x00000000FFFFFFFF;
-       case 2:
-       default: /* impossible */
-               return 0x000000000000FFFF;
+       case 8:
+       default:
+               return 0xFFFFFFFFFFFFFFFF;
        }
 }
 
@@ -511,7 +520,7 @@
 {
        uint64_t mask, cnt;
 
-       mask = mask_from_adsize(adsize);
+       mask = size_to_mask(adsize);
        cnt = state->gprs[NVMM_X64_GPR_RCX] & mask;
 
        return cnt;
@@ -522,28 +531,12 @@
 {
        uint64_t mask;
 
-       mask = mask_from_adsize(adsize);
+       /* XXX: should we zero-extend? */
+       mask = size_to_mask(adsize);
        state->gprs[NVMM_X64_GPR_RCX] &= ~mask;
        state->gprs[NVMM_X64_GPR_RCX] |= cnt;
 }
 
-static uint64_t
-rep_dec_apply(struct nvmm_x64_state *state, size_t adsize)
-{
-       uint64_t mask, cnt;
-
-       mask = mask_from_adsize(adsize);
-
-       cnt = state->gprs[NVMM_X64_GPR_RCX] & mask;
-       cnt -= 1;
-       cnt &= mask;
-
-       state->gprs[NVMM_X64_GPR_RCX] &= ~mask;
-       state->gprs[NVMM_X64_GPR_RCX] |= cnt;
-
-       return cnt;
-}
-
 static int
 read_guest_memory(struct nvmm_machine *mach, struct nvmm_x64_state *state,
     gvaddr_t gva, uint8_t *data, size_t size)
@@ -693,7 +686,7 @@
        uint64_t cnt = 0; /* GCC */
        uint8_t iobuf[8];
        int iocnt = 1;
-       gvaddr_t gva;
+       gvaddr_t gva = 0; /* GCC */
        int reg = 0; /* GCC */
        int ret, seg;
        bool psld = false;
@@ -717,7 +710,8 @@
        if (exit->u.io.rep) {
                cnt = rep_get_cnt(&state, exit->u.io.address_size);
                if (__predict_false(cnt == 0)) {
-                       return 0;
+                       state.gprs[NVMM_X64_GPR_RIP] = exit->u.io.npc;
+                       goto out;
                }
        }
 
@@ -736,24 +730,29 @@
                }
 
                gva = state.gprs[reg];
-               gva &= mask_from_adsize(exit->u.io.address_size);
-
-               if (!is_long_mode(&state)) {
-                       if (exit->u.io.seg != -1) {
-                               seg = exit->u.io.seg;
+               gva &= size_to_mask(exit->u.io.address_size);
+
+               if (exit->u.io.seg != -1) {
+                       seg = exit->u.io.seg;
+               } else {
+                       if (io.in) {
+                               seg = NVMM_X64_SEG_ES;
                        } else {
-                               if (io.in) {
-                                       seg = NVMM_X64_SEG_ES;
-                               } else {
-                                       seg = fetch_segment(mach, &state);
-                                       if (seg == -1)
-                                               return -1;
-                               }
+                               seg = fetch_segment(mach, &state);
+                               if (seg == -1)
+                                       return -1;
                        }
-
-                       ret = segment_apply(&state.segs[seg], &gva, io.size);
+               }
+
+               if (__predict_true(is_long_mode(&state))) {
+                       if (seg == NVMM_X64_SEG_GS || seg == NVMM_X64_SEG_FS) {
+                               segment_apply(&state.segs[seg], &gva);
+                       }
+               } else {
+                       ret = segment_check(&state.segs[seg], gva, io.size);
                        if (ret == -1)
                                return -1;
+                       segment_apply(&state.segs[seg], &gva);
                }
 
                if (exit->u.io.rep && !psld) {
@@ -780,6 +779,10 @@
        if (io.in) {
                if (!exit->u.io.str) {
                        memcpy(&state.gprs[NVMM_X64_GPR_RAX], io.data, io.size);
+                       if (io.size == 4) {
+                               /* Zero-extend to 64 bits. */
+                               state.gprs[NVMM_X64_GPR_RAX] &= size_to_mask(4);
+                       }
                } else {
                        ret = write_guest_memory(mach, &state, gva, io.data,
                            io.size);
@@ -807,6 +810,7 @@
                state.gprs[NVMM_X64_GPR_RIP] = exit->u.io.npc;
        }
 
+out:
        ret = nvmm_vcpu_setstate(mach, cpuid, &state, NVMM_X64_STATE_GPRS);
        if (ret == -1)
                return -1;
@@ -907,7 +911,6 @@
 };
 
 struct x86_immediate {
-       size_t size;    /* 1/2/4/8 */
        uint64_t data;
 };
 
@@ -1016,6 +1019,19 @@
         * Group1
         */
        {
+               /* Ev, Iz */
+               .byte = 0x81,
+               .regmodrm = true,
+               .regtorm = true,
+               .szoverride = true,
+               .defsize = -1,
+               .allsize = OPSIZE_WORD|OPSIZE_DOUB|OPSIZE_QUAD,
+               .group1 = true,
+               .immediate = true,
+               .flags = FLAG_immz,
+               .emul = NULL /* group1 */
+       },
+       {
                /* Ev, Ib */
                .byte = 0x83,
                .regmodrm = true,
@@ -1769,7 +1785,7 @@
        return 0;
 }
 
-static uint64_t
+static inline uint64_t
 sign_extend(uint64_t val, int size)
 {
        if (size == 1) {
@@ -1806,15 +1822,13 @@
        }
 
        store->type = STORE_IMM;
-       store->u.imm.size = immsize;
        if (fsm_read(fsm, (uint8_t *)&store->u.imm.data, immsize) == -1) {
                return -1;
        }
-       fsm_advance(fsm, store->u.imm.size, NULL);
+       fsm_advance(fsm, immsize, NULL);
 
        if (sesize != 0) {
                store->u.imm.data = sign_extend(store->u.imm.data, sesize);
-               store->u.imm.size = sesize;
        }
 
        return 0;
@@ -2204,6 +2218,11 @@
        instr->operand_size = get_operand_size(fsm, instr);
        instr->address_size = get_address_size(fsm, instr);
 
+       if (fsm->is64bit && (instr->operand_size == 4)) {
+               /* Zero-extend to 64 bits. */
+               instr->zeroextend_mask = ~size_to_mask(4);
+       }
+
        if (opcode->regmodrm) {
                fsm_advance(fsm, 1, node_regmodrm);
        } else if (opcode->dmo) {



Home | Main Index | Thread Index | Old Index