Source-Changes-HG archive

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

[src/trunk]: src/sys Add Intel-VMX support in NVMM. This allows us to run har...



details:   https://anonhg.NetBSD.org/src/rev/947cea4af610
branches:  trunk
changeset: 448913:947cea4af610
user:      maxv <maxv%NetBSD.org@localhost>
date:      Wed Feb 13 16:03:16 2019 +0000

description:
Add Intel-VMX support in NVMM. This allows us to run hardware-accelerated
VMs on Intel CPUs. Overall this implementation is fast and reliable, I am
able to run NetBSD VMs with many VCPUs on a quad-core Intel i5.

NVMM-Intel applies several optimizations already present in NVMM-AMD, and
has a code structure similar to it. No change was needed in the NVMM MI
frontend, or in libnvmm.

Some differences exist against AMD:

 - On Intel the ASID space is big, so we don't fall back to a shared ASID
   when there are more VCPUs executing than available ASIDs in the host,
   contrary to AMD. There are enough ASIDs for the maximum number of VCPUs
   supported by NVMM.

 - On Intel there are two TLBs we need to take care of, one for the host
   (EPT) and one for the guest (VPID). Changes in EPT paging flush the
   host TLB, changes to the guest mode flush the guest TLB.

 - On Intel there is no easy way to set/fetch the VTPR, so we intercept
   reads/writes to CR8 and maintain a software TPR, that we give to the
   virtualizer as if it was the effective TPR in the guest.

 - On Intel, because of SVS, the host CR4 and LSTAR are not static, so
   we're forced to save them on each VMENTRY.

 - There is extra Intel weirdness we need to take care of, for example the
   reserved bits in CR0 and CR4 when accesses trap.

While this implementation is functional and can already run many OSes, we
likely have a problem on 32bit-PAE guests, because they require special
care on Intel CPUs, and currently we don't handle that correctly; such
guests may misbehave for now (without altering the host stability). I
expect to fix that soon.

diffstat:

 sys/dev/nvmm/nvmm.c                 |     7 +-
 sys/dev/nvmm/nvmm_internal.h        |     3 +-
 sys/dev/nvmm/x86/nvmm_x86_vmx.c     |  2823 +++++++++++++++++++++++++++++++++++
 sys/dev/nvmm/x86/nvmm_x86_vmxfunc.S |   357 ++++
 sys/modules/nvmm/Makefile           |     3 +-
 5 files changed, 3188 insertions(+), 5 deletions(-)

diffs (truncated from 3249 to 300 lines):

diff -r b215996c038a -r 947cea4af610 sys/dev/nvmm/nvmm.c
--- a/sys/dev/nvmm/nvmm.c       Wed Feb 13 14:55:29 2019 +0000
+++ b/sys/dev/nvmm/nvmm.c       Wed Feb 13 16:03:16 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: nvmm.c,v 1.6 2019/01/26 15:25:51 maxv Exp $    */
+/*     $NetBSD: nvmm.c,v 1.7 2019/02/13 16:03:16 maxv Exp $    */
 
 /*
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvmm.c,v 1.6 2019/01/26 15:25:51 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvmm.c,v 1.7 2019/02/13 16:03:16 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -54,7 +54,8 @@
 static struct nvmm_machine machines[NVMM_MAX_MACHINES];
 
 static const struct nvmm_impl *nvmm_impl_list[] = {
-       &nvmm_x86_svm   /* x86 AMD SVM */
+       &nvmm_x86_svm,  /* x86 AMD SVM */
+       &nvmm_x86_vmx   /* x86 Intel VMX */
 };
 
 static const struct nvmm_impl *nvmm_impl = NULL;
diff -r b215996c038a -r 947cea4af610 sys/dev/nvmm/nvmm_internal.h
--- a/sys/dev/nvmm/nvmm_internal.h      Wed Feb 13 14:55:29 2019 +0000
+++ b/sys/dev/nvmm/nvmm_internal.h      Wed Feb 13 16:03:16 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: nvmm_internal.h,v 1.4 2019/02/11 07:07:37 maxv Exp $   */
+/*     $NetBSD: nvmm_internal.h,v 1.5 2019/02/13 16:03:16 maxv Exp $   */
 
 /*
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -109,5 +109,6 @@
 void nvmm_vcpu_put(struct nvmm_cpu *);
 
 extern const struct nvmm_impl nvmm_x86_svm;
+extern const struct nvmm_impl nvmm_x86_vmx;
 
 #endif /* _NVMM_INTERNAL_H_ */
