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() {
31 page = V3_VAddr(V3_AllocPages(1));
32 memset(page, 0, PAGE_SIZE);
40 int v3_init_ept(struct guest_info * core, struct vmx_hw_info * hw_info) {
41 addr_t ept_pa = (addr_t)V3_PAddr((void *)create_ept_page());
42 vmx_eptp_t * ept_ptr = (vmx_eptp_t *)&(core->direct_map_pt);
45 ept_info = &(hw_info->ept_info);
47 /* TODO: Should we set this to WB?? */
50 if (ept_info->pg_walk_len4) {
53 PrintError("Unsupported EPT Table depth\n");
57 ept_ptr->pml_base_addr = PAGE_BASE_ADDR(ept_pa);
64 /* We can use the default paging macros, since the formats are close enough to allow it */
66 int v3_handle_ept_fault(struct guest_info * core, addr_t fault_addr, struct ept_exit_qual * ept_qual) {
67 ept_pml4_t * pml = NULL;
68 // ept_pdp_1GB_t * pdpe1gb = NULL;
69 ept_pdp_t * pdpe = NULL;
70 ept_pde_2MB_t * pde2mb = NULL;
71 ept_pde_t * pde = NULL;
72 ept_pte_t * pte = NULL;
75 int pml_index = PML4E64_INDEX(fault_addr);
76 int pdpe_index = PDPE64_INDEX(fault_addr);
77 int pde_index = PDE64_INDEX(fault_addr);
78 int pte_index = PTE64_INDEX(fault_addr);
80 struct v3_mem_region * region = v3_get_mem_region(core->vm_info, core->vcpu_id, fault_addr);
81 int page_size = PAGE_SIZE_4KB;
85 pf_error_t error_code = {0};
86 error_code.present = ept_qual->present;
87 error_code.write = ept_qual->write;
90 PrintError("invalid region, addr=%p\n", (void *)fault_addr);
94 if ((core->use_large_pages == 1) || (core->use_giant_pages == 1)) {
95 page_size = v3_get_max_page_size(core, fault_addr, LONG);
100 pml = (ept_pml4_t *)CR3_TO_PML4E64_VA(core->direct_map_pt);
104 //Fix up the PML entry
105 if (pml[pml_index].read == 0) {
106 pdpe = (ept_pdp_t *)create_ept_page();
108 // Set default PML Flags...
109 pml[pml_index].read = 1;
110 pml[pml_index].write = 1;
111 pml[pml_index].exec = 1;
113 pml[pml_index].pdp_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pdpe));
115 pdpe = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pml[pml_index].pdp_base_addr));
119 // Fix up the PDPE entry
120 if (pdpe[pdpe_index].read == 0) {
121 pde = (ept_pde_t *)create_ept_page();
123 // Set default PDPE Flags...
124 pdpe[pdpe_index].read = 1;
125 pdpe[pdpe_index].write = 1;
126 pdpe[pdpe_index].exec = 1;
128 pdpe[pdpe_index].pd_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pde));
130 pde = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pdpe[pdpe_index].pd_base_addr));
135 // Fix up the 2MiB PDE and exit here
136 if (page_size == PAGE_SIZE_2MB) {
137 pde2mb = (ept_pde_2MB_t *)pde; // all but these two lines are the same for PTE
138 pde2mb[pde_index].large_page = 1;
140 if (pde2mb[pde_index].read == 0) {
142 if ( (region->flags.alloced == 1) &&
143 (region->flags.read == 1)) {
145 pde2mb[pde_index].read = 1;
146 pde2mb[pde_index].exec = 1;
148 if (region->flags.write == 1) {
149 pde2mb[pde_index].write = 1;
151 pde2mb[pde_index].write = 0;
154 if (v3_gpa_to_hpa(core, fault_addr, &host_addr) == -1) {
155 PrintError("Error: Could not translate fault addr (%p)\n", (void *)fault_addr);
159 pde2mb[pde_index].page_base_addr = PAGE_BASE_ADDR_2MB(host_addr);
161 return region->unhandled(core, fault_addr, fault_addr, region, error_code);
164 // We fix all permissions on the first pass,
165 // so we only get here if its an unhandled exception
167 return region->unhandled(core, fault_addr, fault_addr, region, error_code);
173 // Continue with the 4KiB page heirarchy
176 // Fix up the PDE entry
177 if (pde[pde_index].read == 0) {
178 pte = (ept_pte_t *)create_ept_page();
180 pde[pde_index].read = 1;
181 pde[pde_index].write = 1;
182 pde[pde_index].exec = 1;
184 pde[pde_index].pt_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pte));
186 pte = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pde[pde_index].pt_base_addr));
192 // Fix up the PTE entry
193 if (pte[pte_index].read == 0) {
195 if ( (region->flags.alloced == 1) &&
196 (region->flags.read == 1)) {
198 pte[pte_index].read = 1;
199 pte[pte_index].exec = 1;
201 if (region->flags.write == 1) {
202 pte[pte_index].write = 1;
204 pte[pte_index].write = 0;
207 if (v3_gpa_to_hpa(core, fault_addr, &host_addr) == -1) {
208 PrintError("Error Could not translate fault addr (%p)\n", (void *)fault_addr);
213 pte[pte_index].page_base_addr = PAGE_BASE_ADDR_4KB(host_addr);
215 return region->unhandled(core, fault_addr, fault_addr, region, error_code);
218 // We fix all permissions on the first pass,
219 // so we only get here if its an unhandled exception
221 return region->unhandled(core, fault_addr, fault_addr, region, error_code);