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.


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