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.


e2fad695db4ee8d68bee82dec2f1f8dafd633c94
[palacios.git] / palacios / src / palacios / vmm_direct_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, Steven Jaconette <stevenjaconette2007@u.northwestern.edu> 
11  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
12  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
13  * All rights reserved.
14  *
15  * Author: Steven Jaconette <stevenjaconette2007@u.northwestern.edu>
16  *         Peter Dinda <pdinda@northwestern.edu> (refactor + events)
17  *
18  * This is free software.  You are permitted to use,
19  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20  */
21
22 #include <palacios/vmm_direct_paging.h>
23 #include <palacios/vmm_paging.h>
24 #include <palacios/vmm.h>
25 #include <palacios/vm_guest_mem.h>
26 #include <palacios/vm_guest.h>
27 #include <palacios/vmm_ctrl_regs.h>
28
29
30 #if !defined(V3_CONFIG_DEBUG_NESTED_PAGING) && !defined(V3_CONFIG_DEBUG_SHADOW_PAGING)
31 #undef PrintDebug
32 #define PrintDebug(fmt, args...)
33 #endif
34
35
36
37 /*
38
39   "Direct Paging" combines these three functionalities:
40
41    1. Passthrough paging for SVM and VMX
42
43       Passthrough paging is used for shadow paging when
44       the guest does not have paging turn on, for example 
45       when it is running in real mode or protected mode 
46       early in a typical boot process.    Passthrough page
47       tables are shadow page tables that are built assuming
48       the guest virtual to guest physical mapping is the identity.
49       Thus, what they implement are the GPA->HPA mapping. 
50
51       Passthrough page tables are built using 32PAE paging.
52       
53
54    2. Nested paging on SVM
55   
56       The SVM nested page tables have the same format as
57       regular page tables.   For this reason, we can reuse 
58       much of the passthrough implementation.   A nested page
59       table mapping is a GPA->HPA mapping, creating a very 
60       simlar model as with passthrough paging, just that it's 
61       always active, whether the guest has paging on or not.
62
63
64    3. Nested paging on VMX
65
66       The VMX nested page tables have a different format
67       than regular page tables.  For this reason, we have
68       implemented them in the vmx_npt.h file.  The code
69       here then is a wrapper, allowing us to make nested
70       paging functionality appear uniform across VMX and SVM
71       elsewhere in the codebase.
72
73 */
74
75
76
77 static inline int is_vmx_nested()
78 {
79     extern v3_cpu_arch_t v3_mach_type;
80
81     return (v3_mach_type==V3_VMX_EPT_CPU || v3_mach_type==V3_VMX_EPT_UG_CPU);
82 }
83
84 static inline int is_svm_nested()
85 {
86     extern v3_cpu_arch_t v3_mach_type;
87
88     return (v3_mach_type==V3_SVM_REV3_CPU);
89 }
90
91
92 struct passthrough_event_callback {
93     int (*callback)(struct guest_info *core, struct v3_passthrough_pg_event *event, void *priv_data);
94     void *priv_data;
95
96     struct list_head node;
97 };
98
99
100 static int have_passthrough_callbacks(struct guest_info *core)
101 {
102     return !list_empty(&(core->vm_info->passthrough_impl.event_callback_list));
103 }
104
105 static void dispatch_passthrough_event(struct guest_info *core, struct v3_passthrough_pg_event *event)
106 {
107     struct passthrough_event_callback *cb,*temp;
108     
109     list_for_each_entry_safe(cb,
110                              temp,
111                              &(core->vm_info->passthrough_impl.event_callback_list),
112                              node) {
113         cb->callback(core,event,cb->priv_data);
114     }
115 }
116
117 struct nested_event_callback {
118     int (*callback)(struct guest_info *core, struct v3_nested_pg_event *event, void *priv_data);
119     void *priv_data;
120
121     struct list_head node;
122 };
123
124
125 static int have_nested_callbacks(struct guest_info *core)
126 {
127     return !list_empty(&(core->vm_info->nested_impl.event_callback_list));
128 }
129
130 static void dispatch_nested_event(struct guest_info *core, struct v3_nested_pg_event *event)
131 {
132     struct nested_event_callback *cb,*temp;
133     
134     list_for_each_entry_safe(cb,
135                              temp,
136                              &(core->vm_info->nested_impl.event_callback_list),
137                              node) {
138         cb->callback(core,event,cb->priv_data);
139     }
140 }
141
142
143
144
145 static addr_t create_generic_pt_page(struct guest_info *core) {
146     void * page = 0;
147     void *temp;
148
149     temp = V3_AllocPagesExtended(1, PAGE_SIZE_4KB, -1, 0); // no constraints
150
151     if (!temp) {  
152         PrintError(VM_NONE, VCORE_NONE,"Cannot allocate page\n");
153         return 0;
154     }
155
156     page = V3_VAddr(temp);
157     memset(page, 0, PAGE_SIZE);
158
159     return (addr_t)page;
160 }
161
162 // Inline handler functions for each cpu mode
163 #include "vmm_direct_paging_32.h"
164 #include "vmm_direct_paging_32pae.h"
165 #include "vmm_direct_paging_64.h"
166
167
168
169 int v3_init_passthrough_pts(struct guest_info * info) {
170     info->direct_map_pt = (addr_t)V3_PAddr((void *)create_generic_pt_page(info));
171     return 0;
172 }
173
174
175 int v3_free_passthrough_pts(struct guest_info * core) {
176     v3_cpu_mode_t mode = v3_get_vm_cpu_mode(core);
177
178     // Delete the old direct map page tables
179     switch(mode) {
180         case REAL:
181         case PROTECTED:
182           // Intentional fallthrough here
183           // There are *only* PAE tables
184         case PROTECTED_PAE:
185         case LONG:
186         case LONG_32_COMPAT:
187             // Long mode will only use 32PAE page tables...
188             delete_page_tables_32pae((pdpe32pae_t *)V3_VAddr((void *)(core->direct_map_pt)));
189             break;
190         default:
191             PrintError(core->vm_info, core, "Unknown CPU Mode\n");
192             return -1;
193             break;
194     }
195
196     return 0;
197 }
198
199
200 int v3_reset_passthrough_pts(struct guest_info * core) {
201
202     v3_free_passthrough_pts(core);
203
204     // create new direct map page table
205     v3_init_passthrough_pts(core);
206     
207     return 0;
208 }
209
210
211
212 int v3_activate_passthrough_pt(struct guest_info * info) {
213     // For now... But we need to change this....
214     // As soon as shadow paging becomes active the passthrough tables are hosed
215     // So this will cause chaos if it is called at that time
216
217     if (have_passthrough_callbacks(info)) { 
218         struct v3_passthrough_pg_event event={PASSTHROUGH_ACTIVATE,PASSTHROUGH_PREIMPL,0,{0,0,0,0,0,0},0,0};
219         dispatch_passthrough_event(info,&event);
220     }
221         
222     struct cr3_32_PAE * shadow_cr3 = (struct cr3_32_PAE *) &(info->ctrl_regs.cr3);
223     struct cr4_32 * shadow_cr4 = (struct cr4_32 *) &(info->ctrl_regs.cr4);
224     addr_t shadow_pt_addr = *(addr_t*)&(info->direct_map_pt);
225     // Passthrough PTs will only be PAE page tables.
226     shadow_cr3->pdpt_base_addr = shadow_pt_addr >> 5;
227     shadow_cr4->pae = 1;
228     PrintDebug(info->vm_info, info, "Activated Passthrough Page tables\n");
229
230     if (have_passthrough_callbacks(info)) { 
231         struct v3_passthrough_pg_event event={PASSTHROUGH_ACTIVATE,PASSTHROUGH_POSTIMPL,0,{0,0,0,0,0,0},0,0};
232         dispatch_passthrough_event(info,&event);
233     }
234
235     return 0;
236 }
237
238
239
240 int v3_handle_passthrough_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code,
241                                     addr_t *actual_start, addr_t *actual_end) {
242     v3_cpu_mode_t mode = v3_get_vm_cpu_mode(info);
243     addr_t start, end;
244     int rc;
245
246     if (have_passthrough_callbacks(info)) {                                    
247         struct v3_passthrough_pg_event event={PASSTHROUGH_PAGEFAULT,PASSTHROUGH_PREIMPL,fault_addr,error_code,fault_addr,fault_addr};
248         dispatch_passthrough_event(info,&event);        
249     }
250
251     if (!actual_start) { actual_start=&start; }
252     if (!actual_end) { actual_end=&end; }
253
254
255     rc=-1;
256
257     switch(mode) {
258         case REAL:
259         case PROTECTED:
260           // Note intentional fallthrough here
261           // There are only PAE page tables now
262         case PROTECTED_PAE:
263         case LONG:
264         case LONG_32_COMPAT:
265             // Long mode will only use 32PAE page tables...
266             rc=handle_passthrough_pagefault_32pae(info, fault_addr, error_code, actual_start, actual_end);
267             break;
268         default:
269             PrintError(info->vm_info, info, "Unknown CPU Mode\n");
270             break;
271     }
272
273     if (have_passthrough_callbacks(info)) {                                    
274         struct v3_passthrough_pg_event event={PASSTHROUGH_PAGEFAULT,PASSTHROUGH_POSTIMPL,fault_addr,error_code,*actual_start,*actual_end};
275         dispatch_passthrough_event(info,&event);        
276     }
277
278     return rc;
279 }
280
281
282
283 int v3_invalidate_passthrough_addr(struct guest_info * info, addr_t inv_addr, 
284                                    addr_t *actual_start, addr_t *actual_end) {
285
286     v3_cpu_mode_t mode = v3_get_vm_cpu_mode(info);
287     addr_t start, end;
288     int rc;
289
290     if (have_passthrough_callbacks(info)) {                                    
291         struct v3_passthrough_pg_event event={PASSTHROUGH_INVALIDATE_RANGE,PASSTHROUGH_PREIMPL,0,{0,0,0,0,0,0},PAGE_ADDR(inv_addr),PAGE_ADDR(inv_addr)+PAGE_SIZE-1};
292         dispatch_passthrough_event(info,&event);        
293     }
294
295     if (!actual_start) { actual_start=&start;}
296     if (!actual_end) { actual_end=&end;}
297
298
299
300     rc=-1;
301
302     switch(mode) {
303         case REAL:
304         case PROTECTED:
305           // Intentional fallthrough - there
306           // are only PAE page tables now
307         case PROTECTED_PAE:
308         case LONG:
309         case LONG_32_COMPAT:
310             // Long mode will only use 32PAE page tables...
311             rc=invalidate_addr_32pae(info, inv_addr, actual_start, actual_end);
312             break;
313         default:
314             PrintError(info->vm_info, info, "Unknown CPU Mode\n");
315             break;
316     }
317
318     if (have_passthrough_callbacks(info)) {                                    
319         struct v3_passthrough_pg_event event={PASSTHROUGH_INVALIDATE_RANGE,PASSTHROUGH_POSTIMPL,0,{0,0,0,0,0,0},*actual_start,*actual_end};
320         dispatch_passthrough_event(info,&event);        
321     }
322
323
324     return rc;
325 }
326
327
328 int v3_invalidate_passthrough_addr_range(struct guest_info * info, 
329                                          addr_t inv_addr_start, addr_t inv_addr_end,
330                                          addr_t *actual_start, addr_t *actual_end) {
331     v3_cpu_mode_t mode = v3_get_vm_cpu_mode(info);
332     addr_t start, end;
333     int rc;
334
335     if (!actual_start) { actual_start=&start;}
336     if (!actual_end) { actual_end=&end;}
337
338     if (have_passthrough_callbacks(info)) {                                    
339         struct v3_passthrough_pg_event event={PASSTHROUGH_INVALIDATE_RANGE,PASSTHROUGH_PREIMPL,0,{0,0,0,0,0,0},PAGE_ADDR(inv_addr_start),PAGE_ADDR(inv_addr_end-1)+PAGE_SIZE-1};
340         dispatch_passthrough_event(info,&event);        
341     }
342     
343     rc=-1;
344
345     switch(mode) {
346         case REAL:
347         case PROTECTED:
348           // Intentional fallthrough
349           // There are only PAE PTs now
350         case PROTECTED_PAE:
351         case LONG:
352         case LONG_32_COMPAT:
353             // Long mode will only use 32PAE page tables...
354           rc=invalidate_addr_32pae_range(info, inv_addr_start, inv_addr_end, actual_start, actual_end);
355           break;
356         default:
357             PrintError(info->vm_info, info, "Unknown CPU Mode\n");
358             break;
359     }
360
361     if (have_passthrough_callbacks(info)) {                                    
362         struct v3_passthrough_pg_event event={PASSTHROUGH_INVALIDATE_RANGE,PASSTHROUGH_POSTIMPL,0,{0,0,0,0,0,0},*actual_start,*actual_end};
363         dispatch_passthrough_event(info,&event);        
364     }
365
366     return rc;
367 }
368
369
370 int v3_init_passthrough_paging(struct v3_vm_info *vm)
371 {
372   INIT_LIST_HEAD(&(vm->passthrough_impl.event_callback_list));
373   return 0;
374 }
375
376 int v3_deinit_passthrough_paging(struct v3_vm_info *vm)
377 {
378   struct passthrough_event_callback *cb,*temp;
379   
380   list_for_each_entry_safe(cb,
381                            temp,
382                            &(vm->passthrough_impl.event_callback_list),
383                            node) {
384     list_del(&(cb->node));
385     V3_Free(cb);
386   }
387   
388   return 0;
389 }
390
391 int v3_init_passthrough_paging_core(struct guest_info *core)
392 {
393   // currently nothing to init
394   return 0;
395 }
396
397 int v3_deinit_passthrough_paging_core(struct guest_info *core)
398 {
399   // currently nothing to deinit
400   return 0;
401 }
402
403
404 int v3_register_passthrough_paging_event_callback(struct v3_vm_info *vm,
405                                                   int (*callback)(struct guest_info *core, 
406                                                                   struct v3_passthrough_pg_event *,
407                                                                   void      *priv_data),
408                                                   void *priv_data)
409 {
410     struct passthrough_event_callback *ec = V3_Malloc(sizeof(struct passthrough_event_callback));
411     
412     if (!ec) { 
413         PrintError(vm, VCORE_NONE, "Unable to allocate for a nested paging event callback\n");
414         return -1;
415     }
416     
417     ec->callback = callback;
418     ec->priv_data = priv_data;
419     
420     list_add(&(ec->node),&(vm->passthrough_impl.event_callback_list));
421
422     return 0;
423
424 }
425
426
427
428 int v3_unregister_passthrough_paging_event_callback(struct v3_vm_info *vm,
429                                                     int (*callback)(struct guest_info *core, 
430                                                                     struct v3_passthrough_pg_event *,
431                                                                     void      *priv_data),
432                                                     void *priv_data)
433 {
434     struct passthrough_event_callback *cb,*temp;
435     
436     list_for_each_entry_safe(cb,
437                              temp,
438                              &(vm->passthrough_impl.event_callback_list),
439                              node) {
440         if ((callback == cb->callback) && (priv_data == cb->priv_data)) { 
441             list_del(&(cb->node));
442             V3_Free(cb);
443             return 0;
444         }
445     }
446     
447     PrintError(vm, VCORE_NONE, "No callback found!\n");
448     
449     return -1;
450 }
451
452
453 // inline nested paging support for Intel and AMD
454 #include "svm_npt.h"
455 #include "vmx_npt.h"
456
457
458 inline void convert_to_pf_error(void *pfinfo, pf_error_t *out)
459 {
460   if (is_vmx_nested()) {
461 #ifdef V3_CONFIG_VMX
462     ept_exit_qual_to_pf_error((struct ept_exit_qual *)pfinfo, out);
463 #endif
464   } else {
465     *out = *(pf_error_t *)pfinfo;
466   }
467 }
468
469 int v3_handle_nested_pagefault(struct guest_info * info, addr_t fault_addr, void *pfinfo, addr_t *actual_start, addr_t *actual_end)
470 {
471   int rc;
472   pf_error_t err;
473   addr_t start, end;
474
475   if (!actual_start) { actual_start=&start; }
476   if (!actual_end) { actual_end=&end; }
477
478   convert_to_pf_error(pfinfo,&err);
479
480   if (have_nested_callbacks(info)) {                                   
481       struct v3_nested_pg_event event={NESTED_PAGEFAULT,NESTED_PREIMPL,fault_addr,err,fault_addr,fault_addr};
482       dispatch_nested_event(info,&event);       
483   }
484
485   
486   if (is_vmx_nested()) { 
487     rc = handle_vmx_nested_pagefault(info,fault_addr,pfinfo,actual_start,actual_end);
488   } else {
489     rc = handle_svm_nested_pagefault(info,fault_addr,pfinfo,actual_start,actual_end);
490   }
491   
492   if (have_nested_callbacks(info)) {
493     struct v3_nested_pg_event event={NESTED_PAGEFAULT,NESTED_POSTIMPL,fault_addr,err,*actual_start,*actual_end};
494     dispatch_nested_event(info,&event);
495   }
496   
497   return rc;
498 }
499   
500
501
502 int v3_invalidate_nested_addr(struct guest_info * info, addr_t inv_addr,
503                               addr_t *actual_start, addr_t *actual_end) 
504 {
505   int rc;
506   
507   addr_t start, end;
508
509   if (!actual_start) { actual_start=&start; }
510   if (!actual_end) { actual_end=&end; }
511   
512
513   if (have_nested_callbacks(info)) { 
514     struct v3_nested_pg_event event={NESTED_INVALIDATE_RANGE,NESTED_PREIMPL,0,{0,0,0,0,0,0},PAGE_ADDR(inv_addr),PAGE_ADDR(inv_addr)+PAGE_SIZE-1};
515     dispatch_nested_event(info,&event);
516   }
517
518   if (is_vmx_nested()) {
519     rc = handle_vmx_invalidate_nested_addr(info, inv_addr, actual_start, actual_end);
520   } else {
521     rc = handle_svm_invalidate_nested_addr(info, inv_addr, actual_start, actual_end);
522   }
523   
524   if (have_nested_callbacks(info)) { 
525     struct v3_nested_pg_event event={NESTED_INVALIDATE_RANGE,NESTED_POSTIMPL,0,{0,0,0,0,0,0},*actual_start, *actual_end};
526     dispatch_nested_event(info,&event);
527   }
528   return rc;
529 }
530
531
532 int v3_invalidate_nested_addr_range(struct guest_info * info, 
533                                     addr_t inv_addr_start, addr_t inv_addr_end,
534                                     addr_t *actual_start, addr_t *actual_end) 
535 {
536   int rc;
537
538   addr_t start, end;
539
540   if (!actual_start) { actual_start=&start; }
541   if (!actual_end) { actual_end=&end; }
542
543   if (have_nested_callbacks(info)) { 
544     struct v3_nested_pg_event event={NESTED_INVALIDATE_RANGE,NESTED_PREIMPL,0,{0,0,0,0,0,0},PAGE_ADDR(inv_addr_start),PAGE_ADDR(inv_addr_end-1)+PAGE_SIZE-1};
545     dispatch_nested_event(info,&event);
546   }
547   
548   if (is_vmx_nested()) {
549     rc = handle_vmx_invalidate_nested_addr_range(info, inv_addr_start, inv_addr_end, actual_start, actual_end);
550   } else {
551     rc = handle_svm_invalidate_nested_addr_range(info, inv_addr_start, inv_addr_end, actual_start, actual_end);
552   }
553   
554
555   if (have_nested_callbacks(info)) { 
556     struct v3_nested_pg_event event={NESTED_INVALIDATE_RANGE,NESTED_PREIMPL,0,{0,0,0,0,0,0},*actual_start, *actual_end};
557     dispatch_nested_event(info,&event);
558   }
559   
560   return rc;
561   
562 }
563
564
565 int v3_init_nested_paging(struct v3_vm_info *vm)
566 {
567   INIT_LIST_HEAD(&(vm->nested_impl.event_callback_list));
568   return 0;
569 }
570
571 int v3_init_nested_paging_core(struct guest_info *core, void *hwinfo)
572 {
573   if (is_vmx_nested()) { 
574     return init_ept(core, (struct vmx_hw_info *) hwinfo);
575   } else {
576     // no initialization for SVM
577     return 0;
578   }
579 }
580     
581 int v3_deinit_nested_paging(struct v3_vm_info *vm)
582 {
583   struct nested_event_callback *cb,*temp;
584   
585   list_for_each_entry_safe(cb,
586                            temp,
587                            &(vm->nested_impl.event_callback_list),
588                            node) {
589     list_del(&(cb->node));
590     V3_Free(cb);
591   }
592   
593   return 0;
594 }
595
596 int v3_deinit_nested_paging_core(struct guest_info *core)
597 {
598   // nothing to do..  probably dealloc?  FIXME PAD
599
600   return 0;
601 }
602
603
604 int v3_register_nested_paging_event_callback(struct v3_vm_info *vm,
605                                             int (*callback)(struct guest_info *core, 
606                                                             struct v3_nested_pg_event *,
607                                                             void      *priv_data),
608                                             void *priv_data)
609 {
610     struct nested_event_callback *ec = V3_Malloc(sizeof(struct nested_event_callback));
611
612     if (!ec) { 
613         PrintError(vm, VCORE_NONE, "Unable to allocate for a nested paging event callback\n");
614         return -1;
615     }
616     
617     ec->callback = callback;
618     ec->priv_data = priv_data;
619
620     list_add(&(ec->node),&(vm->nested_impl.event_callback_list));
621
622     return 0;
623
624 }
625
626
627
628 int v3_unregister_nested_paging_event_callback(struct v3_vm_info *vm,
629                                               int (*callback)(struct guest_info *core, 
630                                                               struct v3_nested_pg_event *,
631                                                               void      *priv_data),
632                                               void *priv_data)
633 {
634     struct nested_event_callback *cb,*temp;
635
636     list_for_each_entry_safe(cb,
637                              temp,
638                              &(vm->nested_impl.event_callback_list),
639                              node) {
640         if ((callback == cb->callback) && (priv_data == cb->priv_data)) { 
641             list_del(&(cb->node));
642             V3_Free(cb);
643             return 0;
644         }
645     }
646     
647     PrintError(vm, VCORE_NONE, "No callback found!\n");
648     
649     return -1;
650 }