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.


ca12fc79db9e712e3fdac68e9271c3d2aff45bb2
[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         if (V3_MOVE_THREAD_TO_CPU(target_cpu, core->core_thread) != 0) {
391             PrintError("Failed to move Vcore %d to CPU %d\n", 
392                        core->vcpu_id, target_cpu);
393             v3_lower_barrier(vm);
394             return -1;
395         } 
396         
397         /* There will be a benign race window here:
398            core->pcpu_id will be set to the target core before its fully "migrated"
399            However the core will NEVER run on the old core again, its just in flight to the new core
400         */
401         core->pcpu_id = target_cpu;
402
403         V3_Print("core now at %d\n", core->pcpu_id);
404         
405     }
406
407
408
409
410     v3_lower_barrier(vm);
411
412     return 0;
413 }
414
415
416
417 int v3_stop_vm(struct v3_vm_info * vm) {
418
419     vm->run_state = VM_STOPPED;
420
421     // force exit all cores via a cross call/IPI
422
423     while (1) {
424         int i = 0;
425         int still_running = 0;
426
427         for (i = 0; i < vm->num_cores; i++) {
428             if (vm->cores[i].core_run_state != CORE_STOPPED) {
429                 still_running = 1;
430             }
431         }
432
433         if (still_running == 0) {
434             break;
435         }
436
437         v3_yield(NULL);
438     }
439     
440     V3_Print("VM stopped. Returning\n");
441
442     return 0;
443 }
444
445
446 int v3_pause_vm(struct v3_vm_info * vm) {
447
448     if (vm->run_state != VM_RUNNING) {
449         PrintError("Tried to pause a VM that was not running\n");
450         return -1;
451     }
452
453     while (v3_raise_barrier(vm, NULL) == -1);
454
455     vm->run_state = VM_PAUSED;
456
457     return 0;
458 }
459
460
461 int v3_continue_vm(struct v3_vm_info * vm) {
462
463     if (vm->run_state != VM_PAUSED) {
464         PrintError("Tried to continue a VM that was not paused\n");
465         return -1;
466     }
467
468     v3_lower_barrier(vm);
469
470     vm->run_state = VM_RUNNING;
471
472     return 0;
473 }
474
475 #ifdef V3_CONFIG_CHECKPOINT
476 #include <palacios/vmm_checkpoint.h>
477
478 int v3_save_vm(struct v3_vm_info * vm, char * store, char * url) {
479     return v3_chkpt_save_vm(vm, store, url);
480 }
481
482
483 int v3_load_vm(struct v3_vm_info * vm, char * store, char * url) {
484     return v3_chkpt_load_vm(vm, store, url);
485 }
486 #endif
487
488
489 int v3_free_vm(struct v3_vm_info * vm) {
490     int i = 0;
491     // deinitialize guest (free memory, etc...)
492
493     v3_free_vm_devices(vm);
494
495     // free cores
496     for (i = 0; i < vm->num_cores; i++) {
497         v3_free_core(&(vm->cores[i]));
498     }
499
500     // free vm
501     v3_free_vm_internal(vm);
502
503     v3_free_config(vm);
504
505     V3_Free(vm);
506
507     return 0;
508 }
509
510
511 #ifdef __V3_32BIT__
512
513 v3_cpu_mode_t v3_get_host_cpu_mode() {
514     uint32_t cr4_val;
515     struct cr4_32 * cr4;
516
517     __asm__ (
518              "movl %%cr4, %0; "
519              : "=r"(cr4_val) 
520              );
521
522     
523     cr4 = (struct cr4_32 *)&(cr4_val);
524
525     if (cr4->pae == 1) {
526         return PROTECTED_PAE;
527     } else {
528         return PROTECTED;
529     }
530 }
531
532 #elif __V3_64BIT__
533
534 v3_cpu_mode_t v3_get_host_cpu_mode() {
535     return LONG;
536 }
537
538 #endif 
539
540
541 #define V3_Yield(addr)                                  \
542     do {                                                \
543         extern struct v3_os_hooks * os_hooks;           \
544         if ((os_hooks) && (os_hooks)->yield_cpu) {      \
545             (os_hooks)->yield_cpu();                    \
546         }                                               \
547     } while (0)                                         \
548
549
550
551 void v3_yield_cond(struct guest_info * info) {
552     uint64_t cur_cycle;
553     cur_cycle = v3_get_host_time(&info->time_state);
554
555     if (cur_cycle > (info->yield_start_cycle + info->vm_info->yield_cycle_period)) {
556
557         /*
558           PrintDebug("Conditional Yield (cur_cyle=%p, start_cycle=%p, period=%p)\n", 
559           (void *)cur_cycle, (void *)info->yield_start_cycle, (void *)info->yield_cycle_period);
560         */
561         V3_Yield();
562         info->yield_start_cycle = v3_get_host_time(&info->time_state);
563     }
564 }
565
566
567 /* 
568  * unconditional cpu yield 
569  * if the yielding thread is a guest context, the guest quantum is reset on resumption 
570  * Non guest context threads should call this function with a NULL argument
571  */
572 void v3_yield(struct guest_info * info) {
573     V3_Yield();
574
575     if (info) {
576         info->yield_start_cycle = v3_get_host_time(&info->time_state);
577     }
578 }
579
580
581
582
583 void v3_print_cond(const char * fmt, ...) {
584     if (v3_dbg_enable == 1) {
585         char buf[2048];
586         va_list ap;
587
588         va_start(ap, fmt);
589         vsnprintf(buf, 2048, fmt, ap);
590         va_end(ap);
591
592         V3_Print("%s", buf);
593     }    
594 }
595
596
597
598 void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector) {
599     extern struct v3_os_hooks * os_hooks;
600
601     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
602         (os_hooks)->interrupt_cpu(vm, logical_cpu, vector);
603     }
604 }
605
606
607
608 int v3_vm_enter(struct guest_info * info) {
609     switch (v3_cpu_types[0]) {
610 #ifdef V3_CONFIG_SVM
611         case V3_SVM_CPU:
612         case V3_SVM_REV3_CPU:
613             return v3_svm_enter(info);
614             break;
615 #endif
616 #if V3_CONFIG_VMX
617         case V3_VMX_CPU:
618         case V3_VMX_EPT_CPU:
619         case V3_VMX_EPT_UG_CPU:
620             return v3_vmx_enter(info);
621             break;
622 #endif
623         default:
624             PrintError("Attemping to enter a guest on an invalid CPU\n");
625             return -1;
626     }
627 }