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.


8074c1689767803b840438ddc0df2d92d87fa35f
[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