Module Name:    src
Committed By:   maxv
Date:           Wed Jan  2 12:18:08 UTC 2019

Modified Files:
        src/lib/libnvmm: libnvmm_x86.c
        src/sys/dev/nvmm/x86: nvmm_x86_svm.c

Log Message:
When there's no DecodeAssist in hardware, decode manually in software. This
is needed on certain AMD CPUs (like mine): the segment base of OUTS can be
overridden, and it is wrong to just assume DS.

We fetch the instruction and look at the prefixes if any to determine the
correct segment.


To generate a diff of this commit:
cvs rdiff -u -r1.7 -r1.8 src/lib/libnvmm/libnvmm_x86.c
cvs rdiff -u -r1.7 -r1.8 src/sys/dev/nvmm/x86/nvmm_x86_svm.c

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.7 src/lib/libnvmm/libnvmm_x86.c:1.8
--- src/lib/libnvmm/libnvmm_x86.c:1.7	Sat Dec 29 17:54:54 2018
+++ src/lib/libnvmm/libnvmm_x86.c	Wed Jan  2 12:18:08 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: libnvmm_x86.c,v 1.7 2018/12/29 17:54:54 maxv Exp $	*/
+/*	$NetBSD: libnvmm_x86.c,v 1.8 2019/01/02 12:18:08 maxv Exp $	*/
 
 /*
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -76,13 +76,14 @@ nvmm_vcpu_dump(struct nvmm_machine *mach
 	printf("| -> RBX=%p\n", (void *)state.gprs[NVMM_X64_GPR_RBX]);
 	printf("| -> RCX=%p\n", (void *)state.gprs[NVMM_X64_GPR_RCX]);
 	for (i = 0; i < NVMM_X64_NSEG; i++) {
-		printf("| -> %s: sel=0x%lx base=%p, limit=%p, P=%d\n",
+		printf("| -> %s: sel=0x%lx base=%p, limit=%p, P=%d, D=%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.p, state.segs[i].attrib.def32);
 	}
+	printf("| -> CPL=%p\n", (void *)state.misc[NVMM_X64_MISC_CPL]);
 
 	return 0;
 }
@@ -619,6 +620,8 @@ write_guest_memory(struct nvmm_machine *
 
 /* -------------------------------------------------------------------------- */
 
+static int fetch_segment(struct nvmm_machine *, struct nvmm_x64_state *);
+
 int
 nvmm_assist_io(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
     struct nvmm_exit *exit)
