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.


fixed debug statement casts
[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_passthrough_pagefault(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 *)(addr_t)page_tail->page_pa, 
227                  (void *)(addr_t)cur_cr3, 
228                  (void *)(addr_t)(page_tail->cr3));
229
230       list_move(&(page_tail->page_list_node), &(state->page_list));
231
232       memset(V3_VAddr((void *)(page_tail->page_pa)), 0, PAGE_SIZE_4KB);
233
234
235       return page_tail;
236     }
237   }
238
239   // else  
240
241   page_tail = (struct shadow_page_data *)V3_Malloc(sizeof(struct shadow_page_data));
242   page_tail->page_pa = (addr_t)V3_AllocPages(1);
243
244   PrintDebug("Allocating new shadow Page: %p (cur_cr3=%p)\n", 
245              (void *)(addr_t)page_tail->page_pa, 
246              (void *)(addr_t)cur_cr3);
247
248   page_tail->cr3 = cur_cr3;
249   list_add(&(page_tail->page_list_node), &(state->page_list));
250
251   shdw_page = (addr_t)V3_VAddr((void *)(page_tail->page_pa));
252   memset((void *)shdw_page, 0, PAGE_SIZE_4KB);
253
254   return page_tail;
255 }
256
257
258 static void inject_guest_pf(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
259   if (info->enable_profiler) {
260     info->profiler.guest_pf_cnt++;
261   }
262
263   info->ctrl_regs.cr2 = fault_addr;
264   v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
265 }
266
267
268 static int is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access) {
269   /* basically the reasoning is that there can be multiple reasons for a page fault:
270      If there is a permissions failure for a page present in the guest _BUT_
271      the reason for the fault was that the page is not present in the shadow,
272      _THEN_ we have to map the shadow page in and reexecute, this will generate
273      a permissions fault which is _THEN_ valid to send to the guest
274      _UNLESS_ both the guest and shadow have marked the page as not present
275
276      whew...
277   */
278   if (guest_access != PT_ACCESS_OK) {
279     // Guest Access Error
280
281     if ((shadow_access != PT_ACCESS_NOT_PRESENT) &&
282         (guest_access != PT_ACCESS_NOT_PRESENT)) {
283       // aka (guest permission error)
284       return 1;
285     }
286
287     if ((shadow_access == PT_ACCESS_NOT_PRESENT) &&
288         (guest_access == PT_ACCESS_NOT_PRESENT)) {
289       // Page tables completely blank, handle guest first
290       return 1;
291     }
292
293     // Otherwise we'll handle the guest fault later...?
294   }
295
296   return 0;
297 }
298
299