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.


Direct paging changes
[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 #include <palacios/vmm_direct_paging.h>
32
33 #ifndef DEBUG_SHADOW_PAGING
34 #undef PrintDebug
35 #define PrintDebug(fmt, args...)
36 #endif
37
38
39 /*** 
40  ***  There be dragons
41  ***/
42
43
44 struct shadow_page_data {
45   v3_reg_t cr3;
46   addr_t page_pa;
47   
48   struct list_head page_list_node;
49 };
50
51
52 DEFINE_HASHTABLE_INSERT(add_pte_map, addr_t, addr_t);
53 DEFINE_HASHTABLE_SEARCH(find_pte_map, addr_t, addr_t);
54 //DEFINE_HASHTABLE_REMOVE(del_pte_map, addr_t, addr_t, 0);
55
56
57
58 static uint_t pte_hash_fn(addr_t key) {
59   return hash_long(key, 32);
60 }
61
62 static int pte_equals(addr_t key1, addr_t key2) {
63   return (key1 == key2);
64 }
65
66 static struct shadow_page_data * create_new_shadow_pt(struct guest_info * info);
67 static void inject_guest_pf(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
68 static int is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access);
69
70
71 #include "vmm_shadow_paging_32.h"
72 #include "vmm_shadow_paging_32pae.h"
73 #include "vmm_shadow_paging_64.h"
74
75
76
77 int v3_init_shadow_page_state(struct guest_info * info) {
78   struct shadow_page_state * state = &(info->shdw_pg_state);
79   
80   state->guest_cr3 = 0;
81   state->guest_cr0 = 0;
82
83   INIT_LIST_HEAD(&(state->page_list));
84
85   state->cached_ptes = NULL;
86   state->cached_cr3 = 0;
87   
88   return 0;
89 }
90
91
92
93 // Reads the guest CR3 register
94 // creates new shadow page tables
95 // updates the shadow CR3 register to point to the new pts
96 int v3_activate_shadow_pt(struct guest_info * info) {
97   switch (v3_get_cpu_mode(info)) {
98
99   case PROTECTED:
100     return activate_shadow_pt_32(info);
101   case PROTECTED_PAE:
102     return activate_shadow_pt_32pae(info);
103   case LONG:
104   case LONG_32_COMPAT:
105   case LONG_16_COMPAT:
106     return activate_shadow_pt_64(info);
107   default:
108     PrintError("Invalid CPU mode: %s\n", v3_cpu_mode_to_str(v3_get_cpu_mode(info)));
109     return -1;
110   }
111
112   return 0;
113 }
114
115
116 int v3_activate_passthrough_pt(struct guest_info * info) {
117   // For now... But we need to change this....
118   // As soon as shadow paging becomes active the passthrough tables are hosed
119   // So this will cause chaos if it is called at that time
120
121   info->ctrl_regs.cr3 = *(addr_t*)&(info->direct_map_pt);
122   //PrintError("Activate Passthrough Page tables not implemented\n");
123   return 0;
124 }
125
126
127
128 int v3_handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
129   
130   if (v3_get_mem_mode(info) == PHYSICAL_MEM) {
131     // If paging is not turned on we need to handle the special cases
132     return v3_handle_shadow_pagefault_physical_mode(info, fault_addr, error_code);
133   } else if (v3_get_mem_mode(info) == VIRTUAL_MEM) {
134
135     switch (v3_get_cpu_mode(info)) {
136     case PROTECTED:
137       return handle_shadow_pagefault_32(info, fault_addr, error_code);
138       break;
139     case PROTECTED_PAE:
140       return handle_shadow_pagefault_32pae(info, fault_addr, error_code);
141     case LONG:
142     case LONG_32_COMPAT:
143     case LONG_16_COMPAT:
144       return handle_shadow_pagefault_64(info, fault_addr, error_code);
145       break;
146     default:
147       PrintError("Unhandled CPU Mode: %s\n", v3_cpu_mode_to_str(v3_get_cpu_mode(info)));
148       return -1;
149     }
150   } else {
151     PrintError("Invalid Memory mode\n");
152     return -1;
153   }
154 }
155
156
157 int v3_handle_shadow_invlpg(struct guest_info * info) {
158   uchar_t instr[15];
159   struct x86_instr dec_instr;
160   int ret = 0;
161   addr_t vaddr = 0;
162
163   if (v3_get_mem_mode(info) != VIRTUAL_MEM) {
164     // Paging must be turned on...
165     // should handle with some sort of fault I think
166     PrintError("ERROR: INVLPG called in non paged mode\n");
167     return -1;
168   }
169
170   if (v3_get_mem_mode(info) == PHYSICAL_MEM) { 
171     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
172   } else { 
173     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
174   }
175
176   if (ret == -1) {
177     PrintError("Could not read instruction into buffer\n");
178     return -1;
179   }
180
181   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
182     PrintError("Decoding Error\n");
183     return -1;
184   }
185   
186   if ((dec_instr.op_type != V3_OP_INVLPG) || 
187       (dec_instr.num_operands != 1) ||
188       (dec_instr.dst_operand.type != MEM_OPERAND)) {
189     PrintError("Decoder Error: Not a valid INVLPG instruction...\n");
190     return -1;
191   }
192
193   vaddr = dec_instr.dst_operand.operand;
194
195   info->rip += dec_instr.instr_length;
196
197   switch (v3_get_cpu_mode(info)) {
198   case PROTECTED:
199     return handle_shadow_invlpg_32(info, vaddr);
200   case PROTECTED_PAE:
201     return handle_shadow_invlpg_32pae(info, vaddr);
202   case LONG:
203   case LONG_32_COMPAT:
204   case LONG_16_COMPAT:
205     return handle_shadow_invlpg_64(info, vaddr);
206   default:
207     PrintError("Invalid CPU mode: %s\n", v3_cpu_mode_to_str(v3_get_cpu_mode(info)));
208     return -1;
209   }
210 }
211
212
213
214
215 static struct shadow_page_data * create_new_shadow_pt(struct guest_info * info) {
216   struct shadow_page_state * state = &(info->shdw_pg_state);
217   v3_reg_t cur_cr3 = info->ctrl_regs.cr3;
218   struct shadow_page_data * page_tail = NULL;
219   addr_t shdw_page = 0;
220
221   if (!list_empty(&(state->page_list))) {
222     page_tail = list_tail_entry(&(state->page_list), struct shadow_page_data, page_list_node);
223     
224     if (page_tail->cr3 != cur_cr3) {
225       PrintDebug("Reusing old shadow Page: %p (cur_CR3=%p)(page_cr3=%p) \n",
226                  (void *) page_tail->page_pa, (void *)cur_cr3, (void *)(page_tail->cr3));
227
228       list_move(&(page_tail->page_list_node), &(state->page_list));
229
230       memset(V3_VAddr((void *)(page_tail->page_pa)), 0, PAGE_SIZE_4KB);
231
232
233       return page_tail;
234     }
235   }
236
237   // else  
238
239   page_tail = (struct shadow_page_data *)V3_Malloc(sizeof(struct shadow_page_data));
240   page_tail->page_pa = (addr_t)V3_AllocPages(1);
241
242   PrintDebug("Allocating new shadow Page: %p (cur_cr3=%p)\n", (void *)page_tail->page_pa, (void *)cur_cr3);
243
244   page_tail->cr3 = cur_cr3;
245   list_add(&(page_tail->page_list_node), &(state->page_list));
246
247   shdw_page = (addr_t)V3_VAddr((void *)(page_tail->page_pa));
248   memset((void *)shdw_page, 0, PAGE_SIZE_4KB);
249
250   return page_tail;
251 }
252
253
254 static void inject_guest_pf(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
255   if (info->enable_profiler) {
256     info->profiler.guest_pf_cnt++;
257   }
258
259   info->ctrl_regs.cr2 = fault_addr;
260   v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
261 }
262
263
264 static int is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access) {
265   /* basically the reasoning is that there can be multiple reasons for a page fault:
266      If there is a permissions failure for a page present in the guest _BUT_
267      the reason for the fault was that the page is not present in the shadow,
268      _THEN_ we have to map the shadow page in and reexecute, this will generate
269      a permissions fault which is _THEN_ valid to send to the guest
270      _UNLESS_ both the guest and shadow have marked the page as not present
271
272      whew...
273   */
274   if (guest_access != PT_ACCESS_OK) {
275     // Guest Access Error
276
277     if ((shadow_access != PT_ACCESS_NOT_PRESENT) &&
278         (guest_access != PT_ACCESS_NOT_PRESENT)) {
279       // aka (guest permission error)
280       return 1;
281     }
282
283     if ((shadow_access == PT_ACCESS_NOT_PRESENT) &&
284         (guest_access == PT_ACCESS_NOT_PRESENT)) {
285       // Page tables completely blank, handle guest first
286       return 1;
287     }
288
289     // Otherwise we'll handle the guest fault later...?
290   }
291
292   return 0;
293 }
294
295