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
391     return 0;
392 }
393
394
395
396 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
397
398
399  
400     if (info->vm_info->vm_class == V3_PC_VM) {
401         if (post_config_pc_core(info, cfg) == -1) {
402             PrintError("PC Post configuration failure\n");
403             return -1;
404         }
405     } else {
406         PrintError("Invalid VM Class\n");
407         return -1;
408     }
409
410
411     return 0;
412 }
413
414
415
416 static struct v3_vm_info * allocate_guest(int num_cores) {
417     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
418     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
419
420     memset(vm, 0, guest_state_size);
421
422     vm->num_cores = num_cores;
423
424     return vm;
425 }
426
427
428
429 struct v3_vm_info * v3_config_guest(void * cfg_blob) {
430     v3_cpu_arch_t cpu_type = v3_get_cpu_type(v3_get_cpu_id());
431     struct v3_config * cfg_data = NULL;
432     struct v3_vm_info * vm = NULL;
433     int num_cores = 0;
434     int i = 0;
435     v3_cfg_tree_t * cores_cfg = NULL;
436     v3_cfg_tree_t * per_core_cfg = NULL;
437
438     if (cpu_type == V3_INVALID_CPU) {
439         PrintError("Configuring guest on invalid CPU\n");
440         return NULL;
441     }
442
443     cfg_data = parse_config(cfg_blob);
444
445     if (!cfg_data) {
446         PrintError("Could not parse configuration\n");
447         return NULL;
448     }
449
450     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
451
452     if (!cores_cfg) {
453         PrintError("Could not find core configuration (new config format required)\n");
454         return NULL;
455     }
456
457     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
458
459     if (num_cores == 0) {
460         PrintError("No cores specified in configuration\n");
461         return NULL;
462     }
463
464     V3_Print("Configuring %d cores\n", num_cores);
465
466     vm = allocate_guest(num_cores);    
467
468     if (!vm) {
469         PrintError("Could not allocate %d core guest\n", vm->num_cores);
470         return NULL;
471     }
472
473     vm->cfg_data = cfg_data;
474
475     V3_Print("Preconfiguration\n");
476
477     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
478         PrintError("Error in preconfiguration\n");
479         return NULL;
480     }
481
482
483     V3_Print("Per core configuration\n");
484     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
485
486     // per core configuration
487     for (i = 0; i < vm->num_cores; i++) {
488         struct guest_info * info = &(vm->cores[i]);
489
490         info->cpu_id = i;
491         info->vm_info = vm;
492
493         if (pre_config_core(info, per_core_cfg) == -1) {
494             PrintError("Error in core %d preconfiguration\n", i);
495             return NULL;
496         }
497
498         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
499     }
500
501
502     V3_Print("Post Configuration\n");
503
504     if (post_config_vm(vm, vm->cfg_data->cfg) == -1) {
505         PrintError("Error in postconfiguration\n");
506         return NULL;
507     }
508
509
510     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
511
512     // per core configuration
513     for (i = 0; i < vm->num_cores; i++) {
514         struct guest_info * info = &(vm->cores[i]);
515
516         post_config_core(info, per_core_cfg);
517
518         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
519     }
520
521     V3_Print("Configuration successfull\n");
522
523     return vm;
524 }
525
526
527
528
529
530 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
531     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
532
533     while (mem_region) {
534         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
535         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
536         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
537
538     
539         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
540             PrintError("Could not map memory region: %p-%p => %p\n", 
541                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
542             return -1;
543         }
544
545         mem_region = v3_cfg_next_branch(mem_region);
546     }
547
548     return 0;
549 }
550
551
552
553
554 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
555     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
556
557     
558     while (device) {
559         char * dev_class = v3_cfg_val(device, "class");
560
561         V3_Print("configuring device %s\n", dev_class);
562
563         if (v3_create_device(vm, dev_class, device) == -1) {
564             PrintError("Error creating device %s\n", dev_class);
565             return -1;
566         }
567         
568         device = v3_cfg_next_branch(device);
569     }
570
571     v3_print_dev_mgr(vm);
572
573     return 0;
574 }
575
576
577
578