@@ -628,7 +631,7 @@ nvmm_assist_io(struct nvmm_machine *mach
 	uint64_t cnt;
 	gvaddr_t gva;
 	int reg = 0; /* GCC */
-	int ret;
+	int ret, seg;
 
 	if (__predict_false(exit->reason != NVMM_EXIT_IO)) {
 		errno = EINVAL;
@@ -659,8 +662,19 @@ nvmm_assist_io(struct nvmm_machine *mach
 		gva &= mask_from_adsize(exit->u.io.address_size);
 
 		if (!is_long_mode(&state)) {
-			ret = segment_apply(&state.segs[exit->u.io.seg], &gva,
-			    io.size);
+			if (exit->u.io.seg != -1) {
+				seg = exit->u.io.seg;
+			} else {
+				if (io.in) {
+					seg = NVMM_X64_SEG_ES;
+				} else {
+					seg = fetch_segment(mach, &state);
+					if (seg == -1)
+						return -1;
+				}
+			}
+
+			ret = segment_apply(&state.segs[seg], &gva, io.size);
 			if (ret == -1)
 				return -1;
 		}
@@ -2091,24 +2105,27 @@ node_rex_prefix(struct x86_decode_fsm *f
 	return 0;
 }
 
-static const uint8_t legpref_table[NLEG] = {
+static const struct {
+	uint8_t byte;
+	int seg;
+} legpref_table[NLEG] = {
 	/* Group 1 */
-	[LEG_LOCK] = 0xF0,
-	[LEG_REPN] = 0xF2,
-	[LEG_REP]  = 0xF3,
+	[LEG_LOCK] = { 0xF0, -1 },
+	[LEG_REPN] = { 0xF2, -1 },
+	[LEG_REP]  = { 0xF3, -1 },
 	/* Group 2 */
-	[LEG_OVR_CS] = 0x2E,
-	[LEG_OVR_SS] = 0x36,
-	[LEG_OVR_DS] = 0x3E,
-	[LEG_OVR_ES] = 0x26,
-	[LEG_OVR_FS] = 0x64,
-	[LEG_OVR_GS] = 0x65,
-	[LEG_BRN_TAKEN]  = 0x2E,
-	[LEG_BRN_NTAKEN] =  0x3E,
+	[LEG_OVR_CS] = { 0x2E, NVMM_X64_SEG_CS },
+	[LEG_OVR_SS] = { 0x36, NVMM_X64_SEG_SS },
+	[LEG_OVR_DS] = { 0x3E, NVMM_X64_SEG_DS },
+	[LEG_OVR_ES] = { 0x26, NVMM_X64_SEG_ES },
+	[LEG_OVR_FS] = { 0x64, NVMM_X64_SEG_FS },
+	[LEG_OVR_GS] = { 0x65, NVMM_X64_SEG_GS },
+	[LEG_BRN_TAKEN]  = { 0x2E, -1 },
+	[LEG_BRN_NTAKEN] = { 0x3E, -1 },
 	/* Group 3 */
-	[LEG_OPR_OVR] = 0x66,
+	[LEG_OPR_OVR] = { 0x66, -1 },
 	/* Group 4 */
-	[LEG_ADR_OVR] = 0x67
+	[LEG_ADR_OVR] = { 0x67, -1 },
 };
 
 static int
@@ -2122,7 +2139,7 @@ node_legacy_prefix(struct x86_decode_fsm
 	}
 
 	for (i = 0; i < NLEG; i++) {
-		if (byte == legpref_table[i])
+		if (byte == legpref_table[i].byte)
 			break;
 	}
 
@@ -2451,6 +2468,46 @@ store_to_mem(struct nvmm_machine *mach, 
 }
 
 static int
+fetch_segment(struct nvmm_machine *mach, struct nvmm_x64_state *state)
+{
+	uint8_t inst_bytes[15], byte;
+	size_t i, n, fetchsize;
+	gvaddr_t gva;
+	int ret, seg;
+
+	fetchsize = sizeof(inst_bytes);
+
+	gva = state->gprs[NVMM_X64_GPR_RIP];
+	if (!is_long_mode(state)) {
+		ret = segment_apply(&state->segs[NVMM_X64_SEG_CS], &gva,
+		    fetchsize);
+		if (ret == -1)
+			return -1;
+	}
+
+	ret = read_guest_memory(mach, state, gva, inst_bytes, fetchsize);
+	if (ret == -1)
+		return -1;
+
+	seg = NVMM_X64_SEG_DS;
+	for (n = 0; n < fetchsize; n++) {
+		byte = inst_bytes[n];
+		for (i = 0; i < NLEG; i++) {
+			if (byte != legpref_table[i].byte)
+				continue;
+			if (i >= LEG_OVR_CS && i <= LEG_OVR_GS)
+				seg = legpref_table[i].seg;
+			break;
+		}
+		if (i == NLEG) {
+			break;
+		}
+	}
+
+	return seg;
+}
+
+static int
 fetch_instruction(struct nvmm_machine *mach, struct nvmm_x64_state *state,
     struct nvmm_exit *exit)
 {

Index: src/sys/dev/nvmm/x86/nvmm_x86_svm.c
diff -u src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.7 src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.8
--- src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.7	Thu Dec 13 16:28:10 2018
+++ src/sys/dev/nvmm/x86/nvmm_x86_svm.c	Wed Jan  2 12:18:08 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvmm_x86_svm.c,v 1.7 2018/12/13 16:28:10 maxv Exp $	*/
+/*	$NetBSD: nvmm_x86_svm.c,v 1.8 2019/01/02 12:18:08 maxv Exp $	*/
 
 /*
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_svm.c,v 1.7 2018/12/13 16:28:10 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_svm.c,v 1.8 2019/01/02 12:18:08 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -803,11 +803,7 @@ svm_exit_io(struct nvmm_machine *mach, s
 		KASSERT(__SHIFTOUT(info, SVM_EXIT_IO_SEG) < 6);
 		exit->u.io.seg = seg_to_nvmm[__SHIFTOUT(info, SVM_EXIT_IO_SEG)];
 	} else {
-		if (exit->u.io.type == NVMM_EXIT_IO_IN) {
-			exit->u.io.seg = NVMM_X64_SEG_ES;
-		} else {
-			exit->u.io.seg = NVMM_X64_SEG_DS;
-		}
+		exit->u.io.seg = -1;
 	}
 
 	if (info & SVM_EXIT_IO_A64) {

Reply via email to