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.


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