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.


revamped the INVLPG handler
[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
172 static addr_t create_new_shadow_pt() {
173   void * host_pde = 0;
174
175   host_pde = V3_VAddr(V3_AllocPages(1));
176   memset(host_pde, 0, PAGE_SIZE);
177
178   return (addr_t)host_pde;
179 }
180
181
182 static void inject_guest_pf(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
183   if (info->enable_profiler) {
184     info->profiler.guest_pf_cnt++;
185   }
186
187   info->ctrl_regs.cr2 = fault_addr;
188   v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
189 }
190
191
192 static int is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access) {
193   /* basically the reasoning is that there can be multiple reasons for a page fault:
194      If there is a permissions failure for a page present in the guest _BUT_ 
195      the reason for the fault was that the page is not present in the shadow, 
196      _THEN_ we have to map the shadow page in and reexecute, this will generate 
197      a permissions fault which is _THEN_ valid to send to the guest
198      _UNLESS_ both the guest and shadow have marked the page as not present
199
200      whew...
201   */
202   if (guest_access != PT_ACCESS_OK) {
203     // Guest Access Error
204     
205     if ((shadow_access != PT_ACCESS_NOT_PRESENT) &&
206         (guest_access != PT_ACCESS_NOT_PRESENT)) {
207       // aka (guest permission error)
208       return 1;
209     }
210
211     if ((shadow_access == PT_ACCESS_NOT_PRESENT) &&
212         (guest_access == PT_ACCESS_NOT_PRESENT)) {      
213       // Page tables completely blank, handle guest first
214       return 1;
215     }
216
217     // Otherwise we'll handle the guest fault later...?
218   }
219
220   return 0;
221 }
222
223
224
225
226
227
228
229
230
231
232 int v3_handle_shadow_invlpg(struct guest_info * info) {
233   uchar_t instr[15];
234   struct x86_instr dec_instr;
235   int ret = 0;
236   addr_t vaddr = 0;
237
238   if (info->mem_mode != VIRTUAL_MEM) {
239     // Paging must be turned on...
240     // should handle with some sort of fault I think
241     PrintError("ERROR: INVLPG called in non paged mode\n");
242     return -1;
243   }
244
245   if (info->mem_mode == PHYSICAL_MEM) { 
246     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
247   } else { 
248     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
249   }
250
251   if (ret == -1) {
252     PrintError("Could not read instruction into buffer\n");
253     return -1;
254   }
255
256   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
257     PrintError("Decoding Error\n");
258     return -1;
259   }
260   
261   if ((dec_instr.op_type != V3_OP_INVLPG) || 
262       (dec_instr.num_operands != 1) ||
263       (dec_instr.dst_operand.type != MEM_OPERAND)) {
264     PrintError("Decoder Error: Not a valid INVLPG instruction...\n");
265     return -1;
266   }
267
268   vaddr = dec_instr.dst_operand.operand;
269
270   info->rip += dec_instr.instr_length;
271
272   switch (info->cpu_mode) {
273   case PROTECTED:
274     return handle_shadow_invlpg_32(info, vaddr);
275   case PROTECTED_PAE:
276     return handle_shadow_invlpg_32pae(info, vaddr);
277   case LONG:
278   case LONG_32_COMPAT:
279   case LONG_16_COMPAT:
280     return handle_shadow_invlpg_64(info, vaddr);
281   default:
282     PrintError("Invalid CPU mode: %d\n", info->cpu_mode);
283     return -1;
284   }
285 }
286