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.


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