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.


information request api for the host - gives a more detailed view of VM and vcore...
[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_STOPPED) {
260         PrintError("VM has already been launched (state=%d)\n", (int)vm->run_state);
261         return -1;
262     }
263
264     
265     // Do not run if any core is using shadow paging and we are out of 4 GB bounds
266     for (i=0;i<vm->num_cores;i++) { 
267         if (vm->cores[i].shdw_pg_mode == SHADOW_PAGING) {
268             if ((vm->mem_map.base_region.host_addr + vm->mem_size ) >= 0x100000000ULL) {
269                 PrintError("Base memory region exceeds 4 GB boundary with shadow paging enabled on core %d.\n",i);
270                 PrintError("Any use of non-64 bit mode in the guest is likely to fail in this configuration.\n");
271                 PrintError("If you would like to proceed anyway, remove this check and recompile Palacios.\n");
272                 PrintError("Alternatively, change this VM to use nested paging.\n");
273                 return -1;
274             }
275         }
276     }
277
278
279
280     /// CHECK IF WE ARE MULTICORE ENABLED....
281
282     V3_Print("V3 --  Starting VM (%u cores)\n", vm->num_cores);
283     V3_Print("CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
284
285
286     // Check that enough cores are present in the mask to handle vcores
287     for (i = 0; i < MAX_CORES; i++) {
288         int major = i / 8;
289         int minor = i % 8;
290         
291         if (core_mask[major] & (0x1 << minor)) {
292             if (v3_cpu_types[i] == V3_INVALID_CPU) {
293                 core_mask[major] &= ~(0x1 << minor);
294             } else {
295                 avail_cores++;
296             }
297         }
298     }
299
300
301     if (vm->num_cores > avail_cores) {
302         PrintError("Attempted to start a VM with too many cores (vm->num_cores = %d, avail_cores = %d, MAX=%d)\n", 
303                    vm->num_cores, avail_cores, MAX_CORES);
304         return -1;
305     }
306
307     vm->run_state = VM_RUNNING;
308
309     // Spawn off threads for each core. 
310     // We work backwards, so that core 0 is always started last.
311     for (i = 0, vcore_id = vm->num_cores - 1; (i < MAX_CORES) && (vcore_id >= 0); i++) {
312         int major = 0;
313         int minor = 0;
314         struct guest_info * core = &(vm->cores[vcore_id]);
315         char * specified_cpu = v3_cfg_val(core->core_cfg_data, "target_cpu");
316         uint32_t core_idx = 0;
317
318         if (specified_cpu != NULL) {
319             core_idx = atoi(specified_cpu);
320             
321             if ((core_idx < 0) || (core_idx >= MAX_CORES)) {
322                 PrintError("Target CPU out of bounds (%d) (MAX_CORES=%d)\n", core_idx, MAX_CORES);
323             }
324
325             i--; // We reset the logical core idx. Not strictly necessary I guess... 
326         } else {
327             core_idx = i;
328         }
329
330         major = core_idx / 8;
331         minor = core_idx % 8;
332
333         if ((core_mask[major] & (0x1 << minor)) == 0) {
334             PrintError("Logical CPU %d not available for virtual core %d; not started\n",
335                        core_idx, vcore_id);
336
337             if (specified_cpu != NULL) {
338                 PrintError("CPU was specified explicitly (%d). HARD ERROR\n", core_idx);
339                 v3_stop_vm(vm);
340                 return -1;
341             }
342
343             continue;
344         }
345
346         PrintDebug("Starting virtual core %u on logical core %u\n", 
347                    vcore_id, core_idx);
348         
349         sprintf(core->exec_name, "%s-%u", vm->name, vcore_id);
350
351         PrintDebug("run: core=%u, func=0x%p, arg=0x%p, name=%s\n",
352                    core_idx, start_core, core, core->exec_name);
353
354         core->core_run_state = CORE_STOPPED;  // core zero will turn itself on
355         core->pcpu_id = core_idx;
356         core->core_thread = V3_CREATE_THREAD_ON_CPU(core_idx, start_core, core, core->exec_name);
357
358         if (core->core_thread == NULL) {
359             PrintError("Thread launch failed\n");
360             v3_stop_vm(vm);
361             return -1;
362         }
363
364         vcore_id--;
365     }
366
367     if (vcore_id >= 0) {
368         PrintError("Error starting VM: Not enough available CPU cores\n");
369         v3_stop_vm(vm);
370         return -1;
371     }
372
373
374     return 0;
375
376 }
377
378
379 int v3_reset_vm_core(struct guest_info * core, addr_t rip) {
380     
381     switch (v3_cpu_types[core->pcpu_id]) {
382 #ifdef V3_CONFIG_SVM
383         case V3_SVM_CPU:
384         case V3_SVM_REV3_CPU:
385             PrintDebug("Resetting SVM Guest CPU %d\n", core->vcpu_id);
386             return v3_reset_svm_vm_core(core, rip);
387 #endif
388 #ifdef V3_CONFIG_VMX
389         case V3_VMX_CPU:
390         case V3_VMX_EPT_CPU:
391         case V3_VMX_EPT_UG_CPU:
392             PrintDebug("Resetting VMX Guest CPU %d\n", core->vcpu_id);
393             return v3_reset_vmx_vm_core(core, rip);
394 #endif
395         case V3_INVALID_CPU:
396         default:
397             PrintError("CPU has no virtualization Extensions\n");
398             break;
399     }
400
401     return -1;
402 }
403
404
405
406 /* move a virtual core to different physical core */
407 int v3_move_vm_core(struct v3_vm_info * vm, int vcore_id, int target_cpu) {
408     struct guest_info * core = NULL;
409
410     if ((vcore_id < 0) || (vcore_id >= vm->num_cores)) {
411         PrintError("Attempted to migrate invalid virtual core (%d)\n", vcore_id);
412         return -1;
413     }
414
415     core = &(vm->cores[vcore_id]);
416
417     if (target_cpu == core->pcpu_id) {
418         PrintError("Attempted to migrate to local core (%d)\n", target_cpu);
419         // well that was pointless
420         return 0;
421     }
422
423     if (core->core_thread == NULL) {
424         PrintError("Attempted to migrate a core without a valid thread context\n");
425         return -1;
426     }
427
428     while (v3_raise_barrier(vm, NULL) == -1);
429
430     V3_Print("Performing Migration from %d to %d\n", core->pcpu_id, target_cpu);
431
432     // Double check that we weren't preemptively migrated
433     if (target_cpu != core->pcpu_id) {    
434
435         V3_Print("Moving Core\n");
436
437
438 #ifdef V3_CONFIG_VMX
439         switch (v3_cpu_types[core->pcpu_id]) {
440             case V3_VMX_CPU:
441             case V3_VMX_EPT_CPU:
442             case V3_VMX_EPT_UG_CPU:
443                 PrintDebug("Flushing VMX Guest CPU %d\n", core->vcpu_id);
444                 V3_Call_On_CPU(core->pcpu_id, (void (*)(void *))v3_flush_vmx_vm_core, (void *)core);
445                 break;
446             default:
447                 break;
448         }
449 #endif
450
451         if (V3_MOVE_THREAD_TO_CPU(target_cpu, core->core_thread) != 0) {
452             PrintError("Failed to move Vcore %d to CPU %d\n", 
453                        core->vcpu_id, target_cpu);
454             v3_lower_barrier(vm);
455             return -1;
456         } 
457         
458         /* There will be a benign race window here:
459            core->pcpu_id will be set to the target core before its fully "migrated"
460            However the core will NEVER run on the old core again, its just in flight to the new core
461         */
462         core->pcpu_id = target_cpu;
463
464         V3_Print("core now at %d\n", core->pcpu_id);    
465     }
466
467     v3_lower_barrier(vm);
468
469     return 0;
470 }
471
472
473
474 int v3_stop_vm(struct v3_vm_info * vm) {
475
476     if ((vm->run_state != VM_RUNNING) && 
477         (vm->run_state != VM_SIMULATING)) {
478         PrintError("Tried to stop VM in invalid runstate (%d)\n", vm->run_state);
479         return -1;
480     }
481
482     vm->run_state = VM_STOPPED;
483
484     // Sanity check to catch any weird execution states
485     if (v3_wait_for_barrier(vm, NULL) == 0) {
486         v3_lower_barrier(vm);
487     }
488     
489     // XXX force exit all cores via a cross call/IPI XXX
490
491     while (1) {
492         int i = 0;
493         int still_running = 0;
494
495         for (i = 0; i < vm->num_cores; i++) {
496             if (vm->cores[i].core_run_state != CORE_STOPPED) {
497                 still_running = 1;
498             }
499         }
500
501         if (still_running == 0) {
502             break;
503         }
504
505         v3_yield(NULL,-1);
506     }
507     
508     V3_Print("VM stopped. Returning\n");
509
510     return 0;
511 }
512
513
514 int v3_pause_vm(struct v3_vm_info * vm) {
515
516     if (vm->run_state != VM_RUNNING) {
517         PrintError("Tried to pause a VM that was not running\n");
518         return -1;
519     }
520
521     while (v3_raise_barrier(vm, NULL) == -1);
522
523     vm->run_state = VM_PAUSED;
524
525     return 0;
526 }
527
528
529 int v3_continue_vm(struct v3_vm_info * vm) {
530
531     if (vm->run_state != VM_PAUSED) {
532         PrintError("Tried to continue a VM that was not paused\n");
533         return -1;
534     }
535
536     vm->run_state = VM_RUNNING;
537
538     v3_lower_barrier(vm);
539
540     return 0;
541 }
542
543
544
545 static int sim_callback(struct guest_info * core, void * private_data) {
546     struct v3_bitmap * timeout_map = private_data;
547
548     v3_bitmap_set(timeout_map, core->vcpu_id);
549     
550     V3_Print("Simulation callback activated (guest_rip=%p)\n", (void *)core->rip);
551
552     while (v3_bitmap_check(timeout_map, core->vcpu_id) == 1) {
553         v3_yield(NULL,-1);
554     }
555
556     return 0;
557 }
558
559
560
561
562 int v3_simulate_vm(struct v3_vm_info * vm, unsigned int msecs) {
563     struct v3_bitmap timeout_map;
564     int i = 0;
565     int all_blocked = 0;
566     uint64_t cycles = 0;
567     uint64_t cpu_khz = V3_CPU_KHZ();
568
569     if (vm->run_state != VM_PAUSED) {
570         PrintError("VM must be paused before simulation begins\n");
571         return -1;
572     }
573
574     /* AT this point VM is paused */
575     
576     // initialize bitmap
577     v3_bitmap_init(&timeout_map, vm->num_cores);
578
579
580
581
582     // calculate cycles from msecs...
583     // IMPORTANT: Floating point not allowed.
584     cycles = (msecs * cpu_khz);
585     
586
587
588     V3_Print("Simulating %u msecs (%llu cycles) [CPU_KHZ=%llu]\n", msecs, cycles, cpu_khz);
589
590     // set timeout
591     
592     for (i = 0; i < vm->num_cores; i++) {
593         if (v3_add_core_timeout(&(vm->cores[i]), cycles, sim_callback, &timeout_map) == -1) {
594             PrintError("Could not register simulation timeout for core %d\n", i);
595             return -1;
596         }
597     }
598
599     V3_Print("timeouts set on all cores\n ");
600
601     
602     // Run the simulation
603 //    vm->run_state = VM_SIMULATING;
604     vm->run_state = VM_RUNNING;
605     v3_lower_barrier(vm);
606
607
608     V3_Print("Barrier lowered: We are now Simulating!!\n");
609
610     // block until simulation is complete    
611     while (all_blocked == 0) {
612         all_blocked = 1;
613
614         for (i = 0; i < vm->num_cores; i++) {
615             if (v3_bitmap_check(&timeout_map, i)  == 0) {
616                 all_blocked = 0;
617             }
618         }
619
620         if (all_blocked == 1) {
621             break;
622         }
623
624         v3_yield(NULL,-1);
625     }
626
627
628     V3_Print("Simulation is complete\n");
629
630     // Simulation is complete
631     // Reset back to PAUSED state
632
633     v3_raise_barrier_nowait(vm, NULL);
634     vm->run_state = VM_PAUSED;
635     
636     v3_bitmap_reset(&timeout_map);
637
638     v3_wait_for_barrier(vm, NULL);
639
640     return 0;
641
642 }
643
644 int v3_get_state_vm(struct v3_vm_info *vm, struct v3_vm_state *s)
645 {
646   uint32_t i;
647   uint32_t numcores = s->num_vcores > vm->num_cores ? vm->num_cores : s->num_vcores;
648
649   switch (vm->run_state) { 
650   case VM_INVALID: s->state = V3_VM_INVALID; break;
651   case VM_RUNNING: s->state = V3_VM_RUNNING; break;
652   case VM_STOPPED: s->state = V3_VM_STOPPED; break;
653   case VM_PAUSED: s->state = V3_VM_PAUSED; break;
654   case VM_ERROR: s->state = V3_VM_ERROR; break;
655   case VM_SIMULATING: s->state = V3_VM_SIMULATING; break;
656   default: s->state = V3_VM_UNKNOWN; break;
657   }
658
659   s->mem_base_paddr = (void*)(vm->mem_map.base_region.host_addr);
660   s->mem_size = vm->mem_size;
661
662   s->num_vcores = numcores;
663
664   for (i=0;i<numcores;i++) {
665     switch (vm->cores[i].core_run_state) {
666     case CORE_INVALID: s->vcore[i].state = V3_VCORE_INVALID; break;
667     case CORE_RUNNING: s->vcore[i].state = V3_VCORE_RUNNING; break;
668     case CORE_STOPPED: s->vcore[i].state = V3_VCORE_STOPPED; break;
669     default: s->vcore[i].state = V3_VCORE_UNKNOWN; break;
670     }
671     switch (vm->cores[i].cpu_mode) {
672     case REAL: s->vcore[i].cpu_mode = V3_VCORE_CPU_REAL; break;
673     case PROTECTED: s->vcore[i].cpu_mode = V3_VCORE_CPU_PROTECTED; break;
674     case PROTECTED_PAE: s->vcore[i].cpu_mode = V3_VCORE_CPU_PROTECTED_PAE; break;
675     case LONG: s->vcore[i].cpu_mode = V3_VCORE_CPU_LONG; break;
676     case LONG_32_COMPAT: s->vcore[i].cpu_mode = V3_VCORE_CPU_LONG_32_COMPAT; break;
677     case LONG_16_COMPAT: s->vcore[i].cpu_mode = V3_VCORE_CPU_LONG_16_COMPAT; break;
678     default: s->vcore[i].cpu_mode = V3_VCORE_CPU_UNKNOWN; break;
679     }
680     switch (vm->cores[i].shdw_pg_mode) { 
681     case SHADOW_PAGING: s->vcore[i].mem_state = V3_VCORE_MEM_STATE_SHADOW; break;
682     case NESTED_PAGING: s->vcore[i].mem_state = V3_VCORE_MEM_STATE_NESTED; break;
683     default: s->vcore[i].mem_state = V3_VCORE_MEM_STATE_UNKNOWN; break;
684     }
685     switch (vm->cores[i].mem_mode) { 
686     case PHYSICAL_MEM: s->vcore[i].mem_mode = V3_VCORE_MEM_MODE_PHYSICAL; break;
687     case VIRTUAL_MEM: s->vcore[i].mem_mode=V3_VCORE_MEM_MODE_VIRTUAL; break;
688     default: s->vcore[i].mem_mode=V3_VCORE_MEM_MODE_UNKNOWN; break;
689     }
690
691     s->vcore[i].pcore=vm->cores[i].pcpu_id;
692     s->vcore[i].last_rip=(void*)(vm->cores[i].rip);
693     s->vcore[i].num_exits=vm->cores[i].num_exits;
694   }
695
696   return 0;
697 }
698
699
700 #ifdef V3_CONFIG_CHECKPOINT
701 #include <palacios/vmm_checkpoint.h>
702
703 int v3_save_vm(struct v3_vm_info * vm, char * store, char * url) {
704     return v3_chkpt_save_vm(vm, store, url);
705 }
706
707
708 int v3_load_vm(struct v3_vm_info * vm, char * store, char * url) {
709     return v3_chkpt_load_vm(vm, store, url);
710 }
711
712 #ifdef V3_CONFIG_LIVE_MIGRATION
713 int v3_send_vm(struct v3_vm_info * vm, char * store, char * url) {
714     return v3_chkpt_send_vm(vm, store, url);
715 }
716
717
718 int v3_receive_vm(struct v3_vm_info * vm, char * store, char * url) {
719     return v3_chkpt_receive_vm(vm, store, url);
720 }
721 #endif
722
723 #endif
724
725
726 int v3_free_vm(struct v3_vm_info * vm) {
727     int i = 0;
728     // deinitialize guest (free memory, etc...)
729
730     if ((vm->run_state != VM_STOPPED) &&
731         (vm->run_state != VM_ERROR)) {
732         PrintError("Tried to Free VM in invalid runstate (%d)\n", vm->run_state);
733         return -1;
734     }
735
736     v3_free_vm_devices(vm);
737
738     // free cores
739     for (i = 0; i < vm->num_cores; i++) {
740         v3_free_core(&(vm->cores[i]));
741     }
742
743     // free vm
744     v3_free_vm_internal(vm);
745
746     v3_free_config(vm);
747
748     V3_Free(vm);
749
750     return 0;
751 }
752
753
754 #ifdef __V3_32BIT__
755
756 v3_cpu_mode_t v3_get_host_cpu_mode() {
757     uint32_t cr4_val;
758     struct cr4_32 * cr4;
759
760     __asm__ (
761              "movl %%cr4, %0; "
762              : "=r"(cr4_val) 
763              );
764
765     
766     cr4 = (struct cr4_32 *)&(cr4_val);
767
768     if (cr4->pae == 1) {
769         return PROTECTED_PAE;
770     } else {
771         return PROTECTED;
772     }
773 }
774
775 #elif __V3_64BIT__
776
777 v3_cpu_mode_t v3_get_host_cpu_mode() {
778     return LONG;
779 }
780
781 #endif 
782
783
784
785
786
787 void v3_yield_cond(struct guest_info * info, int usec) {
788     uint64_t cur_cycle;
789     cur_cycle = v3_get_host_time(&info->time_state);
790
791     if (cur_cycle > (info->yield_start_cycle + info->vm_info->yield_cycle_period)) {
792         //PrintDebug("Conditional Yield (cur_cyle=%p, start_cycle=%p, period=%p)\n", 
793         //           (void *)cur_cycle, (void *)info->yield_start_cycle, 
794         //         (void *)info->yield_cycle_period);
795         
796         if (usec < 0) { 
797             V3_Yield();
798         } else {
799             V3_Sleep(usec);
800         }
801
802         info->yield_start_cycle +=  info->vm_info->yield_cycle_period;
803     }
804 }
805  
806
807 /* 
808  * unconditional cpu yield 
809  * if the yielding thread is a guest context, the guest quantum is reset on resumption 
810  * Non guest context threads should call this function with a NULL argument
811  *
812  * usec <0  => the non-timed yield is used
813  * usec >=0 => the timed yield is used, which also usually implies interruptible
814  */ 
815 void v3_yield(struct guest_info * info, int usec) {
816     if (usec < 0) { 
817         V3_Yield();
818     } else {
819         V3_Sleep(usec);
820     }
821
822     if (info) {
823         info->yield_start_cycle +=  info->vm_info->yield_cycle_period;
824     }
825 }
826
827
828
829
830 void v3_print_cond(const char * fmt, ...) {
831     if (v3_dbg_enable == 1) {
832         char buf[2048];
833         va_list ap;
834
835         va_start(ap, fmt);
836         vsnprintf(buf, 2048, fmt, ap);
837         va_end(ap);
838
839         V3_Print("%s", buf);
840     }    
841 }
842
843
844
845 void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector) {
846     extern struct v3_os_hooks * os_hooks;
847
848     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
849         (os_hooks)->interrupt_cpu(vm, logical_cpu, vector);
850     }
851 }
852
853
854
855 int v3_vm_enter(struct guest_info * info) {
856     switch (v3_mach_type) {
857 #ifdef V3_CONFIG_SVM
858         case V3_SVM_CPU:
859         case V3_SVM_REV3_CPU:
860             return v3_svm_enter(info);
861             break;
862 #endif
863 #if V3_CONFIG_VMX
864         case V3_VMX_CPU:
865         case V3_VMX_EPT_CPU:
866         case V3_VMX_EPT_UG_CPU:
867             return v3_vmx_enter(info);
868             break;
869 #endif
870         default:
871             PrintError("Attemping to enter a guest on an invalid CPU\n");
872             return -1;
873     }
874 }