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.


exported functionality for vmcs flushing via vmcs_clear
[palacios.git] / palacios / src / palacios / vmm.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 #include <palacios/vmm.h>
21 #include <palacios/vmm_intr.h>
22 #include <palacios/vmm_config.h>
23 #include <palacios/vm_guest.h>
24 #include <palacios/vmm_ctrl_regs.h>
25 #include <palacios/vmm_lowlevel.h>
26 #include <palacios/vmm_sprintf.h>
27 #include <palacios/vmm_extensions.h>
28
29 #ifdef V3_CONFIG_SVM
30 #include <palacios/svm.h>
31 #endif
32 #ifdef V3_CONFIG_VMX
33 #include <palacios/vmx.h>
34 #endif
35
36 #ifdef V3_CONFIG_CHECKPOINT
37 #include <palacios/vmm_checkpoint.h>
38 #endif
39
40
41 v3_cpu_arch_t v3_cpu_types[V3_CONFIG_MAX_CPUS];
42 struct v3_os_hooks * os_hooks = NULL;
43 int v3_dbg_enable = 0;
44
45
46
47
48 static void init_cpu(void * arg) {
49     uint32_t cpu_id = (uint32_t)(addr_t)arg;
50
51 #ifdef V3_CONFIG_SVM
52     if (v3_is_svm_capable()) {
53         PrintDebug("Machine is SVM Capable\n");
54         v3_init_svm_cpu(cpu_id);
55         
56     } else 
57 #endif
58 #ifdef V3_CONFIG_VMX
59     if (v3_is_vmx_capable()) {
60         PrintDebug("Machine is VMX Capable\n");
61         v3_init_vmx_cpu(cpu_id);
62
63     } else 
64 #endif
65     {
66        PrintError("CPU has no virtualization Extensions\n");
67     }
68 }
69
70
71 static void deinit_cpu(void * arg) {
72     uint32_t cpu_id = (uint32_t)(addr_t)arg;
73
74
75     switch (v3_cpu_types[cpu_id]) {
76 #ifdef V3_CONFIG_SVM
77         case V3_SVM_CPU:
78         case V3_SVM_REV3_CPU:
79             PrintDebug("Deinitializing SVM CPU %d\n", cpu_id);
80             v3_deinit_svm_cpu(cpu_id);
81             break;
82 #endif
83 #ifdef V3_CONFIG_VMX
84         case V3_VMX_CPU:
85         case V3_VMX_EPT_CPU:
86         case V3_VMX_EPT_UG_CPU:
87             PrintDebug("Deinitializing VMX CPU %d\n", cpu_id);
88             v3_deinit_vmx_cpu(cpu_id);
89             break;
90 #endif
91         case V3_INVALID_CPU:
92         default:
93             PrintError("CPU has no virtualization Extensions\n");
94             break;
95     }
96 }
97
98
99
100 void Init_V3(struct v3_os_hooks * hooks, int num_cpus) {
101     int i;
102
103     V3_Print("V3 Print statement to fix a Kitten page fault bug\n");
104
105     // Set global variables. 
106     os_hooks = hooks;
107
108     for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
109         v3_cpu_types[i] = V3_INVALID_CPU;
110     }
111
112     // Register all the possible device types
113     V3_init_devices();
114
115     // Register all shadow paging handlers
116     V3_init_shdw_paging();
117
118     // Register all extensions
119     V3_init_extensions();
120
121
122 #ifdef V3_CONFIG_SYMMOD
123     V3_init_symmod();
124 #endif
125
126 #ifdef V3_CONFIG_CHECKPOINT
127     V3_init_checkpoint();
128 #endif
129
130
131
132
133     if ((hooks) && (hooks->call_on_cpu)) {
134
135         for (i = 0; i < num_cpus; i++) {
136
137             V3_Print("Initializing VMM extensions on cpu %d\n", i);
138             hooks->call_on_cpu(i, &init_cpu, (void *)(addr_t)i);
139         }
140     }
141
142
143 }
144
145
146 void Shutdown_V3() {
147     int i;
148
149     V3_deinit_devices();
150     V3_deinit_shdw_paging();
151
152     V3_deinit_extensions();
153
154 #ifdef V3_CONFIG_SYMMOD
155     V3_deinit_symmod();
156 #endif
157
158 #ifdef V3_CONFIG_CHECKPOINT
159     V3_deinit_checkpoint();
160 #endif
161
162
163     if ((os_hooks) && (os_hooks->call_on_cpu)) {
164         for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
165             if (v3_cpu_types[i] != V3_INVALID_CPU) {
166                 V3_Call_On_CPU(i, deinit_cpu, (void *)(addr_t)i);
167                 //deinit_cpu((void *)(addr_t)i);
168             }
169         }
170     }
171
172 }
173
174
175 v3_cpu_arch_t v3_get_cpu_type(int cpu_id) {
176     return v3_cpu_types[cpu_id];
177 }
178
179
180 struct v3_vm_info * v3_create_vm(void * cfg, void * priv_data, char * name) {
181     struct v3_vm_info * vm = v3_config_guest(cfg, priv_data);
182
183     if (vm == NULL) {
184         PrintError("Could not configure guest\n");
185         return NULL;
186     }
187
188     V3_Print("CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
189
190     if (name == NULL) {
191         name = "[V3_VM]";
192     } else if (strlen(name) >= 128) {
193         PrintError("VM name is too long. Will be truncated to 128 chars.\n");
194     }
195
196     memset(vm->name, 0, 128);
197     strncpy(vm->name, name, 127);
198
199     return vm;
200 }
201
202
203
204
205 static int start_core(void * p)
206 {
207     struct guest_info * core = (struct guest_info *)p;
208
209
210     PrintDebug("virtual core %u (on logical core %u): in start_core (RIP=%p)\n", 
211                core->vcpu_id, core->pcpu_id, (void *)(addr_t)core->rip);
212
213     switch (v3_cpu_types[0]) {
214 #ifdef V3_CONFIG_SVM
215         case V3_SVM_CPU:
216         case V3_SVM_REV3_CPU:
217             return v3_start_svm_guest(core);
218             break;
219 #endif
220 #if V3_CONFIG_VMX
221         case V3_VMX_CPU:
222         case V3_VMX_EPT_CPU:
223         case V3_VMX_EPT_UG_CPU:
224             return v3_start_vmx_guest(core);
225             break;
226 #endif
227         default:
228             PrintError("Attempting to enter a guest on an invalid CPU\n");
229             return -1;
230     }
231     // should not happen
232     return 0;
233 }
234
235
236 // For the moment very ugly. Eventually we will shift the cpu_mask to an arbitrary sized type...
237 #define MAX_CORES 32
238
239
240 int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
241     uint32_t i;
242     uint8_t * core_mask = (uint8_t *)&cpu_mask; // This is to make future expansion easier
243     uint32_t avail_cores = 0;
244     int vcore_id = 0;
245
246     /// CHECK IF WE ARE MULTICORE ENABLED....
247
248     V3_Print("V3 --  Starting VM (%u cores)\n", vm->num_cores);
249     V3_Print("CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
250
251
252     // Check that enough cores are present in the mask to handle vcores
253     for (i = 0; i < MAX_CORES; i++) {
254         int major = i / 8;
255         int minor = i % 8;
256         
257         if (core_mask[major] & (0x1 << minor)) {
258             avail_cores++;
259         }
260     }
261
262
263     if (vm->num_cores > avail_cores) {
264         PrintError("Attempted to start a VM with too many cores (vm->num_cores = %d, avail_cores = %d, MAX=%d)\n", 
265                    vm->num_cores, avail_cores, MAX_CORES);
266         return -1;
267     }
268
269     // Spawn off threads for each core. 
270     // We work backwards, so that core 0 is always started last.
271     for (i = 0, vcore_id = vm->num_cores - 1; (i < MAX_CORES) && (vcore_id >= 0); i++) {
272         int major = 0;
273         int minor = 0;
274         struct guest_info * core = &(vm->cores[vcore_id]);
275         char * specified_cpu = v3_cfg_val(core->core_cfg_data, "target_cpu");
276         uint32_t core_idx = 0;
277
278         if (specified_cpu != NULL) {
279             core_idx = atoi(specified_cpu);
280             
281             if ((core_idx < 0) || (core_idx >= MAX_CORES)) {
282                 PrintError("Target CPU out of bounds (%d) (MAX_CORES=%d)\n", core_idx, MAX_CORES);
283             }
284
285             i--; // We reset the logical core idx. Not strictly necessary I guess... 
286         } else {
287             core_idx = i;
288         }
289
290         major = core_idx / 8;
291         minor = core_idx % 8;
292
293         if ((core_mask[major] & (0x1 << minor)) == 0) {
294             PrintError("Logical CPU %d not available for virtual core %d; not started\n",
295                        core_idx, vcore_id);
296
297             if (specified_cpu != NULL) {
298                 PrintError("CPU was specified explicitly (%d). HARD ERROR\n", core_idx);
299                 v3_stop_vm(vm);
300                 return -1;
301             }
302
303             continue;
304         }
305
306         PrintDebug("Starting virtual core %u on logical core %u\n", 
307                    vcore_id, core_idx);
308         
309         sprintf(core->exec_name, "%s-%u", vm->name, vcore_id);
310
311         PrintDebug("run: core=%u, func=0x%p, arg=0x%p, name=%s\n",
312                    core_idx, start_core, core, core->exec_name);
313
314         core->pcpu_id = core_idx;
315         core->core_thread = V3_CREATE_THREAD_ON_CPU(core_idx, start_core, core, core->exec_name);
316
317         if (core->core_thread == NULL) {
318             PrintError("Thread launch failed\n");
319             v3_stop_vm(vm);
320             return -1;
321         }
322
323         vcore_id--;
324     }
325
326
327     return 0;
328
329 }
330
331
332 int v3_reset_vm_core(struct guest_info * core, addr_t rip) {
333     
334     switch (v3_cpu_types[core->pcpu_id]) {
335 #ifdef V3_CONFIG_SVM
336         case V3_SVM_CPU:
337         case V3_SVM_REV3_CPU:
338             PrintDebug("Resetting SVM Guest CPU %d\n", core->vcpu_id);
339             return v3_reset_svm_vm_core(core, rip);
340 #endif
341 #ifdef V3_CONFIG_VMX
342         case V3_VMX_CPU:
343         case V3_VMX_EPT_CPU:
344         case V3_VMX_EPT_UG_CPU:
345             PrintDebug("Resetting VMX Guest CPU %d\n", core->vcpu_id);
346             return v3_reset_vmx_vm_core(core, rip);
347 #endif
348         case V3_INVALID_CPU:
349         default:
350             PrintError("CPU has no virtualization Extensions\n");
351             break;
352     }
353
354     return -1;
355 }
356
357
358
359 /* move a virtual core to different physical core */
360 int v3_move_vm_core(struct v3_vm_info * vm, int vcore_id, int target_cpu) {
361     struct guest_info * core = NULL;
362
363     if ((vcore_id < 0) || (vcore_id >= vm->num_cores)) {
364         PrintError("Attempted to migrate invalid virtual core (%d)\n", vcore_id);
365         return -1;
366     }
367
368     core = &(vm->cores[vcore_id]);
369
370     if (target_cpu == core->pcpu_id) {
371         PrintError("Attempted to migrate to local core (%d)\n", target_cpu);
372         // well that was pointless
373         return 0;
374     }
375
376     if (core->core_thread == NULL) {
377         PrintError("Attempted to migrate a core without a valid thread context\n");
378         return -1;
379     }
380
381     while (v3_raise_barrier(vm, NULL) == -1);
382
383     V3_Print("Performing Migration from %d to %d\n", core->pcpu_id, target_cpu);
384
385     // Double check that we weren't preemptively migrated
386     if (target_cpu != core->pcpu_id) {    
387
388         V3_Print("Moving Core\n");
389
390
391 #ifdef V3_CONFIG_VMX
392         switch (v3_cpu_types[core->pcpu_id]) {
393             case V3_VMX_CPU:
394             case V3_VMX_EPT_CPU:
395             case V3_VMX_EPT_UG_CPU:
396                 PrintDebug("Flushing VMX Guest CPU %d\n", core->vcpu_id);
397                 V3_Call_On_CPU(core->pcpu_id, (void (*)(void *))v3_flush_vmx_vm_core, (void *)core);
398                 break;
399             default:
400                 break;
401         }
402 #endif
403
404         if (V3_MOVE_THREAD_TO_CPU(target_cpu, core->core_thread) != 0) {
405             PrintError("Failed to move Vcore %d to CPU %d\n", 
406                        core->vcpu_id, target_cpu);
407             v3_lower_barrier(vm);
408             return -1;
409         } 
410         
411         /* There will be a benign race window here:
412            core->pcpu_id will be set to the target core before its fully "migrated"
413            However the core will NEVER run on the old core again, its just in flight to the new core
414         */
415         core->pcpu_id = target_cpu;
416
417         V3_Print("core now at %d\n", core->pcpu_id);
418         
419     }
420
421
422
423
424     v3_lower_barrier(vm);
425
426     return 0;
427 }
428
429
430
431 int v3_stop_vm(struct v3_vm_info * vm) {
432
433     vm->run_state = VM_STOPPED;
434
435     // force exit all cores via a cross call/IPI
436
437     while (1) {
438         int i = 0;
439         int still_running = 0;
440
441         for (i = 0; i < vm->num_cores; i++) {
442             if (vm->cores[i].core_run_state != CORE_STOPPED) {
443                 still_running = 1;
444             }
445         }
446
447         if (still_running == 0) {
448             break;
449         }
450
451         v3_yield(NULL);
452     }
453     
454     V3_Print("VM stopped. Returning\n");
455
456     return 0;
457 }
458
459
460 int v3_pause_vm(struct v3_vm_info * vm) {
461
462     if (vm->run_state != VM_RUNNING) {
463         PrintError("Tried to pause a VM that was not running\n");
464         return -1;
465     }
466
467     while (v3_raise_barrier(vm, NULL) == -1);
468
469     vm->run_state = VM_PAUSED;
470
471     return 0;
472 }
473
474
475 int v3_continue_vm(struct v3_vm_info * vm) {
476
477     if (vm->run_state != VM_PAUSED) {
478         PrintError("Tried to continue a VM that was not paused\n");
479         return -1;
480     }
481
482     v3_lower_barrier(vm);
483
484     vm->run_state = VM_RUNNING;
485
486     return 0;
487 }
488
489 #ifdef V3_CONFIG_CHECKPOINT
490 #include <palacios/vmm_checkpoint.h>
491
492 int v3_save_vm(struct v3_vm_info * vm, char * store, char * url) {
493     return v3_chkpt_save_vm(vm, store, url);
494 }
495
496
497 int v3_load_vm(struct v3_vm_info * vm, char * store, char * url) {
498     return v3_chkpt_load_vm(vm, store, url);
499 }
500 #endif
501
502
503 int v3_free_vm(struct v3_vm_info * vm) {
504     int i = 0;
505     // deinitialize guest (free memory, etc...)
506
507     v3_free_vm_devices(vm);
508
509     // free cores
510     for (i = 0; i < vm->num_cores; i++) {
511         v3_free_core(&(vm->cores[i]));
512     }
513
514     // free vm
515     v3_free_vm_internal(vm);
516
517     v3_free_config(vm);
518
519     V3_Free(vm);
520
521     return 0;
522 }
523
524
525 #ifdef __V3_32BIT__
526
527 v3_cpu_mode_t v3_get_host_cpu_mode() {
528     uint32_t cr4_val;
529     struct cr4_32 * cr4;
530
531     __asm__ (
532              "movl %%cr4, %0; "
533              : "=r"(cr4_val) 
534              );
535
536     
537     cr4 = (struct cr4_32 *)&(cr4_val);
538
539     if (cr4->pae == 1) {
540         return PROTECTED_PAE;
541     } else {
542         return PROTECTED;
543     }
544 }
545
546 #elif __V3_64BIT__
547
548 v3_cpu_mode_t v3_get_host_cpu_mode() {
549     return LONG;
550 }
551
552 #endif 
553
554
555 #define V3_Yield(addr)                                  \
556     do {                                                \
557         extern struct v3_os_hooks * os_hooks;           \
558         if ((os_hooks) && (os_hooks)->yield_cpu) {      \
559             (os_hooks)->yield_cpu();                    \
560         }                                               \
561     } while (0)                                         \
562
563
564
565 void v3_yield_cond(struct guest_info * info) {
566     uint64_t cur_cycle;
567     cur_cycle = v3_get_host_time(&info->time_state);
568
569     if (cur_cycle > (info->yield_start_cycle + info->vm_info->yield_cycle_period)) {
570
571         /*
572           PrintDebug("Conditional Yield (cur_cyle=%p, start_cycle=%p, period=%p)\n", 
573           (void *)cur_cycle, (void *)info->yield_start_cycle, (void *)info->yield_cycle_period);
574         */
575         V3_Yield();
576         info->yield_start_cycle = v3_get_host_time(&info->time_state);
577     }
578 }
579
580
581 /* 
582  * unconditional cpu yield 
583  * if the yielding thread is a guest context, the guest quantum is reset on resumption 
584  * Non guest context threads should call this function with a NULL argument
585  */
586 void v3_yield(struct guest_info * info) {
587     V3_Yield();
588
589     if (info) {
590         info->yield_start_cycle = v3_get_host_time(&info->time_state);
591     }
592 }
593
594
595
596
597 void v3_print_cond(const char * fmt, ...) {
598     if (v3_dbg_enable == 1) {
599         char buf[2048];
600         va_list ap;
601
602         va_start(ap, fmt);
603         vsnprintf(buf, 2048, fmt, ap);
604         va_end(ap);
605
606         V3_Print("%s", buf);
607     }    
608 }
609
610
611
612 void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector) {
613     extern struct v3_os_hooks * os_hooks;
614
615     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
616         (os_hooks)->interrupt_cpu(vm, logical_cpu, vector);
617     }
618 }
619
620
621
622 int v3_vm_enter(struct guest_info * info) {
623     switch (v3_cpu_types[0]) {
624 #ifdef V3_CONFIG_SVM
625         case V3_SVM_CPU:
626         case V3_SVM_REV3_CPU:
627             return v3_svm_enter(info);
628             break;
629 #endif
630 #if V3_CONFIG_VMX
631         case V3_VMX_CPU:
632         case V3_VMX_EPT_CPU:
633         case V3_VMX_EPT_UG_CPU:
634             return v3_vmx_enter(info);
635             break;
636 #endif
637         default:
638             PrintError("Attemping to enter a guest on an invalid CPU\n");
639             return -1;
640     }
641 }