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.


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