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.


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