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.


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