2 * Copyright (c) 2003-2013 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Mihai Carabas <mihai.carabas@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/systm.h>
36 #include <sys/sfbuf.h>
38 #include <sys/thread.h>
40 #include <machine/pmap.h>
41 #include <machine/specialreg.h>
42 #include <machine/cpufunc.h>
43 #include <machine/vmm.h>
45 #include <vm/vm_extern.h>
46 #include <vm/vm_map.h>
50 #include "vmm_utils.h"
52 static uint64_t pmap_bits_ept[PG_BITS_SIZE];
53 static pt_entry_t pmap_cache_bits_ept[PAT_INDEX_SIZE];
54 static int ept_protection_codes[PROTECTION_CODES_SIZE];
55 static pt_entry_t pmap_cache_mask_ept;
57 static int pmap_pm_flags_ept;
60 extern uint64_t vmx_ept_vpid_cap;
66 /* Chapter 28 VMX SUPPORT FOR ADDRESS TRANSLATION
67 * Intel Manual 3c, page 107
69 vmx_ept_vpid_cap = rdmsr(IA32_VMX_EPT_VPID_CAP);
71 if(!EPT_PWL4(vmx_ept_vpid_cap)||
72 !EPT_MEMORY_TYPE_WB(vmx_ept_vpid_cap)) {
76 eptp_bits |= EPTP_CACHE(PAT_WRITE_BACK) |
77 EPTP_PWLEN(EPT_PWLEVELS - 1);
79 if (EPT_AD_BITS_SUPPORTED(vmx_ept_vpid_cap)) {
80 eptp_bits |= EPTP_AD_ENABLE;
82 pmap_pm_flags_ept = PMAP_EMULATE_AD_BITS;
85 /* Initialize EPT bits
86 * - for PG_V - set READ and EXECUTE to preserve compatibility
87 * - for PG_U and PG_G - set 0 to preserve compatiblity
88 * - for PG_N - set the Uncacheable bit
90 pmap_bits_ept[TYPE_IDX] = EPT_PMAP;
91 pmap_bits_ept[PG_V_IDX] = EPT_PG_READ | EPT_PG_EXECUTE;
92 pmap_bits_ept[PG_RW_IDX] = EPT_PG_WRITE;
93 pmap_bits_ept[PG_PS_IDX] = EPT_PG_PS;
94 pmap_bits_ept[PG_G_IDX] = 0;
95 pmap_bits_ept[PG_U_IDX] = 0;
96 pmap_bits_ept[PG_A_IDX] = EPT_PG_A;
97 pmap_bits_ept[PG_M_IDX] = EPT_PG_M;
98 pmap_bits_ept[PG_W_IDX] = EPT_PG_AVAIL1;
99 pmap_bits_ept[PG_MANAGED_IDX] = EPT_PG_AVAIL2;
100 pmap_bits_ept[PG_DEVICE_IDX] = EPT_PG_AVAIL3;
101 pmap_bits_ept[PG_N_IDX] = EPT_IGNORE_PAT | EPT_MEM_TYPE_UC;
104 pmap_cache_mask_ept = EPT_IGNORE_PAT | EPT_MEM_TYPE_MASK;
106 pmap_cache_bits_ept[PAT_UNCACHEABLE] = EPT_IGNORE_PAT | EPT_MEM_TYPE_UC;
107 pmap_cache_bits_ept[PAT_WRITE_COMBINING] = EPT_IGNORE_PAT | EPT_MEM_TYPE_WC;
108 pmap_cache_bits_ept[PAT_WRITE_THROUGH] = EPT_IGNORE_PAT | EPT_MEM_TYPE_WT;
109 pmap_cache_bits_ept[PAT_WRITE_PROTECTED] = EPT_IGNORE_PAT | EPT_MEM_TYPE_WP;
110 pmap_cache_bits_ept[PAT_WRITE_BACK] = EPT_IGNORE_PAT | EPT_MEM_TYPE_WB;
111 pmap_cache_bits_ept[PAT_UNCACHED] = EPT_IGNORE_PAT | EPT_MEM_TYPE_UC;
113 for (prot = 0; prot < PROTECTION_CODES_SIZE; prot++) {
115 case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE:
116 case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE:
117 case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE:
118 case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE:
119 ept_protection_codes[prot] = 0;
121 case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE:
122 case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE:
123 case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE:
124 case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
125 ept_protection_codes[prot] = pmap_bits_ept[PG_RW_IDX];
134 /* Build the VMCS_EPTP pointer
136 * - the EPTP bits indicating optional features
138 uint64_t vmx_eptp(uint64_t ept_address)
140 return (ept_address | eptp_bits);
143 /* Copyin from guest VMM */
145 ept_copyin(const void *udaddr, void *kaddr, size_t len)
148 struct lwbuf lwb_cache;
153 struct vmspace *vm = curproc->p_vmspace;
154 struct vmx_thread_info *vti = curthread->td_vmm;
155 register_t guest_cr3 = vti->guest_cr3;
158 /* Get the GPA by manually walking the-GUEST page table*/
159 err = guest_phys_addr(vm, &gpa, guest_cr3, (vm_offset_t)udaddr);
161 kprintf("%s: could not get guest_phys_addr\n", __func__);
165 m = vm_fault_page(&vm->vm_map, trunc_page(gpa),
166 VM_PROT_READ, VM_FAULT_NORMAL, &err);
168 kprintf("%s: could not fault in vm map, gpa: %llx\n",
169 __func__, (unsigned long long) gpa);
173 n = PAGE_SIZE - ((vm_offset_t)udaddr & PAGE_MASK);
177 lwb = lwbuf_alloc(m, &lwb_cache);
178 bcopy((char *)lwbuf_kva(lwb)+((vm_offset_t)udaddr & PAGE_MASK), kaddr, n);
180 udaddr = (const char *)udaddr + n;
181 kaddr = (char *)kaddr + n;
190 /* Copyout from guest VMM */
192 ept_copyout(const void *kaddr, void *udaddr, size_t len)
195 struct lwbuf lwb_cache;
200 struct vmspace *vm = curproc->p_vmspace;
201 struct vmx_thread_info *vti = curthread->td_vmm;
202 register_t guest_cr3 = vti->guest_cr3;
205 /* Get the GPA by manually walking the-GUEST page table*/
206 err = guest_phys_addr(vm, &gpa, guest_cr3, (vm_offset_t)udaddr);
208 kprintf("%s: could not get guest_phys_addr\n", __func__);
212 m = vm_fault_page(&vm->vm_map, trunc_page(gpa),
213 VM_PROT_READ | VM_PROT_WRITE,
214 VM_FAULT_NORMAL, &err);
216 kprintf("%s: could not fault in vm map, gpa: %llx\n",
217 __func__, (unsigned long long) gpa);
221 n = PAGE_SIZE - ((vm_offset_t)udaddr & PAGE_MASK);
225 lwb = lwbuf_alloc(m, &lwb_cache);
226 bcopy(kaddr, (char *)lwbuf_kva(lwb) +
227 ((vm_offset_t)udaddr & PAGE_MASK), n);
230 udaddr = (char *)udaddr + n;
231 kaddr = (const char *)kaddr + n;
234 /* should not be needed */
235 cpu_invlpg((char *)lwbuf_kva(lwb) +
236 ((vm_offset_t)udaddr & PAGE_MASK));
247 ept_copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *res)
251 const char *uptr = udaddr;
257 n = PAGE_SIZE - ((vm_offset_t)uptr & PAGE_MASK);
262 if ((error = ept_copyin(uptr, kptr, n)) != 0)
276 return(ENAMETOOLONG);
281 ept_fubyte(const void *base)
285 if (ept_copyin(base, &c, 1) == 0)
291 ept_subyte(void *base, int byte)
293 unsigned char c = byte;
295 if (ept_copyout(&c, base, 1) == 0)
301 ept_fuword(const void *base)
305 if (ept_copyin(base, &v, sizeof(v)) == 0)
311 ept_suword(void *base, long word)
313 if (ept_copyout(&word, base, sizeof(word)) == 0)
319 ept_suword32(void *base, int word)
321 if (ept_copyout(&word, base, sizeof(word)) == 0)
327 vmx_ept_pmap_pinit(pmap_t pmap)
329 pmap->pm_flags |= pmap_pm_flags_ept;
331 bcopy(pmap_bits_ept, pmap->pmap_bits, sizeof(pmap_bits_ept));
332 bcopy(ept_protection_codes, pmap->protection_codes,
333 sizeof(ept_protection_codes));
334 bcopy(pmap_cache_bits_ept, pmap->pmap_cache_bits,
335 sizeof(pmap_cache_bits_ept));
336 pmap->pmap_cache_mask = pmap_cache_mask_ept;
337 pmap->copyinstr = ept_copyinstr;
338 pmap->copyin = ept_copyin;
339 pmap->copyout = ept_copyout;
340 pmap->fubyte = ept_fubyte;
341 pmap->subyte = ept_subyte;
342 pmap->fuword = ept_fuword;
343 pmap->suword = ept_suword;
344 pmap->suword32 = ept_suword32;