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.


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