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.


Basic HRT startup for HVM, plus assorted cleanup
[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 #if V3_CONFIG_HVM
389     if (v3_setup_hvm_vm_for_boot(vm)) { 
390         PrintError(vm, VCORE_NONE, "HVM setup for boot failed\n");
391         return -1;
392     }
393 #endif
394
395     /// CHECK IF WE ARE MULTICORE ENABLED....
396
397     V3_Print(vm, VCORE_NONE, "V3 --  Starting VM (%u cores)\n", vm->num_cores);
398     V3_Print(vm, VCORE_NONE, "CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
399
400
401     // Check that enough cores are present in the mask to handle vcores
402     for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
403         int major = i / 8;
404         int minor = i % 8;
405         
406         if (core_mask[major] & (0x1 << minor)) {
407             if (v3_cpu_types[i] == V3_INVALID_CPU) {
408                 core_mask[major] &= ~(0x1 << minor);
409             } else {
410                 avail_cores++;
411             }
412         }
413     }
414
415     vm->avail_cores = avail_cores;
416
417     if (v3_scheduler_admit_vm(vm) != 0){
418        PrintError(vm, VCORE_NONE,"Error admitting VM %s for scheduling", vm->name);
419     }
420
421     vm->run_state = VM_RUNNING;
422
423     for (vcore_id = 0; vcore_id < vm->num_cores; vcore_id++) {
424
425         struct guest_info * core = &(vm->cores[vcore_id]);
426
427         PrintDebug(vm, VCORE_NONE, "Starting virtual core %u on logical core %u\n", 
428                    vcore_id, core->pcpu_id);
429
430         if (core->core_run_state==CORE_INVALID) {
431           // launch of a fresh VM
432           core->core_run_state = CORE_STOPPED;
433           // core zero will turn itself on
434         } else {
435           // this is a resume - use whatever its current run_state is
436         }
437
438         V3_START_THREAD(core->core_thread);
439
440     }
441
442     return 0;
443
444 }
445
446
447 int v3_reset_vm_core(struct guest_info * core, addr_t rip) {
448     
449     switch (v3_cpu_types[core->pcpu_id]) {
450 #ifdef V3_CONFIG_SVM
451         case V3_SVM_CPU:
452         case V3_SVM_REV3_CPU:
453             PrintDebug(core->vm_info, core, "Resetting SVM Guest CPU %d\n", core->vcpu_id);
454             return v3_reset_svm_vm_core(core, rip);
455 #endif
456 #ifdef V3_CONFIG_VMX
457         case V3_VMX_CPU:
458         case V3_VMX_EPT_CPU:
459         case V3_VMX_EPT_UG_CPU:
460             PrintDebug(core->vm_info, core, "Resetting VMX Guest CPU %d\n", core->vcpu_id);
461             return v3_reset_vmx_vm_core(core, rip);
462 #endif
463         case V3_INVALID_CPU:
464         default:
465             PrintError(core->vm_info, core, "CPU has no virtualization Extensions\n");
466             break;
467     }
468
469     return -1;
470 }
471
472
473
474 /* move a virtual core to different physical core */
475 int v3_move_vm_core(struct v3_vm_info * vm, int vcore_id, int target_cpu) {
476     struct guest_info * core = NULL;
477
478     if (!vm) { 
479         PrintError(VM_NONE, VCORE_NONE, "Asked to move core of nonexistent VM\n");
480         return -1;
481     }
482
483     if ((vcore_id < 0) || (vcore_id >= vm->num_cores)) {
484         PrintError(vm, VCORE_NONE, "Attempted to migrate invalid virtual core (%d)\n", vcore_id);
485         return -1;
486     }
487
488     core = &(vm->cores[vcore_id]);
489
490     if (target_cpu == core->pcpu_id) {
491         PrintError(vm,  core, "Attempted to migrate to local core (%d)\n", target_cpu);
492         // well that was pointless
493         return 0;
494     }
495
496     if (core->core_thread == NULL) {
497         PrintError(vm, core, "Attempted to migrate a core without a valid thread context\n");
498         return -1;
499     }
500
501     while (v3_raise_barrier(vm, NULL) == -1);
502
503     V3_Print(vm, core, "Performing Migration from %d to %d\n", core->pcpu_id, target_cpu);
504
505     // Double check that we weren't preemptively migrated
506     if (target_cpu != core->pcpu_id) {    
507
508         V3_Print(vm, core, "Moving Core\n");
509
510         if(v3_cpu_mapper_admit_core(vm, vcore_id, target_cpu) == -1){
511                 PrintError(vm, core, "Core %d can not be admitted in cpu %d\n",vcore_id, target_cpu);
512                 return -1;
513         }
514
515
516 #ifdef V3_CONFIG_VMX
517         switch (v3_cpu_types[core->pcpu_id]) {
518             case V3_VMX_CPU:
519             case V3_VMX_EPT_CPU:
520             case V3_VMX_EPT_UG_CPU:
521                 PrintDebug(vm, core, "Flushing VMX Guest CPU %d\n", core->vcpu_id);
522                 V3_Call_On_CPU(core->pcpu_id, (void (*)(void *))v3_flush_vmx_vm_core, (void *)core);
523                 break;
524             default:
525                 break;
526         }
527 #endif
528
529         if (V3_MOVE_THREAD_TO_CPU(target_cpu, core->core_thread) != 0) {
530             PrintError(vm, core, "Failed to move Vcore %d to CPU %d\n", 
531                        core->vcpu_id, target_cpu);
532             v3_lower_barrier(vm);
533             return -1;
534         } 
535         
536         /* There will be a benign race window here:
537            core->pcpu_id will be set to the target core before its fully "migrated"
538            However the core will NEVER run on the old core again, its just in flight to the new core
539         */
540         core->pcpu_id = target_cpu;
541
542         V3_Print(vm, core, "core now at %d\n", core->pcpu_id);  
543     }
544
545     v3_lower_barrier(vm);
546
547     return 0;
548 }
549
550 /* move a memory region to memory with affinity for a specific physical core */
551 int v3_move_vm_mem(struct v3_vm_info * vm, void *gpa, int target_cpu) {
552     int old_node;
553     int new_node;
554     struct v3_mem_region *reg;
555     void *new_hpa;
556     int num_pages;
557     void *old_hpa;
558     int i;
559
560     if (!vm) { 
561         PrintError(VM_NONE, VCORE_NONE, "Asked to move memory of nonexistent VM\n");
562         return -1;
563     }
564
565     old_node = v3_numa_gpa_to_node(vm,(addr_t)gpa);
566
567     if (old_node<0) { 
568         PrintError(vm, VCORE_NONE, "Cannot determine current node of gpa %p\n",gpa);
569         return -1;
570     }
571
572     new_node = v3_numa_cpu_to_node(target_cpu);
573
574     if (new_node<0) { 
575         PrintError(vm, VCORE_NONE, "Cannot determine current node of cpu %d\n",target_cpu);
576         return -1;
577     }
578
579     if (new_node==old_node) { 
580         PrintDebug(vm, VCORE_NONE, "Affinity is already established - ignoring request\n");
581         return 0;
582     }
583
584     // We are now going to change the universe, so 
585     // we'll barrier everyone first
586
587     while (v3_raise_barrier(vm, NULL) == -1);
588
589     // get region
590     
591     reg = v3_get_mem_region(vm, V3_MEM_CORE_ANY, (addr_t) gpa);
592
593     if (!reg) { 
594         PrintError(vm, VCORE_NONE, "Attempt to migrate non-existent memory\n");
595         goto out_fail;
596     }
597     
598     if (!(reg->flags.base) || !(reg->flags.alloced)) { 
599         PrintError(vm, VCORE_NONE, "Attempt to migrate invalid region: base=%d alloced=%d\n", reg->flags.base, reg->flags.alloced);
600         goto out_fail;
601     }
602
603     // we now have the allocated base region corresponding to  - and not a copy
604     // we will rewrite this region after moving its contents
605     
606     // first, let's double check that we are in fact changing the numa_id...
607
608     if (reg->numa_id==new_node) { 
609         PrintDebug(vm, VCORE_NONE, "Affinity for this base region is already established - ignoring...\n");
610         goto out_success;
611     }
612
613     // region uses exclusive addressing [guest_start,guest_end)
614     num_pages = (reg->guest_end-reg->guest_start)/PAGE_SIZE;
615
616     new_hpa = V3_AllocPagesExtended(num_pages,
617                                     PAGE_SIZE_4KB,
618                                     new_node,
619                                     0);  // no constraints given new shadow pager impl
620
621     if (!new_hpa) { 
622         PrintError(vm, VCORE_NONE, "Cannot allocate memory for new base region...\n");
623         goto out_fail;
624     }
625
626     // Note, assumes virtual contiguity in the host OS... 
627     memcpy(V3_VAddr((void*)new_hpa), V3_VAddr((void*)(reg->host_addr)), num_pages*PAGE_SIZE);
628
629     old_hpa = (void*)(reg->host_addr);
630     old_node = (int)(reg->numa_id);
631
632     reg->host_addr = (addr_t)new_hpa;
633     reg->numa_id = v3_numa_hpa_to_node((addr_t)new_hpa);
634
635     // flush all page tables / kill all humans 
636
637     for (i=0;i<vm->num_cores;i++) { 
638         if (vm->cores[i].shdw_pg_mode==SHADOW_PAGING) { 
639             v3_invalidate_shadow_pts(&(vm->cores[i]));
640         } else if (vm->cores[i].shdw_pg_mode==NESTED_PAGING) { 
641             // nested invalidator uses inclusive addressing [start,end], not [start,end)
642           v3_invalidate_nested_addr_range(&(vm->cores[i]),reg->guest_start,reg->guest_end-1,NULL,NULL);
643         } else {
644             PrintError(vm,VCORE_NONE, "Cannot determine how to invalidate paging structures! Reverting to previous region.\n");
645             // We'll restore things...
646             reg->host_addr = (addr_t) old_hpa;
647             reg->numa_id = old_node;
648             V3_FreePages(new_hpa,num_pages);
649             goto out_fail;
650         }
651     }
652     
653     // Now the old region can go away...
654     V3_FreePages(old_hpa,num_pages);
655     
656     PrintDebug(vm,VCORE_NONE,"Migration of memory complete - new region is %p to %p\n",
657                (void*)(reg->host_addr),(void*)(reg->host_addr+num_pages*PAGE_SIZE-1));
658     
659  out_success:
660     v3_lower_barrier(vm);
661     return 0;
662     
663     
664  out_fail:
665     v3_lower_barrier(vm);
666     return -1;
667 }
668
669 int v3_stop_vm(struct v3_vm_info * vm) {
670
671     struct guest_info * running_core;
672
673     if (!vm) { 
674         PrintError(VM_NONE, VCORE_NONE, "Asked to stop nonexistent VM\n");
675         return -1;
676     }
677
678     if ((vm->run_state != VM_RUNNING) && 
679         (vm->run_state != VM_SIMULATING)) {
680         PrintError(vm, VCORE_NONE,"Tried to stop VM in invalid runstate (%d)\n", vm->run_state);
681         return -1;
682     }
683
684     vm->run_state = VM_STOPPED;
685
686     // Sanity check to catch any weird execution states
687     if (v3_wait_for_barrier(vm, NULL) == 0) {
688         v3_lower_barrier(vm);
689     }
690     
691     // XXX force exit all cores via a cross call/IPI XXX
692
693     while (1) {
694         int i = 0;
695         int still_running = 0;
696
697         for (i = 0; i < vm->num_cores; i++) {
698             if (vm->cores[i].core_run_state != CORE_STOPPED) {
699                 running_core = &vm->cores[i];
700                 still_running = 1;
701             }
702         }
703
704         if (still_running == 0) {
705             break;
706         }
707
708         v3_scheduler_stop_core(running_core);
709     }
710     
711     V3_Print(vm, VCORE_NONE,"VM stopped. Returning\n");
712
713     return 0;
714 }
715
716
717 int v3_pause_vm(struct v3_vm_info * vm) {
718
719     if (!vm) { 
720         PrintError(VM_NONE, VCORE_NONE, "Asked to pause nonexistent VM\n");
721         return -1;
722     }
723
724     if (vm->run_state != VM_RUNNING) {
725         PrintError(vm, VCORE_NONE,"Tried to pause a VM that was not running\n");
726         return -1;
727     }
728
729     while (v3_raise_barrier(vm, NULL) == -1);
730
731     vm->run_state = VM_PAUSED;
732
733     return 0;
734 }
735
736
737 int v3_continue_vm(struct v3_vm_info * vm) {
738
739     if (!vm) { 
740         PrintError(VM_NONE, VCORE_NONE, "Asked to continue nonexistent VM\n");
741         return -1;
742     }
743
744     if (vm->run_state != VM_PAUSED) {
745         PrintError(vm, VCORE_NONE,"Tried to continue a VM that was not paused\n");
746         return -1;
747     }
748
749     vm->run_state = VM_RUNNING;
750
751     v3_lower_barrier(vm);
752
753     return 0;
754 }
755
756
757
758 static int sim_callback(struct guest_info * core, void * private_data) {
759     struct v3_bitmap * timeout_map = private_data;
760
761     v3_bitmap_set(timeout_map, core->vcpu_id);
762     
763     V3_Print(core->vm_info, core, "Simulation callback activated (guest_rip=%p)\n", (void *)core->rip);
764
765     while (v3_bitmap_check(timeout_map, core->vcpu_id) == 1) {
766         // We spin here if there is noone to yield to
767         v3_yield(NULL,-1);
768     }
769
770     return 0;
771 }
772
773
774
775
776 int v3_simulate_vm(struct v3_vm_info * vm, unsigned int msecs) {
777     struct v3_bitmap timeout_map;
778     int i = 0;
779     int all_blocked = 0;
780     uint64_t cycles = 0;
781     uint64_t cpu_khz = V3_CPU_KHZ();
782
783     if (!vm) { 
784         PrintError(VM_NONE, VCORE_NONE, "Asked to simulate nonexistent VM\n");
785         return -1;
786     }
787
788     if (vm->run_state != VM_PAUSED) {
789         PrintError(vm, VCORE_NONE,"VM must be paused before simulation begins\n");
790         return -1;
791     }
792
793     /* AT this point VM is paused */
794     
795     // initialize bitmap
796     v3_bitmap_init(&timeout_map, vm->num_cores);
797
798
799
800
801     // calculate cycles from msecs...
802     // IMPORTANT: Floating point not allowed.
803     cycles = (msecs * cpu_khz);
804     
805
806
807     V3_Print(vm, VCORE_NONE,"Simulating %u msecs (%llu cycles) [CPU_KHZ=%llu]\n", msecs, cycles, cpu_khz);
808
809     // set timeout
810     
811     for (i = 0; i < vm->num_cores; i++) {
812         if (v3_add_core_timeout(&(vm->cores[i]), cycles, sim_callback, &timeout_map) == -1) {
813             PrintError(vm, VCORE_NONE,"Could not register simulation timeout for core %d\n", i);
814             return -1;
815         }
816     }
817
818     V3_Print(vm, VCORE_NONE,"timeouts set on all cores\n ");
819
820     
821     // Run the simulation
822 //    vm->run_state = VM_SIMULATING;
823     vm->run_state = VM_RUNNING;
824     v3_lower_barrier(vm);
825
826
827     V3_Print(vm, VCORE_NONE,"Barrier lowered: We are now Simulating!!\n");
828
829     // block until simulation is complete    
830     while (all_blocked == 0) {
831         all_blocked = 1;
832
833         for (i = 0; i < vm->num_cores; i++) {
834             if (v3_bitmap_check(&timeout_map, i)  == 0) {
835                 all_blocked = 0;
836             }
837         }
838
839         if (all_blocked == 1) {
840             break;
841         }
842         
843         // Intentionally spin if there is no one to yield to
844         v3_yield(NULL,-1);
845     }
846
847
848     V3_Print(vm, VCORE_NONE,"Simulation is complete\n");
849
850     // Simulation is complete
851     // Reset back to PAUSED state
852
853     v3_raise_barrier_nowait(vm, NULL);
854     vm->run_state = VM_PAUSED;
855     
856     v3_bitmap_reset(&timeout_map);
857
858     v3_wait_for_barrier(vm, NULL);
859
860     return 0;
861
862 }
863
864 int v3_get_state_vm(struct v3_vm_info        *vm, 
865                     struct v3_vm_base_state  *base,
866                     struct v3_vm_core_state  *core,
867                     struct v3_vm_mem_state   *mem)
868 {
869     uint32_t i;
870     uint32_t numcores;
871     uint32_t numregions; 
872     extern uint64_t v3_mem_block_size;
873
874     if (!vm || !base || !core || !mem)  { 
875         PrintError(VM_NONE, VCORE_NONE, "Invalid rquest to v3_get_state_vm\n");
876         return -1;
877     }
878
879     numcores = core->num_vcores > vm->num_cores ? vm->num_cores : core->num_vcores;
880     numregions = mem->num_regions > vm->mem_map.num_base_regions ? vm->mem_map.num_base_regions : mem->num_regions;
881
882     switch (vm->run_state) { 
883         case VM_INVALID: base->state = V3_VM_INVALID; break;
884         case VM_RUNNING: base->state = V3_VM_RUNNING; break;
885         case VM_STOPPED: base->state = V3_VM_STOPPED; break;
886         case VM_RESETTING:  base->state = V3_VM_RESETTING; break;
887         case VM_PAUSED: base->state = V3_VM_PAUSED; break;
888         case VM_ERROR: base->state = V3_VM_ERROR; break;
889         case VM_SIMULATING: base->state = V3_VM_SIMULATING; break;
890         default: base->state = V3_VM_UNKNOWN; break;
891     }
892
893     for (i=0;i<numcores;i++) {
894         switch (vm->cores[i].core_run_state) {
895             case CORE_INVALID: core->vcore[i].state = V3_VCORE_INVALID; break;
896             case CORE_RUNNING: core->vcore[i].state = V3_VCORE_RUNNING; break;
897             case CORE_STOPPED: core->vcore[i].state = V3_VCORE_STOPPED; break;
898             default: core->vcore[i].state = V3_VCORE_UNKNOWN; break;
899         }
900         switch (vm->cores[i].cpu_mode) {
901             case REAL: core->vcore[i].cpu_mode = V3_VCORE_CPU_REAL; break;
902             case PROTECTED: core->vcore[i].cpu_mode = V3_VCORE_CPU_PROTECTED; break;
903             case PROTECTED_PAE: core->vcore[i].cpu_mode = V3_VCORE_CPU_PROTECTED_PAE; break;
904             case LONG: core->vcore[i].cpu_mode = V3_VCORE_CPU_LONG; break;
905             case LONG_32_COMPAT: core->vcore[i].cpu_mode = V3_VCORE_CPU_LONG_32_COMPAT; break;
906             case LONG_16_COMPAT: core->vcore[i].cpu_mode = V3_VCORE_CPU_LONG_16_COMPAT; break;
907             default: core->vcore[i].cpu_mode = V3_VCORE_CPU_UNKNOWN; break;
908         }
909         switch (vm->cores[i].shdw_pg_mode) { 
910             case SHADOW_PAGING: core->vcore[i].mem_state = V3_VCORE_MEM_STATE_SHADOW; break;
911             case NESTED_PAGING: core->vcore[i].mem_state = V3_VCORE_MEM_STATE_NESTED; break;
912             default: core->vcore[i].mem_state = V3_VCORE_MEM_STATE_UNKNOWN; break;
913         }
914         switch (vm->cores[i].mem_mode) { 
915             case PHYSICAL_MEM: core->vcore[i].mem_mode = V3_VCORE_MEM_MODE_PHYSICAL; break;
916             case VIRTUAL_MEM: core->vcore[i].mem_mode=V3_VCORE_MEM_MODE_VIRTUAL; break;
917             default: core->vcore[i].mem_mode=V3_VCORE_MEM_MODE_UNKNOWN; break;
918         }
919         
920         core->vcore[i].pcore=vm->cores[i].pcpu_id;
921         core->vcore[i].last_rip=(void*)(vm->cores[i].rip);
922         core->vcore[i].num_exits=vm->cores[i].num_exits;
923     }
924     
925     core->num_vcores=numcores;
926
927     for (i=0;i<numregions;i++) {
928         mem->region[i].host_paddr =  (void*)(vm->mem_map.base_regions[i].host_addr);
929         mem->region[i].size = v3_mem_block_size;
930 #ifdef V3_CONFIG_SWAPPING
931         mem->region[i].swapped = vm->mem_map.base_regions[i].flags.swapped;
932         mem->region[i].pinned = vm->mem_map.base_regions[i].flags.pinned;
933 #else
934         mem->region[i].swapped = 0;
935         mem->region[i].pinned = 0;
936 #endif
937
938     }
939
940     mem->num_regions=numregions;
941     
942     return 0;
943 }
944
945
946 #ifdef V3_CONFIG_CHECKPOINT
947 #include <palacios/vmm_checkpoint.h>
948
949 int v3_save_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
950     if (!vm || !store || !url) {
951         PrintError(VM_NONE,VCORE_NONE, "Incorrect arguemnts for v3_save_vm\n");
952         return -1;
953     }
954     return v3_chkpt_save_vm(vm, store, url, opts);
955 }
956
957
958 int v3_load_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
959     if (!vm || !store || !url) {
960         PrintError(VM_NONE,VCORE_NONE, "Incorrect arguemnts for v3_load_vm\n");
961         return -1;
962     }
963     return v3_chkpt_load_vm(vm, store, url, opts);
964 }
965
966 #ifdef V3_CONFIG_LIVE_MIGRATION
967 int v3_send_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
968     if (!vm || !store || !url) {
969         PrintError(VM_NONE,VCORE_NONE, "Incorrect arguemnts for v3_send_vm\n");
970         return -1;
971     }
972     return v3_chkpt_send_vm(vm, store, url, opts);
973 }
974
975
976 int v3_receive_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
977     if (!vm || !store || !url) {
978         PrintError(VM_NONE,VCORE_NONE, "Incorrect arguemnts for v3_receive_vm\n");
979         return -1;
980     }
981     return v3_chkpt_receive_vm(vm, store, url, opts);
982 }
983 #endif
984
985 #endif
986
987
988 int v3_free_vm(struct v3_vm_info * vm) {
989     int i = 0;
990     // deinitialize guest (free memory, etc...)
991
992     if (!vm) { 
993         PrintError(VM_NONE, VCORE_NONE, "Asked to free nonexistent VM\n");
994         return -1;
995     }
996
997     if ((vm->run_state != VM_STOPPED) &&
998         (vm->run_state != VM_ERROR)) {
999         PrintError(vm, VCORE_NONE,"Tried to Free VM in invalid runstate (%d)\n", vm->run_state);
1000         return -1;
1001     }
1002
1003     v3_free_vm_devices(vm);
1004
1005     // free cores
1006     for (i = 0; i < vm->num_cores; i++) {
1007         v3_scheduler_free_core(&(vm->cores[i]));
1008         v3_free_core(&(vm->cores[i]));
1009     }
1010
1011     // free vm
1012     v3_scheduler_free_vm(vm);
1013     v3_free_vm_internal(vm);
1014
1015     v3_free_config(vm);
1016
1017     V3_Free(vm);
1018
1019     return 0;
1020 }
1021
1022
1023 #ifdef __V3_32BIT__
1024
1025 v3_cpu_mode_t v3_get_host_cpu_mode() {
1026     uint32_t cr4_val;
1027     struct cr4_32 * cr4;
1028
1029     __asm__ (
1030              "movl %%cr4, %0; "
1031              : "=r"(cr4_val) 
1032              );
1033
1034     
1035     cr4 = (struct cr4_32 *)&(cr4_val);
1036
1037     if (cr4->pae == 1) {
1038         return PROTECTED_PAE;
1039     } else {
1040         return PROTECTED;
1041     }
1042 }
1043
1044 #elif __V3_64BIT__
1045
1046 v3_cpu_mode_t v3_get_host_cpu_mode() {
1047     return LONG;
1048 }
1049
1050 #endif 
1051
1052 void v3_print_cond(const char * fmt, ...) {
1053     if (v3_dbg_enable == 1) {
1054         char buf[2048];
1055         va_list ap;
1056
1057         va_start(ap, fmt);
1058         vsnprintf(buf, 2048, fmt, ap);
1059         va_end(ap);
1060
1061         V3_Print(VM_NONE, VCORE_NONE,"%s", buf);
1062     }    
1063 }
1064
1065
1066
1067 void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector) {
1068     extern struct v3_os_hooks * os_hooks;
1069
1070     if ((os_hooks) && (os_hooks)->interrupt_cpu) {
1071         (os_hooks)->interrupt_cpu(vm, logical_cpu, vector);
1072     }
1073 }
1074
1075
1076
1077 int v3_vm_enter(struct guest_info * info) {
1078     switch (v3_mach_type) {
1079 #ifdef V3_CONFIG_SVM
1080         case V3_SVM_CPU:
1081         case V3_SVM_REV3_CPU:
1082             return v3_svm_enter(info);
1083             break;
1084 #endif
1085 #if V3_CONFIG_VMX
1086         case V3_VMX_CPU:
1087         case V3_VMX_EPT_CPU:
1088         case V3_VMX_EPT_UG_CPU:
1089             return v3_vmx_enter(info);
1090             break;
1091 #endif
1092         default:
1093             PrintError(info->vm_info, info, "Attemping to enter a guest on an invalid CPU\n");
1094             return -1;
1095     }
1096 }
1097
1098
1099 void    *v3_get_host_vm(struct v3_vm_info *x)
1100 {
1101   if (x) { 
1102     return x->host_priv_data;
1103   } else {
1104     return 0;
1105   }
1106 }
1107
1108 int v3_get_vcore(struct guest_info *x)
1109 {
1110   if (x) {
1111     return x->vcpu_id;
1112   } else {
1113     return -1;
1114   }
1115 }