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.


Refactoring and additions to direct paging (nested and passthrough)
[palacios.git] / palacios / src / palacios / vmx_npt.h
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>    (implementation)
14  *         Peter Dinda <pdinda@northwestern.edu> (invalidation)
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm.h>
21 #include <palacios/vmx_ept.h>
22 #include <palacios/vmx_lowlevel.h>
23 #include <palacios/vmm_paging.h>
24 #include <palacios/vm_guest_mem.h>
25
26
27 /*
28
29   Note that the Intel nested page table have a slightly different format
30   than regular page tables.   Also note that our implementation
31   uses only 64 bit (4 level) page tables.  This is unlike the SVM 
32   nested paging implementation.
33
34
35 */
36
37 #ifndef V3_CONFIG_VMX
38
39
40 static int handle_vmx_nested_pagefault(struct guest_info * info, addr_t fault_addr, void *info) 
41 {
42     PrintError(info->vm_info, info, "Cannot do nested page fault as VMX is not enabled.\n");
43     return -1;
44 }
45 static int handle_vmx_invalidate_nested_addr(struct guest_info * info, addr_t inv_addr) 
46 {
47     PrintError(info->vm_info, info, "Cannot do invalidate nested addr as VMX is not enabled.\n");
48     return -1;
49 }
50 static int handle_vmx_invalidate_nested_addr_range(struct guest_info * info, 
51                                                    addr_t inv_addr_start, addr_t inv_addr_end) 
52 {
53     PrintError(info->vm_info, info, "Cannot do invalidate nested addr range as VMX is not enabled.\n");
54     return -1;
55 }
56
57 #else
58
59 static struct vmx_ept_msr * ept_info = NULL;
60
61
62 static addr_t create_ept_page() {
63     void * temp;
64     void * page = 0;
65     
66     temp = V3_AllocPages(1);  // need not be shadow-safe, not exposed to guest
67     if (!temp) {
68         PrintError(VM_NONE, VCORE_NONE, "Cannot allocate EPT page\n");
69         return 0;
70     }
71     page = V3_VAddr(temp);
72     memset(page, 0, PAGE_SIZE);
73
74     return (addr_t)page;
75 }
76
77
78
79
80 static int init_ept(struct guest_info * core, struct vmx_hw_info * hw_info) {
81     addr_t ept_pa = (addr_t)V3_PAddr((void *)create_ept_page());    
82     vmx_eptp_t * ept_ptr = (vmx_eptp_t *)&(core->direct_map_pt);
83
84
85     ept_info = &(hw_info->ept_info);
86
87     /* TODO: Should we set this to WB?? */
88     ept_ptr->psmt = 0;
89
90     if (ept_info->pg_walk_len4) {
91         ept_ptr->pwl1 = 3;
92     } else {
93         PrintError(core->vm_info, core, "Unsupported EPT Table depth\n");
94         return -1;
95     }
96
97     ept_ptr->pml_base_addr = PAGE_BASE_ADDR(ept_pa);
98
99
100     return 0;
101 }
102
103
104 static inline void ept_exit_qual_to_pf_error(struct ept_exit_qual *qual, pf_error_t *error)
105 {
106     memset(error,0,sizeof(pf_error_t));
107     error->present = qual->present;
108     error->write = qual->write;
109     error->ifetch = qual->ifetch;
110 }
111     
112
113 /* We can use the default paging macros, since the formats are close enough to allow it */
114
115
116 static int handle_vmx_nested_pagefault(struct guest_info * core, addr_t fault_addr, void *pfinfo,
117                                        addr_t *actual_start, addr_t *actual_end )
118 {
119     struct ept_exit_qual * ept_qual = (struct ept_exit_qual *) pfinfo;
120     ept_pml4_t    * pml     = NULL;
121     //    ept_pdp_1GB_t * pdpe1gb = NULL;
122     ept_pdp_t     * pdpe    = NULL;
123     ept_pde_2MB_t * pde2mb  = NULL;
124     ept_pde_t     * pde     = NULL;
125     ept_pte_t     * pte     = NULL;
126     addr_t host_addr     = 0;
127
128     int pml_index  = PML4E64_INDEX(fault_addr);
129     int pdpe_index = PDPE64_INDEX(fault_addr);
130     int pde_index  = PDE64_INDEX(fault_addr);
131     int pte_index  = PTE64_INDEX(fault_addr);
132
133     struct v3_mem_region * region = v3_get_mem_region(core->vm_info, core->vcpu_id, fault_addr);
134     int page_size = PAGE_SIZE_4KB;
135
136
137     pf_error_t error_code;
138     
139     ept_exit_qual_to_pf_error(ept_qual, &error_code);
140
141     PrintDebug(info->vm_info, info, "Nested PageFault: fault_addr=%p, error_code=%u, exit_qual=0x%llx\n", (void *)fault_addr, *(uint_t *)&error_code, qual->value);
142
143     
144     if (region == NULL) {
145         PrintError(core->vm_info, core, "invalid region, addr=%p\n", (void *)fault_addr);
146         return -1;
147     }
148
149     if ((core->use_large_pages == 1) || (core->use_giant_pages == 1)) {
150         page_size = v3_get_max_page_size(core, fault_addr, LONG);
151     }
152
153
154
155     pml = (ept_pml4_t *)CR3_TO_PML4E64_VA(core->direct_map_pt);
156
157
158
159     //Fix up the PML entry
160     if (pml[pml_index].read == 0) { 
161         pdpe = (ept_pdp_t *)create_ept_page();
162         
163         // Set default PML Flags...
164         pml[pml_index].read = 1;
165         pml[pml_index].write = 1;
166         pml[pml_index].exec = 1;
167
168         pml[pml_index].pdp_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pdpe));
169     } else {
170         pdpe = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pml[pml_index].pdp_base_addr));
171     }
172
173
174     // Fix up the PDPE entry
175     if (pdpe[pdpe_index].read == 0) {
176         pde = (ept_pde_t *)create_ept_page();
177
178         // Set default PDPE Flags...
179         pdpe[pdpe_index].read = 1;
180         pdpe[pdpe_index].write = 1;
181         pdpe[pdpe_index].exec = 1;
182
183         pdpe[pdpe_index].pd_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pde));
184     } else {
185         pde = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pdpe[pdpe_index].pd_base_addr));
186     }
187
188
189
190     // Fix up the 2MiB PDE and exit here
191     if (page_size == PAGE_SIZE_2MB) {
192         pde2mb = (ept_pde_2MB_t *)pde; // all but these two lines are the same for PTE
193         pde2mb[pde_index].large_page = 1;
194
195         *actual_start = BASE_TO_PAGE_ADDR_2MB(PAGE_BASE_ADDR_2MB(fault_addr));
196         *actual_end = BASE_TO_PAGE_ADDR_2MB(PAGE_BASE_ADDR_2MB(fault_addr)+1)-1;
197
198         if (pde2mb[pde_index].read == 0) {
199
200             if ( (region->flags.alloced == 1) && 
201                  (region->flags.read == 1)) {
202                 // Full access
203                 pde2mb[pde_index].read = 1;
204                 pde2mb[pde_index].exec = 1;
205                 pde2mb[pde_index].ipat = 1;
206                 pde2mb[pde_index].mt = 6;
207
208                 if (region->flags.write == 1) {
209                     pde2mb[pde_index].write = 1;
210                 } else {
211                     pde2mb[pde_index].write = 0;
212                 }
213
214                 if (v3_gpa_to_hpa(core, fault_addr, &host_addr) == -1) {
215                     PrintError(core->vm_info, core, "Error: Could not translate fault addr (%p)\n", (void *)fault_addr);
216                     return -1;
217                 }
218
219                 pde2mb[pde_index].page_base_addr = PAGE_BASE_ADDR_2MB(host_addr);
220             } else {
221                 return region->unhandled(core, fault_addr, fault_addr, region, error_code);
222             }
223         } else {
224             // We fix all permissions on the first pass, 
225             // so we only get here if its an unhandled exception
226
227             return region->unhandled(core, fault_addr, fault_addr, region, error_code);
228         }
229
230         return 0;
231     }
232
233     // Continue with the 4KiB page heirarchy
234     
235
236     // Fix up the PDE entry
237     if (pde[pde_index].read == 0) {
238         pte = (ept_pte_t *)create_ept_page();
239         
240         pde[pde_index].read = 1;
241         pde[pde_index].write = 1;
242         pde[pde_index].exec = 1;
243
244         pde[pde_index].pt_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pte));
245     } else {
246         pte = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pde[pde_index].pt_base_addr));
247     }
248
249
250     *actual_start = BASE_TO_PAGE_ADDR_4KB(PAGE_BASE_ADDR_4KB(fault_addr));
251     *actual_end = BASE_TO_PAGE_ADDR_4KB(PAGE_BASE_ADDR_4KB(fault_addr)+1)-1;
252
253
254     // Fix up the PTE entry
255     if (pte[pte_index].read == 0) {
256
257         if ( (region->flags.alloced == 1) && 
258              (region->flags.read == 1)) {
259             // Full access
260             pte[pte_index].read = 1;
261             pte[pte_index].exec = 1;
262             pte[pte_index].ipat = 1;
263             pte[pte_index].mt = 6;
264
265             if (region->flags.write == 1) {
266                 pte[pte_index].write = 1;
267             } else {
268                 pte[pte_index].write = 0;
269             }
270
271             if (v3_gpa_to_hpa(core, fault_addr, &host_addr) == -1) {
272                 PrintError(core->vm_info, core, "Error Could not translate fault addr (%p)\n", (void *)fault_addr);
273                 return -1;
274             }
275
276
277             pte[pte_index].page_base_addr = PAGE_BASE_ADDR_4KB(host_addr);
278         } else {
279             return region->unhandled(core, fault_addr, fault_addr, region, error_code);
280         }
281     } else {
282         // We fix all permissions on the first pass, 
283         // so we only get here if its an unhandled exception
284
285         return region->unhandled(core, fault_addr, fault_addr, region, error_code);
286     }
287
288
289     return 0;
290 }
291
292
293 static int handle_vmx_invalidate_nested_addr_internal(struct guest_info *core, addr_t inv_addr,
294                                                       addr_t *actual_start, uint64_t *actual_size) {
295   ept_pml4_t    *pml = NULL;
296   ept_pdp_t     *pdpe = NULL;
297   ept_pde_t     *pde = NULL;
298   ept_pte_t     *pte = NULL;
299
300
301  
302   // clear the page table entry
303   
304   int pml_index = PML4E64_INDEX(inv_addr);
305   int pdpe_index = PDPE64_INDEX(inv_addr);
306   int pde_index = PDE64_INDEX(inv_addr);
307   int pte_index = PTE64_INDEX(inv_addr);
308
309  
310   pml = (ept_pml4_t *)CR3_TO_PML4E64_VA(core->direct_map_pt);
311   
312
313   // note that there are no present bits in EPT, so we 
314   // use the read bit to signify this.
315   // either an entry is read/write/exec or it is none of these
316  
317   if (pml[pml_index].read == 0) {
318     // already invalidated
319     *actual_start = BASE_TO_PAGE_ADDR_512GB(PAGE_BASE_ADDR_512GB(inv_addr));
320     *actual_size = PAGE_SIZE_512GB;
321     return 0;
322   }
323
324   pdpe = V3_VAddr((void*)BASE_TO_PAGE_ADDR(pml[pml_index].pdp_base_addr));
325   
326   if (pdpe[pdpe_index].read == 0) {
327     // already invalidated
328     *actual_start = BASE_TO_PAGE_ADDR_1GB(PAGE_BASE_ADDR_1GB(inv_addr));
329     *actual_size = PAGE_SIZE_1GB;
330     return 0;
331   } else if (pdpe[pdpe_index].large_page == 1) { // 1GiB
332     pdpe[pdpe_index].read = 0;
333     pdpe[pdpe_index].write = 0;
334     pdpe[pdpe_index].exec = 0;
335     *actual_start = BASE_TO_PAGE_ADDR_1GB(PAGE_BASE_ADDR_1GB(inv_addr));
336     *actual_size = PAGE_SIZE_1GB;
337     return 0;
338   }
339
340   pde = V3_VAddr((void*)BASE_TO_PAGE_ADDR(pdpe[pdpe_index].pd_base_addr));
341
342   if (pde[pde_index].read == 0) {
343     // already invalidated
344     *actual_start = BASE_TO_PAGE_ADDR_2MB(PAGE_BASE_ADDR_2MB(inv_addr));
345     *actual_size = PAGE_SIZE_2MB;
346     return 0;
347   } else if (pde[pde_index].large_page == 1) { // 2MiB
348     pde[pde_index].read = 0;
349     pde[pde_index].write = 0;
350     pde[pde_index].exec = 0;
351     *actual_start = BASE_TO_PAGE_ADDR_2MB(PAGE_BASE_ADDR_2MB(inv_addr));
352     *actual_size = PAGE_SIZE_2MB;
353     return 0;
354   }
355
356   pte = V3_VAddr((void*)BASE_TO_PAGE_ADDR(pde[pde_index].pt_base_addr));
357   
358   pte[pte_index].read = 0; // 4KiB
359   pte[pte_index].write = 0;
360   pte[pte_index].exec = 0;
361   
362   *actual_start = BASE_TO_PAGE_ADDR_4KB(PAGE_BASE_ADDR_4KB(inv_addr));
363   *actual_size = PAGE_SIZE_4KB;
364   
365   return 0;
366 }
367
368
369 static int handle_vmx_invalidate_nested_addr(struct guest_info *core, addr_t inv_addr, 
370                                              addr_t *actual_start, addr_t *actual_end) 
371 {
372   uint64_t len;
373   int rc;
374   
375   rc = handle_vmx_invalidate_nested_addr_internal(core,inv_addr,actual_start,&len);
376   
377   *actual_end = *actual_start + len - 1;
378
379   return rc;
380 }
381
382
383 static int handle_vmx_invalidate_nested_addr_range(struct guest_info *core, 
384                                                    addr_t inv_addr_start, addr_t inv_addr_end,
385                                                    addr_t *actual_start, addr_t *actual_end) 
386 {
387   addr_t next;
388   addr_t start;
389   uint64_t len;
390   int rc;
391   
392   for (next=inv_addr_start; next<=inv_addr_end; ) {
393     rc = handle_vmx_invalidate_nested_addr_internal(core,next,&start, &len);
394     if (next==inv_addr_start) { 
395       // first iteration, capture where we start invalidating
396       *actual_start = start;
397     }
398     if (rc) { 
399       return rc;
400     }
401     next = start + len;
402     *actual_end = next;
403   }
404   // last iteration, actual_end is off by one
405   (*actual_end)--;
406   return 0;
407 }
408
409 #endif