Module Name: src Committed By: maxv Date: Wed May 1 09:20:21 UTC 2019
Modified Files: src/lib/libnvmm: libnvmm.c src/sys/dev/nvmm: nvmm.c nvmm.h nvmm_internal.h nvmm_ioctl.h src/sys/dev/nvmm/x86: nvmm_x86.h nvmm_x86_svm.c nvmm_x86_vmx.c Log Message: Use the comm page to inject events, rather than ioctls, and commit them in vcpu_run. This saves a few syscalls and copyins. For example on Windows 10, moving the mouse from the left to right sides of the screen generates ~500 events, which now don't result in syscalls. The error handling is done in vcpu_run and it is less precise, but this doesn't matter a lot, and will be solved with future NVMM error codes. To generate a diff of this commit: cvs rdiff -u -r1.11 -r1.12 src/lib/libnvmm/libnvmm.c cvs rdiff -u -r1.19 -r1.20 src/sys/dev/nvmm/nvmm.c cvs rdiff -u -r1.8 -r1.9 src/sys/dev/nvmm/nvmm.h cvs rdiff -u -r1.10 -r1.11 src/sys/dev/nvmm/nvmm_internal.h cvs rdiff -u -r1.6 -r1.7 src/sys/dev/nvmm/nvmm_ioctl.h cvs rdiff -u -r1.13 -r1.14 src/sys/dev/nvmm/x86/nvmm_x86.h cvs rdiff -u -r1.44 -r1.45 src/sys/dev/nvmm/x86/nvmm_x86_svm.c cvs rdiff -u -r1.32 -r1.33 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.c diff -u src/lib/libnvmm/libnvmm.c:1.11 src/lib/libnvmm/libnvmm.c:1.12 --- src/lib/libnvmm/libnvmm.c:1.11 Mon Apr 29 17:27:57 2019 +++ src/lib/libnvmm/libnvmm.c Wed May 1 09:20:21 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm.c,v 1.11 2019/04/29 17:27:57 maxv Exp $ */ +/* $NetBSD: libnvmm.c,v 1.12 2019/05/01 09:20:21 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -362,16 +362,15 @@ int nvmm_vcpu_inject(struct nvmm_machine *mach, nvmm_cpuid_t cpuid, struct nvmm_event *event) { - struct nvmm_ioc_vcpu_inject args; - int ret; - - args.machid = mach->machid; - args.cpuid = cpuid; - memcpy(&args.event, event, sizeof(args.event)); + struct nvmm_comm_page *comm; - ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_INJECT, &args); - if (ret == -1) + if (__predict_false(cpuid >= mach->npages)) { return -1; + } + comm = mach->pages[cpuid]; + + memcpy(&comm->event, event, sizeof(comm->event)); + comm->event_commit = true; return 0; } Index: src/sys/dev/nvmm/nvmm.c diff -u src/sys/dev/nvmm/nvmm.c:1.19 src/sys/dev/nvmm/nvmm.c:1.20 --- src/sys/dev/nvmm/nvmm.c:1.19 Sun Apr 28 14:22:13 2019 +++ src/sys/dev/nvmm/nvmm.c Wed May 1 09:20:21 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: nvmm.c,v 1.19 2019/04/28 14:22:13 maxv Exp $ */ +/* $NetBSD: nvmm.c,v 1.20 2019/05/01 09:20:21 maxv Exp $ */ /* * Copyright (c) 2018-2019 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: nvmm.c,v 1.19 2019/04/28 14:22:13 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nvmm.c,v 1.20 2019/05/01 09:20:21 maxv Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -503,7 +503,7 @@ nvmm_vcpu_inject(struct nvmm_owner *owne if (error) goto out; - error = (*nvmm_impl->vcpu_inject)(mach, vcpu, &args->event); + error = (*nvmm_impl->vcpu_inject)(vcpu); nvmm_vcpu_put(vcpu); out: Index: src/sys/dev/nvmm/nvmm.h diff -u src/sys/dev/nvmm/nvmm.h:1.8 src/sys/dev/nvmm/nvmm.h:1.9 --- src/sys/dev/nvmm/nvmm.h:1.8 Sun Apr 28 14:22:13 2019 +++ src/sys/dev/nvmm/nvmm.h Wed May 1 09:20:21 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: nvmm.h,v 1.8 2019/04/28 14:22:13 maxv Exp $ */ +/* $NetBSD: nvmm.h,v 1.9 2019/05/01 09:20:21 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -94,6 +94,18 @@ struct nvmm_capability { struct nvmm_cap_md arch; }; +struct nvmm_comm_page { + /* State. */ + uint64_t state_wanted; + uint64_t state_cached; + uint64_t state_commit; + struct nvmm_vcpu_state state; + + /* Event. */ + bool event_commit; + struct nvmm_event event; +}; + /* * Bits 20:27 -> machid * Bits 12:19 -> cpuid Index: src/sys/dev/nvmm/nvmm_internal.h diff -u src/sys/dev/nvmm/nvmm_internal.h:1.10 src/sys/dev/nvmm/nvmm_internal.h:1.11 --- src/sys/dev/nvmm/nvmm_internal.h:1.10 Sun Apr 28 14:22:13 2019 +++ src/sys/dev/nvmm/nvmm_internal.h Wed May 1 09:20:21 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: nvmm_internal.h,v 1.10 2019/04/28 14:22:13 maxv Exp $ */ +/* $NetBSD: nvmm_internal.h,v 1.11 2019/05/01 09:20:21 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -107,8 +107,7 @@ struct nvmm_impl { void (*vcpu_destroy)(struct nvmm_machine *, struct nvmm_cpu *); void (*vcpu_setstate)(struct nvmm_cpu *); void (*vcpu_getstate)(struct nvmm_cpu *); - int (*vcpu_inject)(struct nvmm_machine *, struct nvmm_cpu *, - struct nvmm_event *); + int (*vcpu_inject)(struct nvmm_cpu *); int (*vcpu_run)(struct nvmm_machine *, struct nvmm_cpu *, struct nvmm_exit *); }; Index: src/sys/dev/nvmm/nvmm_ioctl.h diff -u src/sys/dev/nvmm/nvmm_ioctl.h:1.6 src/sys/dev/nvmm/nvmm_ioctl.h:1.7 --- src/sys/dev/nvmm/nvmm_ioctl.h:1.6 Sun Apr 28 14:22:13 2019 +++ src/sys/dev/nvmm/nvmm_ioctl.h Wed May 1 09:20:21 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: nvmm_ioctl.h,v 1.6 2019/04/28 14:22:13 maxv Exp $ */ +/* $NetBSD: nvmm_ioctl.h,v 1.7 2019/05/01 09:20:21 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -75,7 +75,6 @@ struct nvmm_ioc_vcpu_getstate { struct nvmm_ioc_vcpu_inject { nvmm_machid_t machid; nvmm_cpuid_t cpuid; - struct nvmm_event event; }; struct nvmm_ioc_vcpu_run { Index: src/sys/dev/nvmm/x86/nvmm_x86.h diff -u src/sys/dev/nvmm/x86/nvmm_x86.h:1.13 src/sys/dev/nvmm/x86/nvmm_x86.h:1.14 --- src/sys/dev/nvmm/x86/nvmm_x86.h:1.13 Sun Apr 28 14:22:13 2019 +++ src/sys/dev/nvmm/x86/nvmm_x86.h Wed May 1 09:20:21 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: nvmm_x86.h,v 1.13 2019/04/28 14:22:13 maxv Exp $ */ +/* $NetBSD: nvmm_x86.h,v 1.14 2019/05/01 09:20:21 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -229,6 +229,8 @@ struct nvmm_x64_state { struct fxsave fpu; }; +#define nvmm_vcpu_state nvmm_x64_state + #define NVMM_X86_CONF_CPUID 0 #define NVMM_X86_NCONF 1 @@ -248,13 +250,6 @@ struct nvmm_x86_conf_cpuid { } del; }; -struct nvmm_comm_page { - uint64_t state_wanted; - uint64_t state_cached; - uint64_t state_commit; - struct nvmm_x64_state state; -}; - #ifdef _KERNEL struct nvmm_x86_cpuid_mask { uint32_t eax; Index: src/sys/dev/nvmm/x86/nvmm_x86_svm.c diff -u src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.44 src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.45 --- src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.44 Mon Apr 29 18:54:25 2019 +++ src/sys/dev/nvmm/x86/nvmm_x86_svm.c Wed May 1 09:20:21 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: nvmm_x86_svm.c,v 1.44 2019/04/29 18:54:25 maxv Exp $ */ +/* $NetBSD: nvmm_x86_svm.c,v 1.45 2019/05/01 09:20:21 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.44 2019/04/29 18:54:25 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_svm.c,v 1.45 2019/05/01 09:20:21 maxv Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -661,46 +661,51 @@ svm_event_has_error(uint64_t vector) } static int -svm_vcpu_inject(struct nvmm_machine *mach, struct nvmm_cpu *vcpu, - struct nvmm_event *event) +svm_vcpu_inject(struct nvmm_cpu *vcpu) { + struct nvmm_comm_page *comm = vcpu->comm; struct svm_cpudata *cpudata = vcpu->cpudata; struct vmcb *vmcb = cpudata->vmcb; + enum nvmm_event_type evtype; + uint64_t vector, error; int type = 0, err = 0; - if (event->vector >= 256) { + evtype = comm->event.type; + vector = comm->event.vector; + error = comm->event.u.error; + __insn_barrier(); + + if (__predict_false(vector >= 256)) { return EINVAL; } - switch (event->type) { + switch (evtype) { case NVMM_EVENT_INTERRUPT_HW: type = SVM_EVENT_TYPE_HW_INT; - if (event->vector == 2) { + if (vector == 2) { type = SVM_EVENT_TYPE_NMI; svm_event_waitexit_enable(vcpu, true); } err = 0; break; - case NVMM_EVENT_INTERRUPT_SW: - return EINVAL; case NVMM_EVENT_EXCEPTION: type = SVM_EVENT_TYPE_EXC; - if (event->vector == 2 || event->vector >= 32) + if (vector == 2 || vector >= 32) return EINVAL; - if (event->vector == 3 || event->vector == 0) + if (vector == 3 || vector == 0) return EINVAL; - err = svm_event_has_error(event->vector); + err = svm_event_has_error(vector); break; default: return EINVAL; } vmcb->ctrl.eventinj = - __SHIFTIN(event->vector, VMCB_CTRL_EVENTINJ_VECTOR) | + __SHIFTIN(vector, VMCB_CTRL_EVENTINJ_VECTOR) | __SHIFTIN(type, VMCB_CTRL_EVENTINJ_TYPE) | __SHIFTIN(err, VMCB_CTRL_EVENTINJ_EV) | __SHIFTIN(1, VMCB_CTRL_EVENTINJ_V) | - __SHIFTIN(event->u.error, VMCB_CTRL_EVENTINJ_ERRORCODE); + __SHIFTIN(error, VMCB_CTRL_EVENTINJ_ERRORCODE); cpudata->evt_pending = true; @@ -708,33 +713,43 @@ svm_vcpu_inject(struct nvmm_machine *mac } static void -svm_inject_ud(struct nvmm_machine *mach, struct nvmm_cpu *vcpu) +svm_inject_ud(struct nvmm_cpu *vcpu) { - struct nvmm_event event; + struct nvmm_comm_page *comm = vcpu->comm; int ret __diagused; - event.type = NVMM_EVENT_EXCEPTION; - event.vector = 6; - event.u.error = 0; + comm->event.type = NVMM_EVENT_EXCEPTION; + comm->event.vector = 6; + comm->event.u.error = 0; - ret = svm_vcpu_inject(mach, vcpu, &event); + ret = svm_vcpu_inject(vcpu); KASSERT(ret == 0); } static void -svm_inject_gp(struct nvmm_machine *mach, struct nvmm_cpu *vcpu) +svm_inject_gp(struct nvmm_cpu *vcpu) { - struct nvmm_event event; + struct nvmm_comm_page *comm = vcpu->comm; int ret __diagused; - event.type = NVMM_EVENT_EXCEPTION; - event.vector = 13; - event.u.error = 0; + comm->event.type = NVMM_EVENT_EXCEPTION; + comm->event.vector = 13; + comm->event.u.error = 0; - ret = svm_vcpu_inject(mach, vcpu, &event); + ret = svm_vcpu_inject(vcpu); KASSERT(ret == 0); } +static inline int +svm_vcpu_event_commit(struct nvmm_cpu *vcpu) +{ + if (__predict_true(!vcpu->comm->event_commit)) { + return 0; + } + vcpu->comm->event_commit = false; + return svm_vcpu_inject(vcpu); +} + static inline void svm_inkernel_advance(struct vmcb *vmcb) { @@ -1018,7 +1033,7 @@ handled: return true; error: - svm_inject_gp(mach, vcpu); + svm_inject_gp(vcpu); return true; } @@ -1117,7 +1132,7 @@ svm_exit_xsetbv(struct nvmm_machine *mac return; error: - svm_inject_gp(mach, vcpu); + svm_inject_gp(vcpu); } static void @@ -1283,6 +1298,9 @@ svm_vcpu_run(struct nvmm_machine *mach, uint64_t machgen; int hcpu, s; + if (__predict_false(svm_vcpu_event_commit(vcpu) != 0)) { + return EINVAL; + } svm_vcpu_state_commit(vcpu); comm->state_cached = 0; @@ -1368,7 +1386,7 @@ svm_vcpu_run(struct nvmm_machine *mach, case VMCB_EXITCODE_CLGI: case VMCB_EXITCODE_SKINIT: case VMCB_EXITCODE_RDTSCP: - svm_inject_ud(mach, vcpu); + svm_inject_ud(vcpu); exit->reason = NVMM_EXIT_NONE; break; case VMCB_EXITCODE_MONITOR: Index: src/sys/dev/nvmm/x86/nvmm_x86_vmx.c diff -u src/sys/dev/nvmm/x86/nvmm_x86_vmx.c:1.32 src/sys/dev/nvmm/x86/nvmm_x86_vmx.c:1.33 --- src/sys/dev/nvmm/x86/nvmm_x86_vmx.c:1.32 Mon Apr 29 18:54:26 2019 +++ src/sys/dev/nvmm/x86/nvmm_x86_vmx.c Wed May 1 09:20:21 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: nvmm_x86_vmx.c,v 1.32 2019/04/29 18:54:26 maxv Exp $ */ +/* $NetBSD: nvmm_x86_vmx.c,v 1.33 2019/05/01 09:20:21 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_vmx.c,v 1.32 2019/04/29 18:54:26 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_vmx.c,v 1.33 2019/05/01 09:20:21 maxv Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -992,49 +992,53 @@ vmx_event_has_error(uint64_t vector) } static int -vmx_vcpu_inject(struct nvmm_machine *mach, struct nvmm_cpu *vcpu, - struct nvmm_event *event) +vmx_vcpu_inject(struct nvmm_cpu *vcpu) { + struct nvmm_comm_page *comm = vcpu->comm; struct vmx_cpudata *cpudata = vcpu->cpudata; int type = 0, err = 0, ret = EINVAL; - uint64_t info; + enum nvmm_event_type evtype; + uint64_t info, vector, error; + + evtype = comm->event.type; + vector = comm->event.vector; + error = comm->event.u.error; + __insn_barrier(); - if (event->vector >= 256) { + if (__predict_false(vector >= 256)) { return EINVAL; } vmx_vmcs_enter(vcpu); - switch (event->type) { + switch (evtype) { case NVMM_EVENT_INTERRUPT_HW: type = INTR_TYPE_EXT_INT; - if (event->vector == 2) { + if (vector == 2) { type = INTR_TYPE_NMI; vmx_event_waitexit_enable(vcpu, true); } err = 0; break; - case NVMM_EVENT_INTERRUPT_SW: - goto out; case NVMM_EVENT_EXCEPTION: - if (event->vector == 2 || event->vector >= 32) + if (vector == 2 || vector >= 32) goto out; - if (event->vector == 3 || event->vector == 0) + if (vector == 3 || vector == 0) goto out; type = INTR_TYPE_HW_EXC; - err = vmx_event_has_error(event->vector); + err = vmx_event_has_error(vector); break; default: goto out; } info = - __SHIFTIN(event->vector, INTR_INFO_VECTOR) | + __SHIFTIN(vector, INTR_INFO_VECTOR) | __SHIFTIN(type, INTR_INFO_TYPE) | __SHIFTIN(err, INTR_INFO_ERROR) | __SHIFTIN(1, INTR_INFO_VALID); vmx_vmwrite(VMCS_ENTRY_INTR_INFO, info); - vmx_vmwrite(VMCS_ENTRY_EXCEPTION_ERROR, event->u.error); + vmx_vmwrite(VMCS_ENTRY_EXCEPTION_ERROR, error); cpudata->evt_pending = true; ret = 0; @@ -1045,33 +1049,43 @@ out: } static void -vmx_inject_ud(struct nvmm_machine *mach, struct nvmm_cpu *vcpu) +vmx_inject_ud(struct nvmm_cpu *vcpu) { - struct nvmm_event event; + struct nvmm_comm_page *comm = vcpu->comm; int ret __diagused; - event.type = NVMM_EVENT_EXCEPTION; - event.vector = 6; - event.u.error = 0; + comm->event.type = NVMM_EVENT_EXCEPTION; + comm->event.vector = 6; + comm->event.u.error = 0; - ret = vmx_vcpu_inject(mach, vcpu, &event); + ret = vmx_vcpu_inject(vcpu); KASSERT(ret == 0); } static void -vmx_inject_gp(struct nvmm_machine *mach, struct nvmm_cpu *vcpu) +vmx_inject_gp(struct nvmm_cpu *vcpu) { - struct nvmm_event event; + struct nvmm_comm_page *comm = vcpu->comm; int ret __diagused; - event.type = NVMM_EVENT_EXCEPTION; - event.vector = 13; - event.u.error = 0; + comm->event.type = NVMM_EVENT_EXCEPTION; + comm->event.vector = 13; + comm->event.u.error = 0; - ret = vmx_vcpu_inject(mach, vcpu, &event); + ret = vmx_vcpu_inject(vcpu); KASSERT(ret == 0); } +static inline int +vmx_vcpu_event_commit(struct nvmm_cpu *vcpu) +{ + if (__predict_true(!vcpu->comm->event_commit)) { + return 0; + } + vcpu->comm->event_commit = false; + return vmx_vcpu_inject(vcpu); +} + static inline void vmx_inkernel_advance(void) { @@ -1430,7 +1444,7 @@ vmx_exit_cr(struct nvmm_machine *mach, s } if (ret == -1) { - vmx_inject_gp(mach, vcpu); + vmx_inject_gp(vcpu); } exit->reason = NVMM_EXIT_NONE; @@ -1575,7 +1589,7 @@ handled: return true; error: - vmx_inject_gp(mach, vcpu); + vmx_inject_gp(vcpu); return true; } @@ -1642,7 +1656,7 @@ vmx_exit_xsetbv(struct nvmm_machine *mac return; error: - vmx_inject_gp(mach, vcpu); + vmx_inject_gp(vcpu); } #define VMX_EPT_VIOLATION_READ __BIT(0) @@ -1873,6 +1887,10 @@ vmx_vcpu_run(struct nvmm_machine *mach, vmx_vmcs_enter(vcpu); + if (__predict_false(vmx_vcpu_event_commit(vcpu) != 0)) { + vmx_vmcs_leave(vcpu); + return EINVAL; + } vmx_vcpu_state_commit(vcpu); comm->state_cached = 0; @@ -1984,7 +2002,7 @@ vmx_vcpu_run(struct nvmm_machine *mach, case VMCS_EXITCODE_VMWRITE: case VMCS_EXITCODE_VMXOFF: case VMCS_EXITCODE_VMXON: - vmx_inject_ud(mach, vcpu); + vmx_inject_ud(vcpu); exit->reason = NVMM_EXIT_NONE; break; case VMCS_EXITCODE_EPT_VIOLATION: