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.


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