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"
53 static uint64_t pmap_bits_ept[PG_BITS_SIZE];
54 static pt_entry_t pmap_cache_bits_ept[PAT_INDEX_SIZE];
55 static uint64_t ept_protection_codes[PROTECTION_CODES_SIZE];
56 static pt_entry_t pmap_cache_mask_ept;
58 static int pmap_pm_flags_ept = PMAP_HVM;
61 extern uint64_t vmx_ept_vpid_cap;
67 /* Chapter 28 VMX SUPPORT FOR ADDRESS TRANSLATION
68 * Intel Manual 3c, page 107
70 vmx_ept_vpid_cap = rdmsr(IA32_VMX_EPT_VPID_CAP);
72 if(!EPT_PWL4(vmx_ept_vpid_cap)||
73 !EPT_MEMORY_TYPE_WB(vmx_ept_vpid_cap)) {
77 eptp_bits |= EPTP_CACHE(PAT_WRITE_BACK) |
78 EPTP_PWLEN(EPT_PWLEVELS - 1);
80 if (EPT_AD_BITS_SUPPORTED(vmx_ept_vpid_cap)) {
81 eptp_bits |= EPTP_AD_ENABLE;
83 pmap_pm_flags_ept |= PMAP_EMULATE_AD_BITS;
86 /* Initialize EPT bits
87 * - for PG_V - set READ and EXECUTE to preserve compatibility
88 * - for PG_U and PG_G - set 0 to preserve compatiblity
89 * - for PG_N - set the Uncacheable bit
91 pmap_bits_ept[TYPE_IDX] = EPT_PMAP;
92 pmap_bits_ept[PG_V_IDX] = EPT_PG_READ | EPT_PG_EXECUTE;
93 pmap_bits_ept[PG_RW_IDX] = EPT_PG_WRITE;
94 pmap_bits_ept[PG_PS_IDX] = EPT_PG_PS;
95 pmap_bits_ept[PG_G_IDX] = 0;
96 pmap_bits_ept[PG_U_IDX] = 0;
97 pmap_bits_ept[PG_A_IDX] = EPT_PG_A;
98 pmap_bits_ept[PG_M_IDX] = EPT_PG_M;
99 pmap_bits_ept[PG_W_IDX] = EPT_PG_AVAIL1;
100 pmap_bits_ept[PG_MANAGED_IDX] = EPT_PG_AVAIL2;
101 pmap_bits_ept[PG_DEVICE_IDX] = EPT_PG_AVAIL3;
102 pmap_bits_ept[PG_N_IDX] = EPT_IGNORE_PAT | EPT_MEM_TYPE_UC;
103 pmap_bits_ept[PG_NX_IDX] = 0; /* XXX inverted sense */
105 pmap_cache_mask_ept = EPT_IGNORE_PAT | EPT_MEM_TYPE_MASK;
107 pmap_cache_bits_ept[PAT_UNCACHEABLE] = EPT_IGNORE_PAT | EPT_MEM_TYPE_UC;
108 pmap_cache_bits_ept[PAT_WRITE_COMBINING] = EPT_IGNORE_PAT | EPT_MEM_TYPE_WC;
109 pmap_cache_bits_ept[PAT_WRITE_THROUGH] = EPT_IGNORE_PAT | EPT_MEM_TYPE_WT;
110 pmap_cache_bits_ept[PAT_WRITE_PROTECTED] = EPT_IGNORE_PAT | EPT_MEM_TYPE_WP;
111 pmap_cache_bits_ept[PAT_WRITE_BACK] = EPT_IGNORE_PAT | EPT_MEM_TYPE_WB;
112 pmap_cache_bits_ept[PAT_UNCACHED] = EPT_IGNORE_PAT | EPT_MEM_TYPE_UC;
114 for (prot = 0; prot < PROTECTION_CODES_SIZE; prot++) {
116 case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE:
117 case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE:
118 case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE:
119 case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE:
120 ept_protection_codes[prot] = 0;
122 case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE:
123 case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE:
124 case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE:
125 case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
126 ept_protection_codes[prot] = pmap_bits_ept[PG_RW_IDX];
135 /* Build the VMCS_EPTP pointer
137 * - the EPTP bits indicating optional features
139 uint64_t vmx_eptp(uint64_t ept_address)
141 return (ept_address | eptp_bits);
144 /* Copyin from guest VMM */
146 ept_copyin(const void *udaddr, void *kaddr, size_t len)
149 struct lwbuf lwb_cache;
154 struct vmspace *vm = curproc->p_vmspace;
155 struct vmx_thread_info *vti = curthread->td_vmm;
156 register_t guest_cr3 = vti->guest_cr3;
161 /* Get the GPA by manually walking the-GUEST page table*/
162 error = guest_phys_addr(vm, &gpa, guest_cr3,
163 (vm_offset_t)udaddr);
165 kprintf("%s: could not get guest_phys_addr\n",
170 m = vm_fault_page(&vm->vm_map, trunc_page(gpa),
171 VM_PROT_READ, VM_FAULT_NORMAL,
175 kprintf("%s: could not fault in "
176 "vm map, gpa: %jx\n",
183 n = PAGE_SIZE - ((vm_offset_t)udaddr & PAGE_MASK);
187 lwb = lwbuf_alloc(m, &lwb_cache);
188 bcopy((char *)lwbuf_kva(lwb) +
189 ((vm_offset_t)udaddr & PAGE_MASK),
192 udaddr = (const char *)udaddr + n;
193 kaddr = (char *)kaddr + n;
202 /* Copyout from guest VMM */
204 ept_copyout(const void *kaddr, void *udaddr, size_t len)
207 struct lwbuf lwb_cache;
212 struct vmspace *vm = curproc->p_vmspace;
213 struct vmx_thread_info *vti = curthread->td_vmm;
214 register_t guest_cr3 = vti->guest_cr3;
221 /* Get the GPA by manually walking the-GUEST page table*/
222 error = guest_phys_addr(vm, &gpa, guest_cr3,
223 (vm_offset_t)udaddr);
225 kprintf("%s: could not get guest_phys_addr\n",
230 m = vm_fault_page(&vm->vm_map, trunc_page(gpa),
231 VM_PROT_READ | VM_PROT_WRITE,
236 kprintf("%s: could not fault in vm map, "
244 n = PAGE_SIZE - ((vm_offset_t)udaddr & PAGE_MASK);
248 lwb = lwbuf_alloc(m, &lwb_cache);
249 bcopy(kaddr, (char *)lwbuf_kva(lwb) +
250 ((vm_offset_t)udaddr & PAGE_MASK), n);
253 udaddr = (char *)udaddr + n;
254 kaddr = (const char *)kaddr + n;
257 /* should not be needed */
258 cpu_invlpg((char *)lwbuf_kva(lwb) +
259 ((vm_offset_t)udaddr & PAGE_MASK));
273 ept_copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *res)
277 const char *uptr = udaddr;
283 n = PAGE_SIZE - ((vm_offset_t)uptr & PAGE_MASK);
288 if ((error = ept_copyin(uptr, kptr, n)) != 0)
302 return(ENAMETOOLONG);
307 ept_fubyte(const uint8_t *base)
311 if (ept_copyin(base, &c, 1) == 0)
317 ept_subyte(uint8_t *base, uint8_t byte)
319 unsigned char c = byte;
321 if (ept_copyout(&c, base, 1) == 0)
327 ept_fuword32(const uint32_t *base)
331 if (ept_copyin(base, &v, sizeof(v)) == 0)
337 ept_fuword64(const uint64_t *base)
341 if (ept_copyin(base, &v, sizeof(v)) == 0)
347 ept_suword64(uint64_t *base, uint64_t word)
349 if (ept_copyout(&word, base, sizeof(word)) == 0)
355 ept_suword32(uint32_t *base, int word)
357 if (ept_copyout(&word, base, sizeof(word)) == 0)
363 ept_swapu32(volatile uint32_t *uaddr, uint32_t v)
366 struct lwbuf lwb_cache;
371 struct vmspace *vm = curproc->p_vmspace;
372 struct vmx_thread_info *vti = curthread->td_vmm;
373 register_t guest_cr3 = vti->guest_cr3;
377 /* Get the GPA by manually walking the-GUEST page table*/
378 error = guest_phys_addr(vm, &gpa, guest_cr3, (vm_offset_t)uaddr);
380 kprintf("%s: could not get guest_phys_addr\n", __func__);
383 m = vm_fault_page(&vm->vm_map, trunc_page(gpa),
384 VM_PROT_READ | VM_PROT_WRITE,
389 kprintf("%s: could not fault in vm map, gpa: %llx\n",
390 __func__, (unsigned long long) gpa);
395 n = PAGE_SIZE - ((vm_offset_t)uaddr & PAGE_MASK);
396 if (n < sizeof(uint32_t)) {
398 v = (uint32_t)-error;
402 lwb = lwbuf_alloc(m, &lwb_cache);
403 ptr = (void *)(lwbuf_kva(lwb) + ((vm_offset_t)uaddr & PAGE_MASK));
404 v = atomic_swap_int(ptr, v);
418 ept_swapu64(volatile uint64_t *uaddr, uint64_t v)
421 struct lwbuf lwb_cache;
426 struct vmspace *vm = curproc->p_vmspace;
427 struct vmx_thread_info *vti = curthread->td_vmm;
428 register_t guest_cr3 = vti->guest_cr3;
432 /* Get the GPA by manually walking the-GUEST page table*/
433 error = guest_phys_addr(vm, &gpa, guest_cr3, (vm_offset_t)uaddr);
435 kprintf("%s: could not get guest_phys_addr\n", __func__);
438 m = vm_fault_page(&vm->vm_map, trunc_page(gpa),
439 VM_PROT_READ | VM_PROT_WRITE,
444 kprintf("%s: could not fault in vm map, gpa: %llx\n",
445 __func__, (unsigned long long) gpa);
450 n = PAGE_SIZE - ((vm_offset_t)uaddr & PAGE_MASK);
451 if (n < sizeof(uint64_t)) {
453 v = (uint64_t)-error;
457 lwb = lwbuf_alloc(m, &lwb_cache);
458 ptr = (void *)(lwbuf_kva(lwb) + ((vm_offset_t)uaddr & PAGE_MASK));
459 v = atomic_swap_long(ptr, v);
473 ept_fuwordadd32(volatile uint32_t *uaddr, uint32_t v)
476 struct lwbuf lwb_cache;
481 struct vmspace *vm = curproc->p_vmspace;
482 struct vmx_thread_info *vti = curthread->td_vmm;
483 register_t guest_cr3 = vti->guest_cr3;
487 /* Get the GPA by manually walking the-GUEST page table*/
488 error = guest_phys_addr(vm, &gpa, guest_cr3, (vm_offset_t)uaddr);
490 kprintf("%s: could not get guest_phys_addr\n", __func__);
493 m = vm_fault_page(&vm->vm_map, trunc_page(gpa),
494 VM_PROT_READ | VM_PROT_WRITE,
499 kprintf("%s: could not fault in vm map, gpa: %llx\n",
500 __func__, (unsigned long long) gpa);
505 n = PAGE_SIZE - ((vm_offset_t)uaddr & PAGE_MASK);
506 if (n < sizeof(uint32_t)) {
508 v = (uint32_t)-error;
512 lwb = lwbuf_alloc(m, &lwb_cache);
513 ptr = (void *)(lwbuf_kva(lwb) + ((vm_offset_t)uaddr & PAGE_MASK));
514 v = atomic_fetchadd_int(ptr, v);
528 ept_fuwordadd64(volatile uint64_t *uaddr, uint64_t v)
531 struct lwbuf lwb_cache;
536 struct vmspace *vm = curproc->p_vmspace;
537 struct vmx_thread_info *vti = curthread->td_vmm;
538 register_t guest_cr3 = vti->guest_cr3;
542 /* Get the GPA by manually walking the-GUEST page table*/
543 error = guest_phys_addr(vm, &gpa, guest_cr3, (vm_offset_t)uaddr);
545 kprintf("%s: could not get guest_phys_addr\n", __func__);
548 m = vm_fault_page(&vm->vm_map, trunc_page(gpa),
549 VM_PROT_READ | VM_PROT_WRITE,
554 kprintf("%s: could not fault in vm map, gpa: %llx\n",
555 __func__, (unsigned long long) gpa);
560 n = PAGE_SIZE - ((vm_offset_t)uaddr & PAGE_MASK);
561 if (n < sizeof(uint64_t)) {
563 v = (uint64_t)-error;
567 lwb = lwbuf_alloc(m, &lwb_cache);
568 ptr = (void *)(lwbuf_kva(lwb) + ((vm_offset_t)uaddr & PAGE_MASK));
569 v = atomic_fetchadd_long(ptr, v);
583 vmx_ept_pmap_pinit(pmap_t pmap)
585 pmap->pm_flags |= pmap_pm_flags_ept;
587 bcopy(pmap_bits_ept, pmap->pmap_bits, sizeof(pmap_bits_ept));
588 bcopy(ept_protection_codes, pmap->protection_codes,
589 sizeof(ept_protection_codes));
590 bcopy(pmap_cache_bits_ept, pmap->pmap_cache_bits,
591 sizeof(pmap_cache_bits_ept));
592 pmap->pmap_cache_mask = pmap_cache_mask_ept;
593 pmap->copyinstr = ept_copyinstr;
594 pmap->copyin = ept_copyin;
595 pmap->copyout = ept_copyout;
596 pmap->fubyte = ept_fubyte;
597 pmap->subyte = ept_subyte;
598 pmap->fuword32 = ept_fuword32;
599 pmap->fuword64 = ept_fuword64;
600 pmap->suword32 = ept_suword32;
601 pmap->suword64 = ept_suword64;
602 pmap->swapu32 = ept_swapu32;
603 pmap->swapu64 = ept_swapu64;
604 pmap->fuwordadd32 = ept_fuwordadd32;
605 pmap->fuwordadd64 = ept_fuwordadd64;