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.


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