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.


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