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;