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.


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