1366f6083SPeter Grehan /*- 2366f6083SPeter Grehan * Copyright (c) 2011 NetApp, Inc. 3366f6083SPeter Grehan * All rights reserved. 4366f6083SPeter Grehan * 5366f6083SPeter Grehan * Redistribution and use in source and binary forms, with or without 6366f6083SPeter Grehan * modification, are permitted provided that the following conditions 7366f6083SPeter Grehan * are met: 8366f6083SPeter Grehan * 1. Redistributions of source code must retain the above copyright 9366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer. 10366f6083SPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 11366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer in the 12366f6083SPeter Grehan * documentation and/or other materials provided with the distribution. 13366f6083SPeter Grehan * 14366f6083SPeter Grehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15366f6083SPeter Grehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16366f6083SPeter Grehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17366f6083SPeter Grehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18366f6083SPeter Grehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19366f6083SPeter Grehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20366f6083SPeter Grehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21366f6083SPeter Grehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22366f6083SPeter Grehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23366f6083SPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24366f6083SPeter Grehan * SUCH DAMAGE. 25366f6083SPeter Grehan * 26366f6083SPeter Grehan * $FreeBSD$ 27366f6083SPeter Grehan */ 28366f6083SPeter Grehan 29366f6083SPeter Grehan #include <sys/cdefs.h> 30366f6083SPeter Grehan __FBSDID("$FreeBSD$"); 31366f6083SPeter Grehan 32318224bbSNeel Natu #include <sys/param.h> 33318224bbSNeel Natu #include <sys/kernel.h> 34366f6083SPeter Grehan #include <sys/types.h> 35366f6083SPeter Grehan #include <sys/systm.h> 36366f6083SPeter Grehan #include <sys/smp.h> 37318224bbSNeel Natu #include <sys/sysctl.h> 38366f6083SPeter Grehan 39366f6083SPeter Grehan #include <vm/vm.h> 40366f6083SPeter Grehan #include <vm/pmap.h> 41318224bbSNeel Natu #include <vm/vm_extern.h> 42366f6083SPeter Grehan 43366f6083SPeter Grehan #include <machine/vmm.h> 44318224bbSNeel Natu 45366f6083SPeter Grehan #include "vmx_cpufunc.h" 46*5515bb73SNeel Natu #include "vmm_ipi.h" 47366f6083SPeter Grehan #include "vmx_msr.h" 48366f6083SPeter Grehan #include "ept.h" 49366f6083SPeter Grehan 50318224bbSNeel Natu #define EPT_SUPPORTS_EXEC_ONLY(cap) ((cap) & (1UL << 0)) 51366f6083SPeter Grehan #define EPT_PWL4(cap) ((cap) & (1UL << 6)) 52366f6083SPeter Grehan #define EPT_MEMORY_TYPE_WB(cap) ((cap) & (1UL << 14)) 53366f6083SPeter Grehan #define EPT_PDE_SUPERPAGE(cap) ((cap) & (1UL << 16)) /* 2MB pages */ 54366f6083SPeter Grehan #define EPT_PDPTE_SUPERPAGE(cap) ((cap) & (1UL << 17)) /* 1GB pages */ 55366f6083SPeter Grehan #define INVEPT_SUPPORTED(cap) ((cap) & (1UL << 20)) 56318224bbSNeel Natu #define AD_BITS_SUPPORTED(cap) ((cap) & (1UL << 21)) 57318224bbSNeel Natu #define INVVPID_SUPPORTED(cap) ((cap) & (1UL << 32)) 58366f6083SPeter Grehan 59366f6083SPeter Grehan #define INVVPID_ALL_TYPES_MASK 0xF0000000000UL 60366f6083SPeter Grehan #define INVVPID_ALL_TYPES_SUPPORTED(cap) \ 61366f6083SPeter Grehan (((cap) & INVVPID_ALL_TYPES_MASK) == INVVPID_ALL_TYPES_MASK) 62366f6083SPeter Grehan 63366f6083SPeter Grehan #define INVEPT_ALL_TYPES_MASK 0x6000000UL 64366f6083SPeter Grehan #define INVEPT_ALL_TYPES_SUPPORTED(cap) \ 65366f6083SPeter Grehan (((cap) & INVEPT_ALL_TYPES_MASK) == INVEPT_ALL_TYPES_MASK) 66366f6083SPeter Grehan 67318224bbSNeel Natu #define EPT_PWLEVELS 4 /* page walk levels */ 68318224bbSNeel Natu #define EPT_ENABLE_AD_BITS (1 << 6) 69366f6083SPeter Grehan 70318224bbSNeel Natu SYSCTL_DECL(_hw_vmm); 71318224bbSNeel Natu SYSCTL_NODE(_hw_vmm, OID_AUTO, ept, CTLFLAG_RW, NULL, NULL); 72366f6083SPeter Grehan 73318224bbSNeel Natu static int ept_enable_ad_bits; 74366f6083SPeter Grehan 75318224bbSNeel Natu static int ept_pmap_flags; 76318224bbSNeel Natu SYSCTL_INT(_hw_vmm_ept, OID_AUTO, pmap_flags, CTLFLAG_RD, 77318224bbSNeel Natu &ept_pmap_flags, 0, NULL); 78e60f5d77SPeter Grehan 79366f6083SPeter Grehan int 80366f6083SPeter Grehan ept_init(void) 81366f6083SPeter Grehan { 82318224bbSNeel Natu int use_hw_ad_bits, use_superpages, use_exec_only; 83366f6083SPeter Grehan uint64_t cap; 84366f6083SPeter Grehan 85366f6083SPeter Grehan cap = rdmsr(MSR_VMX_EPT_VPID_CAP); 86366f6083SPeter Grehan 87366f6083SPeter Grehan /* 88366f6083SPeter Grehan * Verify that: 89366f6083SPeter Grehan * - page walk length is 4 steps 90366f6083SPeter Grehan * - extended page tables can be laid out in write-back memory 91366f6083SPeter Grehan * - invvpid instruction with all possible types is supported 92366f6083SPeter Grehan * - invept instruction with all possible types is supported 93366f6083SPeter Grehan */ 94366f6083SPeter Grehan if (!EPT_PWL4(cap) || 95366f6083SPeter Grehan !EPT_MEMORY_TYPE_WB(cap) || 96366f6083SPeter Grehan !INVVPID_SUPPORTED(cap) || 97366f6083SPeter Grehan !INVVPID_ALL_TYPES_SUPPORTED(cap) || 98366f6083SPeter Grehan !INVEPT_SUPPORTED(cap) || 99366f6083SPeter Grehan !INVEPT_ALL_TYPES_SUPPORTED(cap)) 100366f6083SPeter Grehan return (EINVAL); 101366f6083SPeter Grehan 102*5515bb73SNeel Natu ept_pmap_flags = vmm_ipinum & PMAP_NESTED_IPIMASK; 103*5515bb73SNeel Natu 104318224bbSNeel Natu use_superpages = 1; 105318224bbSNeel Natu TUNABLE_INT_FETCH("hw.vmm.ept.use_superpages", &use_superpages); 106318224bbSNeel Natu if (use_superpages && EPT_PDE_SUPERPAGE(cap)) 107318224bbSNeel Natu ept_pmap_flags |= PMAP_PDE_SUPERPAGE; /* 2MB superpage */ 108366f6083SPeter Grehan 109318224bbSNeel Natu use_hw_ad_bits = 1; 110318224bbSNeel Natu TUNABLE_INT_FETCH("hw.vmm.ept.use_hw_ad_bits", &use_hw_ad_bits); 111318224bbSNeel Natu if (use_hw_ad_bits && AD_BITS_SUPPORTED(cap)) 112318224bbSNeel Natu ept_enable_ad_bits = 1; 113318224bbSNeel Natu else 114318224bbSNeel Natu ept_pmap_flags |= PMAP_EMULATE_AD_BITS; 115366f6083SPeter Grehan 116318224bbSNeel Natu use_exec_only = 1; 117318224bbSNeel Natu TUNABLE_INT_FETCH("hw.vmm.ept.use_exec_only", &use_exec_only); 118318224bbSNeel Natu if (use_exec_only && EPT_SUPPORTS_EXEC_ONLY(cap)) 119318224bbSNeel Natu ept_pmap_flags |= PMAP_SUPPORTS_EXEC_ONLY; 120366f6083SPeter Grehan 121366f6083SPeter Grehan return (0); 122366f6083SPeter Grehan } 123366f6083SPeter Grehan 124bda273f2SNeel Natu #if 0 125bda273f2SNeel Natu static void 126bda273f2SNeel Natu ept_dump(uint64_t *ptp, int nlevels) 127bda273f2SNeel Natu { 128bda273f2SNeel Natu int i, t, tabs; 129bda273f2SNeel Natu uint64_t *ptpnext, ptpval; 130bda273f2SNeel Natu 131bda273f2SNeel Natu if (--nlevels < 0) 132bda273f2SNeel Natu return; 133bda273f2SNeel Natu 134bda273f2SNeel Natu tabs = 3 - nlevels; 135bda273f2SNeel Natu for (t = 0; t < tabs; t++) 136bda273f2SNeel Natu printf("\t"); 137bda273f2SNeel Natu printf("PTP = %p\n", ptp); 138bda273f2SNeel Natu 139bda273f2SNeel Natu for (i = 0; i < 512; i++) { 140bda273f2SNeel Natu ptpval = ptp[i]; 141bda273f2SNeel Natu 142bda273f2SNeel Natu if (ptpval == 0) 143bda273f2SNeel Natu continue; 144bda273f2SNeel Natu 145bda273f2SNeel Natu for (t = 0; t < tabs; t++) 146bda273f2SNeel Natu printf("\t"); 147bda273f2SNeel Natu printf("%3d 0x%016lx\n", i, ptpval); 148bda273f2SNeel Natu 149bda273f2SNeel Natu if (nlevels != 0 && (ptpval & EPT_PG_SUPERPAGE) == 0) { 150bda273f2SNeel Natu ptpnext = (uint64_t *) 151bda273f2SNeel Natu PHYS_TO_DMAP(ptpval & EPT_ADDR_MASK); 152bda273f2SNeel Natu ept_dump(ptpnext, nlevels); 153bda273f2SNeel Natu } 154bda273f2SNeel Natu } 155bda273f2SNeel Natu } 156bda273f2SNeel Natu #endif 157bda273f2SNeel Natu 158366f6083SPeter Grehan static void 159366f6083SPeter Grehan invept_single_context(void *arg) 160366f6083SPeter Grehan { 161366f6083SPeter Grehan struct invept_desc desc = *(struct invept_desc *)arg; 162366f6083SPeter Grehan 163366f6083SPeter Grehan invept(INVEPT_TYPE_SINGLE_CONTEXT, desc); 164366f6083SPeter Grehan } 165366f6083SPeter Grehan 166366f6083SPeter Grehan void 167318224bbSNeel Natu ept_invalidate_mappings(u_long eptp) 168366f6083SPeter Grehan { 169366f6083SPeter Grehan struct invept_desc invept_desc = { 0 }; 170366f6083SPeter Grehan 171318224bbSNeel Natu invept_desc.eptp = eptp; 172366f6083SPeter Grehan 173366f6083SPeter Grehan smp_rendezvous(NULL, invept_single_context, NULL, &invept_desc); 174366f6083SPeter Grehan } 175318224bbSNeel Natu 176318224bbSNeel Natu static int 177318224bbSNeel Natu ept_pinit(pmap_t pmap) 178318224bbSNeel Natu { 179318224bbSNeel Natu 180318224bbSNeel Natu return (pmap_pinit_type(pmap, PT_EPT, ept_pmap_flags)); 181318224bbSNeel Natu } 182318224bbSNeel Natu 183318224bbSNeel Natu struct vmspace * 184318224bbSNeel Natu ept_vmspace_alloc(vm_offset_t min, vm_offset_t max) 185318224bbSNeel Natu { 186318224bbSNeel Natu 187318224bbSNeel Natu return (vmspace_alloc(min, max, ept_pinit)); 188318224bbSNeel Natu } 189318224bbSNeel Natu 190318224bbSNeel Natu void 191318224bbSNeel Natu ept_vmspace_free(struct vmspace *vmspace) 192318224bbSNeel Natu { 193318224bbSNeel Natu 194318224bbSNeel Natu vmspace_free(vmspace); 195318224bbSNeel Natu } 196318224bbSNeel Natu 197318224bbSNeel Natu uint64_t 198318224bbSNeel Natu eptp(uint64_t pml4) 199318224bbSNeel Natu { 200318224bbSNeel Natu uint64_t eptp_val; 201318224bbSNeel Natu 202318224bbSNeel Natu eptp_val = pml4 | (EPT_PWLEVELS - 1) << 3 | PAT_WRITE_BACK; 203318224bbSNeel Natu if (ept_enable_ad_bits) 204318224bbSNeel Natu eptp_val |= EPT_ENABLE_AD_BITS; 205318224bbSNeel Natu 206318224bbSNeel Natu return (eptp_val); 207318224bbSNeel Natu } 208