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.


modified the shadow paging files to separate them based on CPU mode
[palacios.git] / palacios / src / palacios / vmm_shadow_paging.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) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21 #include <palacios/vmm_shadow_paging.h>
22
23
24 #include <palacios/vmm.h>
25 #include <palacios/vm_guest_mem.h>
26 #include <palacios/vmm_decoder.h>
27 #include <palacios/vmm_ctrl_regs.h>
28
29 #include <palacios/vmm_hashtable.h>
30
31 #ifndef DEBUG_SHADOW_PAGING
32 #undef PrintDebug
33 #define PrintDebug(fmt, args...)
34 #endif
35
36
37 /*** 
38  ***  There be dragons
39  ***/
40
41
42 struct guest_table {
43   addr_t cr3;
44   struct list_head link;
45 };
46
47
48 struct backptr {
49   addr_t ptr;
50   struct list_head link;
51 };
52
53
54 struct shadow_page_data {
55   addr_t ptr;
56   addr_t guest_addr; 
57
58   struct list_head backptrs;
59   struct list_head guest_tables;
60 };
61
62
63
64
65 //DEFINE_HASHTABLE_INSERT(add_cr3_to_cache, addr_t, struct hashtable *);
66 //DEFINE_HASHTABLE_SEARCH(find_cr3_in_cache, addr_t, struct hashtable *);
67 //DEFINE_HASHTABLE_REMOVE(del_cr3_from_cache, addr_t, struct hashtable *, 0);
68
69
70 DEFINE_HASHTABLE_INSERT(add_pte_map, addr_t, addr_t);
71 DEFINE_HASHTABLE_SEARCH(find_pte_map, addr_t, addr_t);
72 //DEFINE_HASHTABLE_REMOVE(del_pte_map, addr_t, addr_t, 0);
73
74
75
76 static uint_t pte_hash_fn(addr_t key) {
77   return hash_long(key, 32);
78 }
79
80 static int pte_equals(addr_t key1, addr_t key2) {
81   return (key1 == key2);
82 }
83
84 static addr_t create_new_shadow_pt();
85 static void inject_guest_pf(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
86 static int is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access);
87
88
89 #include "vmm_shadow_paging_32.h"
90 #include "vmm_shadow_paging_32pae.h"
91 #include "vmm_shadow_paging_64.h"
92
93
94
95 int v3_init_shadow_page_state(struct guest_info * info) {
96   struct shadow_page_state * state = &(info->shdw_pg_state);
97   
98   state->guest_cr3 = 0;
99   state->guest_cr0 = 0;
100
101   state->cached_ptes = NULL;
102
103   return 0;
104 }
105
106
107
108
109
110
111
112 // Reads the guest CR3 register
113 // creates new shadow page tables
114 // updates the shadow CR3 register to point to the new pts
115 int v3_activate_shadow_pt(struct guest_info * info) {
116   switch (info->cpu_mode) {
117
118   case PROTECTED:
119     return activate_shadow_pt_32(info);
120   case PROTECTED_PAE:
121     return activate_shadow_pt_32pae(info);
122   case LONG:
123   case LONG_32_COMPAT:
124   case LONG_16_COMPAT:
125     return activate_shadow_pt_64(info);
126   default:
127     PrintError("Invalid CPU mode: %d\n", info->cpu_mode);
128     return -1;
129   }
130
131   return 0;
132 }
133
134
135 int v3_activate_passthrough_pt(struct guest_info * info) {
136   // For now... But we need to change this....
137   // As soon as shadow paging becomes active the passthrough tables are hosed
138   // So this will cause chaos if it is called at that time
139
140   info->ctrl_regs.cr3 = *(addr_t*)&(info->direct_map_pt);
141   //PrintError("Activate Passthrough Page tables not implemented\n");
142   return 0;
143 }
144
145
146
147 int v3_handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
148   
149   if (info->mem_mode == PHYSICAL_MEM) {
150     // If paging is not turned on we need to handle the special cases
151
152 #ifdef DEBUG_SHADOW_PAGING
153     PrintHostPageTree(info->cpu_mode, fault_addr, info->ctrl_regs.cr3);
154     PrintGuestPageTree(info, fault_addr, info->shdw_pg_state.guest_cr3);
155 #endif
156
157     return handle_special_page_fault(info, fault_addr, fault_addr, error_code);
158   } else if (info->mem_mode == VIRTUAL_MEM) {
159
160     switch (info->cpu_mode) {
161     case PROTECTED:
162       return handle_shadow_pagefault_32(info, fault_addr, error_code);
163       break;
164     case PROTECTED_PAE:
165       return handle_shadow_pagefault_32pae(info, fault_addr, error_code);
166     case LONG:
167       return handle_shadow_pagefault_64(info, fault_addr, error_code);
168       break;
169     default:
170       PrintError("Unhandled CPU Mode\n");
171       return -1;
172     }
173   } else {
174     PrintError("Invalid Memory mode\n");
175     return -1;
176   }
177 }
178
179
180
181 static addr_t create_new_shadow_pt() {
182   void * host_pde = 0;
183
184   host_pde = V3_VAddr(V3_AllocPages(1));
185   memset(host_pde, 0, PAGE_SIZE);
186
187   return (addr_t)host_pde;
188 }
189
190
191 static void inject_guest_pf(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
192   if (info->enable_profiler) {
193     info->profiler.guest_pf_cnt++;
194   }
195
196   info->ctrl_regs.cr2 = fault_addr;
197   v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
198 }
199
200
201 static int is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access) {
202   /* basically the reasoning is that there can be multiple reasons for a page fault:
203      If there is a permissions failure for a page present in the guest _BUT_ 
204      the reason for the fault was that the page is not present in the shadow, 
205      _THEN_ we have to map the shadow page in and reexecute, this will generate 
206      a permissions fault which is _THEN_ valid to send to the guest
207      _UNLESS_ both the guest and shadow have marked the page as not present
208
209      whew...
210   */
211   if (guest_access != PT_ACCESS_OK) {
212     // Guest Access Error
213     
214     if ((shadow_access != PT_ACCESS_NOT_PRESENT) &&
215         (guest_access != PT_ACCESS_NOT_PRESENT)) {
216       // aka (guest permission error)
217       return 1;
218     }
219
220     if ((shadow_access == PT_ACCESS_NOT_PRESENT) &&
221         (guest_access == PT_ACCESS_NOT_PRESENT)) {      
222       // Page tables completely blank, handle guest first
223       return 1;
224     }
225
226     // Otherwise we'll handle the guest fault later...?
227   }
228
229   return 0;
230 }
231
232
233
234
235
236
237
238
239
240
241
242
243 /* Currently Does not work with Segmentation!!! */
244 int v3_handle_shadow_invlpg(struct guest_info * info)
245 {
246   if (info->mem_mode != VIRTUAL_MEM) {
247     // Paging must be turned on...
248     // should handle with some sort of fault I think
249     PrintError("ERROR: INVLPG called in non paged mode\n");
250     return -1;
251   }
252   
253   
254   if (info->cpu_mode != PROTECTED) {
255     PrintError("Unsupported CPU mode (mode=%s)\n", v3_cpu_mode_to_str(info->cpu_mode));
256     return -1;
257   }
258   
259   uchar_t instr[15];
260   int index = 0;
261   
262   int ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
263   if (ret != 15) {
264     PrintError("Could not read instruction 0x%p (ret=%d)\n",  (void *)(addr_t)(info->rip), ret);
265     return -1;
266   }
267   
268   
269   /* Can INVLPG work with Segments?? */
270   while (is_prefix_byte(instr[index])) {
271     index++;
272   }
273     
274     
275   if( (instr[index + 0] != (uchar_t) 0x0f) ||  
276       (instr[index + 1] != (uchar_t) 0x01) ) {
277     PrintError("invalid Instruction Opcode\n");
278     PrintTraceMemDump(instr, 15);
279     return -1;
280   }
281   
282   addr_t first_operand;
283   addr_t second_operand;
284   addr_t guest_cr3 =  CR3_TO_PDE32_PA(info->shdw_pg_state.guest_cr3);
285   
286   pde32_t * guest_pd = NULL;
287   
288   if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
289     PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
290     return -1;
291   }
292   
293   index += 2;
294
295   v3_operand_type_t addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
296   
297   if (addr_type != MEM_OPERAND) {
298     PrintError("Invalid Operand type\n");
299     return -1;
300   }
301   
302   pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32_VA(info->ctrl_regs.cr3);
303   pde32_t * shadow_pde = (pde32_t *)&shadow_pd[PDE32_INDEX(first_operand)];
304   pde32_t * guest_pde;
305   
306   //PrintDebug("PDE Index=%d\n", PDE32_INDEX(first_operand));
307   //PrintDebug("FirstOperand = %x\n", first_operand);
308   
309   PrintDebug("Invalidating page for %p\n", (void *)first_operand);
310   
311   guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(first_operand)]);
312   
313   if (guest_pde->large_page == 1) {
314     shadow_pde->present = 0;
315     PrintDebug("Invalidating Large Page\n");
316   } else
317     if (shadow_pde->present == 1) {
318       pte32_t * shadow_pt = (pte32_t *)(addr_t)BASE_TO_PAGE_ADDR(shadow_pde->pt_base_addr);
319       pte32_t * shadow_pte = (pte32_t *) V3_VAddr( (void*) &shadow_pt[PTE32_INDEX(first_operand)] );
320       
321 #ifdef DEBUG_SHADOW_PAGING
322       PrintDebug("Setting not present\n");
323       PrintPTEntry(PAGE_PT32, first_operand, shadow_pte);
324 #endif
325       
326       shadow_pte->present = 0;
327     }
328   
329   info->rip += index;
330   
331   return 0;
332 }
333
334