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.


d239bd2fe7107a8d59785d549c6638cd8e5ccc59
[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("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("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("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                
155                 if (region->flags.write == 1) {
156                     pde2mb[pde_index].write = 1;
157                 } else {
158                     pde2mb[pde_index].write = 0;
159                 }
160
161                 if (v3_gpa_to_hpa(core, fault_addr, &host_addr) == -1) {
162                     PrintError("Error: Could not translate fault addr (%p)\n", (void *)fault_addr);
163                     return -1;
164                 }
165
166                 pde2mb[pde_index].page_base_addr = PAGE_BASE_ADDR_2MB(host_addr);
167             } else {
168                 return region->unhandled(core, fault_addr, fault_addr, region, error_code);
169             }
170         } else {
171             // We fix all permissions on the first pass, 
172             // so we only get here if its an unhandled exception
173
174             return region->unhandled(core, fault_addr, fault_addr, region, error_code);
175         }
176
177         return 0;
178     }
179
180     // Continue with the 4KiB page heirarchy
181     
182
183     // Fix up the PDE entry
184     if (pde[pde_index].read == 0) {
185         pte = (ept_pte_t *)create_ept_page();
186         
187         pde[pde_index].read = 1;
188         pde[pde_index].write = 1;
189         pde[pde_index].exec = 1;
190
191         pde[pde_index].pt_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pte));
192     } else {
193         pte = V3_VAddr((void *)BASE_TO_PAGE_ADDR_4KB(pde[pde_index].pt_base_addr));
194     }
195
196
197
198
199     // Fix up the PTE entry
200     if (pte[pte_index].read == 0) {
201
202         if ( (region->flags.alloced == 1) && 
203              (region->flags.read == 1)) {
204             // Full access
205             pte[pte_index].read = 1;
206             pte[pte_index].exec = 1;
207
208             if (region->flags.write == 1) {
209                 pte[pte_index].write = 1;
210             } else {
211                 pte[pte_index].write = 0;
212             }
213
214             if (v3_gpa_to_hpa(core, fault_addr, &host_addr) == -1) {
215                 PrintError("Error Could not translate fault addr (%p)\n", (void *)fault_addr);
216                 return -1;
217             }
218
219
220             pte[pte_index].page_base_addr = PAGE_BASE_ADDR_4KB(host_addr);
221         } else {
222             return region->unhandled(core, fault_addr, fault_addr, region, error_code);
223         }
224     } else {
225         // We fix all permissions on the first pass, 
226         // so we only get here if its an unhandled exception
227
228         return region->unhandled(core, fault_addr, fault_addr, region, error_code);
229     }
230
231
232     return 0;
233 }