Module Name:    src
Committed By:   maxv
Date:           Sun Oct 27 10:28:55 UTC 2019

Modified Files:
        src/lib/libnvmm: libnvmm.3
        src/sys/dev/nvmm/x86: nvmm_x86.h nvmm_x86_svm.c nvmm_x86_vmx.c

Log Message:
Add a new VCPU conf option, that allows userland to request VMEXITs after a
TPR change. This is supported on all Intel CPUs, and not-too-old AMD CPUs.

The reason for wanting this option is that certain OSes (like Win10 64bit)
manage interrupt priority in hardware via CR8 directly, and for these OSes,
the emulator may want to sync its internal TPR state on each change.

Add two new fields in cap.arch, to report the conf capabilities. Report TPR
only on Intel for now, not AMD, because I don't have a recent AMD CPU on
which to test.


To generate a diff of this commit:
cvs rdiff -u -r1.21 -r1.22 src/lib/libnvmm/libnvmm.3
cvs rdiff -u -r1.16 -r1.17 src/sys/dev/nvmm/x86/nvmm_x86.h
cvs rdiff -u -r1.51 -r1.52 src/sys/dev/nvmm/x86/nvmm_x86_svm.c
cvs rdiff -u -r1.40 -r1.41 src/sys/dev/nvmm/x86/nvmm_x86_vmx.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.3
diff -u src/lib/libnvmm/libnvmm.3:1.21 src/lib/libnvmm/libnvmm.3:1.22
--- src/lib/libnvmm/libnvmm.3:1.21	Sun Oct 27 07:08:15 2019
+++ src/lib/libnvmm/libnvmm.3	Sun Oct 27 10:28:55 2019
@@ -1,4 +1,4 @@
-.\"	$NetBSD: libnvmm.3,v 1.21 2019/10/27 07:08:15 maxv Exp $
+.\"	$NetBSD: libnvmm.3,v 1.22 2019/10/27 10:28:55 maxv Exp $
 .\"
 .\" Copyright (c) 2018, 2019 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -27,7 +27,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd October 25, 2019
+.Dd October 27, 2019
 .Dt LIBNVMM 3
 .Os
 .Sh NAME
@@ -489,6 +489,7 @@ structure is used to handle VM exits:
 #define NVMM_VCPU_EXIT_INT_READY	0x0000000000001001ULL
 #define NVMM_VCPU_EXIT_NMI_READY	0x0000000000001002ULL
 #define NVMM_VCPU_EXIT_HALTED		0x0000000000001003ULL
+#define NVMM_VCPU_EXIT_TPR_CHANGED	0x0000000000001004ULL
 /* x86: instructions. */
 #define NVMM_VCPU_EXIT_RDMSR		0x0000000000002000ULL
 #define NVMM_VCPU_EXIT_WRMSR		0x0000000000002001ULL

Index: src/sys/dev/nvmm/x86/nvmm_x86.h
diff -u src/sys/dev/nvmm/x86/nvmm_x86.h:1.16 src/sys/dev/nvmm/x86/nvmm_x86.h:1.17
--- src/sys/dev/nvmm/x86/nvmm_x86.h:1.16	Wed Oct 23 07:01:11 2019
+++ src/sys/dev/nvmm/x86/nvmm_x86.h	Sun Oct 27 10:28:55 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvmm_x86.h,v 1.16 2019/10/23 07:01:11 maxv Exp $	*/
+/*	$NetBSD: nvmm_x86.h,v 1.17 2019/10/27 10:28:55 maxv Exp $	*/
 
 /*
  * Copyright (c) 2018-2019 The NetBSD Foundation, Inc.
@@ -84,6 +84,7 @@ struct nvmm_x86_exit_invalid {
 #define NVMM_VCPU_EXIT_INT_READY	0x0000000000001001ULL
 #define NVMM_VCPU_EXIT_NMI_READY	0x0000000000001002ULL
 #define NVMM_VCPU_EXIT_HALTED		0x0000000000001003ULL
+#define NVMM_VCPU_EXIT_TPR_CHANGED	0x0000000000001004ULL
 /* x86: instructions. */
 #define NVMM_VCPU_EXIT_RDMSR		0x0000000000002000ULL
 #define NVMM_VCPU_EXIT_WRMSR		0x0000000000002001ULL
