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.


More work on time fixing/debugging
[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     /// CHECK IF WE ARE MULTICORE ENABLED....
259
260     V3_Print("V3 --  Starting VM (%u cores)\n", vm->num_cores);
261     V3_Print("CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
262
263
264     // Check that enough cores are present in the mask to handle vcores
265     for (i = 0; i < MAX_CORES; i++) {
266         int major = i / 8;
267         int minor = i % 8;
268         
269         if (core_mask[major] & (0x1 << minor)) {
270             if (v3_cpu_types[i] == V3_INVALID_CPU) {
271                 core_mask[major] &= ~(0x1 << minor);
272             } else {
273                 avail_cores++;
274             }
275         }
276     }
277
278
279     if (vm->num_cores > avail_cores) {
280         PrintError("Attempted to start a VM with too many cores (vm->num_cores = %d, avail_cores = %d, MAX=%d)\n", 
281                    vm->num_cores, avail_cores, MAX_CORES);
282         return -1;
283     }
284
285     vm->run_state = VM_RUNNING;
286
287     // Spawn off threads for each core. 
288     // We work backwards, so that core 0 is always started last.
289     for (i = 0, vcore_id = vm->num_cores - 1; (i < MAX_CORES) && (vcore_id >= 0); i++) {
290         int major = 0;
291         int minor = 0;
292         struct guest_info * core = &(vm->cores[vcore_id]);
293         char * specified_cpu = v3_cfg_val(core->core_cfg_data, "target_cpu");
294         uint32_t core_idx = 0;
295
296         if (specified_cpu != NULL) {
297             core_idx = atoi(specified_cpu);
298             
299             if ((core_idx < 0) || (core_idx >= MAX_CORES)) {
300                 PrintError("Target CPU out of bounds (%d) (MAX_CORES=%d)\n", core_idx, MAX_CORES);
301             }
302
303             i--; // We reset the logical core idx. Not strictly necessary I guess... 
304         } else {
305             core_idx = i;
306         }
307
308         major = core_idx / 8;
309         minor = core_idx % 8;
310
311         if ((core_mask[major] & (0x1 << minor)) == 0) {
312             PrintError("Logical CPU %d not available for virtual core %d; not started\n",
313                        core_idx, vcore_id);
314
315             if (specified_cpu != NULL) {
316                 PrintError("CPU was specified explicitly (%d). HARD ERROR\n", core_idx);
317                 v3_stop_vm(vm);
318                 return -1;
319             }
320
321             continue;
322         }
323
324         PrintDebug("Starting virtual core %u on logical core %u\n", 
325                    vcore_id, core_idx);
326         
327         sprintf(core->exec_name, "%s-%u", vm->name, vcore_id);
328
329         PrintDebug("run: core=%u, func=0x%p, arg=0x%p, name=%s\n",
330                    core_idx, start_core, core, core->exec_name);
331
332         core->core_run_state = CORE_STOPPED;  // core zero will turn itself on
333         core->pcpu_id = core_idx;
334         core->core_thread = V3_CREATE_THREAD_ON_CPU(core_idx, start_core, core, core->exec_name);
335
336         if (core->core_thread == NULL) {
337             PrintError("Thread launch failed\n");
338             v3_stop_vm(vm);
339             return -1;
340         }
341
342         vcore_id--;
343     }
344
345     if (vcore_id >= 0) {
346         PrintError("Error starting VM: Not enough available CPU cores\n");
347         v3_stop_vm(vm);
348         return -1;
349     }
350
351
352     return 0;
353
354 }
355
356
357 int v3_reset_vm_core(struct guest_info * core, addr_t rip) {
358     
359     switch (v3_cpu_types[core->pcpu_id]) {
360 #ifdef V3_CONFIG_SVM
361         case V3_SVM_CPU:
362         case V3_SVM_REV3_CPU:
363             PrintDebug("Resetting SVM Guest CPU %d\n", core->vcpu_id);
364             return v3_reset_svm_vm_core(core, rip);
365 #endif
366 #ifdef V3_CONFIG_VMX
367         case V3_VMX_CPU:
368         case V3_VMX_EPT_CPU:
369         case V3_VMX_EPT_UG_CPU:
370             PrintDebug("Resetting VMX Guest CPU %d\n", core->vcpu_id);
371             return v3_reset_vmx_vm_core(core, rip);
372 #endif
373         case V3_INVALID_CPU:
374         default:
375             PrintError("CPU has no virtualization Extensions\n");
376             break;
377     }
378
379     return -1;
380 }
381
382
383
384 /* move a virtual core to different physical core */
385 int v3_move_vm_core(struct v3_vm_info * vm, int vcore_id, int target_cpu) {
386     struct guest_info * core = NULL;
387
388     if ((vcore_id < 0) || (vcore_id >= vm->num_cores)) {
389         PrintError("Attempted to migrate invalid virtual core (%d)\n", vcore_id);
390         return -1;
391     }
392
393     core = &(vm->cores[vcore_id]);
394
395     if (target_cpu == core->pcpu_id) {
396         PrintError("Attempted to migrate to local core (%d)\n", target_cpu);
397         // well that was pointless
398         return 0;
399     }
400
401     if (core->core_thread == NULL) {
402         PrintError("Attempted to migrate a core without a valid thread context\n");
403         return -1;
404     }
405
406     while (v3_raise_barrier(vm, NULL) == -1);
407
408     V3_Print("Performing Migration from %d to %d\n", core->pcpu_id, target_cpu);
409
410     // Double check that we weren't preemptively migrated
411     if (target_cpu != core->pcpu_id) {    
412
413         V3_Print("Moving Core\n");
414
415
416 #ifdef V3_CONFIG_VMX
417         switch (v3_cpu_types[core->pcpu_id]) {
418             case V3_VMX_CPU:
419             case V3_VMX_EPT_CPU:
420             case V3_VMX_EPT_UG_CPU:
421                 PrintDebug("Flushing VMX Guest CPU %d\n", core->vcpu_id);
422                 V3_Call_On_CPU(core->pcpu_id, (void (*)(void *))v3_flush_vmx_vm_core, (void *)core);
423                 break;
424             default:
425                 break;
426         }
427 #endif
428
429         if (V3_MOVE_THREAD_TO_CPU(target_cpu, core->core_thread) != 0) {
430             PrintError("Failed to move Vcore %d to CPU %d\n", 
431                        core->vcpu_id, target_cpu);
432             v3_lower_barrier(vm);
433             return -1;
434         } 
435         
436         /* There will be a benign race window here:
437            core->pcpu_id will be set to the target core before its fully "migrated"
438            However the core will NEVER run on the old core again, its just in flight to the new core
439         */
440         core->pcpu_id = target_cpu;
441
442         V3_Print("core now at %d\n", core->pcpu_id);    
443     }
444
445     v3_lower_barrier(vm);
446
447     return 0;
448 }
449
450
451
452 int v3_stop_vm(struct v3_vm_info * vm) {
453
454     vm->run_state = VM_STOPPED;
455
456     // Sanity check to catch any weird execution states
457     if (v3_wait_for_barrier(vm, NULL) == 0) {
458         v3_lower_barrier(vm);
459     }
460     
461     // XXX force exit all cores via a cross call/IPI XXX
462
463     while (1) {
464         int i = 0;
465         int still_running = 0;
466
467         for (i = 0; i < vm->num_cores; i++) {
468             if (vm->cores[i].core_run_state != CORE_STOPPED) {
469                 still_running = 1;
470             }
471         }
472
473         if (still_running == 0) {
474             break;
475         }
476
477         v3_yield(NULL);
478     }
479     
480     V3_Print("VM stopped. Returning\n");
481
482     return 0;
483 }
484
485
486 int v3_pause_vm(struct v3_vm_info * vm) {
487
488     if (vm->run_state != VM_RUNNING) {
489         PrintError("Tried to pause a VM that was not running\n");
490         return -1;
491     }
492
493     while (v3_raise_barrier(vm, NULL) == -1);
494
495     vm->run_state = VM_PAUSED;
496
497     return 0;
498 }
499
500
501 int v3_continue_vm(struct v3_vm_info * vm) {
502
503     if (vm->run_state != VM_PAUSED) {
504         PrintError("Tried to continue a VM that was not paused\n");
505         return -1;
506     }
507
508     vm->run_state = VM_RUNNING;
509
510     v3_lower_barrier(vm);
511
512     return 0;
513 }
514
515
516
517 static int sim_callback(struct guest_info * core, void * private_data) {
518     struct v3_bitmap * timeout_map = private_data;
519
520     v3_bitmap_set(timeout_map, core->vcpu_id);
521     
522     V3_Print("Simulation callback activated (guest_rip=%p)\n", (void *)core->rip);
523
524     while (v3_bitmap_check(timeout_map, core->vcpu_id) == 1) {
525         v3_yield(NULL);
526     }
527
528     return 0;
529 }
530
531
532
533
534 int v3_simulate_vm(struct v3_vm_info * vm, unsigned int msecs) {
535     struct v3_bitmap timeout_map;
536     int i = 0;
537     int all_blocked = 0;
538     uint64_t cycles = 0;
539     uint64_t cpu_khz = V3_CPU_KHZ();
540
541     if (vm->run_state != VM_PAUSED) {
542         PrintError("VM must be paused before simulation begins\n");
543         return -1;
544     }
545
546     /* AT this point VM is paused */
547     
548     // initialize bitmap
549     v3_bitmap_init(&timeout_map, vm->num_cores);
550
551
552
553
554     // calculate cycles from msecs...
555     // IMPORTANT: Floating point not allowed.
556     cycles = (msecs * cpu_khz);
557     
558
559
560     V3_Print("Simulating %u msecs (%llu cycles) [CPU_KHZ=%llu]\n", msecs, cycles, cpu_khz);
561
562     // set timeout
563     
564     for (i = 0; i < vm->num_cores; i++) {
565         if (v3_add_core_timeout(&(vm->cores[i]), cycles, sim_callback, &timeout_map) == -1) {
566             PrintError("Could not register simulation timeout for core %d\n", i);
567             return -1;
568         }
569     }
570
571     V3_Print("timeouts set on all cores\n ");
572
573     
574     // Run the simulation
575 //    vm->run_state = VM_SIMULATING;
576     vm->run_state = VM_RUNNING;
577     v3_lower_barrier(vm);
578
579
580     V3_Print("Barrier lowered: We are now Simulating!!\n");
581
582     // block until simulation is complete    
583     while (all_blocked == 0) {
584         all_blocked = 1;
585
586         for (i = 0; i < vm->num_cores; i++) {
587             if (v3_bitmap_check(&timeout_map, i)  == 0) {
588                 all_blocked = 0;
589             }
590         }
591
592         if (all_blocked == 1) {
593             break;
594         }
595
596         v3_yield(NULL);
597     }
598
599
600     V3_Print("Simulation is complete\n");
601
602     // Simulation is complete
603     // Reset back to PAUSED state
604
605     v3_raise_barrier_nowait(vm, NULL);
606     vm->run_state = VM_PAUSED;
607     
608     v3_bitmap_reset(&timeout_map);
609
610     v3_wait_for_barrier(vm, NULL);
611
612     return 0;
613
614 }
615
616 #ifdef V3_CONFIG_CHECKPOINT
617 #include <palacios/vmm_checkpoint.h>
618
619 int v3_save_vm(struct v3_vm_info * vm, char * store, char * url) {
620     return v3_chkpt_save_vm(vm, store, url);
621 }
622
623
624 int v3_load_vm(struct v3_vm_info * vm, char * store, char * url) {
625     return v3_chkpt_load_vm(vm, store, url);
626 }
627 #endif
628
629
630 int v3_free_vm(struct v3_vm_info * vm) {
631     int i = 0;
632     // deinitialize guest (free memory, etc...)
633
634     v3_free_vm_devices(vm);
635
636     // free cores
637     for (i = 0; i < vm->num_cores; i++) {
638         v3_free_core(&(vm->cores[i]));
639     }
640
641     // free vm
642     v3_free_vm_internal(vm);
643
644     v3_free_config(vm);
645
646     V3_Free(vm);
647
648     return 0;
649 }
650
651
652 #ifdef __V3_32BIT__
653
654 v3_cpu_mode_t v3_get_host_cpu_mode() {
655     uint32_t cr4_val;
656     struct cr4_32 * cr4;
657
658     __asm__ (
659              "movl %%cr4, %0; "
660              : "=r"(cr4_val) 
661              );
662
663     
664     cr4 = (struct cr4_32 *)&(cr4_val);
665
666     if (cr4->pae == 1) {
667         return PROTECTED_PAE;
668     } else {
669         return PROTECTED;
670     }
671 }
672
673 #elif __V3_64BIT__
674
675 v3_cpu_mode_t v3_get_host_cpu_mode() {
676     return LONG;
677 }
678
679 #endif 
680
681
682 #define V3_Yield(addr)                                  \
683     do {                                                \
684         extern struct v3_os_hooks * os_hooks;           \
685         if ((os_hooks) && (os_hooks)->yield_cpu) {      \
686             (os_hooks)->yield_cpu();                    \
687         }                                               \
688     } while (0)                                         \
689
690
691
692 void v3_yield_cond(struct guest_info * info) {
693     uint64_t cur_cycle;
694     cur_cycle = v3_get_host_time(&info->time_state);
695
696     if (cur_cycle > (info->yield_start_cycle + info->vm_info->yield_cycle_period)) {
697         //PrintDebug("Conditional Yield (cur_cyle=%p, start_cycle=%p, period=%p)\n", 
698         //           (void *)cur_cycle, (void *)info->yield_start_cycle, 
699         //         (void *)info->yield_cycle_period);
700         
701         V3_Yield();
702         info->yield_start_cycle +=  info->vm_info->yield_cycle_period;
703     }
704 }
705
706
707 /* 
708  * unconditional cpu yield 
709  * if the yielding thread is a guest context, the guest quantum is reset on resumption 
710  * Non guest context threads should call this function with a NULL argument
711  */
712 void v3_yield(struct guest_info * info) {
713     V3_Yield();
714
715     if (info) {
716         info->yield_start_cycle +=  info->vm_info->yield_cycle_period;
717     }
718 }
719
720
721
722
723 void v3_print_cond(const char * fmt, ...) {
724     if (v3_dbg_enable == 1) {
725         char buf[2048];
726         va_list ap;
727
728         va_start(ap, fmt);
729         vsnprintf(buf, 2048, fmt, ap);
730         va_end(ap);
731
732         V3_Print("%s", buf);
733     }    
734 }
735
736
737
738 void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector) {
739     extern struct v3_os_hooks * os_hooks;
740
741     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
742         (os_hooks)->interrupt_cpu(vm, logical_cpu, vector);
743     }
744 }
745
746
747
748 int v3_vm_enter(struct guest_info * info) {
749     switch (v3_mach_type) {
750 #ifdef V3_CONFIG_SVM
751         case V3_SVM_CPU:
752         case V3_SVM_REV3_CPU:
753             return v3_svm_enter(info);
754             break;
755 #endif
756 #if V3_CONFIG_VMX
757         case V3_VMX_CPU:
758         case V3_VMX_EPT_CPU:
759         case V3_VMX_EPT_UG_CPU:
760             return v3_vmx_enter(info);
761             break;
762 #endif
763         default:
764             PrintError("Attemping to enter a guest on an invalid CPU\n");
765             return -1;
766     }
767 }