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.


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