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.


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