Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


a66ad6bed55566e94f8e8b3658311bbb9935f0f7
[palacios.git] / palacios / src / palacios / vmx_ept.c
1 /* 
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.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2011, Jack Lange <jacklange@cs.pitt.edu> 
11  * All rights reserved.
12  *
13  * Author: Jack Lange <jacklange@cs.pitt.edu>
14  *
15  * This is free software.  You are permitted to use,
16  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
17  */
18
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>
24
25
26 static struct vmx_ept_msr * ept_info = NULL;
27
28
29 static addr_t create_ept_page() {
30     void * page = 0;
31     page = V3_VAddr(V3_AllocPages(1));
32     memset(page, 0, PAGE_SIZE);
33
34     return (addr_t)page;
35 }
36
37
38
39
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);
43
44
45     ept_info = &(hw_info->ept_info);
46
47     /* TODO: Should we set this to WB?? */
48     ept_ptr->psmt = 0;
49
50     if (ept_info->pg_walk_len4) {
51         ept_ptr->pwl1 = 3;
52     } else {
53         PrintError("Unsupported EPT Table depth\n");
54         return -1;
55     }
56
57     ept_ptr->pml_base_addr = PAGE_BASE_ADDR(ept_pa);
58
59
60     return 0;
61 }
62
63
64 /* We can use the default paging macros, since the formats are close enough to allow it */
65
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;
73     addr_t host_addr     = 0;
74
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);
79
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;
82
83
84
85     pf_error_t error_code = {0};
86     error_code.present = ept_qual->present;
87     error_code.write = ept_qual->write;
88     
89     if (region == NULL) {
90         PrintError("invalid region, addr=%p\n", (void *)fault_addr);
91         return -1;
92     }
93
94     if ((core->use_large_pages == 1) || (core->use_giant_pages == 1)) {
95         page_size = v3_get_max_page_size(core, fault_addr, LONG);
96     }
97
98
99
100     pml = (ept_pml4_t *)CR3_TO_PML4E64_VA(core->direct_map_pt);
101
102
103
104     //Fix up the PML entry
105     if (pml[pml_index].read == 0) { 
106         pdpe = (ept_pdp_t *)create_ept_page();
107         
108         // Set default PML Flags...
109         pml[pml_index].read = 1;
110         pml[pml_index].write = 1;
111         pml[pml_index].exec = 1;
112
113         pml[pml_index].pdp_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pdpe));
114     } else {
115         pdpe = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pml[pml_index].pdp_base_addr));
116     }
117
118
119     // Fix up the PDPE entry
120     if (pdpe[pdpe_index].read == 0) {
121         pde = (ept_pde_t *)create_ept_page();
122
123         // Set default PDPE Flags...
124         pdpe[pdpe_index].read = 1;
125         pdpe[pdpe_index].write = 1;
126         pdpe[pdpe_index].exec = 1;
127
128         pdpe[pdpe_index].pd_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pde));
129     } else {
130         pde = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pdpe[pdpe_index].pd_base_addr));
131     }
132
133
134
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;
139
140         if (pde2mb[pde_index].read == 0) {
141
142             if ( (region->flags.alloced == 1) && 
143                  (region->flags.read == 1)) {
144                 // Full access
145                 pde2mb[pde_index].read = 1;
146                 pde2mb[pde_index].exec = 1;
147                
148                 if (region->flags.write == 1) {
149                     pde2mb[pde_index].write = 1;
150                 } else {
151                     pde2mb[pde_index].write = 0;
152                 }
153
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);
156                     return -1;
157                 }
158
159                 pde2mb[pde_index].page_base_addr = PAGE_BASE_ADDR_2MB(host_addr);
160             } else {
161                 return region->unhandled(core, fault_addr, fault_addr, region, error_code);
162             }
163         } else {
164             // We fix all permissions on the first pass, 
165             // so we only get here if its an unhandled exception
166
167             return region->unhandled(core, fault_addr, fault_addr, region, error_code);
168         }
169
170         return 0;
171     }
172
173     // Continue with the 4KiB page heirarchy
174     
175
176     // Fix up the PDE entry
177     if (pde[pde_index].read == 0) {
178         pte = (ept_pte_t *)create_ept_page();
179         
180         pde[pde_index].read = 1;
181         pde[pde_index].write = 1;
182         pde[pde_index].exec = 1;
183
184         pde[pde_index].pt_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pte));
185     } else {
186         pte = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pde[pde_index].pt_base_addr));
187     }
188
189
190
191
192     // Fix up the PTE entry
193     if (pte[pte_index].read == 0) {
194
195         if ( (region->flags.alloced == 1) && 
196              (region->flags.read == 1)) {
197             // Full access
198             pte[pte_index].read = 1;
199             pte[pte_index].exec = 1;
200
201             if (region->flags.write == 1) {
202                 pte[pte_index].write = 1;
203             } else {
204                 pte[pte_index].write = 0;
205             }
206
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);
209                 return -1;
210             }
211
212
213             pte[pte_index].page_base_addr = PAGE_BASE_ADDR_4KB(host_addr);
214         } else {
215             return region->unhandled(core, fault_addr, fault_addr, region, error_code);
216         }
217     } else {
218         // We fix all permissions on the first pass, 
219         // so we only get here if its an unhandled exception
220
221         return region->unhandled(core, fault_addr, fault_addr, region, error_code);
222     }
223
224
225     return 0;
226 }