2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2011, Jack Lange <jacklange@cs.pitt.edu>
11 * All rights reserved.
13 * Author: Jack Lange <jacklange@cs.pitt.edu>
15 * This is free software. You are permitted to use,
16 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
19 #include <palacios/vmm.h>
20 #include <palacios/vmx_ept.h>
21 #include <palacios/vmx_lowlevel.h>
22 #include <palacios/vmm_paging.h>
23 #include <palacios/vm_guest_mem.h>
26 static struct vmx_ept_msr * ept_info = NULL;
29 static addr_t create_ept_page() {
33 temp = V3_AllocPages(1);
35 PrintError(VM_NONE, VCORE_NONE, "Cannot allocate EPT page\n");
38 page = V3_VAddr(temp);
39 memset(page, 0, PAGE_SIZE);
47 int v3_init_ept(struct guest_info * core, struct vmx_hw_info * hw_info) {
48 addr_t ept_pa = (addr_t)V3_PAddr((void *)create_ept_page());
49 vmx_eptp_t * ept_ptr = (vmx_eptp_t *)&(core->direct_map_pt);
52 ept_info = &(hw_info->ept_info);
54 /* TODO: Should we set this to WB?? */
57 if (ept_info->pg_walk_len4) {
60 PrintError(core->vm_info, core, "Unsupported EPT Table depth\n");
64 ept_ptr->pml_base_addr = PAGE_BASE_ADDR(ept_pa);
71 /* We can use the default paging macros, since the formats are close enough to allow it */
73 int v3_handle_ept_fault(struct guest_info * core, addr_t fault_addr, struct ept_exit_qual * ept_qual) {
74 ept_pml4_t * pml = NULL;
75 // ept_pdp_1GB_t * pdpe1gb = NULL;
76 ept_pdp_t * pdpe = NULL;
77 ept_pde_2MB_t * pde2mb = NULL;
78 ept_pde_t * pde = NULL;
79 ept_pte_t * pte = NULL;
82 int pml_index = PML4E64_INDEX(fault_addr);
83 int pdpe_index = PDPE64_INDEX(fault_addr);
84 int pde_index = PDE64_INDEX(fault_addr);
85 int pte_index = PTE64_INDEX(fault_addr);
87 struct v3_mem_region * region = v3_get_mem_region(core->vm_info, core->vcpu_id, fault_addr);
88 int page_size = PAGE_SIZE_4KB;
92 pf_error_t error_code = {0};
93 error_code.present = ept_qual->present;
94 error_code.write = ept_qual->write;
97 PrintError(core->vm_info, core, "invalid region, addr=%p\n", (void *)fault_addr);
101 if ((core->use_large_pages == 1) || (core->use_giant_pages == 1)) {
102 page_size = v3_get_max_page_size(core, fault_addr, LONG);
107 pml = (ept_pml4_t *)CR3_TO_PML4E64_VA(core->direct_map_pt);
111 //Fix up the PML entry
112 if (pml[pml_index].read == 0) {
113 pdpe = (ept_pdp_t *)create_ept_page();
115 // Set default PML Flags...
116 pml[pml_index].read = 1;
117 pml[pml_index].write = 1;
118 pml[pml_index].exec = 1;
120 pml[pml_index].pdp_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pdpe));
122 pdpe = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pml[pml_index].pdp_base_addr));
126 // Fix up the PDPE entry
127 if (pdpe[pdpe_index].read == 0) {
128 pde = (ept_pde_t *)create_ept_page();
130 // Set default PDPE Flags...
131 pdpe[pdpe_index].read = 1;
132 pdpe[pdpe_index].write = 1;
133 pdpe[pdpe_index].exec = 1;
135 pdpe[pdpe_index].pd_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pde));
137 pde = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pdpe[pdpe_index].pd_base_addr));
142 // Fix up the 2MiB PDE and exit here
143 if (page_size == PAGE_SIZE_2MB) {
144 pde2mb = (ept_pde_2MB_t *)pde; // all but these two lines are the same for PTE
145 pde2mb[pde_index].large_page = 1;
147 if (pde2mb[pde_index].read == 0) {
149 if ( (region->flags.alloced == 1) &&
150 (region->flags.read == 1)) {
152 pde2mb[pde_index].read = 1;
153 pde2mb[pde_index].exec = 1;
154 pde2mb[pde_index].ipat = 1;
155 pde2mb[pde_index].mt = 6;
157 if (region->flags.write == 1) {
158 pde2mb[pde_index].write = 1;
160 pde2mb[pde_index].write = 0;
163 if (v3_gpa_to_hpa(core, fault_addr, &host_addr) == -1) {
164 PrintError(core->vm_info, core, "Error: Could not translate fault addr (%p)\n", (void *)fault_addr);
168 pde2mb[pde_index].page_base_addr = PAGE_BASE_ADDR_2MB(host_addr);
170 return region->unhandled(core, fault_addr, fault_addr, region, error_code);
173 // We fix all permissions on the first pass,
174 // so we only get here if its an unhandled exception
176 return region->unhandled(core, fault_addr, fault_addr, region, error_code);
182 // Continue with the 4KiB page heirarchy
185 // Fix up the PDE entry
186 if (pde[pde_index].read == 0) {
187 pte = (ept_pte_t *)create_ept_page();
189 pde[pde_index].read = 1;
190 pde[pde_index].write = 1;
191 pde[pde_index].exec = 1;
193 pde[pde_index].pt_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pte));
195 pte = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pde[pde_index].pt_base_addr));
201 // Fix up the PTE entry
202 if (pte[pte_index].read == 0) {
204 if ( (region->flags.alloced == 1) &&
205 (region->flags.read == 1)) {
207 pte[pte_index].read = 1;
208 pte[pte_index].exec = 1;
209 pte[pte_index].ipat = 1;
210 pte[pte_index].mt = 6;
212 if (region->flags.write == 1) {
213 pte[pte_index].write = 1;
215 pte[pte_index].write = 0;
218 if (v3_gpa_to_hpa(core, fault_addr, &host_addr) == -1) {
219 PrintError(core->vm_info, core, "Error Could not translate fault addr (%p)\n", (void *)fault_addr);
224 pte[pte_index].page_base_addr = PAGE_BASE_ADDR_4KB(host_addr);
226 return region->unhandled(core, fault_addr, fault_addr, region, error_code);
229 // We fix all permissions on the first pass,
230 // so we only get here if its an unhandled exception
232 return region->unhandled(core, fault_addr, fault_addr, region, error_code);