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.


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