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.


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