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.


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