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.


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