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.


Range-based invalidation for nested and direct paging + use in memory region managment
[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 * temp;
31     void * page = 0;
32     
33     temp = V3_AllocPages(1);
34     if (!temp) {
35         PrintError(VM_NONE, VCORE_NONE, "Cannot allocate EPT page\n");
36         return 0;
37     }
38     page = V3_VAddr(temp);
39     memset(page, 0, PAGE_SIZE);
40
41     return (addr_t)page;
42 }
43
44
45
46
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);
50
51
52     ept_info = &(hw_info->ept_info);
53
54     /* TODO: Should we set this to WB?? */
55     ept_ptr->psmt = 0;
56
57     if (ept_info->pg_walk_len4) {
58         ept_ptr->pwl1 = 3;
59     } else {
60         PrintError(core->vm_info, core, "Unsupported EPT Table depth\n");
61         return -1;
62     }
63
64     ept_ptr->pml_base_addr = PAGE_BASE_ADDR(ept_pa);
65
66
67     return 0;
68 }
69
70
71 /* We can use the default paging macros, since the formats are close enough to allow it */
72
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;
80     addr_t host_addr     = 0;
81
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);
86
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;
89
90
91
92     pf_error_t error_code = {0};
93     error_code.present = ept_qual->present;
94     error_code.write = ept_qual->write;
95     
96     if (region == NULL) {
97         PrintError(core->vm_info, core, "invalid region, addr=%p\n", (void *)fault_addr);
98         return -1;
99     }
100
101     if ((core->use_large_pages == 1) || (core->use_giant_pages == 1)) {
102         page_size = v3_get_max_page_size(core, fault_addr, LONG);
103     }
104
105
106
107     pml = (ept_pml4_t *)CR3_TO_PML4E64_VA(core->direct_map_pt);
108
109
110
111     //Fix up the PML entry
112     if (pml[pml_index].read == 0) { 
113         pdpe = (ept_pdp_t *)create_ept_page();
114         
115         // Set default PML Flags...
116         pml[pml_index].read = 1;
117         pml[pml_index].write = 1;
118         pml[pml_index].exec = 1;
119
120         pml[pml_index].pdp_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pdpe));
121     } else {
122         pdpe = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pml[pml_index].pdp_base_addr));
123     }
124
125
126     // Fix up the PDPE entry
127     if (pdpe[pdpe_index].read == 0) {
128         pde = (ept_pde_t *)create_ept_page();
129
130         // Set default PDPE Flags...
131         pdpe[pdpe_index].read = 1;
132         pdpe[pdpe_index].write = 1;
133         pdpe[pdpe_index].exec = 1;
134
135         pdpe[pdpe_index].pd_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pde));
136     } else {
137         pde = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pdpe[pdpe_index].pd_base_addr));
138     }
139
140
141
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;
146
147         if (pde2mb[pde_index].read == 0) {
148
149             if ( (region->flags.alloced == 1) && 
150                  (region->flags.read == 1)) {
151                 // Full access
152                 pde2mb[pde_index].read = 1;
153                 pde2mb[pde_index].exec = 1;
154                 pde2mb[pde_index].ipat = 1;
155                 pde2mb[pde_index].mt = 6;
156
157                 if (region->flags.write == 1) {
158                     pde2mb[pde_index].write = 1;
159                 } else {
160                     pde2mb[pde_index].write = 0;
161                 }
162
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);
165                     return -1;
166                 }
167
168                 pde2mb[pde_index].page_base_addr = PAGE_BASE_ADDR_2MB(host_addr);
169             } else {
170                 return region->unhandled(core, fault_addr, fault_addr, region, error_code);
171             }
172         } else {
173             // We fix all permissions on the first pass, 
174             // so we only get here if its an unhandled exception
175
176             return region->unhandled(core, fault_addr, fault_addr, region, error_code);
177         }
178
179         return 0;
180     }
181
182     // Continue with the 4KiB page heirarchy
183     
184
185     // Fix up the PDE entry
186     if (pde[pde_index].read == 0) {
187         pte = (ept_pte_t *)create_ept_page();
188         
189         pde[pde_index].read = 1;
190         pde[pde_index].write = 1;
191         pde[pde_index].exec = 1;
192
193         pde[pde_index].pt_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pte));
194     } else {
195         pte = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pde[pde_index].pt_base_addr));
196     }
197
198
199
200
201     // Fix up the PTE entry
202     if (pte[pte_index].read == 0) {
203
204         if ( (region->flags.alloced == 1) && 
205              (region->flags.read == 1)) {
206             // Full access
207             pte[pte_index].read = 1;
208             pte[pte_index].exec = 1;
209             pte[pte_index].ipat = 1;
210             pte[pte_index].mt = 6;
211
212             if (region->flags.write == 1) {
213                 pte[pte_index].write = 1;
214             } else {
215                 pte[pte_index].write = 0;
216             }
217
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);
220                 return -1;
221             }
222
223
224             pte[pte_index].page_base_addr = PAGE_BASE_ADDR_4KB(host_addr);
225         } else {
226             return region->unhandled(core, fault_addr, fault_addr, region, error_code);
227         }
228     } else {
229         // We fix all permissions on the first pass, 
230         // so we only get here if its an unhandled exception
231
232         return region->unhandled(core, fault_addr, fault_addr, region, error_code);
233     }
234
235
236     return 0;
237 }