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.


initial shadow paging support
[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
164   shadow_pte_access = can_access_pte32(shadow_pte, fault_addr, error_code);
165
166   if (shadow_pte_access == PT_ENTRY_NOT_PRESENT) {
167     addr_t shadow_pa;
168     addr_t guest_pa = PTE32_T_ADDR((*guest_pte_entry));
169
170     // Page Table Entry Not Present
171
172     if (get_shadow_addr_type(info, guest_pa) == HOST_REGION_INVALID) {
173
174       //
175       // Inject a machine check in the guest
176       //
177
178       PrintDebug("Invalid Guest Address in page table (0x%x)\n", guest_pa);
179       return -1;
180     }
181
182     shadow_pa = get_shadow_addr(info, guest_pa);
183
184     shadow_pte_entry->page_base_addr = PT32_BASE_ADDR(shadow_pa);
185
186     shadow_pte_entry->present = guest_pte_entry->present;
187     shadow_pte_entry->user_page = guest_pte_entry->user_page;
188     
189     //set according to VMM policy
190     shadow_pte_entry->write_through = 0;
191     shadow_pte_entry->cache_disable = 0;
192     shadow_pte_entry->global_page = 0;
193     //
194
195     guest_pte_entry->accessed = 1;
196
197     if (guest_pte_entry->dirty == 1) {
198       shadow_pte_entry->writable = guest_pte_entry->writable;
199     } else if ((guest_pte_entry->dirty == 0) && (error_code.write == 1)) {
200       shadow_pte_entry->writable = guest_pte_entry->writable;
201       guest_pte_entry->dirty = 1;
202     } else if ((guest_pte_entry->dirty = 0) && (error_code.write == 0)) {
203       shadow_pte_entry->writable = 0;
204     }
205
206   } else if (shadow_pte_access == PT_WRITE_ERROR) {
207
208     //
209     // Page Table Entry marked read-only
210     //
211
212     PrintDebug("Shadow Paging Write Error\n");
213     return -1;
214   } else if (shadow_pte_access == PT_USER_ERROR) {
215
216     //
217     // Page Table Entry marked non-user
218     //
219     
220     PrintDebug("Shadow Paging User access error\n");
221     return -1;
222   } else if (shadow_pte_access == PT_ACCESS_OK) {
223
224     PrintDebug("Page Fault occurred for No Reason\n");
225     return -1;
226   } else {
227     PrintDebug("Unknown Error\n");
228     return -1;
229   }
230
231
232   return 0;
233 }
234
235
236
237 addr_t create_new_shadow_pt32(struct guest_info * info) {
238   void * host_pde = 0;
239
240   V3_AllocPages(host_pde, 1);
241   memset(host_pde, 0, PAGE_SIZE);
242
243   return (addr_t)host_pde;
244 }
245
246
247
248
249 addr_t setup_shadow_pt32(struct guest_info * info, addr_t virt_cr3) {
250   addr_t cr3_guest_addr = CR3_TO_PDE32(virt_cr3);
251   pde32_t * guest_pde;
252   pde32_t * host_pde = NULL;
253   int i;
254   
255   // Setup up guest_pde to point to the PageDir in host addr
256   if (guest_pa_to_host_va(info, cr3_guest_addr, (addr_t*)&guest_pde) == -1) {
257     return 0;
258   }
259   
260   V3_AllocPages(host_pde, 1);
261   memset(host_pde, 0, PAGE_SIZE);
262
263   for (i = 0; i < MAX_PDE32_ENTRIES; i++) {
264     if (guest_pde[i].present == 1) {
265       addr_t pt_host_addr;
266       addr_t host_pte;
267
268       if (guest_pa_to_host_va(info, PDE32_T_ADDR(guest_pde[i]), &pt_host_addr) == -1) {
269         return 0;
270       }
271
272       if ((host_pte = setup_shadow_pte32(info, pt_host_addr)) == 0) {
273         return 0;
274       }
275
276       host_pde[i].present = 1;
277       host_pde[i].pt_base_addr = PD32_BASE_ADDR(host_pte);
278
279       //
280       // Set Page DIR flags
281       //
282     }
283   }
284
285   PrintDebugPageTables(host_pde);
286
287   return (addr_t)host_pde;
288 }
289
290
291
292 addr_t setup_shadow_pte32(struct guest_info * info, addr_t pt_host_addr) {
293   pte32_t * guest_pte = (pte32_t *)pt_host_addr;
294   pte32_t * host_pte = NULL;
295   int i;
296
297   V3_AllocPages(host_pte, 1);
298   memset(host_pte, 0, PAGE_SIZE);
299
300   for (i = 0; i < MAX_PTE32_ENTRIES; i++) {
301     if (guest_pte[i].present == 1) {
302       addr_t guest_pa = PTE32_T_ADDR(guest_pte[i]);
303       shadow_mem_type_t page_type;
304       addr_t host_pa = 0;
305
306       page_type = get_shadow_addr_type(info, guest_pa);
307
308       if (page_type == HOST_REGION_PHYSICAL_MEMORY) {
309         host_pa = get_shadow_addr(info, guest_pa);
310       } else {
311         
312         //
313         // Setup various memory types
314         //
315       }
316
317       host_pte[i].page_base_addr = PT32_BASE_ADDR(host_pa);
318       host_pte[i].present = 1;
319     }
320   }
321
322   return (addr_t)host_pte;
323 }
324
325