@@ -118,10 +119,16 @@ struct nvmm_x86_event {
 };
 
 struct nvmm_cap_md {
+	uint64_t mach_conf_support;
+
+	uint64_t vcpu_conf_support;
+#define NVMM_CAP_ARCH_VCPU_CONF_CPUID	__BIT(0)
+#define NVMM_CAP_ARCH_VCPU_CONF_TPR	__BIT(1)
+
 	uint64_t xcr0_mask;
 	uint32_t mxcsr_mask;
 	uint32_t conf_cpuid_maxops;
-	uint64_t rsvd[6];
+	uint64_t rsvd[4];
 };
 
 #endif
@@ -261,6 +268,7 @@ struct nvmm_x64_state {
 };
 
 #define NVMM_VCPU_CONF_CPUID	NVMM_VCPU_CONF_MD_BEGIN
+#define NVMM_VCPU_CONF_TPR	(NVMM_VCPU_CONF_MD_BEGIN + 1)
 
 struct nvmm_vcpu_conf_cpuid {
 	/* The options. */
@@ -290,13 +298,18 @@ struct nvmm_vcpu_conf_cpuid {
 	} u;
 };
 
+struct nvmm_vcpu_conf_tpr {
+	uint32_t exit_changed:1;
+	uint32_t rsvd:31;
+};
+
 #define nvmm_vcpu_exit		nvmm_x86_exit
 #define nvmm_vcpu_event		nvmm_x86_event
 #define nvmm_vcpu_state		nvmm_x64_state
 
 #ifdef _KERNEL
 #define NVMM_X86_MACH_NCONF	0
