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.


architecture independence work
[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
51     //
52     // inject page fault to the guest (Guest PDE fault)
53     //
54
55     PrintDebug("Guest Page fault (currently not handled)\n");
56     return -1;
57   }
58
59   shadow_pde_access = can_access_pde32(shadow_pde, fault_addr, error_code);
60
61
62   if (shadow_pde_access == PT_ENTRY_NOT_PRESENT) {
63     pte32_t * shadow_pte = NULL;
64
65     V3_AllocPages(shadow_pte, 1);
66     memset(shadow_pte, 0, PAGE_SIZE);
67
68     shadow_pde_entry->pt_base_addr = PD32_BASE_ADDR(shadow_pte);
69     
70
71     shadow_pde_entry->present = 1;
72     shadow_pde_entry->user_page = guest_pde_entry->user_page;
73     
74     // VMM Specific options
75     shadow_pde_entry->write_through = 0;
76     shadow_pde_entry->cache_disable = 0;
77     shadow_pde_entry->global_page = 0;
78     //
79
80     guest_pde_entry->accessed = 1;
81
82     if (guest_pde_entry->large_page == 0) {
83       shadow_pde_entry->writable = guest_pde_entry->writable;
84     } else {
85       /*
86        * Check the Intel manual because we are ignoring Large Page issues here
87        */
88     }
89
90   } else if (shadow_pde_access == PT_WRITE_ERROR) {
91
92     //
93     // Page Directory Entry marked read-only
94     //
95
96     PrintDebug("Shadow Paging Write Error\n");
97     return -1;
98   } else if (shadow_pde_access == PT_USER_ERROR) {
99
100     //
101     // Page Directory Entry marked non-user
102     //
103     
104     PrintDebug("Shadow Paging User access error\n");
105     return -1;
106   } else if (shadow_pde_access == PT_ACCESS_OK) {
107     pte32_t * shadow_pte = (pte32_t *)PDE32_T_ADDR((*shadow_pde_entry));
108     pte32_t * guest_pte = NULL;
109
110     // Page Table entry fault
111     
112     if (guest_pa_to_host_va(info, PDE32_T_ADDR((*guest_pde_entry)), (addr_t*)&guest_pte) == -1) {
113       PrintDebug("Invalid Guest PTE Address: 0x%x\n", PDE32_T_ADDR((*guest_pde_entry)));
114       return -1;
115     }
116
117
118     if (handle_shadow_pte32_fault(info, fault_addr, error_code, shadow_pte, guest_pte)  == -1) {
119       PrintDebug("Error handling Page fault caused by PTE\n");
120       return -1;
121     }
122
123  } else {
124     PrintDebug("Unknown Error\n");
125     return -1;
126   }
127
128   PrintDebugPageTables(shadow_pde);
129
130   return 0;
131 }
132
133
134
135 /* 
136  * We assume the the guest pte pointer has already been translated to a host virtual address
137  */
138 int handle_shadow_pte32_fault(struct guest_info* info, 
139                               addr_t fault_addr, 
140                               pf_error_t error_code,
141                               pte32_t * shadow_pte, 
142                               pte32_t * guest_pte) {
143
144   pt_access_status_t guest_pte_access;
145   pt_access_status_t shadow_pte_access;
146   pte32_t * guest_pte_entry = (pte32_t *)&(guest_pte[PTE32_INDEX(fault_addr)]);;
147   pte32_t * shadow_pte_entry = (pte32_t *)&(shadow_pte[PTE32_INDEX(fault_addr)]);
148
149
150   // Check the guest page permissions
151   guest_pte_access = can_access_pte32(guest_pte, fault_addr, error_code);
152
153   if (guest_pte_access != PT_ACCESS_OK) {
154
155     //
156     // Inject page fault into the guest         
157     //
158
159     PrintDebug("Guest Page fault (currently not handled)\n");
160     return -1;
161   }
162
163   shadow_pte_access = can_access_pte32(shadow_pte, fault_addr, error_code);
164
165   if (shadow_pte_access == PT_ENTRY_NOT_PRESENT) {
166     addr_t shadow_pa;
167     addr_t guest_pa = PTE32_T_ADDR((*guest_pte_entry));
168
169     // Page Table Entry Not Present
170
171     if (get_shadow_addr_type(info, guest_pa) == HOST_REGION_INVALID) {
172
173       //
174       // Inject a machine check in the guest
175       //
176
177       PrintDebug("Invalid Guest Address in page table (0x%x)\n", guest_pa);
178       return -1;
179     }
180
181     shadow_pa = get_shadow_addr(info, guest_pa);
182
183     shadow_pte_entry->page_base_addr = PT32_BASE_ADDR(shadow_pa);
184
185     shadow_pte_entry->present = guest_pte_entry->present;
186     shadow_pte_entry->user_page = guest_pte_entry->user_page;
187
188     //set according to VMM policy
189     shadow_pte_entry->write_through = 0;
190     shadow_pte_entry->cache_disable = 0;
191     shadow_pte_entry->global_page = 0;
192     //
193
194     guest_pte_entry->accessed = 1;
195
196     if (guest_pte_entry->dirty == 1) {
197       shadow_pte_entry->writable = guest_pte_entry->writable;
198     } else if ((guest_pte_entry->dirty == 0) && (error_code.write == 1)) {
199       shadow_pte_entry->writable = guest_pte_entry->writable;
200       guest_pte_entry->dirty = 1;
201     } else if ((guest_pte_entry->dirty = 0) && (error_code.write == 0)) {
202       shadow_pte_entry->writable = 0;
203     }
204
205   } else if (shadow_pte_access == PT_WRITE_ERROR) {
206
207     //
208     // Page Table Entry marked read-only
209     //
210
211     PrintDebug("Shadow Paging Write Error\n");
212     return -1;
213   } else if (shadow_pte_access == PT_USER_ERROR) {
214
215     //
216     // Page Table Entry marked non-user
217     //
218
219     PrintDebug("Shadow Paging User access error\n");
220     return -1;
221   } else if (shadow_pte_access == PT_ACCESS_OK) {
222
223     PrintDebug("Page Fault occurred for No Reason\n");
224     return -1;
225   } else {
226     PrintDebug("Unknown Error\n");
227     return -1;
228   }
229
230   return 0;
231 }
232
233
234
235 addr_t create_new_shadow_pt32(struct guest_info * info) {
236   void * host_pde = 0;
237
238   V3_AllocPages(host_pde, 1);
239   memset(host_pde, 0, PAGE_SIZE);
240
241   return (addr_t)host_pde;
242 }
243
244
245
246
247 addr_t setup_shadow_pt32(struct guest_info * info, addr_t virt_cr3) {
248   addr_t cr3_guest_addr = CR3_TO_PDE32(virt_cr3);
249   pde32_t * guest_pde;
250   pde32_t * host_pde = NULL;
251   int i;
252   
253   // Setup up guest_pde to point to the PageDir in host addr
254   if (guest_pa_to_host_va(info, cr3_guest_addr, (addr_t*)&guest_pde) == -1) {
255     return 0;
256   }
257   
258   V3_AllocPages(host_pde, 1);
259   memset(host_pde, 0, PAGE_SIZE);
260
261   for (i = 0; i < MAX_PDE32_ENTRIES; i++) {
262     if (guest_pde[i].present == 1) {
263       addr_t pt_host_addr;
264       addr_t host_pte;
265
266       if (guest_pa_to_host_va(info, PDE32_T_ADDR(guest_pde[i]), &pt_host_addr) == -1) {
267         return 0;
268       }
269
270       if ((host_pte = setup_shadow_pte32(info, pt_host_addr)) == 0) {
271         return 0;
272       }
273
274       host_pde[i].present = 1;
275       host_pde[i].pt_base_addr = PD32_BASE_ADDR(host_pte);
276
277       //
278       // Set Page DIR flags
279       //
280     }
281   }
282
283   PrintDebugPageTables(host_pde);
284
285   return (addr_t)host_pde;
286 }
287
288
289
290 addr_t setup_shadow_pte32(struct guest_info * info, addr_t pt_host_addr) {
291   pte32_t * guest_pte = (pte32_t *)pt_host_addr;
292   pte32_t * host_pte = NULL;
293   int i;
294
295   V3_AllocPages(host_pte, 1);
296   memset(host_pte, 0, PAGE_SIZE);
297
298   for (i = 0; i < MAX_PTE32_ENTRIES; i++) {
299     if (guest_pte[i].present == 1) {
300       addr_t guest_pa = PTE32_T_ADDR(guest_pte[i]);
301       shadow_mem_type_t page_type;
302       addr_t host_pa = 0;
303
304       page_type = get_shadow_addr_type(info, guest_pa);
305
306       if (page_type == HOST_REGION_PHYSICAL_MEMORY) {
307         host_pa = get_shadow_addr(info, guest_pa);
308       } else {
309         
310         //
311         // Setup various memory types
312         //
313       }
314
315       host_pte[i].page_base_addr = PT32_BASE_ADDR(host_pa);
316       host_pte[i].present = 1;
317     }
318   }
319
320   return (addr_t)host_pte;
321 }
322
323