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