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.


Configuration of global performance parameters
[palacios.git] / palacios / src / palacios / vmm_config.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_config.h>
21 #include <palacios/vmm.h>
22 #include <palacios/vmm_debug.h>
23 #include <palacios/vmm_msr.h>
24 #include <palacios/vmm_decoder.h>
25 #include <palacios/vmm_telemetry.h>
26 #include <palacios/vmm_mem.h>
27 #include <palacios/vmm_hypercall.h>
28 #include <palacios/vmm_dev_mgr.h>
29 #include <palacios/vmm_cpuid.h>
30 #include <palacios/vmm_xml.h>
31 #include <palacios/vmm_io.h>
32 #include <palacios/vmm_msr.h>
33 #include <palacios/vmm_sprintf.h>
34
35
36
37
38
39 #include <palacios/vmm_host_events.h>
40 #include <palacios/vmm_perftune.h>
41
42 #include "vmm_config_class.h"
43
44
45 /* The Palacios cookie encodes "v3vee" followed by a 
46    3 byte version code.   There are currently two versions:
47
48     \0\0\0 => original (no checksum)
49     \0\0\1 => checksum
50 */
51 #define COOKIE_LEN 8
52 #define COOKIE_V0 "v3vee\0\0\0"
53 #define COOKIE_V1 "v3vee\0\0\1"
54
55
56
57
58 // This is used to access the configuration file index table
59 struct file_hdr_v0 {
60     uint32_t index;
61     uint32_t size;
62     uint64_t offset;
63 };
64
65 struct file_hdr_v1 {
66     uint32_t index;
67     uint32_t size;
68     uint64_t offset;
69     ulong_t  hash;
70 };
71
72
73 struct file_idx_table_v0 {
74     uint64_t num_files;
75     struct file_hdr_v0 hdrs[0];
76 };
77
78 struct file_idx_table_v1 {
79     uint64_t num_files;
80     struct file_hdr_v1 hdrs[0];
81 };
82
83
84
85
86 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg);
87 static int setup_extensions(struct v3_vm_info * vm, v3_cfg_tree_t * cfg);
88 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg);
89
90
91
92 char * v3_cfg_val(v3_cfg_tree_t * tree, char * tag) {
93     char * attrib = (char *)v3_xml_attr(tree, tag);
94     v3_cfg_tree_t * child_entry = v3_xml_child(tree, tag);
95     char * val = NULL;
96
97     if ((child_entry != NULL) && (attrib != NULL)) {
98         PrintError("Duplicate Configuration parameters present for %s\n", tag);
99         return NULL;
100     }
101
102     if (attrib == NULL) {
103         val = v3_xml_txt(child_entry);
104         
105         if ( val[0] == 0 )
106                 val = NULL;
107     } else {
108         val = attrib;
109     }
110     
111     return val;
112 }
113
114 v3_cfg_tree_t * v3_cfg_subtree(v3_cfg_tree_t * tree, char * tag) {
115     return v3_xml_child(tree, tag);
116 }
117
118 v3_cfg_tree_t * v3_cfg_next_branch(v3_cfg_tree_t * tree) {
119     return v3_xml_next(tree);
120 }
121
122
123
124 struct v3_cfg_file * v3_cfg_get_file(struct v3_vm_info * vm, char * tag) {
125     struct v3_cfg_file * file = NULL;
126
127     file = (struct v3_cfg_file *)v3_htable_search(vm->cfg_data->file_table, (addr_t)tag);
128
129     return file;
130 }
131
132
133 static uint_t file_hash_fn(addr_t key) {
134     char * name = (char *)key;
135     return v3_hash_buffer((uchar_t *)name, strlen(name));
136 }
137
138 static int file_eq_fn(addr_t key1, addr_t key2) {
139     char * name1 = (char *)key1;
140     char * name2 = (char *)key2;
141
142     return (strcmp(name1, name2) == 0);
143 }
144
145 static struct v3_config * parse_config(void * cfg_blob) {
146     struct v3_config * cfg = NULL;
147     int offset = 0;
148     uint_t xml_len = 0; 
149     struct file_idx_table_v0 * files_v0 = NULL;
150     struct file_idx_table_v1 * files_v1 = NULL;
151     v3_cfg_tree_t * file_tree = NULL;
152     int version=-1;
153
154     V3_Print("cfg data at %p\n", cfg_blob);
155
156     if (memcmp(cfg_blob, COOKIE_V0, COOKIE_LEN) == 0) {
157         version = 0;
158     } else if (memcmp(cfg_blob, COOKIE_V1, COOKIE_LEN) == 0) { 
159         version = 1;
160     } else {
161         PrintError("Invalid Configuration Header Or Unknown Version\n");
162         return NULL;
163     } 
164
165     V3_Print("Handling Palacios Image Format, Version 0x%x\n",version);
166
167     offset += COOKIE_LEN;
168
169     cfg = (struct v3_config *)V3_Malloc(sizeof(struct v3_config));
170
171     if (!cfg) {
172         PrintError("Unable to allocate while parsing\n");
173         return NULL;
174     }
175
176     memset(cfg, 0, sizeof(struct v3_config));
177
178     cfg->blob = cfg_blob;
179     INIT_LIST_HEAD(&(cfg->file_list));
180     cfg->file_table = v3_create_htable(0, file_hash_fn, file_eq_fn);
181
182     if (!(cfg->file_table)) {
183         PrintError("Unable to allocate hash table while parsing\n");
184         V3_Free(cfg);
185         return NULL;
186     }
187     
188     xml_len = *(uint32_t *)(cfg_blob + offset);
189     offset += 4;
190
191     cfg->cfg = (v3_cfg_tree_t *)v3_xml_parse((uint8_t *)(cfg_blob + offset));
192     offset += xml_len;
193    
194     offset += 8;
195
196     // This is hideous, but the file formats are still very close
197     if (version==0) { 
198         files_v0 = (struct file_idx_table_v0 *)(cfg_blob + offset);
199         V3_Print("Number of files in cfg: %d\n", (uint32_t)(files_v0->num_files));
200     } else {
201         files_v1 = (struct file_idx_table_v1 *)(cfg_blob + offset);
202         V3_Print("Number of files in cfg: %d\n", (uint32_t)(files_v1->num_files));
203     }
204
205
206     file_tree = v3_cfg_subtree(v3_cfg_subtree(cfg->cfg, "files"), "file");
207
208     while (file_tree) {
209         char * id = v3_cfg_val(file_tree, "id");
210         char * index = v3_cfg_val(file_tree, "index");
211         int idx = atoi(index);
212         struct v3_cfg_file * file = NULL;
213
214         file = (struct v3_cfg_file *)V3_Malloc(sizeof(struct v3_cfg_file));
215         
216         if (!file) {
217             PrintError("Could not allocate file structure\n");
218             v3_free_htable(cfg->file_table,0,0);
219             V3_Free(cfg);
220             return NULL;
221         }
222
223         V3_Print("File index=%d id=%s\n", idx, id);
224
225         strncpy(file->tag, id, V3_MAX_TAG_LEN);
226
227         if (version==0) { 
228             struct file_hdr_v0 * hdr = &(files_v0->hdrs[idx]);
229
230             file->size = hdr->size;
231             file->data = cfg_blob + hdr->offset;
232             file->hash = 0;
233             
234             V3_Print("Storing file data offset = %d, size=%d\n", (uint32_t)hdr->offset, hdr->size);
235             V3_Print("file data at %p\n", file->data);
236
237         } else if (version==1) { 
238             struct file_hdr_v1 * hdr = &(files_v1->hdrs[idx]);
239             unsigned long hash;
240
241             file->size = hdr->size;
242             file->data = cfg_blob + hdr->offset;
243             file->hash = hdr->hash;
244
245             V3_Print("Storing file data offset = %d, size=%d\n", (uint32_t)hdr->offset, hdr->size);
246             V3_Print("file data at %p\n", file->data);
247             V3_Print("Checking file data integrity...\n");
248             if ((hash = v3_hash_buffer(file->data, file->size)) != file->hash) {
249                 PrintError("File data corrupted! (orig hash=0x%lx, new=0x%lx\n",
250                            file->hash, hash);
251                 return NULL;
252             }
253             V3_Print("File data OK\n");
254             
255         }
256             
257             
258         list_add( &(file->file_node), &(cfg->file_list));
259
260         V3_Print("Keying file to name\n");
261         v3_htable_insert(cfg->file_table, (addr_t)(file->tag), (addr_t)(file));
262
263         V3_Print("Iterating to next file\n");
264
265         file_tree = v3_cfg_next_branch(file_tree);
266     }
267
268     V3_Print("Configuration parsed successfully\n");
269
270     return cfg;
271 }
272
273
274 static inline uint32_t get_alignment(char * align_str) {
275     // default is 4KB alignment
276     uint32_t alignment = PAGE_SIZE_4KB;
277
278     if (align_str != NULL) {
279         if (strcasecmp(align_str, "2MB") == 0) {
280             alignment = PAGE_SIZE_2MB;
281         } else if (strcasecmp(align_str, "4MB") == 0) {
282             alignment = PAGE_SIZE_4MB;
283         }
284     }
285     
286 #ifndef V3_CONFIG_ALIGNED_PG_ALLOC
287     if (alignment != PAGE_SIZE_4KB) {
288         PrintError("Aligned page allocations are not supported in this host (requested alignment=%d)\n", alignment);
289         PrintError("Ignoring alignment request\n");
290     }
291 #endif 
292
293     return alignment;
294 }
295
296
297 static int pre_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * vm_cfg) {
298     char * memory_str = v3_cfg_val(vm_cfg, "memory");
299     char * schedule_hz_str = v3_cfg_val(vm_cfg, "schedule_hz");
300     char * vm_class = v3_cfg_val(vm_cfg, "class");
301     char * align_str = v3_cfg_val(v3_cfg_subtree(vm_cfg, "memory"), "alignment");
302     uint32_t sched_hz = 100;    // set the schedule frequency to 100 HZ
303
304
305     if (!memory_str) {
306         PrintError("Memory is a required configuration parameter\n");
307         return -1;
308     }
309     
310     PrintDebug("Memory=%s\n", memory_str);
311     if (align_str) {
312          PrintDebug("Alignment=%s\n", align_str);
313     } else {
314          PrintDebug("Alignment defaulted to 4KB.\n");
315     }
316
317     // Amount of ram the Guest will have, always in MB
318     vm->mem_size = (addr_t)atoi(memory_str) * 1024 * 1024;
319     vm->mem_align = get_alignment(align_str);
320
321
322     PrintDebug("Alignment for %lu bytes of memory computed as 0x%x\n", vm->mem_size, vm->mem_align);
323
324     if (strcasecmp(vm_class, "PC") == 0) {
325         vm->vm_class = V3_PC_VM;
326     } else {
327         PrintError("Invalid VM class\n");
328         return -1;
329     }
330
331 #ifdef V3_CONFIG_TELEMETRY
332     {
333         char * telemetry = v3_cfg_val(vm_cfg, "telemetry");
334
335         // This should go first, because other subsystems will depend on the guest_info flag    
336         if ((telemetry) && (strcasecmp(telemetry, "enable") == 0)) {
337             vm->enable_telemetry = 1;
338         } else {
339             vm->enable_telemetry = 0;
340         }
341     }
342 #endif
343
344     if (v3_init_vm(vm) == -1) {
345         PrintError("Failed to initialize VM\n");
346         return -1;
347     }
348
349
350
351    if (schedule_hz_str) {
352         sched_hz = atoi(schedule_hz_str);
353     }
354
355     PrintDebug("CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(), 
356                (void *)(addr_t)sched_hz);
357
358     vm->yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
359     
360     return 0;
361 }
362
363
364 static int determine_paging_mode(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
365     extern v3_cpu_arch_t v3_mach_type;
366
367     v3_cfg_tree_t * vm_tree = info->vm_info->cfg_data->cfg;
368     v3_cfg_tree_t * pg_tree = v3_cfg_subtree(vm_tree, "paging");
369     char * pg_mode          = v3_cfg_val(pg_tree, "mode");
370     
371     PrintDebug("Paging mode specified as %s\n", pg_mode);
372
373     if (pg_mode) {
374         if ((strcasecmp(pg_mode, "nested") == 0)) {
375             // we assume symmetric cores, so if core 0 has nested paging they all do
376             if ((v3_mach_type == V3_SVM_REV3_CPU) || 
377                 (v3_mach_type == V3_VMX_EPT_CPU) ||
378                 (v3_mach_type == V3_VMX_EPT_UG_CPU)) {
379                 
380                 V3_Print("Setting paging mode to NESTED\n");
381                 info->shdw_pg_mode = NESTED_PAGING;
382             } else {
383                 PrintError("Nested paging not supported on this hardware. Defaulting to shadow paging\n");
384                 info->shdw_pg_mode = SHADOW_PAGING;
385             }
386         } else if ((strcasecmp(pg_mode, "shadow") == 0)) {
387             V3_Print("Setting paging mode to SHADOW\n");
388             info->shdw_pg_mode = SHADOW_PAGING;
389         } else {
390             PrintError("Invalid paging mode (%s) specified in configuration. Defaulting to shadow paging\n", pg_mode);
391             info->shdw_pg_mode = SHADOW_PAGING;
392         }
393     } else {
394         V3_Print("No paging type specified in configuration. Defaulting to shadow paging\n");
395         info->shdw_pg_mode = SHADOW_PAGING;
396     }
397
398
399     if (v3_cfg_val(pg_tree, "large_pages") != NULL) {
400         if (strcasecmp(v3_cfg_val(pg_tree, "large_pages"), "true") == 0) {
401             info->use_large_pages = 1;
402             PrintDebug("Use of large pages in memory virtualization enabled.\n");
403         }
404     }
405     return 0;
406 }
407
408 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
409     if (determine_paging_mode(info, core_cfg) != 0) {
410         return -1;
411     }
412
413     if (v3_init_core(info) == -1) {
414         PrintError("Error Initializing Core\n");
415         return -1;
416     }
417
418     if (info->vm_info->vm_class == V3_PC_VM) {
419         if (pre_config_pc_core(info, core_cfg) == -1) {
420             PrintError("PC Post configuration failure\n");
421             return -1;
422         }
423     } else {
424         PrintError("Invalid VM Class\n");
425         return -1;
426     }
427
428     return 0;
429 }
430
431
432
433 static int post_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
434     
435
436
437     // Configure the memory map for the guest
438     if (setup_memory_map(vm, cfg) == -1) {
439         PrintError("Setting up guest memory map failed...\n");
440         return -1;
441     }
442
443
444     if (vm->vm_class == V3_PC_VM) {
445         if (post_config_pc(vm, cfg) == -1) {
446             PrintError("PC Post configuration failure\n");
447             return -1;
448         }
449     } else {
450         PrintError("Invalid VM Class\n");
451         return -1;
452     }
453
454
455     /* 
456      * Initialize configured devices
457      */
458     if (setup_devices(vm, cfg) == -1) {
459         PrintError("Failed to setup devices\n");
460         return -1;
461     }
462
463
464     //    v3_print_io_map(info);
465     v3_print_msr_map(vm);
466
467
468
469
470     /* 
471      * Initialize configured extensions 
472      */
473     if (setup_extensions(vm, cfg) == -1) {
474         PrintError("Failed to setup extensions\n");
475         return -1;
476     }
477
478     if (v3_setup_performance_tuning(vm, cfg) == -1) { 
479         PrintError("Failed to configure performance tuning parameters\n");
480         return -1;
481     }
482
483
484     vm->run_state = VM_STOPPED;
485
486     return 0;
487 }
488
489
490
491 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
492
493  
494     if (v3_init_core_extensions(info) == -1) {
495         PrintError("Error intializing extension core states\n");
496         return -1;
497     }
498
499     if (info->vm_info->vm_class == V3_PC_VM) {
500         if (post_config_pc_core(info, cfg) == -1) {
501             PrintError("PC Post configuration failure\n");
502             return -1;
503         }
504     } else {
505         PrintError("Invalid VM Class\n");
506         return -1;
507     }
508
509
510     return 0;
511 }
512
513
514
515 static struct v3_vm_info * allocate_guest(int num_cores) {
516     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
517     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
518
519     if (!vm) {
520         PrintError("Unable to allocate space for guest data structures\n");
521         return NULL;
522     }
523
524     int i = 0;
525
526     memset(vm, 0, guest_state_size);
527
528     vm->num_cores = num_cores;
529
530     for (i = 0; i < num_cores; i++) {
531         vm->cores[i].core_run_state = CORE_INVALID;
532     }
533
534     vm->run_state = VM_INVALID;
535
536     return vm;
537 }
538
539
540
541 struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
542     extern v3_cpu_arch_t v3_mach_type;
543     struct v3_config * cfg_data = NULL;
544     struct v3_vm_info * vm = NULL;
545     int num_cores = 0;
546     int i = 0;
547     v3_cfg_tree_t * cores_cfg = NULL;
548     v3_cfg_tree_t * per_core_cfg = NULL;
549
550     if (v3_mach_type == V3_INVALID_CPU) {
551         PrintError("Configuring guest on invalid CPU\n");
552         return NULL;
553     }
554
555     cfg_data = parse_config(cfg_blob);
556
557     if (!cfg_data) {
558         PrintError("Could not parse configuration\n");
559         return NULL;
560     }
561
562     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
563
564     if (!cores_cfg) {
565         PrintError("Could not find core configuration (new config format required)\n");
566         return NULL;
567     }
568
569     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
570     if (num_cores == 0) {
571         PrintError("No cores specified in configuration\n");
572         return NULL;
573     }
574
575     V3_Print("Configuring %d cores\n", num_cores);
576
577     vm = allocate_guest(num_cores);    
578
579     if (!vm) {
580         PrintError("Could not allocate %d core guest\n", vm->num_cores);
581         return NULL;
582     }
583
584     vm->host_priv_data = priv_data;
585
586     vm->cfg_data = cfg_data;
587
588     V3_Print("Preconfiguration\n");
589
590     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
591         PrintError("Error in preconfiguration\n");
592         return NULL;
593     }
594
595     V3_Print("Per core configuration\n");
596     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
597
598     // per core configuration
599     for (i = 0; i < vm->num_cores; i++) {
600         struct guest_info * info = &(vm->cores[i]);
601
602         info->vcpu_id = i;
603         info->vm_info = vm;
604         info->core_cfg_data = per_core_cfg;
605
606         if (pre_config_core(info, per_core_cfg) == -1) {
607             PrintError("Error in core %d preconfiguration\n", i);
608             return NULL;
609         }
610
611
612         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
613     }
614
615
616     V3_Print("Post Configuration\n");
617
618     if (post_config_vm(vm, vm->cfg_data->cfg) == -1) {
619         PrintError("Error in postconfiguration\n");
620         return NULL;
621     }
622
623
624     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
625
626     // per core configuration
627     for (i = 0; i < vm->num_cores; i++) {
628         struct guest_info * info = &(vm->cores[i]);
629
630         post_config_core(info, per_core_cfg);
631
632         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
633     }
634
635     V3_Print("Configuration successfull\n");
636
637     return vm;
638 }
639
640
641
642 int v3_free_config(struct v3_vm_info * vm) {
643    
644     v3_free_htable(vm->cfg_data->file_table, 1, 0);
645
646     v3_xml_free(vm->cfg_data->cfg);
647
648     V3_Free(vm->cfg_data);
649     return 0;
650 }
651
652
653
654
655 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
656     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
657
658     while (mem_region) {
659         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
660         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
661         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
662
663     
664         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
665             PrintError("Could not map memory region: %p-%p => %p\n", 
666                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
667             return -1;
668         }
669
670         mem_region = v3_cfg_next_branch(mem_region);
671     }
672
673     return 0;
674 }
675
676
677 static int setup_extensions(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
678     v3_cfg_tree_t * extension = v3_cfg_subtree(v3_cfg_subtree(cfg, "extensions"), "extension");
679
680     while (extension) {
681         char * ext_name = v3_cfg_val(extension, "name");
682
683         if (!ext_name) {
684             PrintError("Extension has no name\n");
685             return -1;
686         }
687
688         V3_Print("Configuring extension %s\n", ext_name);
689
690         if (v3_add_extension(vm, ext_name, extension) == -1) {
691             PrintError("Error adding extension %s\n", ext_name);
692             return -1;
693         }
694
695         extension = v3_cfg_next_branch(extension);
696     }
697
698     return 0;
699 }
700
701
702 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
703     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
704
705     
706     while (device) {
707         char * dev_class = v3_cfg_val(device, "class");
708
709         V3_Print("configuring device %s\n", dev_class);
710
711         if (v3_create_device(vm, dev_class, device) == -1) {
712             PrintError("Error creating device %s\n", dev_class);
713             return -1;
714         }
715         
716         device = v3_cfg_next_branch(device);
717     }
718
719     v3_print_dev_mgr(vm);
720
721     return 0;
722 }
723
724
725