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.


Minor configuration fix for large page->large page fix.
[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
243 #ifdef CONFIG_TELEMETRY
244     {
245         char * telemetry = v3_cfg_val(vm_cfg, "telemetry");
246
247         // This should go first, because other subsystems will depend on the guest_info flag    
248         if ((telemetry) && (strcasecmp(telemetry, "enable") == 0)) {
249             vm->enable_telemetry = 1;
250         } else {
251             vm->enable_telemetry = 0;
252         }
253     }
254 #endif
255
256     if (v3_init_vm(vm) == -1) {
257         PrintError("Failed to initialize VM\n");
258         return -1;
259     }
260
261
262
263    if (schedule_hz_str) {
264         sched_hz = atoi(schedule_hz_str);
265     }
266
267     PrintDebug("CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(), 
268                (void *)(addr_t)sched_hz);
269
270     vm->yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
271     
272     return 0;
273 }
274
275 static int determine_paging_mode(struct guest_info *info, v3_cfg_tree_t * core_cfg)
276 {
277     extern v3_cpu_arch_t v3_cpu_types[];
278
279     v3_cfg_tree_t *vm_tree = info->vm_info->cfg_data->cfg;
280     v3_cfg_tree_t *pg_tree = v3_cfg_subtree(vm_tree, "paging");
281     char *pg_mode = v3_cfg_val(pg_tree, "mode");
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 mode specified in configuration.\n");
301         info->shdw_pg_mode = SHADOW_PAGING;
302     }
303
304     if (info->shdw_pg_mode == NESTED_PAGING) {
305         PrintDebug("Guest Paging Mode: NESTED_PAGING\n");
306     } else if (info->shdw_pg_mode == SHADOW_PAGING) {
307         PrintDebug("Guest Paging Mode: SHADOW_PAGING\n");
308     } else {
309         PrintError("Guest paging mode incorrectly set.\n");
310         return -1;
311     }
312     return 0;
313 }
314
315 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
316
317     if (determine_paging_mode(info, core_cfg))
318         return -1;
319
320     v3_init_core(info);
321
322     if (info->vm_info->vm_class == V3_PC_VM) {
323         if (pre_config_pc_core(info, core_cfg) == -1) {
324             PrintError("PC Post configuration failure\n");
325             return -1;
326         }
327     } else {
328         PrintError("Invalid VM Class\n");
329         return -1;
330     }
331
332     return 0;
333 }
334
335
336
337 static int post_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
338     
339     vm->run_state = VM_STOPPED;
340
341     // Configure the memory map for the guest
342     if (setup_memory_map(vm, cfg) == -1) {
343         PrintError("Setting up guest memory map failed...\n");
344         return -1;
345     }
346     
347     //v3_hook_io_port(info, 1234, &IO_Read, NULL, info);
348   
349     if (setup_devices(vm, cfg) == -1) {
350         PrintError("Failed to setup devices\n");
351         return -1;
352     }
353
354
355     //    v3_print_io_map(info);
356     v3_print_msr_map(vm);
357
358
359     if (vm->vm_class == V3_PC_VM) {
360         if (post_config_pc(vm, cfg) == -1) {
361             PrintError("PC Post configuration failure\n");
362             return -1;
363         }
364     } else {
365         PrintError("Invalid VM Class\n");
366         return -1;
367     }
368
369     if (v3_inject_mptable(vm)==-1) { 
370         PrintError("Failed to inject mptable during configuration\n");
371         return -1;
372     }
373
374     return 0;
375 }
376
377
378
379 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
380
381
382  
383     if (info->vm_info->vm_class == V3_PC_VM) {
384         if (post_config_pc_core(info, cfg) == -1) {
385             PrintError("PC Post configuration failure\n");
386             return -1;
387         }
388     } else {
389         PrintError("Invalid VM Class\n");
390         return -1;
391     }
392
393
394     return 0;
395 }
396
397
398
399 static struct v3_vm_info * allocate_guest(int num_cores) {
400     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
401     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
402
403     memset(vm, 0, guest_state_size);
404
405     vm->num_cores = num_cores;
406
407     return vm;
408 }
409
410
411
412 struct v3_vm_info * v3_config_guest(void * cfg_blob) {
413     v3_cpu_arch_t cpu_type = v3_get_cpu_type(v3_get_cpu_id());
414     struct v3_config * cfg_data = NULL;
415     struct v3_vm_info * vm = NULL;
416     int num_cores = 0;
417     int i = 0;
418     v3_cfg_tree_t * cores_cfg = NULL;
419     v3_cfg_tree_t * per_core_cfg = NULL;
420
421     if (cpu_type == V3_INVALID_CPU) {
422         PrintError("Configuring guest on invalid CPU\n");
423         return NULL;
424     }
425
426     cfg_data = parse_config(cfg_blob);
427
428     if (!cfg_data) {
429         PrintError("Could not parse configuration\n");
430         return NULL;
431     }
432
433     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
434
435     if (!cores_cfg) {
436         PrintError("Could not find core configuration (new config format required)\n");
437         return NULL;
438     }
439
440     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
441
442     if (num_cores == 0) {
443         PrintError("No cores specified in configuration\n");
444         return NULL;
445     }
446
447     V3_Print("Configuring %d cores\n", num_cores);
448
449     vm = allocate_guest(num_cores);    
450
451     if (!vm) {
452         PrintError("Could not allocate %d core guest\n", vm->num_cores);
453         return NULL;
454     }
455
456     vm->cfg_data = cfg_data;
457
458     V3_Print("Preconfiguration\n");
459
460     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
461         PrintError("Error in preconfiguration\n");
462         return NULL;
463     }
464
465
466     V3_Print("Per core configuration\n");
467     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
468
469     // per core configuration
470     for (i = 0; i < vm->num_cores; i++) {
471         struct guest_info * info = &(vm->cores[i]);
472
473         info->cpu_id = i;
474         info->vm_info = vm;
475
476         if (pre_config_core(info, per_core_cfg) == -1) {
477             PrintError("Error in core %d preconfiguration\n", i);
478             return NULL;
479         }
480
481         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
482     }
483
484
485     V3_Print("Post Configuration\n");
486
487     if (post_config_vm(vm, vm->cfg_data->cfg) == -1) {
488         PrintError("Error in postconfiguration\n");
489         return NULL;
490     }
491
492
493     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
494
495     // per core configuration
496     for (i = 0; i < vm->num_cores; i++) {
497         struct guest_info * info = &(vm->cores[i]);
498
499         post_config_core(info, per_core_cfg);
500
501         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
502     }
503
504     V3_Print("Configuration successfull\n");
505
506     return vm;
507 }
508
509
510
511
512
513 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
514     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
515
516     while (mem_region) {
517         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
518         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
519         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
520
521     
522         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
523             PrintError("Could not map memory region: %p-%p => %p\n", 
524                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
525             return -1;
526         }
527
528         mem_region = v3_cfg_next_branch(mem_region);
529     }
530
531     return 0;
532 }
533
534
535
536
537 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
538     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
539
540     
541     while (device) {
542         char * id = v3_cfg_val(device, "id");
543
544         V3_Print("configuring device %s\n", id);
545
546         if (v3_create_device(vm, id, device) == -1) {
547             PrintError("Error creating device %s\n", id);
548             return -1;
549         }
550         
551         device = v3_cfg_next_branch(device);
552     }
553
554     v3_print_dev_mgr(vm);
555
556     return 0;
557 }
558
559
560
561