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.


slight modifications to the shadow paging handlers
[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   state->cached_cr3 = 0;
103   
104   return 0;
105 }
106
107
108
109 // Reads the guest CR3 register
110 // creates new shadow page tables
111 // updates the shadow CR3 register to point to the new pts
112 int v3_activate_shadow_pt(struct guest_info * info) {
113   switch (info->cpu_mode) {
114
115   case PROTECTED:
116     return activate_shadow_pt_32(info);
117   case PROTECTED_PAE:
118     return activate_shadow_pt_32pae(info);
119   case LONG:
120   case LONG_32_COMPAT:
121   case LONG_16_COMPAT:
122     return activate_shadow_pt_64(info);
123   default:
124     PrintError("Invalid CPU mode: %d\n", info->cpu_mode);
125     return -1;
126   }
127
128   return 0;
129 }
130
131
132 int v3_activate_passthrough_pt(struct guest_info * info) {
133   // For now... But we need to change this....
134   // As soon as shadow paging becomes active the passthrough tables are hosed
135   // So this will cause chaos if it is called at that time
136
137   info->ctrl_regs.cr3 = *(addr_t*)&(info->direct_map_pt);
138   //PrintError("Activate Passthrough Page tables not implemented\n");
139   return 0;
140 }
141
142
143
144 int v3_handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
145   
146   if (info->mem_mode == PHYSICAL_MEM) {
147     // If paging is not turned on we need to handle the special cases
148     return handle_special_page_fault(info, fault_addr, fault_addr, error_code);
149   } else if (info->mem_mode == VIRTUAL_MEM) {
150
151     switch (info->cpu_mode) {
152     case PROTECTED:
153       return handle_shadow_pagefault_32(info, fault_addr, error_code);
154       break;
155     case PROTECTED_PAE:
156       return handle_shadow_pagefault_32pae(info, fault_addr, error_code);
157     case LONG:
158       return handle_shadow_pagefault_64(info, fault_addr, error_code);
159       break;
160     default:
161       PrintError("Unhandled CPU Mode\n");
162       return -1;
163     }
164   } else {
165     PrintError("Invalid Memory mode\n");
166     return -1;
167   }
168 }
169
170
171 int v3_handle_shadow_invlpg(struct guest_info * info) {
172   uchar_t instr[15];
173   struct x86_instr dec_instr;
174   int ret = 0;
175   addr_t vaddr = 0;
176
177   if (info->mem_mode != VIRTUAL_MEM) {
178     // Paging must be turned on...
179     // should handle with some sort of fault I think
180     PrintError("ERROR: INVLPG called in non paged mode\n");
181     return -1;
182   }
183
184   if (info->mem_mode == PHYSICAL_MEM) { 
185     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
186   } else { 
187     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
188   }
189
190   if (ret == -1) {
191     PrintError("Could not read instruction into buffer\n");
192     return -1;
193   }
194
195   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
196     PrintError("Decoding Error\n");
197     return -1;
198   }
199   
200   if ((dec_instr.op_type != V3_OP_INVLPG) || 
201       (dec_instr.num_operands != 1) ||
202       (dec_instr.dst_operand.type != MEM_OPERAND)) {
203     PrintError("Decoder Error: Not a valid INVLPG instruction...\n");
204     return -1;
205   }
206
207   vaddr = dec_instr.dst_operand.operand;
208
209   info->rip += dec_instr.instr_length;
210
211   switch (info->cpu_mode) {
212   case PROTECTED:
213     return handle_shadow_invlpg_32(info, vaddr);
214   case PROTECTED_PAE:
215     return handle_shadow_invlpg_32pae(info, vaddr);
216   case LONG:
217   case LONG_32_COMPAT:
218   case LONG_16_COMPAT:
219     return handle_shadow_invlpg_64(info, vaddr);
220   default:
221     PrintError("Invalid CPU mode: %d\n", info->cpu_mode);
222     return -1;
223   }
224 }
225
226
227
228
229 static addr_t create_new_shadow_pt() {
230   void * host_pde = 0;
231
232   host_pde = V3_VAddr(V3_AllocPages(1));
233   memset(host_pde, 0, PAGE_SIZE);
234
235   return (addr_t)host_pde;
236 }
237
238
239 static void inject_guest_pf(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
240   if (info->enable_profiler) {
241     info->profiler.guest_pf_cnt++;
242   }
243
244   info->ctrl_regs.cr2 = fault_addr;
245   v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
246 }
247
248
249 static int is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access) {
250   /* basically the reasoning is that there can be multiple reasons for a page fault:
251      If there is a permissions failure for a page present in the guest _BUT_ 
252      the reason for the fault was that the page is not present in the shadow, 
253      _THEN_ we have to map the shadow page in and reexecute, this will generate 
254      a permissions fault which is _THEN_ valid to send to the guest
255      _UNLESS_ both the guest and shadow have marked the page as not present
256
257      whew...
258   */
259   if (guest_access != PT_ACCESS_OK) {
260     // Guest Access Error
261     
262     if ((shadow_access != PT_ACCESS_NOT_PRESENT) &&
263         (guest_access != PT_ACCESS_NOT_PRESENT)) {
264       // aka (guest permission error)
265       return 1;
266     }
267
268     if ((shadow_access == PT_ACCESS_NOT_PRESENT) &&
269         (guest_access == PT_ACCESS_NOT_PRESENT)) {      
270       // Page tables completely blank, handle guest first
271       return 1;
272     }
273
274     // Otherwise we'll handle the guest fault later...?
275   }
276
277   return 0;
278 }
279
280