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.


added a global machine type to determine machine architecture
[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                 info->shdw_pg_mode = NESTED_PAGING;
298             } else {
299                 PrintError("Nested paging not supported on this hardware. Defaulting to shadow paging\n");
300                 info->shdw_pg_mode = SHADOW_PAGING;
301             }
302         } else if ((strcasecmp(pg_mode, "shadow") == 0)) {
303             info->shdw_pg_mode = SHADOW_PAGING;
304         } else {
305             PrintError("Invalid paging mode (%s) specified in configuration. Defaulting to shadow paging\n", pg_mode);
306             info->shdw_pg_mode = SHADOW_PAGING;
307         }
308     } else {
309         PrintDebug("No paging type specified in configuration. Defaulting to shadow paging\n");
310         info->shdw_pg_mode = SHADOW_PAGING;
311     }
312
313
314     if (v3_cfg_val(pg_tree, "large_pages") != NULL) {
315         if (strcasecmp(v3_cfg_val(pg_tree, "large_pages"), "true") == 0) {
316             info->use_large_pages = 1;
317             PrintDebug("Use of large pages in memory virtualization enabled.\n");
318         }
319     }
320     return 0;
321 }
322
323 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
324     if (determine_paging_mode(info, core_cfg) != 0) {
325         return -1;
326     }
327
328     v3_init_core(info);
329
330     if (info->vm_info->vm_class == V3_PC_VM) {
331         if (pre_config_pc_core(info, core_cfg) == -1) {
332             PrintError("PC Post configuration failure\n");
333             return -1;
334         }
335     } else {
336         PrintError("Invalid VM Class\n");
337         return -1;
338     }
339
340     return 0;
341 }
342
343
344
345 static int post_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
346     
347     vm->run_state = VM_STOPPED;
348
349     // Configure the memory map for the guest
350     if (setup_memory_map(vm, cfg) == -1) {
351         PrintError("Setting up guest memory map failed...\n");
352         return -1;
353     }
354
355
356     if (vm->vm_class == V3_PC_VM) {
357         if (post_config_pc(vm, cfg) == -1) {
358             PrintError("PC Post configuration failure\n");
359             return -1;
360         }
361     } else {
362         PrintError("Invalid VM Class\n");
363         return -1;
364     }
365
366
367     /* 
368      * Initialize configured devices
369      */
370     if (setup_devices(vm, cfg) == -1) {
371         PrintError("Failed to setup devices\n");
372         return -1;
373     }
374
375
376     //    v3_print_io_map(info);
377     v3_print_msr_map(vm);
378
379
380
381
382     /* 
383      * Initialize configured extensions 
384      */
385     if (setup_extensions(vm, cfg) == -1) {
386         PrintError("Failed to setup extensions\n");
387         return -1;
388     }
389
390
391     return 0;
392 }
393
394
395
396 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
397
398     info->core_run_state = CORE_STOPPED;
399  
400     if (v3_init_core_extensions(info) == -1) {
401         PrintError("Error intializing extension core states\n");
402         return -1;
403     }
404
405     if (info->vm_info->vm_class == V3_PC_VM) {
406         if (post_config_pc_core(info, cfg) == -1) {
407             PrintError("PC Post configuration failure\n");
408             return -1;
409         }
410     } else {
411         PrintError("Invalid VM Class\n");
412         return -1;
413     }
414
415
416     return 0;
417 }
418
419
420
421 static struct v3_vm_info * allocate_guest(int num_cores) {
422     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
423     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
424
425     memset(vm, 0, guest_state_size);
426
427     vm->num_cores = num_cores;
428
429     return vm;
430 }
431
432
433
434 struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
435     extern v3_cpu_arch_t v3_mach_type;
436     struct v3_config * cfg_data = NULL;
437     struct v3_vm_info * vm = NULL;
438     int num_cores = 0;
439     int i = 0;
440     v3_cfg_tree_t * cores_cfg = NULL;
441     v3_cfg_tree_t * per_core_cfg = NULL;
442
443     if (v3_mach_type == V3_INVALID_CPU) {
444         PrintError("Configuring guest on invalid CPU\n");
445         return NULL;
446     }
447
448     cfg_data = parse_config(cfg_blob);
449
450     if (!cfg_data) {
451         PrintError("Could not parse configuration\n");
452         return NULL;
453     }
454
455     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
456
457     if (!cores_cfg) {
458         PrintError("Could not find core configuration (new config format required)\n");
459         return NULL;
460     }
461
462     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
463     if (num_cores == 0) {
464         PrintError("No cores specified in configuration\n");
465         return NULL;
466     }
467
468     V3_Print("Configuring %d cores\n", num_cores);
469
470     vm = allocate_guest(num_cores);    
471
472     if (!vm) {
473         PrintError("Could not allocate %d core guest\n", vm->num_cores);
474         return NULL;
475     }
476
477     vm->host_priv_data = priv_data;
478
479     vm->cfg_data = cfg_data;
480
481     V3_Print("Preconfiguration\n");
482
483     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
484         PrintError("Error in preconfiguration\n");
485         return NULL;
486     }
487
488     V3_Print("Per core configuration\n");
489     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
490
491     // per core configuration
492     for (i = 0; i < vm->num_cores; i++) {
493         struct guest_info * info = &(vm->cores[i]);
494
495         info->vcpu_id = i;
496         info->vm_info = vm;
497         info->core_cfg_data = per_core_cfg;
498
499         if (pre_config_core(info, per_core_cfg) == -1) {
500             PrintError("Error in core %d preconfiguration\n", i);
501             return NULL;
502         }
503
504
505         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
506     }
507
508
509     V3_Print("Post Configuration\n");
510
511     if (post_config_vm(vm, vm->cfg_data->cfg) == -1) {
512         PrintError("Error in postconfiguration\n");
513         return NULL;
514     }
515
516
517     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
518
519     // per core configuration
520     for (i = 0; i < vm->num_cores; i++) {
521         struct guest_info * info = &(vm->cores[i]);
522
523         post_config_core(info, per_core_cfg);
524
525         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
526     }
527
528     V3_Print("Configuration successfull\n");
529
530     return vm;
531 }
532
533
534
535 int v3_free_config(struct v3_vm_info * vm) {
536    
537     v3_free_htable(vm->cfg_data->file_table, 1, 0);
538
539     v3_xml_free(vm->cfg_data->cfg);
540
541     V3_Free(vm->cfg_data);
542     return 0;
543 }
544
545
546
547
548 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
549     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
550
551     while (mem_region) {
552         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
553         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
554         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
555
556     
557         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
558             PrintError("Could not map memory region: %p-%p => %p\n", 
559                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
560             return -1;
561         }
562
563         mem_region = v3_cfg_next_branch(mem_region);
564     }
565
566     return 0;
567 }
568
569
570 static int setup_extensions(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
571     v3_cfg_tree_t * extension = v3_cfg_subtree(v3_cfg_subtree(cfg, "extensions"), "extension");
572
573     while (extension) {
574         char * ext_name = v3_cfg_val(extension, "name");
575
576         V3_Print("Configuring extension %s\n", ext_name);
577
578         if (v3_add_extension(vm, ext_name, extension) == -1) {
579             PrintError("Error adding extension %s\n", ext_name);
580             return -1;
581         }
582
583         extension = v3_cfg_next_branch(extension);
584     }
585
586     return 0;
587 }
588
589
590 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
591     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
592
593     
594     while (device) {
595         char * dev_class = v3_cfg_val(device, "class");
596
597         V3_Print("configuring device %s\n", dev_class);
598
599         if (v3_create_device(vm, dev_class, device) == -1) {
600             PrintError("Error creating device %s\n", dev_class);
601             return -1;
602         }
603         
604         device = v3_cfg_next_branch(device);
605     }
606
607     v3_print_dev_mgr(vm);
608
609     return 0;
610 }
611
612
613