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 load-time configurable memory block size
[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     // 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     // Memory manager initialization
124     v3_init_mem();
125
126     // Register all the possible device types
127     V3_init_devices();
128
129     // Register all shadow paging handlers
130     V3_init_shdw_paging();
131
132     // Initialize the cpu_mapper framework (must be before extensions)
133     V3_init_cpu_mapper();
134
135     // Initialize the scheduler framework (must be before extensions)
136     V3_init_scheduling();
137  
138     // Register all extensions
139     V3_init_extensions();
140
141     // Enabling cpu_mapper
142     V3_enable_cpu_mapper();
143
144     // Enabling scheduler
145     V3_enable_scheduler();
146
147
148 #ifdef V3_CONFIG_SYMMOD
149     V3_init_symmod();
150 #endif
151
152 #ifdef V3_CONFIG_CHECKPOINT
153     V3_init_checkpoint();
154 #endif
155
156     if ((hooks) && (hooks->call_on_cpu)) {
157
158         for (i = 0; i < num_cpus; i++) {
159             major = i / 8;
160             minor = i % 8;
161
162             if ((cpu_mask == NULL) || (*(cpu_mask + major) & (0x1 << minor))) {
163                 V3_Print(VM_NONE, VCORE_NONE, "Initializing VMM extensions on cpu %d\n", i);
164                 hooks->call_on_cpu(i, &init_cpu, (void *)(addr_t)i);
165
166                 if (v3_mach_type == V3_INVALID_CPU) {
167                     v3_mach_type = v3_cpu_types[i];
168                 }   
169             }
170         }
171     }
172 }
173
174
175
176 void Shutdown_V3() {
177     int i;
178
179     V3_deinit_devices();
180     V3_deinit_shdw_paging();
181
182     V3_deinit_extensions();
183
184 #ifdef V3_CONFIG_SYMMOD
185     V3_deinit_symmod();
186 #endif
187
188 #ifdef V3_CONFIG_CHECKPOINT
189     V3_deinit_checkpoint();
190 #endif
191
192
193     if ((os_hooks) && (os_hooks->call_on_cpu)) {
194         for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
195             if (v3_cpu_types[i] != V3_INVALID_CPU) {
196                 V3_Call_On_CPU(i, deinit_cpu, (void *)(addr_t)i);
197                 //deinit_cpu((void *)(addr_t)i);
198             }
199         }
200     }
201
202     v3_deinit_mem();
203
204 }
205
206
207 v3_cpu_arch_t v3_get_cpu_type(int cpu_id) {
208     return v3_cpu_types[cpu_id];
209 }
210
211
212 struct v3_vm_info * v3_create_vm(void * cfg, void * priv_data, char * name) {
213     struct v3_vm_info * vm = v3_config_guest(cfg, priv_data);
214
215     if (vm == NULL) {
216         PrintError(VM_NONE, VCORE_NONE, "Could not configure guest\n");
217         return NULL;
218     }
219
220     V3_Print(vm, VCORE_NONE, "CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
221
222     if (name == NULL) {
223         name = "[V3_VM]";
224     } else if (strlen(name) >= 128) {
225         PrintError(vm, VCORE_NONE,"VM name is too long. Will be truncated to 128 chars.\n");
226     }
227
228     memset(vm->name, 0, 128);
229     strncpy(vm->name, name, 127);
230
231     /*
232      * Register this VM with the palacios scheduler. It will ask for admission
233      * prior to launch.
234      */
235     if(v3_scheduler_register_vm(vm) == -1) {
236     
237         PrintError(vm, VCORE_NONE,"Error registering VM with scheduler\n");
238     }
239
240     return vm;
241 }
242
243
244
245
246 static int start_core(void * p)
247 {
248     struct guest_info * core = (struct guest_info *)p;
249
250     if (v3_scheduler_register_core(core) == -1){
251         PrintError(core->vm_info, core,"Error initializing scheduling in core %d\n", core->vcpu_id);
252     }
253
254     PrintDebug(core->vm_info,core,"virtual core %u (on logical core %u): in start_core (RIP=%p)\n", 
255                core->vcpu_id, core->pcpu_id, (void *)(addr_t)core->rip);
256
257     switch (v3_mach_type) {
258 #ifdef V3_CONFIG_SVM
259         case V3_SVM_CPU:
260         case V3_SVM_REV3_CPU:
261             return v3_start_svm_guest(core);
262             break;
263 #endif
264 #if V3_CONFIG_VMX
265         case V3_VMX_CPU:
266         case V3_VMX_EPT_CPU:
267         case V3_VMX_EPT_UG_CPU:
268             return v3_start_vmx_guest(core);
269             break;
270 #endif
271         default:
272             PrintError(core->vm_info, core, "Attempting to enter a guest on an invalid CPU\n");
273             return -1;
274     }
275     // should not happen
276     return 0;
277 }
278
279 int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
280
281     uint32_t i,j;
282     uint8_t * core_mask = (uint8_t *)&cpu_mask; // This is to make future expansion easier
283     uint32_t avail_cores = 0;
284     int vcore_id = 0;
285     extern uint64_t v3_mem_block_size;
286
287
288     if (vm->run_state != VM_STOPPED) {
289         PrintError(vm, VCORE_NONE, "VM has already been launched (state=%d)\n", (int)vm->run_state);
290         return -1;
291     }
292
293     
294     // Do not run if any core is using shadow paging and we are out of 4 GB bounds
295     for (i=0;i<vm->num_cores;i++) { 
296         if (vm->cores[i].shdw_pg_mode == SHADOW_PAGING) {
297             for (j=0;j<vm->mem_map.num_base_regions;j++) {
298                 if ((vm->mem_map.base_regions[i].host_addr + v3_mem_block_size)  >= 0x100000000ULL) {
299                     PrintError(vm, VCORE_NONE, "Base memory region %d exceeds 4 GB boundary with shadow paging enabled on core %d.\n",j, i);
300                     PrintError(vm, VCORE_NONE, "Any use of non-64 bit mode in the guest is likely to fail in this configuration.\n");
301                     PrintError(vm, VCORE_NONE, "If you would like to proceed anyway, remove this check and recompile Palacios.\n");
302                     PrintError(vm, VCORE_NONE, "Alternatively, change this VM to use nested paging.\n");
303                     return -1;
304                 }
305             }
306         }
307     }
308     
309     /// CHECK IF WE ARE MULTICORE ENABLED....
310
311     V3_Print(vm, VCORE_NONE, "V3 --  Starting VM (%u cores)\n", vm->num_cores);
312     V3_Print(vm, VCORE_NONE, "CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
313
314
315     // Check that enough cores are present in the mask to handle vcores
316     for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
317         int major = i / 8;
318         int minor = i % 8;
319         
320         if (core_mask[major] & (0x1 << minor)) {
321             if (v3_cpu_types[i] == V3_INVALID_CPU) {
322                 core_mask[major] &= ~(0x1 << minor);
323             } else {
324                 avail_cores++;
325             }
326         }
327     }
328
329     vm->avail_cores = avail_cores;
330  
331     if (v3_scheduler_admit_vm(vm) != 0){
332        PrintError(vm, VCORE_NONE,"Error admitting VM %s for scheduling", vm->name);
333     }
334
335     if (v3_cpu_mapper_admit_vm(vm) != 0){
336         PrintError(vm, VCORE_NONE,"Error admitting VM %s for mapping", vm->name);
337     }
338
339     vm->run_state = VM_RUNNING;
340
341     if(v3_cpu_mapper_register_vm(vm,cpu_mask) == -1) {
342
343         PrintError(vm, VCORE_NONE,"Error registering VM with cpu_mapper\n");
344     }
345
346
347     for (vcore_id = 0; vcore_id < vm->num_cores; vcore_id++) {
348
349         struct guest_info * core = &(vm->cores[vcore_id]);
350
351         PrintDebug(vm, VCORE_NONE, "Starting virtual core %u on logical core %u\n", 
352                    vcore_id, core->pcpu_id);
353         
354         sprintf(core->exec_name, "%s-%u", vm->name, vcore_id);
355
356         PrintDebug(vm, VCORE_NONE, "run: core=%u, func=0x%p, arg=0x%p, name=%s\n",
357                    core->pcpu_id, start_core, core, core->exec_name);
358
359         core->core_run_state = CORE_STOPPED;  // core zero will turn itself on
360         core->core_thread = V3_CREATE_THREAD_ON_CPU(core->pcpu_id, start_core, core, core->exec_name);
361
362         if (core->core_thread == NULL) {
363             PrintError(vm, VCORE_NONE, "Thread launch failed\n");
364             v3_stop_vm(vm);
365             return -1;
366         }
367     }
368
369     return 0;
370
371 }
372
373
374 int v3_reset_vm_core(struct guest_info * core, addr_t rip) {
375     
376     switch (v3_cpu_types[core->pcpu_id]) {
377 #ifdef V3_CONFIG_SVM
378         case V3_SVM_CPU:
379         case V3_SVM_REV3_CPU:
380             PrintDebug(core->vm_info, core, "Resetting SVM Guest CPU %d\n", core->vcpu_id);
381             return v3_reset_svm_vm_core(core, rip);
382 #endif
383 #ifdef V3_CONFIG_VMX
384         case V3_VMX_CPU:
385         case V3_VMX_EPT_CPU:
386         case V3_VMX_EPT_UG_CPU:
387             PrintDebug(core->vm_info, core, "Resetting VMX Guest CPU %d\n", core->vcpu_id);
388             return v3_reset_vmx_vm_core(core, rip);
389 #endif
390         case V3_INVALID_CPU:
391         default:
392             PrintError(core->vm_info, core, "CPU has no virtualization Extensions\n");
393             break;
394     }
395
396     return -1;
397 }
398
399
400
401 /* move a virtual core to different physical core */
402 int v3_move_vm_core(struct v3_vm_info * vm, int vcore_id, int target_cpu) {
403     struct guest_info * core = NULL;
404
405     if ((vcore_id < 0) || (vcore_id >= vm->num_cores)) {
406         PrintError(vm, VCORE_NONE, "Attempted to migrate invalid virtual core (%d)\n", vcore_id);
407         return -1;
408     }
409
410     core = &(vm->cores[vcore_id]);
411
412     if (target_cpu == core->pcpu_id) {
413         PrintError(vm,  core, "Attempted to migrate to local core (%d)\n", target_cpu);
414         // well that was pointless
415         return 0;
416     }
417
418     if (core->core_thread == NULL) {
419         PrintError(vm, core, "Attempted to migrate a core without a valid thread context\n");
420         return -1;
421     }
422
423     while (v3_raise_barrier(vm, NULL) == -1);
424
425     V3_Print(vm, core, "Performing Migration from %d to %d\n", core->pcpu_id, target_cpu);
426
427     // Double check that we weren't preemptively migrated
428     if (target_cpu != core->pcpu_id) {    
429
430         V3_Print(vm, core, "Moving Core\n");
431
432         if(v3_cpu_mapper_admit_core(vm, vcore_id, target_cpu) == -1){
433                 PrintError(vm, core, "Core %d can not be admitted in cpu %d\n",vcore_id, target_cpu);
434                 return -1;
435         }
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(vm, core, "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(vm, core, "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(vm, core, "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(vm, VCORE_NONE,"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, VCORE_NONE,"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(vm, VCORE_NONE,"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(vm, VCORE_NONE,"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(core->vm_info, core, "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, VCORE_NONE,"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(vm, VCORE_NONE,"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(vm, VCORE_NONE,"Could not register simulation timeout for core %d\n", i);
595             return -1;
596         }
597     }
598
599     V3_Print(vm, VCORE_NONE,"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(vm, VCORE_NONE,"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(vm, VCORE_NONE,"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, 
645                     struct v3_vm_base_state  *base,
646                     struct v3_vm_core_state  *core,
647                     struct v3_vm_mem_state   *mem)
648 {
649     uint32_t i;
650     uint32_t numcores = core->num_vcores > vm->num_cores ? vm->num_cores : core->num_vcores;
651     uint32_t numregions = mem->num_regions > vm->mem_map.num_base_regions ? vm->mem_map.num_base_regions : mem->num_regions;
652     extern uint64_t v3_mem_block_size;
653
654     switch (vm->run_state) { 
655         case VM_INVALID: base->state = V3_VM_INVALID; break;
656         case VM_RUNNING: base->state = V3_VM_RUNNING; break;
657         case VM_STOPPED: base->state = V3_VM_STOPPED; break;
658         case VM_PAUSED: base->state = V3_VM_PAUSED; break;
659         case VM_ERROR: base->state = V3_VM_ERROR; break;
660         case VM_SIMULATING: base->state = V3_VM_SIMULATING; break;
661         default: base->state = V3_VM_UNKNOWN; break;
662     }
663
664     for (i=0;i<numcores;i++) {
665         switch (vm->cores[i].core_run_state) {
666             case CORE_INVALID: core->vcore[i].state = V3_VCORE_INVALID; break;
667             case CORE_RUNNING: core->vcore[i].state = V3_VCORE_RUNNING; break;
668             case CORE_STOPPED: core->vcore[i].state = V3_VCORE_STOPPED; break;
669             default: core->vcore[i].state = V3_VCORE_UNKNOWN; break;
670         }
671         switch (vm->cores[i].cpu_mode) {
672             case REAL: core->vcore[i].cpu_mode = V3_VCORE_CPU_REAL; break;
673             case PROTECTED: core->vcore[i].cpu_mode = V3_VCORE_CPU_PROTECTED; break;
674             case PROTECTED_PAE: core->vcore[i].cpu_mode = V3_VCORE_CPU_PROTECTED_PAE; break;
675             case LONG: core->vcore[i].cpu_mode = V3_VCORE_CPU_LONG; break;
676             case LONG_32_COMPAT: core->vcore[i].cpu_mode = V3_VCORE_CPU_LONG_32_COMPAT; break;
677             case LONG_16_COMPAT: core->vcore[i].cpu_mode = V3_VCORE_CPU_LONG_16_COMPAT; break;
678             default: core->vcore[i].cpu_mode = V3_VCORE_CPU_UNKNOWN; break;
679         }
680         switch (vm->cores[i].shdw_pg_mode) { 
681             case SHADOW_PAGING: core->vcore[i].mem_state = V3_VCORE_MEM_STATE_SHADOW; break;
682             case NESTED_PAGING: core->vcore[i].mem_state = V3_VCORE_MEM_STATE_NESTED; break;
683             default: core->vcore[i].mem_state = V3_VCORE_MEM_STATE_UNKNOWN; break;
684         }
685         switch (vm->cores[i].mem_mode) { 
686             case PHYSICAL_MEM: core->vcore[i].mem_mode = V3_VCORE_MEM_MODE_PHYSICAL; break;
687             case VIRTUAL_MEM: core->vcore[i].mem_mode=V3_VCORE_MEM_MODE_VIRTUAL; break;
688             default: core->vcore[i].mem_mode=V3_VCORE_MEM_MODE_UNKNOWN; break;
689         }
690         
691         core->vcore[i].pcore=vm->cores[i].pcpu_id;
692         core->vcore[i].last_rip=(void*)(vm->cores[i].rip);
693         core->vcore[i].num_exits=vm->cores[i].num_exits;
694     }
695     
696     core->num_vcores=numcores;
697
698     for (i=0;i<vm->mem_map.num_base_regions;i++) {
699         mem->region[i].host_paddr =  (void*)(vm->mem_map.base_regions[i].host_addr);
700         mem->region[i].size = v3_mem_block_size;
701     }
702
703     mem->num_regions=numregions;
704     
705     return 0;
706 }
707
708
709 #ifdef V3_CONFIG_CHECKPOINT
710 #include <palacios/vmm_checkpoint.h>
711
712 int v3_save_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
713   return v3_chkpt_save_vm(vm, store, url, opts);
714 }
715
716
717 int v3_load_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
718   return v3_chkpt_load_vm(vm, store, url, opts);
719 }
720
721 #ifdef V3_CONFIG_LIVE_MIGRATION
722 int v3_send_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
723   return v3_chkpt_send_vm(vm, store, url, opts);
724 }
725
726
727 int v3_receive_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
728   return v3_chkpt_receive_vm(vm, store, url, opts);
729 }
730 #endif
731
732 #endif
733
734
735 int v3_free_vm(struct v3_vm_info * vm) {
736     int i = 0;
737     // deinitialize guest (free memory, etc...)
738
739     if ((vm->run_state != VM_STOPPED) &&
740         (vm->run_state != VM_ERROR)) {
741         PrintError(vm, VCORE_NONE,"Tried to Free VM in invalid runstate (%d)\n", vm->run_state);
742         return -1;
743     }
744
745     v3_free_vm_devices(vm);
746
747     // free cores
748     for (i = 0; i < vm->num_cores; i++) {
749         v3_free_core(&(vm->cores[i]));
750     }
751
752     // free vm
753     v3_free_vm_internal(vm);
754
755     v3_free_config(vm);
756
757     V3_Free(vm);
758
759     return 0;
760 }
761
762
763 #ifdef __V3_32BIT__
764
765 v3_cpu_mode_t v3_get_host_cpu_mode() {
766     uint32_t cr4_val;
767     struct cr4_32 * cr4;
768
769     __asm__ (
770              "movl %%cr4, %0; "
771              : "=r"(cr4_val) 
772              );
773
774     
775     cr4 = (struct cr4_32 *)&(cr4_val);
776
777     if (cr4->pae == 1) {
778         return PROTECTED_PAE;
779     } else {
780         return PROTECTED;
781     }
782 }
783
784 #elif __V3_64BIT__
785
786 v3_cpu_mode_t v3_get_host_cpu_mode() {
787     return LONG;
788 }
789
790 #endif 
791
792 void v3_print_cond(const char * fmt, ...) {
793     if (v3_dbg_enable == 1) {
794         char buf[2048];
795         va_list ap;
796
797         va_start(ap, fmt);
798         vsnprintf(buf, 2048, fmt, ap);
799         va_end(ap);
800
801         V3_Print(VM_NONE, VCORE_NONE,"%s", buf);
802     }    
803 }
804
805
806
807 void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector) {
808     extern struct v3_os_hooks * os_hooks;
809
810     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
811         (os_hooks)->interrupt_cpu(vm, logical_cpu, vector);
812     }
813 }
814
815
816
817 int v3_vm_enter(struct guest_info * info) {
818     switch (v3_mach_type) {
819 #ifdef V3_CONFIG_SVM
820         case V3_SVM_CPU:
821         case V3_SVM_REV3_CPU:
822             return v3_svm_enter(info);
823             break;
824 #endif
825 #if V3_CONFIG_VMX
826         case V3_VMX_CPU:
827         case V3_VMX_EPT_CPU:
828         case V3_VMX_EPT_UG_CPU:
829             return v3_vmx_enter(info);
830             break;
831 #endif
832         default:
833             PrintError(info->vm_info, info, "Attemping to enter a guest on an invalid CPU\n");
834             return -1;
835     }
836 }
837
838
839 void    *v3_get_host_vm(struct v3_vm_info *x)
840 {
841   if (x) { 
842     return x->host_priv_data;
843   } else {
844     return 0;
845   }
846 }
847
848 int v3_get_vcore(struct guest_info *x)
849 {
850   if (x) {
851     return x->vcpu_id;
852   } else {
853     return -1;
854   }
855 }