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.


*** empty log message ***
[palacios.git] / palacios / src / palacios / vmm_shadow_paging.c
1 #include <palacios/vmm_shadow_paging.h>
2
3
4 #include <palacios/vmm.h>
5 #include <palacios/vm_guest_mem.h>
6
7
8
9
10 int init_shadow_page_state(struct shadow_page_state * state) {
11   state->guest_mode = PDE32;
12   state->shadow_mode = PDE32;
13   
14   state->guest_cr3 = 0;
15   state->shadow_cr3 = 0;
16
17   return 0;
18 }
19
20 int handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
21   if (info->cpu_mode == PROTECTED_PG) {
22     return handle_shadow_pagefault32(info, fault_addr, error_code);
23   } else {
24     return -1;
25   }
26 }
27
28
29 int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
30   pde32_t * guest_pde = NULL;
31   pde32_t * shadow_pde = (pde32_t *)CR3_TO_PDE32(info->shdw_pg_state.shadow_cr3);
32   addr_t guest_cr3 = CR3_TO_PDE32(info->shdw_pg_state.guest_cr3);
33   pt_access_status_t guest_pde_access;
34   pt_access_status_t shadow_pde_access;
35   pde32_t * guest_pde_entry = NULL;
36   pde32_t * shadow_pde_entry = (pde32_t *)&(shadow_pde[PDE32_INDEX(fault_addr)]);
37
38   if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pde) == -1) {
39     PrintDebug("Invalid Guest PDE Address: 0x%x\n", guest_cr3);
40     return -1;
41   }
42
43
44   guest_pde_entry = (pde32_t *)&(guest_pde[PDE32_INDEX(fault_addr)]);
45
46   // Check the guest page permissions
47   guest_pde_access = can_access_pde32(guest_pde, fault_addr, error_code);
48
49   if (guest_pde_access != PT_ACCESS_OK) {
50     // inject page fault to the guest (Guest PDE fault)
51
52     info->ctrl_regs.cr2 = fault_addr;
53     raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
54
55     return 0;
56   }
57
58   shadow_pde_access = can_access_pde32(shadow_pde, fault_addr, error_code);
59
60
61   if (shadow_pde_access == PT_ENTRY_NOT_PRESENT) {
62     pte32_t * shadow_pte = NULL;
63
64     V3_AllocPages(shadow_pte, 1);
65     memset(shadow_pte, 0, PAGE_SIZE);
66
67     shadow_pde_entry->pt_base_addr = PD32_BASE_ADDR(shadow_pte);
68     
69
70     shadow_pde_entry->present = 1;
71     shadow_pde_entry->user_page = guest_pde_entry->user_page;
72     
73     // VMM Specific options
74     shadow_pde_entry->write_through = 0;
75     shadow_pde_entry->cache_disable = 0;
76     shadow_pde_entry->global_page = 0;
77     //
78
79     guest_pde_entry->accessed = 1;
80
81     if (guest_pde_entry->large_page == 0) {
82       shadow_pde_entry->writable = guest_pde_entry->writable;
83     } else {
84       /*
85        * Check the Intel manual because we are ignoring Large Page issues here
86        */
87     }
88
89   } else if (shadow_pde_access == PT_WRITE_ERROR) {
90
91     //
92     // Page Directory Entry marked read-only
93     //
94
95     PrintDebug("Shadow Paging Write Error\n");
96     return -1;
97   } else if (shadow_pde_access == PT_USER_ERROR) {
98
99     //
100     // Page Directory Entry marked non-user
101     //
102     
103     PrintDebug("Shadow Paging User access error\n");
104     return -1;
105   } else if (shadow_pde_access == PT_ACCESS_OK) {
106     pte32_t * shadow_pte = (pte32_t *)PDE32_T_ADDR((*shadow_pde_entry));
107     pte32_t * guest_pte = NULL;
108
109     // Page Table Entry fault
110     
111     if (guest_pa_to_host_va(info, PDE32_T_ADDR((*guest_pde_entry)), (addr_t*)&guest_pte) == -1) {
112       PrintDebug("Invalid Guest PTE Address: 0x%x\n", PDE32_T_ADDR((*guest_pde_entry)));
113       // Machine check the guest
114
115       raise_exception(info, MC_EXCEPTION);
116       
117       return 0;
118     }
119
120
121     if (handle_shadow_pte32_fault(info, fault_addr, error_code, shadow_pte, guest_pte)  == -1) {
122       PrintDebug("Error handling Page fault caused by PTE\n");
123       return -1;
124     }
125
126  } else {
127     // Unknown error raise page fault in guest
128     info->ctrl_regs.cr2 = fault_addr;
129     raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
130
131     // For debugging we will return an error here for the time being, 
132     // this probably shouldn't ever happen
133     PrintDebug("Unknown Error occurred\n");
134     PrintDebug("Manual Says to inject page fault into guest\n");
135     return -1;
136   }
137
138   PrintDebugPageTables(shadow_pde);
139
140   return 0;
141 }
142
143
144
145 /* 
146  * We assume the the guest pte pointer has already been translated to a host virtual address
147  */
148 int handle_shadow_pte32_fault(struct guest_info * info, 
149                               addr_t fault_addr, 
150                               pf_error_t error_code,
151                               pte32_t * shadow_pte, 
152                               pte32_t * guest_pte) {
153
154   pt_access_status_t guest_pte_access;
155   pt_access_status_t shadow_pte_access;
156   pte32_t * guest_pte_entry = (pte32_t *)&(guest_pte[PTE32_INDEX(fault_addr)]);;
157   pte32_t * shadow_pte_entry = (pte32_t *)&(shadow_pte[PTE32_INDEX(fault_addr)]);
158
159
160   // Check the guest page permissions
161   guest_pte_access = can_access_pte32(guest_pte, fault_addr, error_code);
162
163   
164   if (guest_pte_access != PT_ACCESS_OK) {
165     // Inject page fault into the guest 
166     
167     info->ctrl_regs.cr2 = fault_addr;
168     raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
169     
170     return 0;
171   }
172   
173   
174   shadow_pte_access = can_access_pte32(shadow_pte, fault_addr, error_code);
175
176   if (shadow_pte_access == PT_ACCESS_OK) {
177     // Inconsistent state...
178     // Guest Re-Entry will flush page tables and everything should now work
179     return 0;
180   } else if (shadow_pte_access == PT_ENTRY_NOT_PRESENT) {
181     addr_t shadow_pa;
182     addr_t guest_pa = PTE32_T_ADDR((*guest_pte_entry));
183
184     // Page Table Entry Not Present
185
186     if (get_shadow_addr_type(info, guest_pa) == HOST_REGION_INVALID) {
187       // Inject a machine check in the guest
188
189       raise_exception(info, MC_EXCEPTION);
190
191       PrintDebug("Invalid Guest Address in page table (0x%x)\n", guest_pa);
192       return 0;
193     }
194
195     shadow_pa = get_shadow_addr(info, guest_pa);
196
197     shadow_pte_entry->page_base_addr = PT32_BASE_ADDR(shadow_pa);
198
199     shadow_pte_entry->present = guest_pte_entry->present;
200     shadow_pte_entry->user_page = guest_pte_entry->user_page;
201
202     //set according to VMM policy
203     shadow_pte_entry->write_through = 0;
204     shadow_pte_entry->cache_disable = 0;
205     shadow_pte_entry->global_page = 0;
206     //
207
208     guest_pte_entry->accessed = 1;
209
210     if (guest_pte_entry->dirty == 1) {
211       shadow_pte_entry->writable = guest_pte_entry->writable;
212     } else if ((guest_pte_entry->dirty == 0) && (error_code.write == 1)) {
213       shadow_pte_entry->writable = guest_pte_entry->writable;
214       guest_pte_entry->dirty = 1;
215     } else if ((guest_pte_entry->dirty = 0) && (error_code.write == 0)) {
216       shadow_pte_entry->writable = 0;
217     }
218
219   } else if ((shadow_pte_access == PT_WRITE_ERROR) &&
220              (guest_pte_entry->dirty == 0)) {
221     guest_pte_entry->dirty = 1;
222     shadow_pte_entry->writable = guest_pte_entry->writable;
223
224     return 0;
225   } else {
226     // Inject page fault into the guest 
227         
228     info->ctrl_regs.cr2 = fault_addr;
229     raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
230
231     PrintDebug("PTE Page fault fell through... Not sure if this should ever happen\n");
232     PrintDebug("Manual Says to inject page fault into guest\n");
233     return -1;
234   }
235
236   return 0;
237 }
238
239
240
241 addr_t create_new_shadow_pt32(struct guest_info * info) {
242   void * host_pde = 0;
243
244   V3_AllocPages(host_pde, 1);
245   memset(host_pde, 0, PAGE_SIZE);
246
247   return (addr_t)host_pde;
248 }
249
250
251
252
253 /* Deprecated */
254 /*
255 addr_t setup_shadow_pt32(struct guest_info * info, addr_t virt_cr3) {
256   addr_t cr3_guest_addr = CR3_TO_PDE32(virt_cr3);
257   pde32_t * guest_pde;
258   pde32_t * host_pde = NULL;
259   int i;
260   
261   // Setup up guest_pde to point to the PageDir in host addr
262   if (guest_pa_to_host_va(info, cr3_guest_addr, (addr_t*)&guest_pde) == -1) {
263     return 0;
264   }
265   
266   V3_AllocPages(host_pde, 1);
267   memset(host_pde, 0, PAGE_SIZE);
268
269   for (i = 0; i < MAX_PDE32_ENTRIES; i++) {
270     if (guest_pde[i].present == 1) {
271       addr_t pt_host_addr;
272       addr_t host_pte;
273
274       if (guest_pa_to_host_va(info, PDE32_T_ADDR(guest_pde[i]), &pt_host_addr) == -1) {
275         return 0;
276       }
277
278       if ((host_pte = setup_shadow_pte32(info, pt_host_addr)) == 0) {
279         return 0;
280       }
281
282       host_pde[i].present = 1;
283       host_pde[i].pt_base_addr = PD32_BASE_ADDR(host_pte);
284
285       //
286       // Set Page DIR flags
287       //
288     }
289   }
290
291   PrintDebugPageTables(host_pde);
292
293   return (addr_t)host_pde;
294 }
295
296
297
298 addr_t setup_shadow_pte32(struct guest_info * info, addr_t pt_host_addr) {
299   pte32_t * guest_pte = (pte32_t *)pt_host_addr;
300   pte32_t * host_pte = NULL;
301   int i;
302
303   V3_AllocPages(host_pte, 1);
304   memset(host_pte, 0, PAGE_SIZE);
305
306   for (i = 0; i < MAX_PTE32_ENTRIES; i++) {
307     if (guest_pte[i].present == 1) {
308       addr_t guest_pa = PTE32_T_ADDR(guest_pte[i]);
309       shadow_mem_type_t page_type;
310       addr_t host_pa = 0;
311
312       page_type = get_shadow_addr_type(info, guest_pa);
313
314       if (page_type == HOST_REGION_PHYSICAL_MEMORY) {
315         host_pa = get_shadow_addr(info, guest_pa);
316       } else {
317         
318         //
319         // Setup various memory types
320         //
321       }
322
323       host_pte[i].page_base_addr = PT32_BASE_ADDR(host_pa);
324       host_pte[i].present = 1;
325     }
326   }
327
328   return (addr_t)host_pte;
329 }
330
331 */