diff -r b215996c038a -r 947cea4af610 sys/dev/nvmm/x86/nvmm_x86_vmx.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/nvmm/x86/nvmm_x86_vmx.c   Wed Feb 13 16:03:16 2019 +0000
@@ -0,0 +1,2823 @@
+/*     $NetBSD: nvmm_x86_vmx.c,v 1.1 2019/02/13 16:03:16 maxv Exp $    */
+
+/*
+ * Copyright (c) 2018 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Maxime Villard.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_vmx.c,v 1.1 2019/02/13 16:03:16 maxv Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/kmem.h>
+#include <sys/cpu.h>
+#include <sys/xcall.h>
+
+#include <uvm/uvm.h>
+#include <uvm/uvm_page.h>
+
+#include <x86/cputypes.h>
+#include <x86/specialreg.h>
+#include <x86/pmap.h>
+#include <x86/dbregs.h>
+#include <machine/cpuvar.h>
+
+#include <dev/nvmm/nvmm.h>
+#include <dev/nvmm/nvmm_internal.h>
+#include <dev/nvmm/x86/nvmm_x86.h>
+
+int _vmx_vmxon(paddr_t *pa);
+int _vmx_vmxoff(void);
+int _vmx_invept(uint64_t op, void *desc);
+int _vmx_invvpid(uint64_t op, void *desc);
+int _vmx_vmread(uint64_t op, uint64_t *val);
+int _vmx_vmwrite(uint64_t op, uint64_t val);
+int _vmx_vmptrld(paddr_t *pa);
+int _vmx_vmptrst(paddr_t *pa);
+int _vmx_vmclear(paddr_t *pa);
+int vmx_vmlaunch(uint64_t *gprs);
+int vmx_vmresume(uint64_t *gprs);
+
+#define vmx_vmxon(a) \
+       if (__predict_false(_vmx_vmxon(a) != 0)) { \
+               panic("%s: VMXON failed", __func__); \
+       }
+#define vmx_vmxoff() \
+       if (__predict_false(_vmx_vmxoff() != 0)) { \
+               panic("%s: VMXOFF failed", __func__); \
+       }
+#define vmx_invept(a, b) \
+       if (__predict_false(_vmx_invept(a, b) != 0)) { \
+               panic("%s: INVEPT failed", __func__); \
+       }
+#define vmx_invvpid(a, b) \
+       if (__predict_false(_vmx_invvpid(a, b) != 0)) { \
+               panic("%s: INVVPID failed", __func__); \
+       }
+#define vmx_vmread(a, b) \
+       if (__predict_false(_vmx_vmread(a, b) != 0)) { \
+               panic("%s: VMREAD failed", __func__); \
+       }
+#define vmx_vmwrite(a, b) \
+       if (__predict_false(_vmx_vmwrite(a, b) != 0)) { \
+               panic("%s: VMWRITE failed", __func__); \
+       }
+#define vmx_vmptrld(a) \
+       if (__predict_false(_vmx_vmptrld(a) != 0)) { \
+               panic("%s: VMPTRLD failed", __func__); \
+       }
+#define vmx_vmptrst(a) \
+       if (__predict_false(_vmx_vmptrst(a) != 0)) { \
+               panic("%s: VMPTRST failed", __func__); \
+       }
+#define vmx_vmclear(a) \
+       if (__predict_false(_vmx_vmclear(a) != 0)) { \
+               panic("%s: VMCLEAR failed", __func__); \
+       }
+
+#define MSR_IA32_FEATURE_CONTROL       0x003A
+#define                IA32_FEATURE_CONTROL_LOCK       __BIT(0)
+#define                IA32_FEATURE_CONTROL_IN_SMX     __BIT(1)
+#define                IA32_FEATURE_CONTROL_OUT_SMX    __BIT(2)
+
+#define MSR_IA32_VMX_BASIC             0x0480
+#define                IA32_VMX_BASIC_IDENT            __BITS(30,0)
+#define                IA32_VMX_BASIC_DATA_SIZE        __BITS(44,32)
+#define                IA32_VMX_BASIC_MEM_WIDTH        __BIT(48)
+#define                IA32_VMX_BASIC_DUAL             __BIT(49)
+#define                IA32_VMX_BASIC_MEM_TYPE         __BITS(53,50)
+#define                        MEM_TYPE_UC             0
+#define                        MEM_TYPE_WB             6
+#define                IA32_VMX_BASIC_IO_REPORT        __BIT(54)
+#define                IA32_VMX_BASIC_TRUE_CTLS        __BIT(55)
+
+#define MSR_IA32_VMX_PINBASED_CTLS             0x0481
+#define MSR_IA32_VMX_PROCBASED_CTLS            0x0482
+#define MSR_IA32_VMX_EXIT_CTLS                 0x0483
+#define MSR_IA32_VMX_ENTRY_CTLS                        0x0484
+#define MSR_IA32_VMX_PROCBASED_CTLS2           0x048B
+
+#define MSR_IA32_VMX_TRUE_PINBASED_CTLS                0x048D
+#define MSR_IA32_VMX_TRUE_PROCBASED_CTLS       0x048E
+#define MSR_IA32_VMX_TRUE_EXIT_CTLS            0x048F
+#define MSR_IA32_VMX_TRUE_ENTRY_CTLS           0x0490
+
+#define MSR_IA32_VMX_CR0_FIXED0                        0x0486
+#define MSR_IA32_VMX_CR0_FIXED1                        0x0487
+#define MSR_IA32_VMX_CR4_FIXED0                        0x0488
+#define MSR_IA32_VMX_CR4_FIXED1                        0x0489
+
+#define MSR_IA32_VMX_EPT_VPID_CAP      0x048C
+#define                IA32_VMX_EPT_VPID_WALKLENGTH_4          __BIT(6)
+#define                IA32_VMX_EPT_VPID_UC                    __BIT(8)
+#define                IA32_VMX_EPT_VPID_WB                    __BIT(14)
+#define                IA32_VMX_EPT_VPID_INVEPT                __BIT(20)
+#define                IA32_VMX_EPT_VPID_FLAGS_AD              __BIT(21)
+#define                IA32_VMX_EPT_VPID_INVEPT_CONTEXT        __BIT(25)
+#define                IA32_VMX_EPT_VPID_INVEPT_ALL            __BIT(26)
+#define                IA32_VMX_EPT_VPID_INVVPID               __BIT(32)
+#define                IA32_VMX_EPT_VPID_INVVPID_ADDR          __BIT(40)
+#define                IA32_VMX_EPT_VPID_INVVPID_CONTEXT       __BIT(41)
+#define                IA32_VMX_EPT_VPID_INVVPID_ALL           __BIT(42)
+#define                IA32_VMX_EPT_VPID_INVVPID_CONTEXT_NOG   __BIT(43)
+
+/* -------------------------------------------------------------------------- */
+
+/* 16-bit control fields */
+#define VMCS_VPID                              0x00000000
+#define VMCS_PIR_VECTOR                                0x00000002
+#define VMCS_EPTP_INDEX                                0x00000004
+/* 16-bit guest-state fields */
+#define VMCS_GUEST_ES_SELECTOR                 0x00000800
+#define VMCS_GUEST_CS_SELECTOR                 0x00000802
+#define VMCS_GUEST_SS_SELECTOR                 0x00000804
+#define VMCS_GUEST_DS_SELECTOR                 0x00000806
+#define VMCS_GUEST_FS_SELECTOR                 0x00000808
+#define VMCS_GUEST_GS_SELECTOR                 0x0000080A
+#define VMCS_GUEST_LDTR_SELECTOR               0x0000080C
+#define VMCS_GUEST_TR_SELECTOR                 0x0000080E
+#define VMCS_GUEST_INTR_STATUS                 0x00000810
+#define VMCS_PML_INDEX                         0x00000812
+/* 16-bit host-state fields */
+#define VMCS_HOST_ES_SELECTOR                  0x00000C00
+#define VMCS_HOST_CS_SELECTOR                  0x00000C02
+#define VMCS_HOST_SS_SELECTOR                  0x00000C04
+#define VMCS_HOST_DS_SELECTOR                  0x00000C06
+#define VMCS_HOST_FS_SELECTOR                  0x00000C08
+#define VMCS_HOST_GS_SELECTOR                  0x00000C0A
+#define VMCS_HOST_TR_SELECTOR                  0x00000C0C
+/* 64-bit control fields */
+#define VMCS_IO_BITMAP_A                       0x00002000
+#define VMCS_IO_BITMAP_B                       0x00002002
+#define VMCS_MSR_BITMAP                                0x00002004
+#define VMCS_EXIT_MSR_STORE_ADDRESS            0x00002006
+#define VMCS_EXIT_MSR_LOAD_ADDRESS             0x00002008
+#define VMCS_ENTRY_MSR_LOAD_ADDRESS            0x0000200A
+#define VMCS_EXECUTIVE_VMCS                    0x0000200C
+#define VMCS_PML_ADDRESS                       0x0000200E
+#define VMCS_TSC_OFFSET                                0x00002010
+#define VMCS_VIRTUAL_APIC                      0x00002012
+#define VMCS_APIC_ACCESS                       0x00002014
+#define VMCS_PIR_DESC                          0x00002016
+#define VMCS_VM_CONTROL                                0x00002018
+#define VMCS_EPTP                              0x0000201A
+#define                EPTP_TYPE                       __BITS(2,0)
+#define                        EPTP_TYPE_UC            0
+#define                        EPTP_TYPE_WB            6
+#define                EPTP_WALKLEN                    __BITS(5,3)
+#define                EPTP_FLAGS_AD                   __BIT(6)
+#define                EPTP_PHYSADDR                   __BITS(63,12)
+#define VMCS_EOI_EXIT0                         0x0000201C
+#define VMCS_EOI_EXIT1                         0x0000201E
+#define VMCS_EOI_EXIT2                         0x00002020
+#define VMCS_EOI_EXIT3                         0x00002022
+#define VMCS_EPTP_LIST                         0x00002024
+#define VMCS_VMREAD_BITMAP                     0x00002026
+#define VMCS_VMWRITE_BITMAP                    0x00002028
+#define VMCS_VIRTUAL_EXCEPTION                 0x0000202A
+#define VMCS_XSS_EXIT_BITMAP                   0x0000202C
+#define VMCS_ENCLS_EXIT_BITMAP                 0x0000202E
+#define VMCS_TSC_MULTIPLIER                    0x00002032
+/* 64-bit read-only fields */
+#define VMCS_GUEST_PHYSICAL_ADDRESS            0x00002400
+/* 64-bit guest-state fields */
+#define VMCS_LINK_POINTER                      0x00002800
+#define VMCS_GUEST_IA32_DEBUGCTL               0x00002802
+#define VMCS_GUEST_IA32_PAT                    0x00002804
+#define VMCS_GUEST_IA32_EFER                   0x00002806
+#define VMCS_GUEST_IA32_PERF_GLOBAL_CTRL       0x00002808
+#define VMCS_GUEST_PDPTE0                      0x0000280A
+#define VMCS_GUEST_PDPTE1                      0x0000280C
+#define VMCS_GUEST_PDPTE2                      0x0000280E
+#define VMCS_GUEST_PDPTE3                      0x00002810
+#define VMCS_GUEST_BNDCFGS                     0x00002812
+/* 64-bit host-state fields */
+#define VMCS_HOST_IA32_PAT                     0x00002C00
+#define VMCS_HOST_IA32_EFER                    0x00002C02
+#define VMCS_HOST_IA32_PERF_GLOBAL_CTRL                0x00002C04
+/* 32-bit control fields */
+#define VMCS_PINBASED_CTLS                     0x00004000
+#define                PIN_CTLS_INT_EXITING            __BIT(0)
+#define                PIN_CTLS_NMI_EXITING            __BIT(3)
+#define                PIN_CTLS_VIRTUAL_NMIS           __BIT(5)
+#define                PIN_CTLS_ACTIVATE_PREEMPT_TIMER __BIT(6)
+#define                PIN_CTLS_PROCESS_POSTEd_INTS    __BIT(7)
+#define VMCS_PROCBASED_CTLS                    0x00004002
+#define                PROC_CTLS_INT_WINDOW_EXITING    __BIT(2)
+#define                PROC_CTLS_USE_TSC_OFFSETTING    __BIT(3)
+#define                PROC_CTLS_HLT_EXITING           __BIT(7)
+#define                PROC_CTLS_INVLPG_EXITING        __BIT(9)
+#define                PROC_CTLS_MWAIT_EXITING         __BIT(10)
+#define                PROC_CTLS_RDPMC_EXITING         __BIT(11)
+#define                PROC_CTLS_RDTSC_EXITING         __BIT(12)
+#define                PROC_CTLS_RCR3_EXITING          __BIT(15)
+#define                PROC_CTLS_LCR3_EXITING          __BIT(16)
+#define                PROC_CTLS_RCR8_EXITING          __BIT(19)
+#define                PROC_CTLS_LCR8_EXITING          __BIT(20)
+#define                PROC_CTLS_USE_TPR_SHADOW        __BIT(21)
+#define                PROC_CTLS_NMI_WINDOW_EXITING    __BIT(22)
+#define                PROC_CTLS_DR_EXITING            __BIT(23)
+#define                PROC_CTLS_UNCOND_IO_EXITING     __BIT(24)
+#define                PROC_CTLS_USE_IO_BITMAPS        __BIT(25)
+#define                PROC_CTLS_MONITOR_TRAP_FLAG     __BIT(27)
+#define                PROC_CTLS_USE_MSR_BITMAPS       __BIT(28)
+#define                PROC_CTLS_MONITOR_EXITING       __BIT(29)
+#define                PROC_CTLS_PAUSE_EXITING         __BIT(30)
+#define                PROC_CTLS_ACTIVATE_CTLS2        __BIT(31)



Home | Main Index | Thread Index | Old Index