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 null check to option processing call.
[palacios.git] / palacios / src / palacios / vmm.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_intr.h>
22 #include <palacios/vmm_config.h>
23 #include <palacios/vm_guest.h>
24 #include <palacios/vmm_ctrl_regs.h>
25 #include <palacios/vmm_lowlevel.h>
26 #include <palacios/vmm_sprintf.h>
27 #include <palacios/vmm_extensions.h>
28 #include <palacios/vmm_timeout.h>
29
30
31 #ifdef V3_CONFIG_SVM
32 #include <palacios/svm.h>
33 #endif
34 #ifdef V3_CONFIG_VMX
35 #include <palacios/vmx.h>
36 #endif
37
38 #ifdef V3_CONFIG_CHECKPOINT
39 #include <palacios/vmm_checkpoint.h>
40 #endif
41
42
43 v3_cpu_arch_t v3_cpu_types[V3_CONFIG_MAX_CPUS];
44 v3_cpu_arch_t v3_mach_type = V3_INVALID_CPU;
45
46 struct v3_os_hooks * os_hooks = NULL;
47 int v3_dbg_enable = 0;
48
49
50
51
52 static void init_cpu(void * arg) {
53     uint32_t cpu_id = (uint32_t)(addr_t)arg;
54
55 #ifdef V3_CONFIG_SVM
56     if (v3_is_svm_capable()) {
57         PrintDebug(VM_NONE, VCORE_NONE, "Machine is SVM Capable\n");
58         v3_init_svm_cpu(cpu_id);
59         
60     } else 
61 #endif
62 #ifdef V3_CONFIG_VMX
63     if (v3_is_vmx_capable()) {
64         PrintDebug(VM_NONE, VCORE_NONE, "Machine is VMX Capable\n");
65         v3_init_vmx_cpu(cpu_id);
66
67     } else 
68 #endif
69     {
70        PrintError(VM_NONE, VCORE_NONE, "CPU has no virtualization Extensions\n");
71     }
72 }
73
74
75 static void deinit_cpu(void * arg) {
76     uint32_t cpu_id = (uint32_t)(addr_t)arg;
77
78
79     switch (v3_cpu_types[cpu_id]) {
80 #ifdef V3_CONFIG_SVM
81         case V3_SVM_CPU:
82         case V3_SVM_REV3_CPU:
83             PrintDebug(VM_NONE, VCORE_NONE, "Deinitializing SVM CPU %d\n", cpu_id);
84             v3_deinit_svm_cpu(cpu_id);
85             break;
86 #endif
87 #ifdef V3_CONFIG_VMX
88         case V3_VMX_CPU:
89         case V3_VMX_EPT_CPU:
90         case V3_VMX_EPT_UG_CPU:
91             PrintDebug(VM_NONE, VCORE_NONE, "Deinitializing VMX CPU %d\n", cpu_id);
92             v3_deinit_vmx_cpu(cpu_id);
93             break;
94 #endif
95         case V3_INVALID_CPU:
96         default:
97             PrintError(VM_NONE, VCORE_NONE, "CPU has no virtualization Extensions\n");
98             break;
99     }
100 }
101
102 /* Options are space-separated values of the form "X=Y", for example
103  * scheduler=EDF CPUs=1,2,3,4
104  * THe following code pushes them into a hashtable for each of access
105  * by other code. Storage is allocated for keys and values as part
106  * of this process. XXX Need a way to deallocate this storage if the 
107  * module is removed XXX
108  */
109 static char *option_storage;
110 static struct hashtable *option_table;
111 static char *truevalue = "true";
112
113 static uint_t option_hash_fn(addr_t key) {
114     char * name = (char *)key;
115     return v3_hash_buffer((uint8_t *)name, strlen(name));
116 }
117 static int option_eq_fn(addr_t key1, addr_t key2) {
118     char * name1 = (char *)key1;
119     char * name2 = (char *)key2;
120
121     return (strcmp(name1, name2) == 0);
122 }
123
124 void V3_parse_options(char *options)
125 {
126     char *currKey = NULL, *currVal = NULL;
127     int parseKey = 1;
128     int len;
129     char *c;
130     if (!options) {
131         return; 
132     }
133
134     len = strlen(options);
135     option_storage = V3_Malloc(len + 1);
136     strcpy(option_storage, options);
137     c = option_storage;
138
139     option_table = v3_create_htable(0, option_hash_fn, option_eq_fn);
140     while (c && *c) {
141         /* Skip whitespace */
142         if (*c == ' ') {
143             *c = 0;
144             if (currKey) {
145                 if (!currVal) {
146                     currVal = truevalue;
147                 }
148                 v3_htable_insert(option_table, (addr_t)currKey, (addr_t)currVal);
149                 parseKey = 1;
150                 currKey = NULL;
151                 currVal = NULL;
152             } 
153             c++;
154         } else if (parseKey) {
155             if (!currKey) {
156                 currKey = c;
157             } 
158             if (*c == '=') {
159                 parseKey = 0;
160                 *c = 0;
161             }
162             c++;
163         } else /* !parseKey */ {
164             if (!currVal) {
165                 currVal = c;
166             }
167             c++;
168         }
169     }
170     if (currKey) {
171         if (!currVal) {
172             currVal = truevalue;
173         } 
174         v3_htable_insert(option_table, (addr_t)currKey, (addr_t)currVal);
175     }
176     return;
177 }
178
179 char *v3_lookup_option(char *key) {
180     return (char *)v3_htable_search(option_table, (addr_t)(key));
181 }
182
183 void Init_V3(struct v3_os_hooks * hooks, char * cpu_mask, int num_cpus, char *options) {
184     int i = 0;
185     int minor = 0;
186     int major = 0;
187
188     V3_Print(VM_NONE, VCORE_NONE, "V3 Print statement to fix a Kitten page fault bug\n");
189
190     // Set global variables. 
191     os_hooks = hooks;
192
193     // Determine the global machine type
194     v3_mach_type = V3_INVALID_CPU;
195
196     for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
197         v3_cpu_types[i] = V3_INVALID_CPU;
198     }
199
200     // Parse host-os defined options into an easily-accessed format.
201     V3_parse_options(options);
202
203     // Register all the possible device types
204     V3_init_devices();
205
206     // Register all shadow paging handlers
207     V3_init_shdw_paging();
208
209     // Initialize the scheduler framework (must be before extensions)
210     V3_init_scheduling();
211  
212     // Register all extensions
213     V3_init_extensions();
214
215     // Enabling scheduler
216     V3_enable_scheduler();
217
218
219 #ifdef V3_CONFIG_SYMMOD
220     V3_init_symmod();
221 #endif
222
223 #ifdef V3_CONFIG_CHECKPOINT
224     V3_init_checkpoint();
225 #endif
226
227     if ((hooks) && (hooks->call_on_cpu)) {
228
229         for (i = 0; i < num_cpus; i++) {
230             major = i / 8;
231             minor = i % 8;
232
233             if ((cpu_mask == NULL) || (*(cpu_mask + major) & (0x1 << minor))) {
234                 V3_Print(VM_NONE, VCORE_NONE, "Initializing VMM extensions on cpu %d\n", i);
235                 hooks->call_on_cpu(i, &init_cpu, (void *)(addr_t)i);
236
237                 if (v3_mach_type == V3_INVALID_CPU) {
238                     v3_mach_type = v3_cpu_types[i];
239                 }   
240             }
241         }
242     }
243 }
244
245
246
247 void Shutdown_V3() {
248     int i;
249
250     V3_deinit_devices();
251     V3_deinit_shdw_paging();
252
253     V3_deinit_extensions();
254
255 #ifdef V3_CONFIG_SYMMOD
256     V3_deinit_symmod();
257 #endif
258
259 #ifdef V3_CONFIG_CHECKPOINT
260     V3_deinit_checkpoint();
261 #endif
262
263
264     if ((os_hooks) && (os_hooks->call_on_cpu)) {
265         for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
266             if (v3_cpu_types[i] != V3_INVALID_CPU) {
267                 V3_Call_On_CPU(i, deinit_cpu, (void *)(addr_t)i);
268                 //deinit_cpu((void *)(addr_t)i);
269             }
270         }
271     }
272
273 }
274
275
276 v3_cpu_arch_t v3_get_cpu_type(int cpu_id) {
277     return v3_cpu_types[cpu_id];
278 }
279
280
281 struct v3_vm_info * v3_create_vm(void * cfg, void * priv_data, char * name) {
282     struct v3_vm_info * vm = v3_config_guest(cfg, priv_data);
283
284     if (vm == NULL) {
285         PrintError(VM_NONE, VCORE_NONE, "Could not configure guest\n");
286         return NULL;
287     }
288
289     V3_Print(vm, VCORE_NONE, "CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
290
291     if (name == NULL) {
292         name = "[V3_VM]";
293     } else if (strlen(name) >= 128) {
294         PrintError(vm, VCORE_NONE,"VM name is too long. Will be truncated to 128 chars.\n");
295     }
296
297     memset(vm->name, 0, 128);
298     strncpy(vm->name, name, 127);
299
300     /*
301      * Register this VM with the palacios scheduler. It will ask for admission
302      * prior to launch.
303      */
304     if(v3_scheduler_register_vm(vm) != -1) {
305     
306         PrintError(vm, VCORE_NONE,"Error registering VM with scheduler\n");
307     }
308
309     return vm;
310 }
311
312
313
314
315 static int start_core(void * p)
316 {
317     struct guest_info * core = (struct guest_info *)p;
318
319     if (v3_scheduler_register_core(core) == -1){
320         PrintError(core->vm_info, core,"Error initializing scheduling in core %d\n", core->vcpu_id);
321     }
322
323     PrintDebug(core->vm_info,core,"virtual core %u (on logical core %u): in start_core (RIP=%p)\n", 
324                core->vcpu_id, core->pcpu_id, (void *)(addr_t)core->rip);
325
326     switch (v3_mach_type) {
327 #ifdef V3_CONFIG_SVM
328         case V3_SVM_CPU:
329         case V3_SVM_REV3_CPU:
330             return v3_start_svm_guest(core);
331             break;
332 #endif
333 #if V3_CONFIG_VMX
334         case V3_VMX_CPU:
335         case V3_VMX_EPT_CPU:
336         case V3_VMX_EPT_UG_CPU:
337             return v3_start_vmx_guest(core);
338             break;
339 #endif
340         default:
341             PrintError(core->vm_info, core, "Attempting to enter a guest on an invalid CPU\n");
342             return -1;
343     }
344     // should not happen
345     return 0;
346 }
347
348
349 // For the moment very ugly. Eventually we will shift the cpu_mask to an arbitrary sized type...
350 #define MAX_CORES 32
351
352
353 int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
354     uint32_t i;
355     uint8_t * core_mask = (uint8_t *)&cpu_mask; // This is to make future expansion easier
356     uint32_t avail_cores = 0;
357     int vcore_id = 0;
358
359
360     if (vm->run_state != VM_STOPPED) {
361         PrintError(vm, VCORE_NONE, "VM has already been launched (state=%d)\n", (int)vm->run_state);
362         return -1;
363     }
364
365     
366     // Do not run if any core is using shadow paging and we are out of 4 GB bounds
367     for (i=0;i<vm->num_cores;i++) { 
368         if (vm->cores[i].shdw_pg_mode == SHADOW_PAGING) {
369             if ((vm->mem_map.base_region.host_addr + vm->mem_size ) >= 0x100000000ULL) {
370                 PrintError(vm, VCORE_NONE, "Base memory region exceeds 4 GB boundary with shadow paging enabled on core %d.\n",i);
371                 PrintError(vm, VCORE_NONE, "Any use of non-64 bit mode in the guest is likely to fail in this configuration.\n");
372                 PrintError(vm, VCORE_NONE, "If you would like to proceed anyway, remove this check and recompile Palacios.\n");
373                 PrintError(vm, VCORE_NONE, "Alternatively, change this VM to use nested paging.\n");
374                 return -1;
375             }
376         }
377     }
378
379
380
381     /// CHECK IF WE ARE MULTICORE ENABLED....
382
383     V3_Print(vm, VCORE_NONE, "V3 --  Starting VM (%u cores)\n", vm->num_cores);
384     V3_Print(vm, VCORE_NONE, "CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
385
386
387     // Check that enough cores are present in the mask to handle vcores
388     for (i = 0; i < MAX_CORES; i++) {
389         int major = i / 8;
390         int minor = i % 8;
391         
392         if (core_mask[major] & (0x1 << minor)) {
393             if (v3_cpu_types[i] == V3_INVALID_CPU) {
394                 core_mask[major] &= ~(0x1 << minor);
395             } else {
396                 avail_cores++;
397             }
398         }
399     }
400
401
402     vm->avail_cores = avail_cores;
403  
404     if (v3_scheduler_admit_vm(vm) != 0){
405         PrintError(vm, VCORE_NONE,"Error admitting VM %s for scheduling", vm->name);
406     }
407
408     vm->run_state = VM_RUNNING;
409
410     // Spawn off threads for each core. 
411     // We work backwards, so that core 0 is always started last.
412     for (i = 0, vcore_id = vm->num_cores - 1; (i < MAX_CORES) && (vcore_id >= 0); i++) {
413         int major = 0;
414         int minor = 0;
415         struct guest_info * core = &(vm->cores[vcore_id]);
416         char * specified_cpu = v3_cfg_val(core->core_cfg_data, "target_cpu");
417         uint32_t core_idx = 0;
418
419         if (specified_cpu != NULL) {
420             core_idx = atoi(specified_cpu);
421             
422             if ((core_idx < 0) || (core_idx >= MAX_CORES)) {
423                 PrintError(vm, VCORE_NONE, "Target CPU out of bounds (%d) (MAX_CORES=%d)\n", core_idx, MAX_CORES);
424             }
425
426             i--; // We reset the logical core idx. Not strictly necessary I guess... 
427         } else {
428             core_idx = i;
429         }
430
431         major = core_idx / 8;
432         minor = core_idx % 8;
433
434         if ((core_mask[major] & (0x1 << minor)) == 0) {
435             PrintError(vm, VCORE_NONE, "Logical CPU %d not available for virtual core %d; not started\n",
436                        core_idx, vcore_id);
437
438             if (specified_cpu != NULL) {
439                 PrintError(vm, VCORE_NONE, "CPU was specified explicitly (%d). HARD ERROR\n", core_idx);
440                 v3_stop_vm(vm);
441                 return -1;
442             }
443
444             continue;
445         }
446
447         PrintDebug(vm, VCORE_NONE, "Starting virtual core %u on logical core %u\n", 
448                    vcore_id, core_idx);
449         
450         sprintf(core->exec_name, "%s-%u", vm->name, vcore_id);
451
452         PrintDebug(vm, VCORE_NONE, "run: core=%u, func=0x%p, arg=0x%p, name=%s\n",
453                    core_idx, start_core, core, core->exec_name);
454
455         core->core_run_state = CORE_STOPPED;  // core zero will turn itself on
456         core->pcpu_id = core_idx;
457         core->core_thread = V3_CREATE_THREAD_ON_CPU(core_idx, start_core, core, core->exec_name);
458
459         if (core->core_thread == NULL) {
460             PrintError(vm, VCORE_NONE, "Thread launch failed\n");
461             v3_stop_vm(vm);
462             return -1;
463         }
464
465         vcore_id--;
466     }
467
468     if (vcore_id >= 0) {
469         PrintError(vm, VCORE_NONE, "Error starting VM: Not enough available CPU cores\n");
470         v3_stop_vm(vm);
471         return -1;
472     }
473
474
475     return 0;
476
477 }
478
479
480 int v3_reset_vm_core(struct guest_info * core, addr_t rip) {
481     
482     switch (v3_cpu_types[core->pcpu_id]) {
483 #ifdef V3_CONFIG_SVM
484         case V3_SVM_CPU:
485         case V3_SVM_REV3_CPU:
486             PrintDebug(core->vm_info, core, "Resetting SVM Guest CPU %d\n", core->vcpu_id);
487             return v3_reset_svm_vm_core(core, rip);
488 #endif
489 #ifdef V3_CONFIG_VMX
490         case V3_VMX_CPU:
491         case V3_VMX_EPT_CPU:
492         case V3_VMX_EPT_UG_CPU:
493             PrintDebug(core->vm_info, core, "Resetting VMX Guest CPU %d\n", core->vcpu_id);
494             return v3_reset_vmx_vm_core(core, rip);
495 #endif
496         case V3_INVALID_CPU:
497         default:
498             PrintError(core->vm_info, core, "CPU has no virtualization Extensions\n");
499             break;
500     }
501
502     return -1;
503 }
504
505
506
507 /* move a virtual core to different physical core */
508 int v3_move_vm_core(struct v3_vm_info * vm, int vcore_id, int target_cpu) {
509     struct guest_info * core = NULL;
510
511     if ((vcore_id < 0) || (vcore_id >= vm->num_cores)) {
512         PrintError(vm, VCORE_NONE, "Attempted to migrate invalid virtual core (%d)\n", vcore_id);
513         return -1;
514     }
515
516     core = &(vm->cores[vcore_id]);
517
518     if (target_cpu == core->pcpu_id) {
519         PrintError(vm,  core, "Attempted to migrate to local core (%d)\n", target_cpu);
520         // well that was pointless
521         return 0;
522     }
523
524     if (core->core_thread == NULL) {
525         PrintError(vm, core, "Attempted to migrate a core without a valid thread context\n");
526         return -1;
527     }
528
529     while (v3_raise_barrier(vm, NULL) == -1);
530
531     V3_Print(vm, core, "Performing Migration from %d to %d\n", core->pcpu_id, target_cpu);
532
533     // Double check that we weren't preemptively migrated
534     if (target_cpu != core->pcpu_id) {    
535
536         V3_Print(vm, core, "Moving Core\n");
537
538
539 #ifdef V3_CONFIG_VMX
540         switch (v3_cpu_types[core->pcpu_id]) {
541             case V3_VMX_CPU:
542             case V3_VMX_EPT_CPU:
543             case V3_VMX_EPT_UG_CPU:
544                 PrintDebug(vm, core, "Flushing VMX Guest CPU %d\n", core->vcpu_id);
545                 V3_Call_On_CPU(core->pcpu_id, (void (*)(void *))v3_flush_vmx_vm_core, (void *)core);
546                 break;
547             default:
548                 break;
549         }
550 #endif
551
552         if (V3_MOVE_THREAD_TO_CPU(target_cpu, core->core_thread) != 0) {
553             PrintError(vm, core, "Failed to move Vcore %d to CPU %d\n", 
554                        core->vcpu_id, target_cpu);
555             v3_lower_barrier(vm);
556             return -1;
557         } 
558         
559         /* There will be a benign race window here:
560            core->pcpu_id will be set to the target core before its fully "migrated"
561            However the core will NEVER run on the old core again, its just in flight to the new core
562         */
563         core->pcpu_id = target_cpu;
564
565         V3_Print(vm, core, "core now at %d\n", core->pcpu_id);  
566     }
567
568     v3_lower_barrier(vm);
569
570     return 0;
571 }
572
573
574
575 int v3_stop_vm(struct v3_vm_info * vm) {
576
577     if ((vm->run_state != VM_RUNNING) && 
578         (vm->run_state != VM_SIMULATING)) {
579         PrintError(vm, VCORE_NONE,"Tried to stop VM in invalid runstate (%d)\n", vm->run_state);
580         return -1;
581     }
582
583     vm->run_state = VM_STOPPED;
584
585     // Sanity check to catch any weird execution states
586     if (v3_wait_for_barrier(vm, NULL) == 0) {
587         v3_lower_barrier(vm);
588     }
589     
590     // XXX force exit all cores via a cross call/IPI XXX
591
592     while (1) {
593         int i = 0;
594         int still_running = 0;
595
596         for (i = 0; i < vm->num_cores; i++) {
597             if (vm->cores[i].core_run_state != CORE_STOPPED) {
598                 still_running = 1;
599             }
600         }
601
602         if (still_running == 0) {
603             break;
604         }
605
606         v3_yield(NULL,-1);
607     }
608     
609     V3_Print(vm, VCORE_NONE,"VM stopped. Returning\n");
610
611     return 0;
612 }
613
614
615 int v3_pause_vm(struct v3_vm_info * vm) {
616
617     if (vm->run_state != VM_RUNNING) {
618         PrintError(vm, VCORE_NONE,"Tried to pause a VM that was not running\n");
619         return -1;
620     }
621
622     while (v3_raise_barrier(vm, NULL) == -1);
623
624     vm->run_state = VM_PAUSED;
625
626     return 0;
627 }
628
629
630 int v3_continue_vm(struct v3_vm_info * vm) {
631
632     if (vm->run_state != VM_PAUSED) {
633         PrintError(vm, VCORE_NONE,"Tried to continue a VM that was not paused\n");
634         return -1;
635     }
636
637     vm->run_state = VM_RUNNING;
638
639     v3_lower_barrier(vm);
640
641     return 0;
642 }
643
644
645
646 static int sim_callback(struct guest_info * core, void * private_data) {
647     struct v3_bitmap * timeout_map = private_data;
648
649     v3_bitmap_set(timeout_map, core->vcpu_id);
650     
651     V3_Print(core->vm_info, core, "Simulation callback activated (guest_rip=%p)\n", (void *)core->rip);
652
653     while (v3_bitmap_check(timeout_map, core->vcpu_id) == 1) {
654         v3_yield(NULL,-1);
655     }
656
657     return 0;
658 }
659
660
661
662
663 int v3_simulate_vm(struct v3_vm_info * vm, unsigned int msecs) {
664     struct v3_bitmap timeout_map;
665     int i = 0;
666     int all_blocked = 0;
667     uint64_t cycles = 0;
668     uint64_t cpu_khz = V3_CPU_KHZ();
669
670     if (vm->run_state != VM_PAUSED) {
671         PrintError(vm, VCORE_NONE,"VM must be paused before simulation begins\n");
672         return -1;
673     }
674
675     /* AT this point VM is paused */
676     
677     // initialize bitmap
678     v3_bitmap_init(&timeout_map, vm->num_cores);
679
680
681
682
683     // calculate cycles from msecs...
684     // IMPORTANT: Floating point not allowed.
685     cycles = (msecs * cpu_khz);
686     
687
688
689     V3_Print(vm, VCORE_NONE,"Simulating %u msecs (%llu cycles) [CPU_KHZ=%llu]\n", msecs, cycles, cpu_khz);
690
691     // set timeout
692     
693     for (i = 0; i < vm->num_cores; i++) {
694         if (v3_add_core_timeout(&(vm->cores[i]), cycles, sim_callback, &timeout_map) == -1) {
695             PrintError(vm, VCORE_NONE,"Could not register simulation timeout for core %d\n", i);
696             return -1;
697         }
698     }
699
700     V3_Print(vm, VCORE_NONE,"timeouts set on all cores\n ");
701
702     
703     // Run the simulation
704 //    vm->run_state = VM_SIMULATING;
705     vm->run_state = VM_RUNNING;
706     v3_lower_barrier(vm);
707
708
709     V3_Print(vm, VCORE_NONE,"Barrier lowered: We are now Simulating!!\n");
710
711     // block until simulation is complete    
712     while (all_blocked == 0) {
713         all_blocked = 1;
714
715         for (i = 0; i < vm->num_cores; i++) {
716             if (v3_bitmap_check(&timeout_map, i)  == 0) {
717                 all_blocked = 0;
718             }
719         }
720
721         if (all_blocked == 1) {
722             break;
723         }
724
725         v3_yield(NULL,-1);
726     }
727
728
729     V3_Print(vm, VCORE_NONE,"Simulation is complete\n");
730
731     // Simulation is complete
732     // Reset back to PAUSED state
733
734     v3_raise_barrier_nowait(vm, NULL);
735     vm->run_state = VM_PAUSED;
736     
737     v3_bitmap_reset(&timeout_map);
738
739     v3_wait_for_barrier(vm, NULL);
740
741     return 0;
742
743 }
744
745 int v3_get_state_vm(struct v3_vm_info *vm, struct v3_vm_state *s)
746 {
747   uint32_t i;
748   uint32_t numcores = s->num_vcores > vm->num_cores ? vm->num_cores : s->num_vcores;
749
750   switch (vm->run_state) { 
751   case VM_INVALID: s->state = V3_VM_INVALID; break;
752   case VM_RUNNING: s->state = V3_VM_RUNNING; break;
753   case VM_STOPPED: s->state = V3_VM_STOPPED; break;
754   case VM_PAUSED: s->state = V3_VM_PAUSED; break;
755   case VM_ERROR: s->state = V3_VM_ERROR; break;
756   case VM_SIMULATING: s->state = V3_VM_SIMULATING; break;
757   default: s->state = V3_VM_UNKNOWN; break;
758   }
759
760   s->mem_base_paddr = (void*)(vm->mem_map.base_region.host_addr);
761   s->mem_size = vm->mem_size;
762
763   s->num_vcores = numcores;
764
765   for (i=0;i<numcores;i++) {
766     switch (vm->cores[i].core_run_state) {
767     case CORE_INVALID: s->vcore[i].state = V3_VCORE_INVALID; break;
768     case CORE_RUNNING: s->vcore[i].state = V3_VCORE_RUNNING; break;
769     case CORE_STOPPED: s->vcore[i].state = V3_VCORE_STOPPED; break;
770     default: s->vcore[i].state = V3_VCORE_UNKNOWN; break;
771     }
772     switch (vm->cores[i].cpu_mode) {
773     case REAL: s->vcore[i].cpu_mode = V3_VCORE_CPU_REAL; break;
774     case PROTECTED: s->vcore[i].cpu_mode = V3_VCORE_CPU_PROTECTED; break;
775     case PROTECTED_PAE: s->vcore[i].cpu_mode = V3_VCORE_CPU_PROTECTED_PAE; break;
776     case LONG: s->vcore[i].cpu_mode = V3_VCORE_CPU_LONG; break;
777     case LONG_32_COMPAT: s->vcore[i].cpu_mode = V3_VCORE_CPU_LONG_32_COMPAT; break;
778     case LONG_16_COMPAT: s->vcore[i].cpu_mode = V3_VCORE_CPU_LONG_16_COMPAT; break;
779     default: s->vcore[i].cpu_mode = V3_VCORE_CPU_UNKNOWN; break;
780     }
781     switch (vm->cores[i].shdw_pg_mode) { 
782     case SHADOW_PAGING: s->vcore[i].mem_state = V3_VCORE_MEM_STATE_SHADOW; break;
783     case NESTED_PAGING: s->vcore[i].mem_state = V3_VCORE_MEM_STATE_NESTED; break;
784     default: s->vcore[i].mem_state = V3_VCORE_MEM_STATE_UNKNOWN; break;
785     }
786     switch (vm->cores[i].mem_mode) { 
787     case PHYSICAL_MEM: s->vcore[i].mem_mode = V3_VCORE_MEM_MODE_PHYSICAL; break;
788     case VIRTUAL_MEM: s->vcore[i].mem_mode=V3_VCORE_MEM_MODE_VIRTUAL; break;
789     default: s->vcore[i].mem_mode=V3_VCORE_MEM_MODE_UNKNOWN; break;
790     }
791
792     s->vcore[i].pcore=vm->cores[i].pcpu_id;
793     s->vcore[i].last_rip=(void*)(vm->cores[i].rip);
794     s->vcore[i].num_exits=vm->cores[i].num_exits;
795   }
796
797   return 0;
798 }
799
800
801 #ifdef V3_CONFIG_CHECKPOINT
802 #include <palacios/vmm_checkpoint.h>
803
804 int v3_save_vm(struct v3_vm_info * vm, char * store, char * url) {
805     return v3_chkpt_save_vm(vm, store, url);
806 }
807
808
809 int v3_load_vm(struct v3_vm_info * vm, char * store, char * url) {
810     return v3_chkpt_load_vm(vm, store, url);
811 }
812
813 #ifdef V3_CONFIG_LIVE_MIGRATION
814 int v3_send_vm(struct v3_vm_info * vm, char * store, char * url) {
815     return v3_chkpt_send_vm(vm, store, url);
816 }
817
818
819 int v3_receive_vm(struct v3_vm_info * vm, char * store, char * url) {
820     return v3_chkpt_receive_vm(vm, store, url);
821 }
822 #endif
823
824 #endif
825
826
827 int v3_free_vm(struct v3_vm_info * vm) {
828     int i = 0;
829     // deinitialize guest (free memory, etc...)
830
831     if ((vm->run_state != VM_STOPPED) &&
832         (vm->run_state != VM_ERROR)) {
833         PrintError(vm, VCORE_NONE,"Tried to Free VM in invalid runstate (%d)\n", vm->run_state);
834         return -1;
835     }
836
837     v3_free_vm_devices(vm);
838
839     // free cores
840     for (i = 0; i < vm->num_cores; i++) {
841         v3_free_core(&(vm->cores[i]));
842     }
843
844     // free vm
845     v3_free_vm_internal(vm);
846
847     v3_free_config(vm);
848
849     V3_Free(vm);
850
851     return 0;
852 }
853
854
855 #ifdef __V3_32BIT__
856
857 v3_cpu_mode_t v3_get_host_cpu_mode() {
858     uint32_t cr4_val;
859     struct cr4_32 * cr4;
860
861     __asm__ (
862              "movl %%cr4, %0; "
863              : "=r"(cr4_val) 
864              );
865
866     
867     cr4 = (struct cr4_32 *)&(cr4_val);
868
869     if (cr4->pae == 1) {
870         return PROTECTED_PAE;
871     } else {
872         return PROTECTED;
873     }
874 }
875
876 #elif __V3_64BIT__
877
878 v3_cpu_mode_t v3_get_host_cpu_mode() {
879     return LONG;
880 }
881
882 #endif 
883
884 void v3_print_cond(const char * fmt, ...) {
885     if (v3_dbg_enable == 1) {
886         char buf[2048];
887         va_list ap;
888
889         va_start(ap, fmt);
890         vsnprintf(buf, 2048, fmt, ap);
891         va_end(ap);
892
893         V3_Print(VM_NONE, VCORE_NONE,"%s", buf);
894     }    
895 }
896
897
898
899 void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector) {
900     extern struct v3_os_hooks * os_hooks;
901
902     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
903         (os_hooks)->interrupt_cpu(vm, logical_cpu, vector);
904     }
905 }
906
907
908
909 int v3_vm_enter(struct guest_info * info) {
910     switch (v3_mach_type) {
911 #ifdef V3_CONFIG_SVM
912         case V3_SVM_CPU:
913         case V3_SVM_REV3_CPU:
914             return v3_svm_enter(info);
915             break;
916 #endif
917 #if V3_CONFIG_VMX
918         case V3_VMX_CPU:
919         case V3_VMX_EPT_CPU:
920         case V3_VMX_EPT_UG_CPU:
921             return v3_vmx_enter(info);
922             break;
923 #endif
924         default:
925             PrintError(info->vm_info, info, "Attemping to enter a guest on an invalid CPU\n");
926             return -1;
927     }
928 }
929
930
931 void    *v3_get_host_vm(struct v3_vm_info *x)
932 {
933   if (x) { 
934     return x->host_priv_data;
935   } else {
936     return 0;
937   }
938 }
939
940 int v3_get_vcore(struct guest_info *x)
941 {
942   if (x) {
943     return x->vcpu_id;
944   } else {
945     return -1;
946   }
947 }