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.


6257294a8a5435284d14d3557e807e6af43116ed
[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 #include <palacios/vmm_direct_paging.h>
33 #include <interfaces/vmm_numa.h>
34 #include <interfaces/vmm_file.h>
35
36 #ifdef V3_CONFIG_SVM
37 #include <palacios/svm.h>
38 #endif
39 #ifdef V3_CONFIG_VMX
40 #include <palacios/vmx.h>
41 #endif
42
43 #ifdef V3_CONFIG_CHECKPOINT
44 #include <palacios/vmm_checkpoint.h>
45 #endif
46
47
48 v3_cpu_arch_t v3_cpu_types[V3_CONFIG_MAX_CPUS];
49 v3_cpu_arch_t v3_mach_type = V3_INVALID_CPU;
50
51 struct v3_os_hooks * os_hooks = NULL;
52 int v3_dbg_enable = 0;
53
54
55
56 static void init_cpu(void * arg) {
57     uint32_t cpu_id = (uint32_t)(addr_t)arg;
58
59     v3_init_fp();
60
61 #ifdef V3_CONFIG_SVM
62     if (v3_is_svm_capable()) {
63         PrintDebug(VM_NONE, VCORE_NONE, "Machine is SVM Capable\n");
64         v3_init_svm_cpu(cpu_id);
65         
66     } else 
67 #endif
68 #ifdef V3_CONFIG_VMX
69     if (v3_is_vmx_capable()) {
70         PrintDebug(VM_NONE, VCORE_NONE, "Machine is VMX Capable\n");
71         v3_init_vmx_cpu(cpu_id);
72
73     } else 
74 #endif
75     {
76        PrintError(VM_NONE, VCORE_NONE, "CPU has no virtualization Extensions\n");
77     }
78 }
79
80
81 static void deinit_cpu(void * arg) {
82     uint32_t cpu_id = (uint32_t)(addr_t)arg;
83
84
85     switch (v3_cpu_types[cpu_id]) {
86 #ifdef V3_CONFIG_SVM
87         case V3_SVM_CPU:
88         case V3_SVM_REV3_CPU:
89             PrintDebug(VM_NONE, VCORE_NONE, "Deinitializing SVM CPU %d\n", cpu_id);
90             v3_deinit_svm_cpu(cpu_id);
91             break;
92 #endif
93 #ifdef V3_CONFIG_VMX
94         case V3_VMX_CPU:
95         case V3_VMX_EPT_CPU:
96         case V3_VMX_EPT_UG_CPU:
97             PrintDebug(VM_NONE, VCORE_NONE, "Deinitializing VMX CPU %d\n", cpu_id);
98             v3_deinit_vmx_cpu(cpu_id);
99             break;
100 #endif
101         case V3_INVALID_CPU:
102         default:
103             PrintError(VM_NONE, VCORE_NONE, "CPU has no virtualization Extensions\n");
104             break;
105     }
106
107     v3_deinit_fp();
108
109 }
110
111
112 static int in_long_mode()
113 {
114   uint32_t high, low;
115
116   v3_get_msr(0xc0000080,&high,&low); // EFER
117   
118   return ((low & 0x500)== 0x500);  // LMA and LME set
119 }
120   
121
122 void Init_V3(struct v3_os_hooks * hooks, char * cpu_mask, int num_cpus, char *options) {
123     int i = 0;
124     int minor = 0;
125     int major = 0;
126
127     V3_Print(VM_NONE, VCORE_NONE, "V3 Print statement to fix a Kitten page fault bug\n");
128
129
130
131 #ifndef __V3_64BIT__
132 #error Palacios does not support compilation for a 32 bit host OS!!!!
133 #else
134     if (!in_long_mode()) { 
135       PrintError(VM_NONE,VCORE_NONE,"Palacios supports execution only in long mode (64 bit).\n");
136       return;
137     }
138 #endif
139
140     // Set global variables. 
141     os_hooks = hooks;
142
143     if (num_cpus>V3_CONFIG_MAX_CPUS) { 
144         PrintError(VM_NONE,VCORE_NONE, "Requesting as many as %d cpus, but Palacios is compiled for a maximum of %d.  Only the first %d cpus will be considered\n", num_cpus, V3_CONFIG_MAX_CPUS, V3_CONFIG_MAX_CPUS);
145     }
146
147     // Determine the global machine type
148     v3_mach_type = V3_INVALID_CPU;
149
150     for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
151         v3_cpu_types[i] = V3_INVALID_CPU;
152     }
153
154     // Parse host-os defined options into an easily-accessed format.
155     v3_parse_options(options);
156
157 #ifdef V3_CONFIG_MULTIBOOT
158     v3_init_multiboot();
159 #endif
160
161 #ifdef V3_CONFIG_HVM
162     v3_init_hvm();
163 #endif
164
165     // Memory manager initialization
166     v3_init_mem();
167
168     // Register all the possible device types
169     V3_init_devices();
170
171     // Register all shadow paging handlers
172     V3_init_shdw_paging();
173
174 #ifdef V3_CONFIG_SWAPPING
175     v3_init_swapping();
176 #endif
177
178     // Initialize the cpu_mapper framework (must be before extensions)
179     V3_init_cpu_mapper();
180
181     // Initialize the scheduler framework (must be before extensions)
182     V3_init_scheduling();
183  
184     // Register all extensions
185     V3_init_extensions();
186
187     // Enabling cpu_mapper
188     V3_enable_cpu_mapper();
189
190     // Enabling scheduler
191     V3_enable_scheduler();
192
193
194 #ifdef V3_CONFIG_SYMMOD
195     V3_init_symmod();
196 #endif
197
198 #ifdef V3_CONFIG_CHECKPOINT
199     V3_init_checkpoint();
200 #endif
201
202     if ((hooks) && (hooks->call_on_cpu)) {
203
204         for (i = 0; i < num_cpus && i < V3_CONFIG_MAX_CPUS; i++) {
205             major = i / 8;
206             minor = i % 8;
207
208             if ((cpu_mask == NULL) || (*(cpu_mask + major) & (0x1 << minor))) {
209                 V3_Print(VM_NONE, VCORE_NONE, "Initializing VMM extensions on cpu %d\n", i);
210                 hooks->call_on_cpu(i, &init_cpu, (void *)(addr_t)i);
211
212                 if (v3_mach_type == V3_INVALID_CPU) {
213                     v3_mach_type = v3_cpu_types[i];
214                 }   
215             }
216         }
217     }
218 }
219
220
221
222 void Shutdown_V3() {
223     int i;
224
225     // Reverse order of Init_V3
226
227     // bring down CPUs
228
229     if ((os_hooks) && (os_hooks->call_on_cpu)) {
230         for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
231             if (v3_cpu_types[i] != V3_INVALID_CPU) {
232                 V3_Call_On_CPU(i, deinit_cpu, (void *)(addr_t)i);
233                 //deinit_cpu((void *)(addr_t)i);
234             }
235         }
236     }
237
238 #ifdef V3_CONFIG_CHECKPOINT
239     V3_deinit_checkpoint();
240 #endif
241
242 #ifdef V3_CONFIG_SYMMOD
243     V3_deinit_symmod();
244 #endif
245
246     V3_disable_scheduler();
247
248     V3_disable_cpu_mapper();
249
250     V3_deinit_extensions();
251
252     V3_deinit_scheduling();
253     
254     V3_deinit_cpu_mapper();
255
256 #ifdef V3_CONFIG_SWAPPING
257     v3_deinit_swapping();
258 #endif
259     
260     V3_deinit_shdw_paging();
261     
262     V3_deinit_devices();
263
264     v3_deinit_mem();
265     
266 #ifdef V3_CONFIG_HVM
267     v3_deinit_hvm();
268 #endif
269
270 #ifdef V3_CONFIG_MULTIBOOT
271     v3_deinit_multiboot();
272 #endif
273
274     v3_deinit_options();
275     
276
277 }
278
279
280 v3_cpu_arch_t v3_get_cpu_type(int cpu_id) {
281     return v3_cpu_types[cpu_id];
282 }
283
284 static int start_core(void * p)
285 {
286     struct guest_info * core = (struct guest_info *)p;
287
288     if (v3_scheduler_register_core(core) == -1){
289         PrintError(core->vm_info, core,"Error initializing scheduling in core %d\n", core->vcpu_id);
290     }
291
292     PrintDebug(core->vm_info,core,"virtual core %u (on logical core %u): in start_core (RIP=%p)\n",
293                core->vcpu_id, core->pcpu_id, (void *)(addr_t)core->rip);
294
295     switch (v3_mach_type) {
296 #ifdef V3_CONFIG_SVM
297         case V3_SVM_CPU:
298         case V3_SVM_REV3_CPU:
299             return v3_start_svm_guest(core);
300             break;
301 #endif
302 #if V3_CONFIG_VMX
303         case V3_VMX_CPU:
304         case V3_VMX_EPT_CPU:
305         case V3_VMX_EPT_UG_CPU:
306             return v3_start_vmx_guest(core);
307             break;
308 #endif
309         default:
310             PrintError(core->vm_info, core, "Attempting to enter a guest on an invalid CPU\n");
311             return -1;
312     }
313     // should not happen
314     return 0;
315 }
316
317 struct v3_vm_info * v3_create_vm(void * cfg, void * priv_data, char * name, unsigned int cpu_mask) {
318     struct v3_vm_info * vm = v3_config_guest(cfg, priv_data);
319     int vcore_id = 0;
320
321     if (vm == NULL) {
322         PrintError(VM_NONE, VCORE_NONE, "Could not configure guest\n");
323         return NULL;
324     }
325
326     V3_Print(vm, VCORE_NONE, "CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
327
328     if (name == NULL) {
329         name = "[V3_VM]";
330     } else if (strlen(name) >= 128) {
331         PrintError(vm, VCORE_NONE,"VM name is too long. Will be truncated to 128 chars.\n");
332     }
333
334     memset(vm->name, 0, 128);
335     strncpy(vm->name, name, 127);
336
337     if(v3_cpu_mapper_register_vm(vm) == -1) {
338
339         PrintError(vm, VCORE_NONE,"Error registering VM with cpu_mapper\n");
340     }
341
342     /*
343      * Register this VM with the palacios scheduler. It will ask for admission
344      * prior to launch.
345      */
346     if(v3_scheduler_register_vm(vm) == -1) {
347     
348         PrintError(vm, VCORE_NONE,"Error registering VM with scheduler\n");
349     }
350
351     if (v3_cpu_mapper_admit_vm(vm,cpu_mask) != 0){
352         PrintError(vm, VCORE_NONE,"Error admitting VM %s for mapping", vm->name);
353     }
354
355     for (vcore_id = 0; vcore_id < vm->num_cores; vcore_id++) {
356
357         struct guest_info * core = &(vm->cores[vcore_id]);
358
359         PrintDebug(vm, VCORE_NONE, "Creating virtual core %u on logical core %u\n",
360                    vcore_id, core->pcpu_id);
361
362         sprintf(core->exec_name, "%s-%u", vm->name, vcore_id);
363
364         PrintDebug(vm, VCORE_NONE, "run: core=%u, func=0x%p, arg=0x%p, name=%s\n",
365                    core->pcpu_id, start_core, core, core->exec_name);
366
367         core->core_thread = V3_CREATE_THREAD_ON_CPU(core->pcpu_id, start_core, core, core->exec_name);
368
369         if (core->core_thread == NULL) {
370             PrintError(vm, VCORE_NONE, "Thread creation failed\n");
371             v3_stop_vm(vm);
372             return NULL;
373         }
374
375     }
376     return vm;
377 }
378
379 int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
380
381     uint32_t i;
382     uint8_t * core_mask = (uint8_t *)&cpu_mask; // This is to make future expansion easier
383     uint32_t avail_cores = 0;
384     int vcore_id = 0;
385
386     if (!vm) { 
387         PrintError(VM_NONE, VCORE_NONE, "Asked to start nonexistent VM\n");
388         return -1;
389     }
390
391     if (vm->run_state != VM_STOPPED) {
392         PrintError(vm, VCORE_NONE, "VM has already been launched (state=%d)\n", (int)vm->run_state);
393         return -1;
394     }
395
396 #if V3_CONFIG_MULTIBOOT
397     if (v3_setup_multiboot_vm_for_boot(vm)) { 
398         PrintError(vm, VCORE_NONE, "Multiboot setup for boot failed\n");
399         return -1;
400     }
401 #endif
402 #if V3_CONFIG_HVM
403     if (v3_setup_hvm_vm_for_boot(vm)) { 
404         PrintError(vm, VCORE_NONE, "HVM setup for boot failed\n");
405         return -1;
406     }
407 #endif
408
409     /// CHECK IF WE ARE MULTICORE ENABLED....
410
411     V3_Print(vm, VCORE_NONE, "V3 --  Starting VM (%u cores)\n", vm->num_cores);
412     V3_Print(vm, VCORE_NONE, "CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
413
414
415     // Check that enough cores are present in the mask to handle vcores
416     for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
417         int major = i / 8;
418         int minor = i % 8;
419         
420         if (core_mask[major] & (0x1 << minor)) {
421             if (v3_cpu_types[i] == V3_INVALID_CPU) {
422                 core_mask[major] &= ~(0x1 << minor);
423             } else {
424                 avail_cores++;
425             }
426         }
427     }
428
429     vm->avail_cores = avail_cores;
430
431     if (v3_scheduler_admit_vm(vm) != 0){
432        PrintError(vm, VCORE_NONE,"Error admitting VM %s for scheduling", vm->name);
433     }
434
435     vm->run_state = VM_RUNNING;
436
437     for (vcore_id = 0; vcore_id < vm->num_cores; vcore_id++) {
438
439         struct guest_info * core = &(vm->cores[vcore_id]);
440
441         PrintDebug(vm, VCORE_NONE, "Starting virtual core %u on logical core %u\n", 
442                    vcore_id, core->pcpu_id);
443
444         if (core->core_run_state==CORE_INVALID) {
445           // launch of a fresh VM
446           core->core_run_state = CORE_STOPPED;
447           // core zero will turn itself on
448         } else {
449           // this is a resume - use whatever its current run_state is
450         }
451
452         V3_START_THREAD(core->core_thread);
453
454     }
455
456     return 0;
457
458 }
459
460
461 int v3_reset_vm_core(struct guest_info * core, addr_t rip) {
462     
463     switch (v3_cpu_types[core->pcpu_id]) {
464 #ifdef V3_CONFIG_SVM
465         case V3_SVM_CPU:
466         case V3_SVM_REV3_CPU:
467             PrintDebug(core->vm_info, core, "Resetting SVM Guest CPU %d\n", core->vcpu_id);
468             return v3_reset_svm_vm_core(core, rip);
469 #endif
470 #ifdef V3_CONFIG_VMX
471         case V3_VMX_CPU:
472         case V3_VMX_EPT_CPU:
473         case V3_VMX_EPT_UG_CPU:
474             PrintDebug(core->vm_info, core, "Resetting VMX Guest CPU %d\n", core->vcpu_id);
475             return v3_reset_vmx_vm_core(core, rip);
476 #endif
477         case V3_INVALID_CPU:
478         default:
479             PrintError(core->vm_info, core, "CPU has no virtualization Extensions\n");
480             break;
481     }
482
483     return -1;
484 }
485
486
487
488 /* move a virtual core to different physical core */
489 int v3_move_vm_core(struct v3_vm_info * vm, int vcore_id, int target_cpu) {
490     struct guest_info * core = NULL;
491
492     if (!vm) { 
493         PrintError(VM_NONE, VCORE_NONE, "Asked to move core of nonexistent VM\n");
494         return -1;
495     }
496
497     if ((vcore_id < 0) || (vcore_id >= vm->num_cores)) {
498         PrintError(vm, VCORE_NONE, "Attempted to migrate invalid virtual core (%d)\n", vcore_id);
499         return -1;
500     }
501
502     core = &(vm->cores[vcore_id]);
503
504     if (target_cpu == core->pcpu_id) {
505         PrintError(vm,  core, "Attempted to migrate to local core (%d)\n", target_cpu);
506         // well that was pointless
507         return 0;
508     }
509
510     if (core->core_thread == NULL) {
511         PrintError(vm, core, "Attempted to migrate a core without a valid thread context\n");
512         return -1;
513     }
514
515     while (v3_raise_barrier(vm, NULL) == -1);
516
517     V3_Print(vm, core, "Performing Migration from %d to %d\n", core->pcpu_id, target_cpu);
518
519     // Double check that we weren't preemptively migrated
520     if (target_cpu != core->pcpu_id) {    
521
522         V3_Print(vm, core, "Moving Core\n");
523
524         if(v3_cpu_mapper_admit_core(vm, vcore_id, target_cpu) == -1){
525                 PrintError(vm, core, "Core %d can not be admitted in cpu %d\n",vcore_id, target_cpu);
526                 return -1;
527         }
528
529
530 #ifdef V3_CONFIG_VMX
531         switch (v3_cpu_types[core->pcpu_id]) {
532             case V3_VMX_CPU:
533             case V3_VMX_EPT_CPU:
534             case V3_VMX_EPT_UG_CPU:
535                 PrintDebug(vm, core, "Flushing VMX Guest CPU %d\n", core->vcpu_id);
536                 V3_Call_On_CPU(core->pcpu_id, (void (*)(void *))v3_flush_vmx_vm_core, (void *)core);
537                 break;
538             default:
539                 break;
540         }
541 #endif
542
543         if (V3_MOVE_THREAD_TO_CPU(target_cpu, core->core_thread) != 0) {
544             PrintError(vm, core, "Failed to move Vcore %d to CPU %d\n", 
545                        core->vcpu_id, target_cpu);
546             v3_lower_barrier(vm);
547             return -1;
548         } 
549         
550         /* There will be a benign race window here:
551            core->pcpu_id will be set to the target core before its fully "migrated"
552            However the core will NEVER run on the old core again, its just in flight to the new core
553         */
554         core->pcpu_id = target_cpu;
555
556         V3_Print(vm, core, "core now at %d\n", core->pcpu_id);  
557     }
558
559     v3_lower_barrier(vm);
560
561     return 0;
562 }
563
564 /* move a memory region to memory with affinity for a specific physical core */
565 int v3_move_vm_mem(struct v3_vm_info * vm, void *gpa, int target_cpu) {
566     int old_node;
567     int new_node;
568     struct v3_mem_region *reg;
569     void *new_hpa;
570     int num_pages;
571     void *old_hpa;
572     int i;
573
574     if (!vm) { 
575         PrintError(VM_NONE, VCORE_NONE, "Asked to move memory of nonexistent VM\n");
576         return -1;
577     }
578
579     old_node = v3_numa_gpa_to_node(vm,(addr_t)gpa);
580
581     if (old_node<0) { 
582         PrintError(vm, VCORE_NONE, "Cannot determine current node of gpa %p\n",gpa);
583         return -1;
584     }
585
586     new_node = v3_numa_cpu_to_node(target_cpu);
587
588     if (new_node<0) { 
589         PrintError(vm, VCORE_NONE, "Cannot determine current node of cpu %d\n",target_cpu);
590         return -1;
591     }
592
593     if (new_node==old_node) { 
594         PrintDebug(vm, VCORE_NONE, "Affinity is already established - ignoring request\n");
595         return 0;
596     }
597
598     // We are now going to change the universe, so 
599     // we'll barrier everyone first
600
601     while (v3_raise_barrier(vm, NULL) == -1);
602
603     // get region
604     
605     reg = v3_get_mem_region(vm, V3_MEM_CORE_ANY, (addr_t) gpa);
606
607     if (!reg) { 
608         PrintError(vm, VCORE_NONE, "Attempt to migrate non-existent memory\n");
609         goto out_fail;
610     }
611     
612     if (!(reg->flags.base) || !(reg->flags.alloced)) { 
613         PrintError(vm, VCORE_NONE, "Attempt to migrate invalid region: base=%d alloced=%d\n", reg->flags.base, reg->flags.alloced);
614         goto out_fail;
615     }
616
617     // we now have the allocated base region corresponding to  - and not a copy
618     // we will rewrite this region after moving its contents
619     
620     // first, let's double check that we are in fact changing the numa_id...
621
622     if (reg->numa_id==new_node) { 
623         PrintDebug(vm, VCORE_NONE, "Affinity for this base region is already established - ignoring...\n");
624         goto out_success;
625     }
626
627     // region uses exclusive addressing [guest_start,guest_end)
628     num_pages = (reg->guest_end-reg->guest_start)/PAGE_SIZE;
629
630     new_hpa = V3_AllocPagesExtended(num_pages,
631                                     PAGE_SIZE_4KB,
632                                     new_node,
633                                     0, 0);  // no constraints given new shadow pager impl
634
635     if (!new_hpa) { 
636         PrintError(vm, VCORE_NONE, "Cannot allocate memory for new base region...\n");
637         goto out_fail;
638     }
639
640     // Note, assumes virtual contiguity in the host OS... 
641     memcpy(V3_VAddr((void*)new_hpa), V3_VAddr((void*)(reg->host_addr)), num_pages*PAGE_SIZE);
642
643     old_hpa = (void*)(reg->host_addr);
644     old_node = (int)(reg->numa_id);
645
646     reg->host_addr = (addr_t)new_hpa;
647     reg->numa_id = v3_numa_hpa_to_node((addr_t)new_hpa);
648
649     // flush all page tables / kill all humans 
650
651     for (i=0;i<vm->num_cores;i++) { 
652         if (vm->cores[i].shdw_pg_mode==SHADOW_PAGING) { 
653             v3_invalidate_shadow_pts(&(vm->cores[i]));
654         } else if (vm->cores[i].shdw_pg_mode==NESTED_PAGING) { 
655             // nested invalidator uses inclusive addressing [start,end], not [start,end)
656           v3_invalidate_nested_addr_range(&(vm->cores[i]),reg->guest_start,reg->guest_end-1,NULL,NULL);
657         } else {
658             PrintError(vm,VCORE_NONE, "Cannot determine how to invalidate paging structures! Reverting to previous region.\n");
659             // We'll restore things...
660             reg->host_addr = (addr_t) old_hpa;
661             reg->numa_id = old_node;
662             V3_FreePages(new_hpa,num_pages);
663             goto out_fail;
664         }
665     }
666     
667     // Now the old region can go away...
668     V3_FreePages(old_hpa,num_pages);
669     
670     PrintDebug(vm,VCORE_NONE,"Migration of memory complete - new region is %p to %p\n",
671                (void*)(reg->host_addr),(void*)(reg->host_addr+num_pages*PAGE_SIZE-1));
672     
673  out_success:
674     v3_lower_barrier(vm);
675     return 0;
676     
677     
678  out_fail:
679     v3_lower_barrier(vm);
680     return -1;
681 }
682
683 int v3_stop_vm(struct v3_vm_info * vm) {
684
685     struct guest_info * running_core;
686
687     if (!vm) { 
688         PrintError(VM_NONE, VCORE_NONE, "Asked to stop nonexistent VM\n");
689         return -1;
690     }
691
692     if ((vm->run_state != VM_RUNNING) && 
693         (vm->run_state != VM_SIMULATING)) {
694         PrintError(vm, VCORE_NONE,"Tried to stop VM in invalid runstate (%d)\n", vm->run_state);
695         return -1;
696     }
697
698     vm->run_state = VM_STOPPED;
699
700     // Sanity check to catch any weird execution states
701     if (v3_wait_for_barrier(vm, NULL) == 0) {
702         v3_lower_barrier(vm);
703     }
704     
705     // XXX force exit all cores via a cross call/IPI XXX
706
707     while (1) {
708         int i = 0;
709         int still_running = 0;
710
711         for (i = 0; i < vm->num_cores; i++) {
712             if (vm->cores[i].core_run_state != CORE_STOPPED) {
713                 running_core = &vm->cores[i];
714                 still_running = 1;
715             }
716         }
717
718         if (still_running == 0) {
719             break;
720         }
721
722         v3_scheduler_stop_core(running_core);
723     }
724     
725     V3_Print(vm, VCORE_NONE,"VM stopped. Returning\n");
726
727     return 0;
728 }
729
730
731 int v3_pause_vm(struct v3_vm_info * vm) {
732
733     if (!vm) { 
734         PrintError(VM_NONE, VCORE_NONE, "Asked to pause nonexistent VM\n");
735         return -1;
736     }
737
738     if (vm->run_state != VM_RUNNING) {
739         PrintError(vm, VCORE_NONE,"Tried to pause a VM that was not running\n");
740         return -1;
741     }
742
743     while (v3_raise_barrier(vm, NULL) == -1);
744
745     vm->run_state = VM_PAUSED;
746
747     return 0;
748 }
749
750
751 int v3_continue_vm(struct v3_vm_info * vm) {
752
753     if (!vm) { 
754         PrintError(VM_NONE, VCORE_NONE, "Asked to continue nonexistent VM\n");
755         return -1;
756     }
757
758     if (vm->run_state != VM_PAUSED) {
759         PrintError(vm, VCORE_NONE,"Tried to continue a VM that was not paused\n");
760         return -1;
761     }
762
763     vm->run_state = VM_RUNNING;
764
765     v3_lower_barrier(vm);
766
767     return 0;
768 }
769
770
771
772 static int sim_callback(struct guest_info * core, void * private_data) {
773     struct v3_bitmap * timeout_map = private_data;
774
775     v3_bitmap_set(timeout_map, core->vcpu_id);
776     
777     V3_Print(core->vm_info, core, "Simulation callback activated (guest_rip=%p)\n", (void *)core->rip);
778
779     while (v3_bitmap_check(timeout_map, core->vcpu_id) == 1) {
780         // We spin here if there is noone to yield to
781         v3_yield(NULL,-1);
782     }
783
784     return 0;
785 }
786
787
788
789
790 int v3_simulate_vm(struct v3_vm_info * vm, unsigned int msecs) {
791     struct v3_bitmap timeout_map;
792     int i = 0;
793     int all_blocked = 0;
794     uint64_t cycles = 0;
795     uint64_t cpu_khz = V3_CPU_KHZ();
796
797     if (!vm) { 
798         PrintError(VM_NONE, VCORE_NONE, "Asked to simulate nonexistent VM\n");
799         return -1;
800     }
801
802     if (vm->run_state != VM_PAUSED) {
803         PrintError(vm, VCORE_NONE,"VM must be paused before simulation begins\n");
804         return -1;
805     }
806
807     /* AT this point VM is paused */
808     
809     // initialize bitmap
810     v3_bitmap_init(&timeout_map, vm->num_cores);
811
812
813
814
815     // calculate cycles from msecs...
816     // IMPORTANT: Floating point not allowed.
817     cycles = (msecs * cpu_khz);
818     
819
820
821     V3_Print(vm, VCORE_NONE,"Simulating %u msecs (%llu cycles) [CPU_KHZ=%llu]\n", msecs, cycles, cpu_khz);
822
823     // set timeout
824     
825     for (i = 0; i < vm->num_cores; i++) {
826         if (v3_add_core_timeout(&(vm->cores[i]), cycles, sim_callback, &timeout_map) == -1) {
827             PrintError(vm, VCORE_NONE,"Could not register simulation timeout for core %d\n", i);
828             return -1;
829         }
830     }
831
832     V3_Print(vm, VCORE_NONE,"timeouts set on all cores\n ");
833
834     
835     // Run the simulation
836 //    vm->run_state = VM_SIMULATING;
837     vm->run_state = VM_RUNNING;
838     v3_lower_barrier(vm);
839
840
841     V3_Print(vm, VCORE_NONE,"Barrier lowered: We are now Simulating!!\n");
842
843     // block until simulation is complete    
844     while (all_blocked == 0) {
845         all_blocked = 1;
846
847         for (i = 0; i < vm->num_cores; i++) {
848             if (v3_bitmap_check(&timeout_map, i)  == 0) {
849                 all_blocked = 0;
850             }
851         }
852
853         if (all_blocked == 1) {
854             break;
855         }
856         
857         // Intentionally spin if there is no one to yield to
858         v3_yield(NULL,-1);
859     }
860
861
862     V3_Print(vm, VCORE_NONE,"Simulation is complete\n");
863
864     // Simulation is complete
865     // Reset back to PAUSED state
866
867     v3_raise_barrier_nowait(vm, NULL);
868     vm->run_state = VM_PAUSED;
869     
870     v3_bitmap_reset(&timeout_map);
871
872     v3_wait_for_barrier(vm, NULL);
873
874     return 0;
875
876 }
877
878 int v3_get_state_vm(struct v3_vm_info        *vm, 
879                     struct v3_vm_base_state  *base,
880                     struct v3_vm_core_state  *core,
881                     struct v3_vm_mem_state   *mem)
882 {
883     uint32_t i;
884     uint32_t numcores;
885     uint32_t numregions; 
886     extern uint64_t v3_mem_block_size;
887
888     if (!vm || !base || !core || !mem)  { 
889         PrintError(VM_NONE, VCORE_NONE, "Invalid rquest to v3_get_state_vm\n");
890         return -1;
891     }
892
893     numcores = core->num_vcores > vm->num_cores ? vm->num_cores : core->num_vcores;
894     numregions = mem->num_regions > vm->mem_map.num_base_regions ? vm->mem_map.num_base_regions : mem->num_regions;
895
896     switch (vm->run_state) { 
897         case VM_INVALID: base->state = V3_VM_INVALID; break;
898         case VM_RUNNING: base->state = V3_VM_RUNNING; break;
899         case VM_STOPPED: base->state = V3_VM_STOPPED; break;
900         case VM_PAUSED: base->state = V3_VM_PAUSED; break;
901         case VM_ERROR: base->state = V3_VM_ERROR; break;
902         case VM_SIMULATING: base->state = V3_VM_SIMULATING; break;
903         default: base->state = V3_VM_UNKNOWN; break;
904     }
905
906     for (i=0;i<numcores;i++) {
907         switch (vm->cores[i].core_run_state) {
908             case CORE_INVALID: core->vcore[i].state = V3_VCORE_INVALID; break;
909             case CORE_RUNNING: core->vcore[i].state = V3_VCORE_RUNNING; break;
910             case CORE_STOPPED: core->vcore[i].state = V3_VCORE_STOPPED; break;
911             default: core->vcore[i].state = V3_VCORE_UNKNOWN; break;
912         }
913         switch (vm->cores[i].cpu_mode) {
914             case REAL: core->vcore[i].cpu_mode = V3_VCORE_CPU_REAL; break;
915             case PROTECTED: core->vcore[i].cpu_mode = V3_VCORE_CPU_PROTECTED; break;
916             case PROTECTED_PAE: core->vcore[i].cpu_mode = V3_VCORE_CPU_PROTECTED_PAE; break;
917             case LONG: core->vcore[i].cpu_mode = V3_VCORE_CPU_LONG; break;
918             case LONG_32_COMPAT: core->vcore[i].cpu_mode = V3_VCORE_CPU_LONG_32_COMPAT; break;
919             case LONG_16_COMPAT: core->vcore[i].cpu_mode = V3_VCORE_CPU_LONG_16_COMPAT; break;
920             default: core->vcore[i].cpu_mode = V3_VCORE_CPU_UNKNOWN; break;
921         }
922         switch (vm->cores[i].shdw_pg_mode) { 
923             case SHADOW_PAGING: core->vcore[i].mem_state = V3_VCORE_MEM_STATE_SHADOW; break;
924             case NESTED_PAGING: core->vcore[i].mem_state = V3_VCORE_MEM_STATE_NESTED; break;
925             default: core->vcore[i].mem_state = V3_VCORE_MEM_STATE_UNKNOWN; break;
926         }
927         switch (vm->cores[i].mem_mode) { 
928             case PHYSICAL_MEM: core->vcore[i].mem_mode = V3_VCORE_MEM_MODE_PHYSICAL; break;
929             case VIRTUAL_MEM: core->vcore[i].mem_mode=V3_VCORE_MEM_MODE_VIRTUAL; break;
930             default: core->vcore[i].mem_mode=V3_VCORE_MEM_MODE_UNKNOWN; break;
931         }
932         
933         core->vcore[i].pcore=vm->cores[i].pcpu_id;
934         core->vcore[i].last_rip=(void*)(vm->cores[i].rip);
935         core->vcore[i].num_exits=vm->cores[i].num_exits;
936     }
937     
938     core->num_vcores=numcores;
939
940     for (i=0;i<numregions;i++) {
941         mem->region[i].host_paddr =  (void*)(vm->mem_map.base_regions[i].host_addr);
942         mem->region[i].size = v3_mem_block_size;
943 #ifdef V3_CONFIG_SWAPPING
944         mem->region[i].swapped = vm->mem_map.base_regions[i].flags.swapped;
945         mem->region[i].pinned = vm->mem_map.base_regions[i].flags.pinned;
946 #else
947         mem->region[i].swapped = 0;
948         mem->region[i].pinned = 0;
949 #endif
950
951     }
952
953     mem->num_regions=numregions;
954     
955     return 0;
956 }
957
958
959 #ifdef V3_CONFIG_CHECKPOINT
960 #include <palacios/vmm_checkpoint.h>
961
962 int v3_save_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
963     if (!vm || !store || !url) {
964         PrintError(VM_NONE,VCORE_NONE, "Incorrect arguemnts for v3_save_vm\n");
965         return -1;
966     }
967     return v3_chkpt_save_vm(vm, store, url, opts);
968 }
969
970
971 int v3_load_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
972     if (!vm || !store || !url) {
973         PrintError(VM_NONE,VCORE_NONE, "Incorrect arguemnts for v3_load_vm\n");
974         return -1;
975     }
976     return v3_chkpt_load_vm(vm, store, url, opts);
977 }
978
979 #ifdef V3_CONFIG_LIVE_MIGRATION
980 int v3_send_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
981     if (!vm || !store || !url) {
982         PrintError(VM_NONE,VCORE_NONE, "Incorrect arguemnts for v3_send_vm\n");
983         return -1;
984     }
985     return v3_chkpt_send_vm(vm, store, url, opts);
986 }
987
988
989 int v3_receive_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
990     if (!vm || !store || !url) {
991         PrintError(VM_NONE,VCORE_NONE, "Incorrect arguemnts for v3_receive_vm\n");
992         return -1;
993     }
994     return v3_chkpt_receive_vm(vm, store, url, opts);
995 }
996 #endif
997
998 #endif
999
1000
1001 int v3_free_vm(struct v3_vm_info * vm) {
1002     int i = 0;
1003     // deinitialize guest (free memory, etc...)
1004
1005     if (!vm) { 
1006         PrintError(VM_NONE, VCORE_NONE, "Asked to free nonexistent VM\n");
1007         return -1;
1008     }
1009
1010     if ((vm->run_state != VM_STOPPED) &&
1011         (vm->run_state != VM_ERROR)) {
1012         PrintError(vm, VCORE_NONE,"Tried to Free VM in invalid runstate (%d)\n", vm->run_state);
1013         return -1;
1014     }
1015
1016     v3_free_vm_devices(vm);
1017
1018     // free cores
1019     for (i = 0; i < vm->num_cores; i++) {
1020         v3_scheduler_free_core(&(vm->cores[i]));
1021         v3_free_core(&(vm->cores[i]));
1022     }
1023
1024     // free vm
1025     v3_scheduler_free_vm(vm);
1026     v3_free_vm_internal(vm);
1027
1028     v3_free_config(vm);
1029
1030     V3_Free(vm);
1031
1032     return 0;
1033 }
1034
1035
1036 #ifdef __V3_32BIT__
1037
1038 v3_cpu_mode_t v3_get_host_cpu_mode() {
1039     uint32_t cr4_val;
1040     struct cr4_32 * cr4;
1041
1042     __asm__ (
1043              "movl %%cr4, %0; "
1044              : "=r"(cr4_val) 
1045              );
1046
1047     
1048     cr4 = (struct cr4_32 *)&(cr4_val);
1049
1050     if (cr4->pae == 1) {
1051         return PROTECTED_PAE;
1052     } else {
1053         return PROTECTED;
1054     }
1055 }
1056
1057 #elif __V3_64BIT__
1058
1059 v3_cpu_mode_t v3_get_host_cpu_mode() {
1060     return LONG;
1061 }
1062
1063 #endif 
1064
1065 void v3_print_cond(const char * fmt, ...) {
1066     if (v3_dbg_enable == 1) {
1067         char buf[2048];
1068         va_list ap;
1069
1070         va_start(ap, fmt);
1071         vsnprintf(buf, 2048, fmt, ap);
1072         va_end(ap);
1073
1074         V3_Print(VM_NONE, VCORE_NONE,"%s", buf);
1075     }    
1076 }
1077
1078
1079
1080 void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector) {
1081     extern struct v3_os_hooks * os_hooks;
1082
1083     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
1084         (os_hooks)->interrupt_cpu(vm, logical_cpu, vector);
1085     }
1086 }
1087
1088
1089
1090 int v3_vm_enter(struct guest_info * info) {
1091     switch (v3_mach_type) {
1092 #ifdef V3_CONFIG_SVM
1093         case V3_SVM_CPU:
1094         case V3_SVM_REV3_CPU:
1095             return v3_svm_enter(info);
1096             break;
1097 #endif
1098 #if V3_CONFIG_VMX
1099         case V3_VMX_CPU:
1100         case V3_VMX_EPT_CPU:
1101         case V3_VMX_EPT_UG_CPU:
1102             return v3_vmx_enter(info);
1103             break;
1104 #endif
1105         default:
1106             PrintError(info->vm_info, info, "Attemping to enter a guest on an invalid CPU\n");
1107             return -1;
1108     }
1109 }
1110
1111
1112 void    *v3_get_host_vm(struct v3_vm_info *x)
1113 {
1114   if (x) { 
1115     return x->host_priv_data;
1116   } else {
1117     return 0;
1118   }
1119 }
1120
1121 int v3_get_vcore(struct guest_info *x)
1122 {
1123   if (x) {
1124     return x->vcpu_id;
1125   } else {
1126     return -1;
1127   }
1128 }