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.


moved mptable to a device for the moment
[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_cpu_types[];
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_cpu_types[0] == V3_SVM_REV3_CPU) || 
295                 (v3_cpu_types[0] == V3_VMX_EPT_CPU) ||
296                 (v3_cpu_types[0] == 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     /* 
357      * Initialize configured devices
358      */
359     if (setup_devices(vm, cfg) == -1) {
360         PrintError("Failed to setup devices\n");
361         return -1;
362     }
363
364
365     //    v3_print_io_map(info);
366     v3_print_msr_map(vm);
367
368
369     if (vm->vm_class == V3_PC_VM) {
370         if (post_config_pc(vm, cfg) == -1) {
371             PrintError("PC Post configuration failure\n");
372             return -1;
373         }
374     } else {
375         PrintError("Invalid VM Class\n");
376         return -1;
377     }
378
379     /* 
380      * Initialize configured extensions 
381      */
382     if (setup_extensions(vm, cfg) == -1) {
383         PrintError("Failed to setup extensions\n");
384         return -1;
385     }
386
387
388     return 0;
389 }
390
391
392
393 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
394
395     info->core_run_state = CORE_STOPPED;
396  
397     if (v3_init_core_extensions(info) == -1) {
398         PrintError("Error intializing extension core states\n");
399         return -1;
400     }
401
402     if (info->vm_info->vm_class == V3_PC_VM) {
403         if (post_config_pc_core(info, cfg) == -1) {
404             PrintError("PC Post configuration failure\n");
405             return -1;
406         }
407     } else {
408         PrintError("Invalid VM Class\n");
409         return -1;
410     }
411
412
413     return 0;
414 }
415
416
417
418 static struct v3_vm_info * allocate_guest(int num_cores) {
419     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
420     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
421
422     memset(vm, 0, guest_state_size);
423
424     vm->num_cores = num_cores;
425
426     return vm;
427 }
428
429
430
431 struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
432     v3_cpu_arch_t cpu_type = v3_get_cpu_type(V3_Get_CPU());
433     struct v3_config * cfg_data = NULL;
434     struct v3_vm_info * vm = NULL;
435     int num_cores = 0;
436     int i = 0;
437     v3_cfg_tree_t * cores_cfg = NULL;
438     v3_cfg_tree_t * per_core_cfg = NULL;
439
440     if (cpu_type == V3_INVALID_CPU) {
441         PrintError("Configuring guest on invalid CPU\n");
442         return NULL;
443     }
444
445     cfg_data = parse_config(cfg_blob);
446
447     if (!cfg_data) {
448         PrintError("Could not parse configuration\n");
449         return NULL;
450     }
451
452     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
453
454     if (!cores_cfg) {
455         PrintError("Could not find core configuration (new config format required)\n");
456         return NULL;
457     }
458
459     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
460     if (num_cores == 0) {
461         PrintError("No cores specified in configuration\n");
462         return NULL;
463     }
464
465     V3_Print("Configuring %d cores\n", num_cores);
466
467     vm = allocate_guest(num_cores);    
468
469     if (!vm) {
470         PrintError("Could not allocate %d core guest\n", vm->num_cores);
471         return NULL;
472     }
473
474     vm->host_priv_data = priv_data;
475
476     vm->cfg_data = cfg_data;
477
478     V3_Print("Preconfiguration\n");
479
480     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
481         PrintError("Error in preconfiguration\n");
482         return NULL;
483     }
484
485     V3_Print("Per core configuration\n");
486     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
487
488     // per core configuration
489     for (i = 0; i < vm->num_cores; i++) {
490         struct guest_info * info = &(vm->cores[i]);
491
492         info->cpu_id = i;
493         info->vm_info = vm;
494         info->core_cfg_data = per_core_cfg;
495
496         if (pre_config_core(info, per_core_cfg) == -1) {
497             PrintError("Error in core %d preconfiguration\n", i);
498             return NULL;
499         }
500
501
502         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
503     }
504
505
506     V3_Print("Post Configuration\n");
507
508     if (post_config_vm(vm, vm->cfg_data->cfg) == -1) {
509         PrintError("Error in postconfiguration\n");
510         return NULL;
511     }
512
513
514     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
515
516     // per core configuration
517     for (i = 0; i < vm->num_cores; i++) {
518         struct guest_info * info = &(vm->cores[i]);
519
520         post_config_core(info, per_core_cfg);
521
522         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
523     }
524
525     V3_Print("Configuration successfull\n");
526
527     return vm;
528 }
529
530
531
532 int v3_free_config(struct v3_vm_info * vm) {
533    
534     v3_free_htable(vm->cfg_data->file_table, 1, 0);
535
536     v3_xml_free(vm->cfg_data->cfg);
537
538     V3_Free(vm->cfg_data);
539     return 0;
540 }
541
542
543
544
545 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
546     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
547
548     while (mem_region) {
549         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
550         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
551         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
552
553     
554         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
555             PrintError("Could not map memory region: %p-%p => %p\n", 
556                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
557             return -1;
558         }
559
560         mem_region = v3_cfg_next_branch(mem_region);
561     }
562
563     return 0;
564 }
565
566
567 static int setup_extensions(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
568     v3_cfg_tree_t * extension = v3_cfg_subtree(v3_cfg_subtree(cfg, "extensions"), "extension");
569
570     while (extension) {
571         char * ext_name = v3_cfg_val(extension, "name");
572
573         V3_Print("Configuring extension %s\n", ext_name);
574
575         if (v3_add_extension(vm, ext_name, extension) == -1) {
576             PrintError("Error adding extension %s\n", ext_name);
577             return -1;
578         }
579
580         extension = v3_cfg_next_branch(extension);
581     }
582
583     return 0;
584 }
585
586
587 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
588     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
589
590     
591     while (device) {
592         char * dev_class = v3_cfg_val(device, "class");
593
594         V3_Print("configuring device %s\n", dev_class);
595
596         if (v3_create_device(vm, dev_class, device) == -1) {
597             PrintError("Error creating device %s\n", dev_class);
598             return -1;
599         }
600         
601         device = v3_cfg_next_branch(device);
602     }
603
604     v3_print_dev_mgr(vm);
605
606     return 0;
607 }
608
609
610