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.


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