-#define NVMM_X86_VCPU_NCONF	1
+#define NVMM_X86_VCPU_NCONF	2
 struct nvmm_x86_cpuid_mask {
 	uint32_t eax;
 	uint32_t ebx;

Index: src/sys/dev/nvmm/x86/nvmm_x86_svm.c
diff -u src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.51 src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.52
--- src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.51	Wed Oct 23 07:01:11 2019
+++ src/sys/dev/nvmm/x86/nvmm_x86_svm.c	Sun Oct 27 10:28:55 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvmm_x86_svm.c,v 1.51 2019/10/23 07:01:11 maxv Exp $	*/
+/*	$NetBSD: nvmm_x86_svm.c,v 1.52 2019/10/27 10:28:55 maxv Exp $	*/
 
 /*
  * Copyright (c) 2018-2019 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_svm.c,v 1.51 2019/10/23 07:01:11 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_svm.c,v 1.52 2019/10/27 10:28:55 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -509,7 +509,9 @@ struct svm_machdata {
 
 static const size_t svm_vcpu_conf_sizes[NVMM_X86_VCPU_NCONF] = {
 	[NVMM_VCPU_CONF_MD(NVMM_VCPU_CONF_CPUID)] =
-	    sizeof(struct nvmm_vcpu_conf_cpuid)
+	    sizeof(struct nvmm_vcpu_conf_cpuid),
+	[NVMM_VCPU_CONF_MD(NVMM_VCPU_CONF_TPR)] =
+	    sizeof(struct nvmm_vcpu_conf_tpr)
 };
 
 struct svm_cpudata {
@@ -2128,18 +2130,14 @@ svm_vcpu_destroy(struct nvmm_machine *ma
 	    roundup(sizeof(*cpudata), PAGE_SIZE), UVM_KMF_WIRED);
 }
 
+/* -------------------------------------------------------------------------- */
+
 static int
-svm_vcpu_configure(struct nvmm_cpu *vcpu, uint64_t op, void *data)
+svm_vcpu_configure_cpuid(struct svm_cpudata *cpudata, void *data)
 {
-	struct svm_cpudata *cpudata = vcpu->cpudata;
-	struct nvmm_vcpu_conf_cpuid *cpuid;
+	struct nvmm_vcpu_conf_cpuid *cpuid = data;
 	size_t i;
 
-	if (__predict_false(op != NVMM_VCPU_CONF_MD(NVMM_VCPU_CONF_CPUID))) {
-		return EINVAL;
-	}
-	cpuid = data;
-
 	if (__predict_false(cpuid->mask && cpuid->exit)) {
 		return EINVAL;
 	}
@@ -2189,6 +2187,19 @@ svm_vcpu_configure(struct nvmm_cpu *vcpu
 	return ENOBUFS;
 }
 
+static int
+svm_vcpu_configure(struct nvmm_cpu *vcpu, uint64_t op, void *data)
+{
+	struct svm_cpudata *cpudata = vcpu->cpudata;
+
+	switch (op) {
+	case NVMM_VCPU_CONF_MD(NVMM_VCPU_CONF_CPUID):
+		return svm_vcpu_configure_cpuid(cpudata, data);
+	default:
+		return EINVAL;
+	}
+}
+
 /* -------------------------------------------------------------------------- */
 
 static void
@@ -2387,6 +2398,9 @@ svm_fini(void)
 static void
 svm_capability(struct nvmm_capability *cap)
 {
+	cap->arch.mach_conf_support = 0;
+	cap->arch.vcpu_conf_support =
+	    NVMM_CAP_ARCH_VCPU_CONF_CPUID;
 	cap->arch.xcr0_mask = svm_xcr0_mask;
 	cap->arch.mxcsr_mask = x86_fpu_mxcsr_mask;
 	cap->arch.conf_cpuid_maxops = SVM_NCPUIDS;

Index: src/sys/dev/nvmm/x86/nvmm_x86_vmx.c
diff -u src/sys/dev/nvmm/x86/nvmm_x86_vmx.c:1.40 src/sys/dev/nvmm/x86/nvmm_x86_vmx.c:1.41
--- src/sys/dev/nvmm/x86/nvmm_x86_vmx.c:1.40	Wed Oct 23 07:01:11 2019
+++ src/sys/dev/nvmm/x86/nvmm_x86_vmx.c	Sun Oct 27 10:28:55 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvmm_x86_vmx.c,v 1.40 2019/10/23 07:01:11 maxv Exp $	*/
+/*	$NetBSD: nvmm_x86_vmx.c,v 1.41 2019/10/27 10:28:55 maxv Exp $	*/
 
 /*
  * Copyright (c) 2018-2019 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_vmx.c,v 1.40 2019/10/23 07:01:11 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_vmx.c,v 1.41 2019/10/27 10:28:55 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -702,7 +702,9 @@ struct vmx_machdata {
 
 static const size_t vmx_vcpu_conf_sizes[NVMM_X86_VCPU_NCONF] = {
 	[NVMM_VCPU_CONF_MD(NVMM_VCPU_CONF_CPUID)] =
-	    sizeof(struct nvmm_vcpu_conf_cpuid)
+	    sizeof(struct nvmm_vcpu_conf_cpuid),
+	[NVMM_VCPU_CONF_MD(NVMM_VCPU_CONF_TPR)] =
+	    sizeof(struct nvmm_vcpu_conf_tpr)
 };
 
 struct vmx_cpudata {
@@ -752,6 +754,7 @@ struct vmx_cpudata {
 	/* VCPU configuration. */
 	bool cpuidpresent[VMX_NCPUIDS];
 	struct nvmm_vcpu_conf_cpuid cpuid[VMX_NCPUIDS];
+	struct nvmm_vcpu_conf_tpr tpr;
 };
 
 static const struct {
@@ -1404,7 +1407,7 @@ vmx_inkernel_handle_cr4(struct nvmm_mach
 
 static int
 vmx_inkernel_handle_cr8(struct nvmm_machine *mach, struct nvmm_cpu *vcpu,
-    uint64_t qual)
+    uint64_t qual, struct nvmm_vcpu_exit *exit)
 {
 	struct vmx_cpudata *cpudata = vcpu->cpudata;
 	uint64_t type, gpr;
@@ -1428,6 +1431,9 @@ vmx_inkernel_handle_cr8(struct nvmm_mach
 		} else {
 			cpudata->gcr8 = cpudata->gprs[gpr];
 		}
+		if (cpudata->tpr.exit_changed) {
+			exit->reason = NVMM_VCPU_EXIT_TPR_CHANGED;
+		}
 	} else {
 		if (gpr == NVMM_X64_GPR_RSP) {
 			vmx_vmwrite(VMCS_GUEST_RSP, cpudata->gcr8);
@@ -1447,6 +1453,8 @@ vmx_exit_cr(struct nvmm_machine *mach, s
 	uint64_t qual;
 	int ret;
 
+	exit->reason = NVMM_VCPU_EXIT_NONE;
+
 	qual = vmx_vmread(VMCS_EXIT_QUALIFICATION);
 
 	switch (__SHIFTOUT(qual, VMX_QUAL_CR_NUM)) {
@@ -1457,7 +1465,7 @@ vmx_exit_cr(struct nvmm_machine *mach, s
 		ret = vmx_inkernel_handle_cr4(mach, vcpu, qual);
 		break;
 	case 8:
-		ret = vmx_inkernel_handle_cr8(mach, vcpu, qual);
+		ret = vmx_inkernel_handle_cr8(mach, vcpu, qual, exit);
 		break;
 	default:
 		ret = -1;
@@ -1467,8 +1475,6 @@ vmx_exit_cr(struct nvmm_machine *mach, s
 	if (ret == -1) {
 		vmx_inject_gp(vcpu);
 	}
-
-	exit->reason = NVMM_VCPU_EXIT_NONE;
 }
 
 #define VMX_QUAL_IO_SIZE	__BITS(2,0)
@@ -2750,18 +2756,14 @@ vmx_vcpu_destroy(struct nvmm_machine *ma
 	    roundup(sizeof(*cpudata), PAGE_SIZE), UVM_KMF_WIRED);
 }
 
+/* -------------------------------------------------------------------------- */
+
 static int
-vmx_vcpu_configure(struct nvmm_cpu *vcpu, uint64_t op, void *data)
+vmx_vcpu_configure_cpuid(struct vmx_cpudata *cpudata, void *data)
 {
-	struct vmx_cpudata *cpudata = vcpu->cpudata;
-	struct nvmm_vcpu_conf_cpuid *cpuid;
+	struct nvmm_vcpu_conf_cpuid *cpuid = data;
 	size_t i;
 
-	if (__predict_false(op != NVMM_VCPU_CONF_MD(NVMM_VCPU_CONF_CPUID))) {
-		return EINVAL;
-	}
-	cpuid = data;
-
 	if (__predict_false(cpuid->mask && cpuid->exit)) {
 		return EINVAL;
 	}
@@ -2811,6 +2813,30 @@ vmx_vcpu_configure(struct nvmm_cpu *vcpu
 	return ENOBUFS;
 }
 
+static int
+vmx_vcpu_configure_tpr(struct vmx_cpudata *cpudata, void *data)
+{
+	struct nvmm_vcpu_conf_tpr *tpr = data;
+
+	memcpy(&cpudata->tpr, tpr, sizeof(*tpr));
+	return 0;
+}
+
+static int
+vmx_vcpu_configure(struct nvmm_cpu *vcpu, uint64_t op, void *data)
+{
+	struct vmx_cpudata *cpudata = vcpu->cpudata;
+
+	switch (op) {
+	case NVMM_VCPU_CONF_MD(NVMM_VCPU_CONF_CPUID):
+		return vmx_vcpu_configure_cpuid(cpudata, data);
+	case NVMM_VCPU_CONF_MD(NVMM_VCPU_CONF_TPR):
+		return vmx_vcpu_configure_tpr(cpudata, data);
+	default:
+		return EINVAL;
+	}
+}
+
 /* -------------------------------------------------------------------------- */
 
 static void
@@ -3170,6 +3196,10 @@ vmx_fini(void)
 static void
 vmx_capability(struct nvmm_capability *cap)
 {
+	cap->arch.mach_conf_support = 0;
+	cap->arch.vcpu_conf_support =
+	    NVMM_CAP_ARCH_VCPU_CONF_CPUID |
+	    NVMM_CAP_ARCH_VCPU_CONF_TPR;
 	cap->arch.xcr0_mask = vmx_xcr0_mask;
 	cap->arch.mxcsr_mask = x86_fpu_mxcsr_mask;
 	cap->arch.conf_cpuid_maxops = VMX_NCPUIDS;

Reply via email to