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.


config fix
[palacios.releases.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_mptable.h>
34
35
36
37
38
39
40 #include <palacios/vmm_host_events.h>
41 #include <palacios/vmm_socket.h>
42
43 #include "vmm_config_class.h"
44
45 // This is used to access the configuration file index table
46 struct file_hdr {
47     uint32_t index;
48     uint32_t size;
49     uint64_t offset;
50 };
51
52 struct file_idx_table {
53     uint64_t num_files;
54     struct file_hdr hdrs[0];
55 };
56
57
58
59
60 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg);
61 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg);
62
63
64
65 char * v3_cfg_val(v3_cfg_tree_t * tree, char * tag) {
66     char * attrib = (char *)v3_xml_attr(tree, tag);
67     v3_cfg_tree_t * child_entry = v3_xml_child(tree, tag);
68     char * val = NULL;
69
70     if ((child_entry != NULL) && (attrib != NULL)) {
71         PrintError("Duplicate Configuration parameters present for %s\n", tag);
72         return NULL;
73     }
74
75     if (attrib == NULL) {
76         val = v3_xml_txt(child_entry);
77         
78         if ( val[0] == 0 )
79                 val = NULL;
80     } else {
81         val = attrib;
82     }
83     
84     return val;
85 }
86
87 v3_cfg_tree_t * v3_cfg_subtree(v3_cfg_tree_t * tree, char * tag) {
88     return v3_xml_child(tree, tag);
89 }
90
91 v3_cfg_tree_t * v3_cfg_next_branch(v3_cfg_tree_t * tree) {
92     return v3_xml_next(tree);
93 }
94
95
96
97 struct v3_cfg_file * v3_cfg_get_file(struct v3_vm_info * vm, char * tag) {
98     struct v3_cfg_file * file = NULL;
99
100     file = (struct v3_cfg_file *)v3_htable_search(vm->cfg_data->file_table, (addr_t)tag);
101
102     return file;
103 }
104
105
106 static uint_t file_hash_fn(addr_t key) {
107     char * name = (char *)key;
108     return v3_hash_buffer((uchar_t *)name, strlen(name));
109 }
110
111 static int file_eq_fn(addr_t key1, addr_t key2) {
112     char * name1 = (char *)key1;
113     char * name2 = (char *)key2;
114
115     return (strcmp(name1, name2) == 0);
116 }
117
118 static struct v3_config * parse_config(void * cfg_blob) {
119     struct v3_config * cfg = NULL;
120     int offset = 0;
121     uint_t xml_len = 0; 
122     struct file_idx_table * files = NULL;
123     v3_cfg_tree_t * file_tree = NULL;
124
125     V3_Print("cfg data at %p\n", cfg_blob);
126
127     if (memcmp(cfg_blob, "v3vee\0\0\0", 8) != 0) {
128         PrintError("Invalid Configuration Header\n");
129         return NULL;
130     }
131
132     offset += 8;
133
134     cfg = (struct v3_config *)V3_Malloc(sizeof(struct v3_config));
135     memset(cfg, 0, sizeof(struct v3_config));
136
137     cfg->blob = cfg_blob;
138     INIT_LIST_HEAD(&(cfg->file_list));
139     cfg->file_table = v3_create_htable(0, file_hash_fn, file_eq_fn);
140     
141     xml_len = *(uint32_t *)(cfg_blob + offset);
142     offset += 4;
143
144     cfg->cfg = (v3_cfg_tree_t *)v3_xml_parse((uint8_t *)(cfg_blob + offset));
145     offset += xml_len;
146    
147     offset += 8;
148
149     files = (struct file_idx_table *)(cfg_blob + offset);
150
151     V3_Print("Number of files in cfg: %d\n", (uint32_t)(files->num_files));
152
153     file_tree = v3_cfg_subtree(v3_cfg_subtree(cfg->cfg, "files"), "file");
154
155     while (file_tree) {
156         char * id = v3_cfg_val(file_tree, "id");
157         char * index = v3_cfg_val(file_tree, "index");
158         int idx = atoi(index);
159         struct file_hdr * hdr = &(files->hdrs[idx]);
160         struct v3_cfg_file * file = NULL;
161
162         file = (struct v3_cfg_file *)V3_Malloc(sizeof(struct v3_cfg_file));
163         
164         if (!file) {
165             PrintError("Could not allocate file structure\n");
166             return NULL;
167         }
168
169
170         V3_Print("File index=%d id=%s\n", idx, id);
171
172         strncpy(file->tag, id, 256);
173         file->size = hdr->size;
174         file->data = cfg_blob + hdr->offset;
175
176         V3_Print("Storing file data offset = %d, size=%d\n", (uint32_t)hdr->offset, hdr->size);
177         V3_Print("file data at %p\n", file->data);
178         list_add( &(file->file_node), &(cfg->file_list));
179
180         V3_Print("Keying file to name\n");
181         v3_htable_insert(cfg->file_table, (addr_t)(file->tag), (addr_t)(file));
182
183         V3_Print("Iterating to next file\n");
184
185         file_tree = v3_cfg_next_branch(file_tree);
186     }
187
188     V3_Print("Configuration parsed successfully\n");
189
190     return cfg;
191 }
192
193
194 static inline uint32_t get_alignment(char * align_str) {
195     // default is 4KB alignment
196     uint32_t alignment = PAGE_SIZE_4KB;
197
198     if (align_str != NULL) {
199         if (strcasecmp(align_str, "2MB") == 0) {
200             alignment = PAGE_SIZE_2MB;
201         } else if (strcasecmp(align_str, "4MB") == 0) {
202             alignment = PAGE_SIZE_4MB;
203         }
204     }
205     
206 #ifndef CONFIG_ALIGNED_PG_ALLOC
207     if (alignment != PAGE_SIZE_4KB) {
208         PrintError("Aligned page allocations are not supported in this host (requested alignment=%d)\n", alignment);
209         PrintError("Ignoring alignment request\n");
210     }
211 #endif 
212
213     return alignment;
214 }
215 static int pre_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * vm_cfg) {
216
217
218     char * memory_str = v3_cfg_val(vm_cfg, "memory");
219     char * schedule_hz_str = v3_cfg_val(vm_cfg, "schedule_hz");
220     char * vm_class = v3_cfg_val(vm_cfg, "class");
221     char * align_str = v3_cfg_val(v3_cfg_subtree(vm_cfg, "memory"), "alignment");
222     uint32_t sched_hz = 100;    // set the schedule frequency to 100 HZ
223     
224     if (!memory_str) {
225         PrintError("Memory is a required configuration parameter\n");
226         return -1;
227     }
228     
229     PrintDebug("Memory=%s\n", memory_str);
230     if (align_str) {
231          PrintDebug("Alignment=%s\n", align_str);
232     } else {
233          PrintDebug("Alignment defaulted to 4KB.\n");
234     }
235
236     // Amount of ram the Guest will have, always in MB
237     vm->mem_size = atoi(memory_str) * 1024 * 1024;
238     vm->mem_align = get_alignment(align_str);
239
240     PrintDebug("Alignment computed as 0x%x\n", 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 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 static int determine_paging_mode(struct guest_info *info, v3_cfg_tree_t * core_cfg)
282 {
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     char *page_size        = v3_cfg_val(pg_tree, "page_size");
289     
290     PrintDebug("Paging mode specified as %s\n", pg_mode);
291
292     if (pg_mode) {
293         if ((strcasecmp(pg_mode, "nested") == 0)) {
294             if (v3_cpu_types[info->cpu_id] == V3_SVM_REV3_CPU) {
295                 info->shdw_pg_mode = NESTED_PAGING;
296             } else {
297                 PrintError("Nested paging not supported on this hardware. Defaulting to shadow paging\n");
298                 info->shdw_pg_mode = SHADOW_PAGING;
299             }
300         } else if ((strcasecmp(pg_mode, "shadow") == 0)) {
301             info->shdw_pg_mode = SHADOW_PAGING;
302         } else {
303             PrintError("Invalid paging mode (%s) specified in configuration. Defaulting to shadow paging\n", pg_mode);
304             info->shdw_pg_mode = SHADOW_PAGING;
305         }
306     } else {
307         PrintDebug("No paging type specified in configuration. Defaulting to shadow paging\n");
308         info->shdw_pg_mode = SHADOW_PAGING;
309     }
310
311
312     if (info->shdw_pg_mode == NESTED_PAGING) {
313         PrintDebug("Guest Paging Mode: NESTED_PAGING\n");
314         if (strcasecmp(page_size, "4kb") == 0) { /* TODO: this may not be an ideal place for this */
315             info->vm_info->paging_size = PAGING_4KB;
316         } else if (strcasecmp(page_size, "2mb") == 0) {
317             info->vm_info->paging_size = PAGING_2MB;
318         } else {
319             PrintError("Invalid VM paging size: '%s'\n", page_size);
320             return -1;
321         }
322         PrintDebug("VM page size=%s\n", page_size);
323     } else if (info->shdw_pg_mode == SHADOW_PAGING) {
324         PrintDebug("Guest Paging Mode: SHADOW_PAGING\n");
325     } else {
326         PrintError("Guest paging mode incorrectly set.\n");
327         return -1;
328     }
329
330     if (strcasecmp(v3_cfg_val(pg_tree, "large_pages"), "true") == 0) {
331         info->use_large_pages = 1;
332         PrintDebug("Use of large pages in memory virtualization enabled.\n");
333     }
334
335     return 0;
336 }
337
338 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
339
340     if (determine_paging_mode(info, core_cfg))
341         return -1;
342
343     v3_init_core(info);
344
345     if (info->vm_info->vm_class == V3_PC_VM) {
346         if (pre_config_pc_core(info, core_cfg) == -1) {
347             PrintError("PC Post configuration failure\n");
348             return -1;
349         }
350     } else {
351         PrintError("Invalid VM Class\n");
352         return -1;
353     }
354
355     return 0;
356 }
357
358
359
360 static int post_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
361     
362     vm->run_state = VM_STOPPED;
363
364     // Configure the memory map for the guest
365     if (setup_memory_map(vm, cfg) == -1) {
366         PrintError("Setting up guest memory map failed...\n");
367         return -1;
368     }
369     
370     //v3_hook_io_port(info, 1234, &IO_Read, NULL, info);
371   
372     if (setup_devices(vm, cfg) == -1) {
373         PrintError("Failed to setup devices\n");
374         return -1;
375     }
376
377
378     //    v3_print_io_map(info);
379     v3_print_msr_map(vm);
380
381
382     if (vm->vm_class == V3_PC_VM) {
383         if (post_config_pc(vm, cfg) == -1) {
384             PrintError("PC Post configuration failure\n");
385             return -1;
386         }
387     } else {
388         PrintError("Invalid VM Class\n");
389         return -1;
390     }
391
392     if (v3_inject_mptable(vm) == -1) { 
393         PrintError("Failed to inject mptable during configuration\n");
394         return -1;
395     }
396
397
398     return 0;
399 }
400
401
402
403 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
404
405
406  
407     if (info->vm_info->vm_class == V3_PC_VM) {
408         if (post_config_pc_core(info, cfg) == -1) {
409             PrintError("PC Post configuration failure\n");
410             return -1;
411         }
412     } else {
413         PrintError("Invalid VM Class\n");
414         return -1;
415     }
416
417
418     return 0;
419 }
420
421
422
423 static struct v3_vm_info * allocate_guest(int num_cores) {
424     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
425     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
426
427     memset(vm, 0, guest_state_size);
428
429     vm->num_cores = num_cores;
430
431     return vm;
432 }
433
434
435
436 struct v3_vm_info * v3_config_guest(void * cfg_blob) {
437     v3_cpu_arch_t cpu_type = v3_get_cpu_type(v3_get_cpu_id());
438     struct v3_config * cfg_data = NULL;
439     struct v3_vm_info * vm = NULL;
440     int num_cores = 0;
441     int i = 0;
442     v3_cfg_tree_t * cores_cfg = NULL;
443     v3_cfg_tree_t * per_core_cfg = NULL;
444
445     if (cpu_type == V3_INVALID_CPU) {
446         PrintError("Configuring guest on invalid CPU\n");
447         return NULL;
448     }
449
450     cfg_data = parse_config(cfg_blob);
451
452     if (!cfg_data) {
453         PrintError("Could not parse configuration\n");
454         return NULL;
455     }
456
457     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
458
459     if (!cores_cfg) {
460         PrintError("Could not find core configuration (new config format required)\n");
461         return NULL;
462     }
463
464     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
465
466     if (num_cores == 0) {
467         PrintError("No cores specified in configuration\n");
468         return NULL;
469     }
470
471     V3_Print("Configuring %d cores\n", num_cores);
472
473     vm = allocate_guest(num_cores);    
474
475     if (!vm) {
476         PrintError("Could not allocate %d core guest\n", vm->num_cores);
477         return NULL;
478     }
479
480     vm->cfg_data = cfg_data;
481
482     V3_Print("Preconfiguration\n");
483
484     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
485         PrintError("Error in preconfiguration\n");
486         return NULL;
487     }
488
489
490     V3_Print("Per core configuration\n");
491     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
492
493     // per core configuration
494     for (i = 0; i < vm->num_cores; i++) {
495         struct guest_info * info = &(vm->cores[i]);
496
497         info->cpu_id = i;
498         info->vm_info = vm;
499
500         if (pre_config_core(info, per_core_cfg) == -1) {
501             PrintError("Error in core %d preconfiguration\n", i);
502             return NULL;
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
536
537 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
538     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
539
540     while (mem_region) {
541         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
542         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
543         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
544
545     
546         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
547             PrintError("Could not map memory region: %p-%p => %p\n", 
548                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
549             return -1;
550         }
551
552         mem_region = v3_cfg_next_branch(mem_region);
553     }
554
555     return 0;
556 }
557
558
559
560
561 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
562     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
563
564     
565     while (device) {
566         char * dev_class = v3_cfg_val(device, "class");
567
568         V3_Print("configuring device %s\n", dev_class);
569
570         if (v3_create_device(vm, dev_class, device) == -1) {
571             PrintError("Error creating device %s\n", dev_class);
572             return -1;
573         }
574         
575         device = v3_cfg_next_branch(device);
576     }
577
578     v3_print_dev_mgr(vm);
579
580     return 0;
581 }
582
583
584
585