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.


Correction of scheduler registration check
[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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "Machine is VMX Capable\n");
65         v3_init_vmx_cpu(cpu_id);
66
67     } else 
68 #endif
69     {
70        PrintError(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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     // Initialize the scheduler framework (must be before extensions)
127     V3_init_scheduling();
128  
129     // Register all extensions
130     V3_init_extensions();
131
132     // Enabling scheduler
133     V3_enable_scheduler();
134
135
136 #ifdef V3_CONFIG_SYMMOD
137     V3_init_symmod();
138 #endif
139
140 #ifdef V3_CONFIG_CHECKPOINT
141     V3_init_checkpoint();
142 #endif
143
144     if ((hooks) && (hooks->call_on_cpu)) {
145
146         for (i = 0; i < num_cpus; i++) {
147             major = i / 8;
148             minor = i % 8;
149
150             if ((cpu_mask == NULL) || (*(cpu_mask + major) & (0x1 << minor))) {
151                 V3_Print(VM_NONE, VCORE_NONE, "Initializing VMM extensions on cpu %d\n", i);
152                 hooks->call_on_cpu(i, &init_cpu, (void *)(addr_t)i);
153
154                 if (v3_mach_type == V3_INVALID_CPU) {
155                     v3_mach_type = v3_cpu_types[i];
156                 }   
157             }
158         }
159     }
160 }
161
162
163
164 void Shutdown_V3() {
165     int i;
166
167     V3_deinit_devices();
168     V3_deinit_shdw_paging();
169
170     V3_deinit_extensions();
171
172 #ifdef V3_CONFIG_SYMMOD
173     V3_deinit_symmod();
174 #endif
175
176 #ifdef V3_CONFIG_CHECKPOINT
177     V3_deinit_checkpoint();
178 #endif
179
180
181     if ((os_hooks) && (os_hooks->call_on_cpu)) {
182         for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
183             if (v3_cpu_types[i] != V3_INVALID_CPU) {
184                 V3_Call_On_CPU(i, deinit_cpu, (void *)(addr_t)i);
185                 //deinit_cpu((void *)(addr_t)i);
186             }
187         }
188     }
189
190 }
191
192
193 v3_cpu_arch_t v3_get_cpu_type(int cpu_id) {
194     return v3_cpu_types[cpu_id];
195 }
196
197
198 struct v3_vm_info * v3_create_vm(void * cfg, void * priv_data, char * name) {
199     struct v3_vm_info * vm = v3_config_guest(cfg, priv_data);
200
201     if (vm == NULL) {
202         PrintError(VM_NONE, VCORE_NONE, "Could not configure guest\n");
203         return NULL;
204     }
205
206     V3_Print(vm, VCORE_NONE, "CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
207
208     if (name == NULL) {
209         name = "[V3_VM]";
210     } else if (strlen(name) >= 128) {
211         PrintError(vm, VCORE_NONE,"VM name is too long. Will be truncated to 128 chars.\n");
212     }
213
214     memset(vm->name, 0, 128);
215     strncpy(vm->name, name, 127);
216
217     /*
218      * Register this VM with the palacios scheduler. It will ask for admission
219      * prior to launch.
220      */
221     if(v3_scheduler_register_vm(vm) == -1) {
222     
223         PrintError(vm, VCORE_NONE,"Error registering VM with scheduler\n");
224     }
225
226     return vm;
227 }
228
229
230
231
232 static int start_core(void * p)
233 {
234     struct guest_info * core = (struct guest_info *)p;
235
236     if (v3_scheduler_register_core(core) == -1){
237         PrintError(core->vm_info, core,"Error initializing scheduling in core %d\n", core->vcpu_id);
238     }
239
240     PrintDebug(core->vm_info,core,"virtual core %u (on logical core %u): in start_core (RIP=%p)\n", 
241                core->vcpu_id, core->pcpu_id, (void *)(addr_t)core->rip);
242
243     switch (v3_mach_type) {
244 #ifdef V3_CONFIG_SVM
245         case V3_SVM_CPU:
246         case V3_SVM_REV3_CPU:
247             return v3_start_svm_guest(core);
248             break;
249 #endif
250 #if V3_CONFIG_VMX
251         case V3_VMX_CPU:
252         case V3_VMX_EPT_CPU:
253         case V3_VMX_EPT_UG_CPU:
254             return v3_start_vmx_guest(core);
255             break;
256 #endif
257         default:
258             PrintError(core->vm_info, core, "Attempting to enter a guest on an invalid CPU\n");
259             return -1;
260     }
261     // should not happen
262     return 0;
263 }
264
265
266 // For the moment very ugly. Eventually we will shift the cpu_mask to an arbitrary sized type...
267 #define MAX_CORES 32
268
269
270 int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
271     uint32_t i;
272     uint8_t * core_mask = (uint8_t *)&cpu_mask; // This is to make future expansion easier
273     uint32_t avail_cores = 0;
274     int vcore_id = 0;
275
276
277     if (vm->run_state != VM_STOPPED) {
278         PrintError(vm, VCORE_NONE, "VM has already been launched (state=%d)\n", (int)vm->run_state);
279         return -1;
280     }
281
282     
283     // Do not run if any core is using shadow paging and we are out of 4 GB bounds
284     for (i=0;i<vm->num_cores;i++) { 
285         if (vm->cores[i].shdw_pg_mode == SHADOW_PAGING) {
286             if ((vm->mem_map.base_region.host_addr + vm->mem_size ) >= 0x100000000ULL) {
287                 PrintError(vm, VCORE_NONE, "Base memory region exceeds 4 GB boundary with shadow paging enabled on core %d.\n",i);
288                 PrintError(vm, VCORE_NONE, "Any use of non-64 bit mode in the guest is likely to fail in this configuration.\n");
289                 PrintError(vm, VCORE_NONE, "If you would like to proceed anyway, remove this check and recompile Palacios.\n");
290                 PrintError(vm, VCORE_NONE, "Alternatively, change this VM to use nested paging.\n");
291                 return -1;
292             }
293         }
294     }
295
296
297
298     /// CHECK IF WE ARE MULTICORE ENABLED....
299
300     V3_Print(vm, VCORE_NONE, "V3 --  Starting VM (%u cores)\n", vm->num_cores);
301     V3_Print(vm, VCORE_NONE, "CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
302
303
304     // Check that enough cores are present in the mask to handle vcores
305     for (i = 0; i < MAX_CORES; i++) {
306         int major = i / 8;
307         int minor = i % 8;
308         
309         if (core_mask[major] & (0x1 << minor)) {
310             if (v3_cpu_types[i] == V3_INVALID_CPU) {
311                 core_mask[major] &= ~(0x1 << minor);
312             } else {
313                 avail_cores++;
314             }
315         }
316     }
317
318
319     vm->avail_cores = avail_cores;
320  
321     if (v3_scheduler_admit_vm(vm) != 0){
322         PrintError(vm, VCORE_NONE,"Error admitting VM %s for scheduling", vm->name);
323     }
324
325     vm->run_state = VM_RUNNING;
326
327     // Spawn off threads for each core. 
328     // We work backwards, so that core 0 is always started last.
329     for (i = 0, vcore_id = vm->num_cores - 1; (i < MAX_CORES) && (vcore_id >= 0); i++) {
330         int major = 0;
331         int minor = 0;
332         struct guest_info * core = &(vm->cores[vcore_id]);
333         char * specified_cpu = v3_cfg_val(core->core_cfg_data, "target_cpu");
334         uint32_t core_idx = 0;
335
336         if (specified_cpu != NULL) {
337             core_idx = atoi(specified_cpu);
338             
339             if ((core_idx < 0) || (core_idx >= MAX_CORES)) {
340                 PrintError(vm, VCORE_NONE, "Target CPU out of bounds (%d) (MAX_CORES=%d)\n", core_idx, MAX_CORES);
341             }
342
343             i--; // We reset the logical core idx. Not strictly necessary I guess... 
344         } else {
345             core_idx = i;
346         }
347
348         major = core_idx / 8;
349         minor = core_idx % 8;
350
351         if ((core_mask[major] & (0x1 << minor)) == 0) {
352             PrintError(vm, VCORE_NONE, "Logical CPU %d not available for virtual core %d; not started\n",
353                        core_idx, vcore_id);
354
355             if (specified_cpu != NULL) {
356                 PrintError(vm, VCORE_NONE, "CPU was specified explicitly (%d). HARD ERROR\n", core_idx);
357                 v3_stop_vm(vm);
358                 return -1;
359             }
360
361             continue;
362         }
363
364         PrintDebug(vm, VCORE_NONE, "Starting virtual core %u on logical core %u\n", 
365                    vcore_id, core_idx);
366         
367         sprintf(core->exec_name, "%s-%u", vm->name, vcore_id);
368
369         PrintDebug(vm, VCORE_NONE, "run: core=%u, func=0x%p, arg=0x%p, name=%s\n",
370                    core_idx, start_core, core, core->exec_name);
371
372         core->core_run_state = CORE_STOPPED;  // core zero will turn itself on
373         core->pcpu_id = core_idx;
374         core->core_thread = V3_CREATE_THREAD_ON_CPU(core_idx, start_core, core, core->exec_name);
375
376         if (core->core_thread == NULL) {
377             PrintError(vm, VCORE_NONE, "Thread launch failed\n");
378             v3_stop_vm(vm);
379             return -1;
380         }
381
382         vcore_id--;
383     }
384
385     if (vcore_id >= 0) {
386         PrintError(vm, VCORE_NONE, "Error starting VM: Not enough available CPU cores\n");
387         v3_stop_vm(vm);
388         return -1;
389     }
390
391
392     return 0;
393
394 }
395
396
397 int v3_reset_vm_core(struct guest_info * core, addr_t rip) {
398     
399     switch (v3_cpu_types[core->pcpu_id]) {
400 #ifdef V3_CONFIG_SVM
401         case V3_SVM_CPU:
402         case V3_SVM_REV3_CPU:
403             PrintDebug(core->vm_info, core, "Resetting SVM Guest CPU %d\n", core->vcpu_id);
404             return v3_reset_svm_vm_core(core, rip);
405 #endif
406 #ifdef V3_CONFIG_VMX
407         case V3_VMX_CPU:
408         case V3_VMX_EPT_CPU:
409         case V3_VMX_EPT_UG_CPU:
410             PrintDebug(core->vm_info, core, "Resetting VMX Guest CPU %d\n", core->vcpu_id);
411             return v3_reset_vmx_vm_core(core, rip);
412 #endif
413         case V3_INVALID_CPU:
414         default:
415             PrintError(core->vm_info, core, "CPU has no virtualization Extensions\n");
416             break;
417     }
418
419     return -1;
420 }
421
422
423
424 /* move a virtual core to different physical core */
425 int v3_move_vm_core(struct v3_vm_info * vm, int vcore_id, int target_cpu) {
426     struct guest_info * core = NULL;
427
428     if ((vcore_id < 0) || (vcore_id >= vm->num_cores)) {
429         PrintError(vm, VCORE_NONE, "Attempted to migrate invalid virtual core (%d)\n", vcore_id);
430         return -1;
431     }
432
433     core = &(vm->cores[vcore_id]);
434
435     if (target_cpu == core->pcpu_id) {
436         PrintError(vm,  core, "Attempted to migrate to local core (%d)\n", target_cpu);
437         // well that was pointless
438         return 0;
439     }
440
441     if (core->core_thread == NULL) {
442         PrintError(vm, core, "Attempted to migrate a core without a valid thread context\n");
443         return -1;
444     }
445
446     while (v3_raise_barrier(vm, NULL) == -1);
447
448     V3_Print(vm, core, "Performing Migration from %d to %d\n", core->pcpu_id, target_cpu);
449
450     // Double check that we weren't preemptively migrated
451     if (target_cpu != core->pcpu_id) {    
452
453         V3_Print(vm, core, "Moving Core\n");
454
455
456 #ifdef V3_CONFIG_VMX
457         switch (v3_cpu_types[core->pcpu_id]) {
458             case V3_VMX_CPU:
459             case V3_VMX_EPT_CPU:
460             case V3_VMX_EPT_UG_CPU:
461                 PrintDebug(vm, core, "Flushing VMX Guest CPU %d\n", core->vcpu_id);
462                 V3_Call_On_CPU(core->pcpu_id, (void (*)(void *))v3_flush_vmx_vm_core, (void *)core);
463                 break;
464             default:
465                 break;
466         }
467 #endif
468
469         if (V3_MOVE_THREAD_TO_CPU(target_cpu, core->core_thread) != 0) {
470             PrintError(vm, core, "Failed to move Vcore %d to CPU %d\n", 
471                        core->vcpu_id, target_cpu);
472             v3_lower_barrier(vm);
473             return -1;
474         } 
475         
476         /* There will be a benign race window here:
477            core->pcpu_id will be set to the target core before its fully "migrated"
478            However the core will NEVER run on the old core again, its just in flight to the new core
479         */
480         core->pcpu_id = target_cpu;
481
482         V3_Print(vm, core, "core now at %d\n", core->pcpu_id);  
483     }
484
485     v3_lower_barrier(vm);
486
487     return 0;
488 }
489
490
491
492 int v3_stop_vm(struct v3_vm_info * vm) {
493
494     if ((vm->run_state != VM_RUNNING) && 
495         (vm->run_state != VM_SIMULATING)) {
496         PrintError(vm, VCORE_NONE,"Tried to stop VM in invalid runstate (%d)\n", vm->run_state);
497         return -1;
498     }
499
500     vm->run_state = VM_STOPPED;
501
502     // Sanity check to catch any weird execution states
503     if (v3_wait_for_barrier(vm, NULL) == 0) {
504         v3_lower_barrier(vm);
505     }
506     
507     // XXX force exit all cores via a cross call/IPI XXX
508
509     while (1) {
510         int i = 0;
511         int still_running = 0;
512
513         for (i = 0; i < vm->num_cores; i++) {
514             if (vm->cores[i].core_run_state != CORE_STOPPED) {
515                 still_running = 1;
516             }
517         }
518
519         if (still_running == 0) {
520             break;
521         }
522
523         v3_yield(NULL,-1);
524     }
525     
526     V3_Print(vm, VCORE_NONE,"VM stopped. Returning\n");
527
528     return 0;
529 }
530
531
532 int v3_pause_vm(struct v3_vm_info * vm) {
533
534     if (vm->run_state != VM_RUNNING) {
535         PrintError(vm, VCORE_NONE,"Tried to pause a VM that was not running\n");
536         return -1;
537     }
538
539     while (v3_raise_barrier(vm, NULL) == -1);
540
541     vm->run_state = VM_PAUSED;
542
543     return 0;
544 }
545
546
547 int v3_continue_vm(struct v3_vm_info * vm) {
548
549     if (vm->run_state != VM_PAUSED) {
550         PrintError(vm, VCORE_NONE,"Tried to continue a VM that was not paused\n");
551         return -1;
552     }
553
554     vm->run_state = VM_RUNNING;
555
556     v3_lower_barrier(vm);
557
558     return 0;
559 }
560
561
562
563 static int sim_callback(struct guest_info * core, void * private_data) {
564     struct v3_bitmap * timeout_map = private_data;
565
566     v3_bitmap_set(timeout_map, core->vcpu_id);
567     
568     V3_Print(core->vm_info, core, "Simulation callback activated (guest_rip=%p)\n", (void *)core->rip);
569
570     while (v3_bitmap_check(timeout_map, core->vcpu_id) == 1) {
571         v3_yield(NULL,-1);
572     }
573
574     return 0;
575 }
576
577
578
579
580 int v3_simulate_vm(struct v3_vm_info * vm, unsigned int msecs) {
581     struct v3_bitmap timeout_map;
582     int i = 0;
583     int all_blocked = 0;
584     uint64_t cycles = 0;
585     uint64_t cpu_khz = V3_CPU_KHZ();
586
587     if (vm->run_state != VM_PAUSED) {
588         PrintError(vm, VCORE_NONE,"VM must be paused before simulation begins\n");
589         return -1;
590     }
591
592     /* AT this point VM is paused */
593     
594     // initialize bitmap
595     v3_bitmap_init(&timeout_map, vm->num_cores);
596
597
598
599
600     // calculate cycles from msecs...
601     // IMPORTANT: Floating point not allowed.
602     cycles = (msecs * cpu_khz);
603     
604
605
606     V3_Print(vm, VCORE_NONE,"Simulating %u msecs (%llu cycles) [CPU_KHZ=%llu]\n", msecs, cycles, cpu_khz);
607
608     // set timeout
609     
610     for (i = 0; i < vm->num_cores; i++) {
611         if (v3_add_core_timeout(&(vm->cores[i]), cycles, sim_callback, &timeout_map) == -1) {
612             PrintError(vm, VCORE_NONE,"Could not register simulation timeout for core %d\n", i);
613             return -1;
614         }
615     }
616
617     V3_Print(vm, VCORE_NONE,"timeouts set on all cores\n ");
618
619     
620     // Run the simulation
621 //    vm->run_state = VM_SIMULATING;
622     vm->run_state = VM_RUNNING;
623     v3_lower_barrier(vm);
624
625
626     V3_Print(vm, VCORE_NONE,"Barrier lowered: We are now Simulating!!\n");
627
628     // block until simulation is complete    
629     while (all_blocked == 0) {
630         all_blocked = 1;
631
632         for (i = 0; i < vm->num_cores; i++) {
633             if (v3_bitmap_check(&timeout_map, i)  == 0) {
634                 all_blocked = 0;
635             }
636         }
637
638         if (all_blocked == 1) {
639             break;
640         }
641
642         v3_yield(NULL,-1);
643     }
644
645
646     V3_Print(vm, VCORE_NONE,"Simulation is complete\n");
647
648     // Simulation is complete
649     // Reset back to PAUSED state
650
651     v3_raise_barrier_nowait(vm, NULL);
652     vm->run_state = VM_PAUSED;
653     
654     v3_bitmap_reset(&timeout_map);
655
656     v3_wait_for_barrier(vm, NULL);
657
658     return 0;
659
660 }
661
662 int v3_get_state_vm(struct v3_vm_info *vm, struct v3_vm_state *s)
663 {
664   uint32_t i;
665   uint32_t numcores = s->num_vcores > vm->num_cores ? vm->num_cores : s->num_vcores;
666
667   switch (vm->run_state) { 
668   case VM_INVALID: s->state = V3_VM_INVALID; break;
669   case VM_RUNNING: s->state = V3_VM_RUNNING; break;
670   case VM_STOPPED: s->state = V3_VM_STOPPED; break;
671   case VM_PAUSED: s->state = V3_VM_PAUSED; break;
672   case VM_ERROR: s->state = V3_VM_ERROR; break;
673   case VM_SIMULATING: s->state = V3_VM_SIMULATING; break;
674   default: s->state = V3_VM_UNKNOWN; break;
675   }
676
677   s->mem_base_paddr = (void*)(vm->mem_map.base_region.host_addr);
678   s->mem_size = vm->mem_size;
679
680   s->num_vcores = numcores;
681
682   for (i=0;i<numcores;i++) {
683     switch (vm->cores[i].core_run_state) {
684     case CORE_INVALID: s->vcore[i].state = V3_VCORE_INVALID; break;
685     case CORE_RUNNING: s->vcore[i].state = V3_VCORE_RUNNING; break;
686     case CORE_STOPPED: s->vcore[i].state = V3_VCORE_STOPPED; break;
687     default: s->vcore[i].state = V3_VCORE_UNKNOWN; break;
688     }
689     switch (vm->cores[i].cpu_mode) {
690     case REAL: s->vcore[i].cpu_mode = V3_VCORE_CPU_REAL; break;
691     case PROTECTED: s->vcore[i].cpu_mode = V3_VCORE_CPU_PROTECTED; break;
692     case PROTECTED_PAE: s->vcore[i].cpu_mode = V3_VCORE_CPU_PROTECTED_PAE; break;
693     case LONG: s->vcore[i].cpu_mode = V3_VCORE_CPU_LONG; break;
694     case LONG_32_COMPAT: s->vcore[i].cpu_mode = V3_VCORE_CPU_LONG_32_COMPAT; break;
695     case LONG_16_COMPAT: s->vcore[i].cpu_mode = V3_VCORE_CPU_LONG_16_COMPAT; break;
696     default: s->vcore[i].cpu_mode = V3_VCORE_CPU_UNKNOWN; break;
697     }
698     switch (vm->cores[i].shdw_pg_mode) { 
699     case SHADOW_PAGING: s->vcore[i].mem_state = V3_VCORE_MEM_STATE_SHADOW; break;
700     case NESTED_PAGING: s->vcore[i].mem_state = V3_VCORE_MEM_STATE_NESTED; break;
701     default: s->vcore[i].mem_state = V3_VCORE_MEM_STATE_UNKNOWN; break;
702     }
703     switch (vm->cores[i].mem_mode) { 
704     case PHYSICAL_MEM: s->vcore[i].mem_mode = V3_VCORE_MEM_MODE_PHYSICAL; break;
705     case VIRTUAL_MEM: s->vcore[i].mem_mode=V3_VCORE_MEM_MODE_VIRTUAL; break;
706     default: s->vcore[i].mem_mode=V3_VCORE_MEM_MODE_UNKNOWN; break;
707     }
708
709     s->vcore[i].pcore=vm->cores[i].pcpu_id;
710     s->vcore[i].last_rip=(void*)(vm->cores[i].rip);
711     s->vcore[i].num_exits=vm->cores[i].num_exits;
712   }
713
714   return 0;
715 }
716
717
718 #ifdef V3_CONFIG_CHECKPOINT
719 #include <palacios/vmm_checkpoint.h>
720
721 int v3_save_vm(struct v3_vm_info * vm, char * store, char * url) {
722     return v3_chkpt_save_vm(vm, store, url);
723 }
724
725
726 int v3_load_vm(struct v3_vm_info * vm, char * store, char * url) {
727     return v3_chkpt_load_vm(vm, store, url);
728 }
729
730 #ifdef V3_CONFIG_LIVE_MIGRATION
731 int v3_send_vm(struct v3_vm_info * vm, char * store, char * url) {
732     return v3_chkpt_send_vm(vm, store, url);
733 }
734
735
736 int v3_receive_vm(struct v3_vm_info * vm, char * store, char * url) {
737     return v3_chkpt_receive_vm(vm, store, url);
738 }
739 #endif
740
741 #endif
742
743
744 int v3_free_vm(struct v3_vm_info * vm) {
745     int i = 0;
746     // deinitialize guest (free memory, etc...)
747
748     if ((vm->run_state != VM_STOPPED) &&
749         (vm->run_state != VM_ERROR)) {
750         PrintError(vm, VCORE_NONE,"Tried to Free VM in invalid runstate (%d)\n", vm->run_state);
751         return -1;
752     }
753
754     v3_free_vm_devices(vm);
755
756     // free cores
757     for (i = 0; i < vm->num_cores; i++) {
758         v3_free_core(&(vm->cores[i]));
759     }
760
761     // free vm
762     v3_free_vm_internal(vm);
763
764     v3_free_config(vm);
765
766     V3_Free(vm);
767
768     return 0;
769 }
770
771
772 #ifdef __V3_32BIT__
773
774 v3_cpu_mode_t v3_get_host_cpu_mode() {
775     uint32_t cr4_val;
776     struct cr4_32 * cr4;
777
778     __asm__ (
779              "movl %%cr4, %0; "
780              : "=r"(cr4_val) 
781              );
782
783     
784     cr4 = (struct cr4_32 *)&(cr4_val);
785
786     if (cr4->pae == 1) {
787         return PROTECTED_PAE;
788     } else {
789         return PROTECTED;
790     }
791 }
792
793 #elif __V3_64BIT__
794
795 v3_cpu_mode_t v3_get_host_cpu_mode() {
796     return LONG;
797 }
798
799 #endif 
800
801 void v3_print_cond(const char * fmt, ...) {
802     if (v3_dbg_enable == 1) {
803         char buf[2048];
804         va_list ap;
805
806         va_start(ap, fmt);
807         vsnprintf(buf, 2048, fmt, ap);
808         va_end(ap);
809
810         V3_Print(VM_NONE, VCORE_NONE,"%s", buf);
811     }    
812 }
813
814
815
816 void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector) {
817     extern struct v3_os_hooks * os_hooks;
818
819     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
820         (os_hooks)->interrupt_cpu(vm, logical_cpu, vector);
821     }
822 }
823
824
825
826 int v3_vm_enter(struct guest_info * info) {
827     switch (v3_mach_type) {
828 #ifdef V3_CONFIG_SVM
829         case V3_SVM_CPU:
830         case V3_SVM_REV3_CPU:
831             return v3_svm_enter(info);
832             break;
833 #endif
834 #if V3_CONFIG_VMX
835         case V3_VMX_CPU:
836         case V3_VMX_EPT_CPU:
837         case V3_VMX_EPT_UG_CPU:
838             return v3_vmx_enter(info);
839             break;
840 #endif
841         default:
842             PrintError(info->vm_info, info, "Attemping to enter a guest on an invalid CPU\n");
843             return -1;
844     }
845 }
846
847
848 void    *v3_get_host_vm(struct v3_vm_info *x)
849 {
850   if (x) { 
851     return x->host_priv_data;
852   } else {
853     return 0;
854   }
855 }
856
857 int v3_get_vcore(struct guest_info *x)
858 {
859   if (x) {
860     return x->vcpu_id;
861   } else {
862     return -1;
863   }
864 }