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.


change to device configuration syntax
[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
305     if (info->shdw_pg_mode == NESTED_PAGING) {
306         PrintDebug("Guest Paging Mode: NESTED_PAGING\n");
307     } else if (info->shdw_pg_mode == SHADOW_PAGING) {
308         PrintDebug("Guest Paging Mode: SHADOW_PAGING\n");
309     } else {
310         PrintError("Guest paging mode incorrectly set.\n");
311         return -1;
312     }
313
314     if (strcasecmp(v3_cfg_val(pg_tree, "large_pages"), "true") == 0) {
315         info->use_large_pages = 1;
316         PrintDebug("Use of large pages in memory virtualization enabled.\n");
317     }
318
319     return 0;
320 }
321
322 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
323
324     if (determine_paging_mode(info, core_cfg))
325         return -1;
326
327     v3_init_core(info);
328
329     if (info->vm_info->vm_class == V3_PC_VM) {
330         if (pre_config_pc_core(info, core_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     return 0;
340 }
341
342
343
344 static int post_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
345     
346     vm->run_state = VM_STOPPED;
347
348     // Configure the memory map for the guest
349     if (setup_memory_map(vm, cfg) == -1) {
350         PrintError("Setting up guest memory map failed...\n");
351         return -1;
352     }
353     
354     //v3_hook_io_port(info, 1234, &IO_Read, NULL, info);
355   
356     if (setup_devices(vm, cfg) == -1) {
357         PrintError("Failed to setup devices\n");
358         return -1;
359     }
360
361
362     //    v3_print_io_map(info);
363     v3_print_msr_map(vm);
364
365
366     if (vm->vm_class == V3_PC_VM) {
367         if (post_config_pc(vm, cfg) == -1) {
368             PrintError("PC Post configuration failure\n");
369             return -1;
370         }
371     } else {
372         PrintError("Invalid VM Class\n");
373         return -1;
374     }
375
376     if (v3_inject_mptable(vm)==-1) { 
377         PrintError("Failed to inject mptable during configuration\n");
378         return -1;
379     }
380
381     return 0;
382 }
383
384
385
386 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
387
388
389  
390     if (info->vm_info->vm_class == V3_PC_VM) {
391         if (post_config_pc_core(info, cfg) == -1) {
392             PrintError("PC Post configuration failure\n");
393             return -1;
394         }
395     } else {
396         PrintError("Invalid VM Class\n");
397         return -1;
398     }
399
400
401     return 0;
402 }
403
404
405
406 static struct v3_vm_info * allocate_guest(int num_cores) {
407     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
408     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
409
410     memset(vm, 0, guest_state_size);
411
412     vm->num_cores = num_cores;
413
414     return vm;
415 }
416
417
418
419 struct v3_vm_info * v3_config_guest(void * cfg_blob) {
420     v3_cpu_arch_t cpu_type = v3_get_cpu_type(v3_get_cpu_id());
421     struct v3_config * cfg_data = NULL;
422     struct v3_vm_info * vm = NULL;
423     int num_cores = 0;
424     int i = 0;
425     v3_cfg_tree_t * cores_cfg = NULL;
426     v3_cfg_tree_t * per_core_cfg = NULL;
427
428     if (cpu_type == V3_INVALID_CPU) {
429         PrintError("Configuring guest on invalid CPU\n");
430         return NULL;
431     }
432
433     cfg_data = parse_config(cfg_blob);
434
435     if (!cfg_data) {
436         PrintError("Could not parse configuration\n");
437         return NULL;
438     }
439
440     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
441
442     if (!cores_cfg) {
443         PrintError("Could not find core configuration (new config format required)\n");
444         return NULL;
445     }
446
447     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
448
449     if (num_cores == 0) {
450         PrintError("No cores specified in configuration\n");
451         return NULL;
452     }
453
454     V3_Print("Configuring %d cores\n", num_cores);
455
456     vm = allocate_guest(num_cores);    
457
458     if (!vm) {
459         PrintError("Could not allocate %d core guest\n", vm->num_cores);
460         return NULL;
461     }
462
463     vm->cfg_data = cfg_data;
464
465     V3_Print("Preconfiguration\n");
466
467     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
468         PrintError("Error in preconfiguration\n");
469         return NULL;
470     }
471
472
473     V3_Print("Per core configuration\n");
474     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
475
476     // per core configuration
477     for (i = 0; i < vm->num_cores; i++) {
478         struct guest_info * info = &(vm->cores[i]);
479
480         info->cpu_id = i;
481         info->vm_info = vm;
482
483         if (pre_config_core(info, per_core_cfg) == -1) {
484             PrintError("Error in core %d preconfiguration\n", i);
485             return NULL;
486         }
487
488         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
489     }
490
491
492     V3_Print("Post Configuration\n");
493
494     if (post_config_vm(vm, vm->cfg_data->cfg) == -1) {
495         PrintError("Error in postconfiguration\n");
496         return NULL;
497     }
498
499
500     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
501
502     // per core configuration
503     for (i = 0; i < vm->num_cores; i++) {
504         struct guest_info * info = &(vm->cores[i]);
505
506         post_config_core(info, per_core_cfg);
507
508         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
509     }
510
511     V3_Print("Configuration successfull\n");
512
513     return vm;
514 }
515
516
517
518
519
520 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
521     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
522
523     while (mem_region) {
524         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
525         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
526         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
527
528     
529         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
530             PrintError("Could not map memory region: %p-%p => %p\n", 
531                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
532             return -1;
533         }
534
535         mem_region = v3_cfg_next_branch(mem_region);
536     }
537
538     return 0;
539 }
540
541
542
543
544 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
545     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
546
547     
548     while (device) {
549         char * dev_class = v3_cfg_val(device, "class");
550
551         V3_Print("configuring device %s\n", dev_class);
552
553         if (v3_create_device(vm, dev_class, device) == -1) {
554             PrintError("Error creating device %s\n", dev_class);
555             return -1;
556         }
557         
558         device = v3_cfg_next_branch(device);
559     }
560
561     v3_print_dev_mgr(vm);
562
563     return 0;
564 }
565
566
567
568