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.


reworked launch code
[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 #include <palacios/vmm_sprintf.h>
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     if (attrib == NULL) {
76         val = v3_xml_txt(child_entry);
77         
78         if ( val[0] == 0 )
79                 val = NULL;
80     } else {
81         val = attrib;
82     }
83     
84     return val;
85 }
86
87 v3_cfg_tree_t * v3_cfg_subtree(v3_cfg_tree_t * tree, char * tag) {
88     return v3_xml_child(tree, tag);
89 }
90
91 v3_cfg_tree_t * v3_cfg_next_branch(v3_cfg_tree_t * tree) {
92     return v3_xml_next(tree);
93 }
94
95
96
97 struct v3_cfg_file * v3_cfg_get_file(struct v3_vm_info * vm, char * tag) {
98     struct v3_cfg_file * file = NULL;
99
100     file = (struct v3_cfg_file *)v3_htable_search(vm->cfg_data->file_table, (addr_t)tag);
101
102     return file;
103 }
104
105
106 static uint_t file_hash_fn(addr_t key) {
107     char * name = (char *)key;
108     return v3_hash_buffer((uchar_t *)name, strlen(name));
109 }
110
111 static int file_eq_fn(addr_t key1, addr_t key2) {
112     char * name1 = (char *)key1;
113     char * name2 = (char *)key2;
114
115     return (strcmp(name1, name2) == 0);
116 }
117
118 static struct v3_config * parse_config(void * cfg_blob) {
119     struct v3_config * cfg = NULL;
120     int offset = 0;
121     uint_t xml_len = 0; 
122     struct file_idx_table * files = NULL;
123     v3_cfg_tree_t * file_tree = NULL;
124
125     V3_Print("cfg data at %p\n", cfg_blob);
126
127     if (memcmp(cfg_blob, "v3vee\0\0\0", 8) != 0) {
128         PrintError("Invalid Configuration Header\n");
129         return NULL;
130     }
131
132     offset += 8;
133
134     cfg = (struct v3_config *)V3_Malloc(sizeof(struct v3_config));
135     memset(cfg, 0, sizeof(struct v3_config));
136
137     cfg->blob = cfg_blob;
138     INIT_LIST_HEAD(&(cfg->file_list));
139     cfg->file_table = v3_create_htable(0, file_hash_fn, file_eq_fn);
140     
141     xml_len = *(uint32_t *)(cfg_blob + offset);
142     offset += 4;
143
144     cfg->cfg = (v3_cfg_tree_t *)v3_xml_parse((uint8_t *)(cfg_blob + offset));
145     offset += xml_len;
146    
147     offset += 8;
148
149     files = (struct file_idx_table *)(cfg_blob + offset);
150
151     V3_Print("Number of files in cfg: %d\n", (uint32_t)(files->num_files));
152
153     file_tree = v3_cfg_subtree(v3_cfg_subtree(cfg->cfg, "files"), "file");
154
155     while (file_tree) {
156         char * id = v3_cfg_val(file_tree, "id");
157         char * index = v3_cfg_val(file_tree, "index");
158         int idx = atoi(index);
159         struct file_hdr * hdr = &(files->hdrs[idx]);
160         struct v3_cfg_file * file = NULL;
161
162         file = (struct v3_cfg_file *)V3_Malloc(sizeof(struct v3_cfg_file));
163         
164         if (!file) {
165             PrintError("Could not allocate file structure\n");
166             return NULL;
167         }
168
169
170         V3_Print("File index=%d id=%s\n", idx, id);
171
172         strncpy(file->tag, id, 256);
173         file->size = hdr->size;
174         file->data = cfg_blob + hdr->offset;
175
176         V3_Print("Storing file data offset = %d, size=%d\n", (uint32_t)hdr->offset, hdr->size);
177         V3_Print("file data at %p\n", file->data);
178         list_add( &(file->file_node), &(cfg->file_list));
179
180         V3_Print("Keying file to name\n");
181         v3_htable_insert(cfg->file_table, (addr_t)(file->tag), (addr_t)(file));
182
183         V3_Print("Iterating to next file\n");
184
185         file_tree = v3_cfg_next_branch(file_tree);
186     }
187
188     V3_Print("Configuration parsed successfully\n");
189
190     return cfg;
191 }
192
193
194 static inline uint32_t get_alignment(char * align_str) {
195     // default is 4KB alignment
196     uint32_t alignment = PAGE_SIZE_4KB;
197
198     if (align_str != NULL) {
199         if (strcasecmp(align_str, "2MB") == 0) {
200             alignment = PAGE_SIZE_2MB;
201         } else if (strcasecmp(align_str, "4MB") == 0) {
202             alignment = PAGE_SIZE_4MB;
203         }
204     }
205     
206 #ifndef CONFIG_ALIGNED_PG_ALLOC
207     if (alignment != PAGE_SIZE_4KB) {
208         PrintError("Aligned page allocations are not supported in this host (requested alignment=%d)\n", alignment);
209         PrintError("Ignoring alignment request\n");
210     }
211 #endif 
212
213     return alignment;
214 }
215 static int pre_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * vm_cfg) {
216
217
218     char * memory_str = v3_cfg_val(vm_cfg, "memory");
219     char * schedule_hz_str = v3_cfg_val(vm_cfg, "schedule_hz");
220     char * vm_class = v3_cfg_val(vm_cfg, "class");
221     char * align_str = v3_cfg_val(v3_cfg_subtree(vm_cfg, "memory"), "alignment");
222     uint32_t sched_hz = 100;    // set the schedule frequency to 100 HZ
223
224
225     if (!memory_str) {
226         PrintError("Memory is a required configuration parameter\n");
227         return -1;
228     }
229     
230     PrintDebug("Memory=%s\n", memory_str);
231     if (align_str) {
232          PrintDebug("Alignment=%s\n", align_str);
233     } else {
234          PrintDebug("Alignment defaulted to 4KB.\n");
235     }
236
237     // Amount of ram the Guest will have, always in MB
238     vm->mem_size = (addr_t)atoi(memory_str) * 1024 * 1024;
239     vm->mem_align = get_alignment(align_str);
240
241     PrintDebug("Alignment for %lu bytes of memory computed as 0x%x\n", vm->mem_size, vm->mem_align);
242
243     if (strcasecmp(vm_class, "PC") == 0) {
244         vm->vm_class = V3_PC_VM;
245     } else {
246         PrintError("Invalid VM class\n");
247         return -1;
248     }
249
250 #ifdef CONFIG_TELEMETRY
251     {
252         char * telemetry = v3_cfg_val(vm_cfg, "telemetry");
253
254         // This should go first, because other subsystems will depend on the guest_info flag    
255         if ((telemetry) && (strcasecmp(telemetry, "enable") == 0)) {
256             vm->enable_telemetry = 1;
257         } else {
258             vm->enable_telemetry = 0;
259         }
260     }
261 #endif
262
263     if (v3_init_vm(vm) == -1) {
264         PrintError("Failed to initialize VM\n");
265         return -1;
266     }
267
268
269
270    if (schedule_hz_str) {
271         sched_hz = atoi(schedule_hz_str);
272     }
273
274     PrintDebug("CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(), 
275                (void *)(addr_t)sched_hz);
276
277     vm->yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
278     
279     return 0;
280 }
281
282 static int determine_paging_mode(struct guest_info *info, v3_cfg_tree_t * core_cfg)
283 {
284     extern v3_cpu_arch_t v3_cpu_types[];
285
286     v3_cfg_tree_t * vm_tree = info->vm_info->cfg_data->cfg;
287     v3_cfg_tree_t * pg_tree = v3_cfg_subtree(vm_tree, "paging");
288     char * pg_mode          = v3_cfg_val(pg_tree, "mode");
289     char * page_size        = v3_cfg_val(pg_tree, "page_size");
290     
291     PrintDebug("Paging mode specified as %s\n", pg_mode);
292
293     if (pg_mode) {
294         if ((strcasecmp(pg_mode, "nested") == 0)) {
295             if (v3_cpu_types[info->cpu_id] == V3_SVM_REV3_CPU) {
296                 info->shdw_pg_mode = NESTED_PAGING;
297             } else {
298                 PrintError("Nested paging not supported on this hardware. Defaulting to shadow paging\n");
299                 info->shdw_pg_mode = SHADOW_PAGING;
300             }
301         } else if ((strcasecmp(pg_mode, "shadow") == 0)) {
302             info->shdw_pg_mode = SHADOW_PAGING;
303         } else {
304             PrintError("Invalid paging mode (%s) specified in configuration. Defaulting to shadow paging\n", pg_mode);
305             info->shdw_pg_mode = SHADOW_PAGING;
306         }
307     } else {
308         PrintDebug("No paging type specified in configuration. Defaulting to shadow paging\n");
309         info->shdw_pg_mode = SHADOW_PAGING;
310     }
311
312
313     if (info->shdw_pg_mode == NESTED_PAGING) {
314         PrintDebug("Guest Paging Mode: NESTED_PAGING\n");
315         if (strcasecmp(page_size, "4kb") == 0) { /* TODO: this may not be an ideal place for this */
316             info->vm_info->paging_size = PAGING_4KB;
317         } else if (strcasecmp(page_size, "2mb") == 0) {
318             info->vm_info->paging_size = PAGING_2MB;
319         } else {
320             PrintError("Invalid VM paging size: '%s'\n", page_size);
321             return -1;
322         }
323         PrintDebug("VM page size=%s\n", page_size);
324     } else if (info->shdw_pg_mode == SHADOW_PAGING) {
325         PrintDebug("Guest Paging Mode: SHADOW_PAGING\n");
326     } else {
327         PrintError("Guest paging mode incorrectly set.\n");
328         return -1;
329     }
330
331     if (v3_cfg_val(pg_tree, "large_pages") != NULL) {
332         if (strcasecmp(v3_cfg_val(pg_tree, "large_pages"), "true") == 0) {
333             info->use_large_pages = 1;
334             PrintDebug("Use of large pages in memory virtualization enabled.\n");
335         }
336     }
337     return 0;
338 }
339
340 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
341
342     if (determine_paging_mode(info, core_cfg))
343         return -1;
344
345     v3_init_core(info);
346
347     if (info->vm_info->vm_class == V3_PC_VM) {
348         if (pre_config_pc_core(info, core_cfg) == -1) {
349             PrintError("PC Post configuration failure\n");
350             return -1;
351         }
352     } else {
353         PrintError("Invalid VM Class\n");
354         return -1;
355     }
356
357     return 0;
358 }
359
360
361
362 static int post_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
363     
364     vm->run_state = VM_STOPPED;
365
366     // Configure the memory map for the guest
367     if (setup_memory_map(vm, cfg) == -1) {
368         PrintError("Setting up guest memory map failed...\n");
369         return -1;
370     }
371     
372     //v3_hook_io_port(info, 1234, &IO_Read, NULL, info);
373   
374     if (setup_devices(vm, cfg) == -1) {
375         PrintError("Failed to setup devices\n");
376         return -1;
377     }
378
379
380     //    v3_print_io_map(info);
381     v3_print_msr_map(vm);
382
383
384     if (vm->vm_class == V3_PC_VM) {
385         if (post_config_pc(vm, cfg) == -1) {
386             PrintError("PC Post configuration failure\n");
387             return -1;
388         }
389     } else {
390         PrintError("Invalid VM Class\n");
391         return -1;
392     }
393
394     return 0;
395 }
396
397
398
399 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
400
401     info->core_run_state = CORE_STOPPED;
402  
403     if (info->vm_info->vm_class == V3_PC_VM) {
404         if (post_config_pc_core(info, cfg) == -1) {
405             PrintError("PC Post configuration failure\n");
406             return -1;
407         }
408     } else {
409         PrintError("Invalid VM Class\n");
410         return -1;
411     }
412
413
414     return 0;
415 }
416
417
418
419 static struct v3_vm_info * allocate_guest(int num_cores) {
420     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
421     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
422
423     memset(vm, 0, guest_state_size);
424
425     vm->num_cores = num_cores;
426
427     return vm;
428 }
429
430
431
432 struct v3_vm_info * v3_config_guest(void * cfg_blob) {
433     v3_cpu_arch_t cpu_type = v3_get_cpu_type(V3_Get_CPU());
434     struct v3_config * cfg_data = NULL;
435     struct v3_vm_info * vm = NULL;
436     int num_cores = 0;
437     int i = 0;
438     v3_cfg_tree_t * cores_cfg = NULL;
439     v3_cfg_tree_t * per_core_cfg = NULL;
440
441     if (cpu_type == V3_INVALID_CPU) {
442         PrintError("Configuring guest on invalid CPU\n");
443         return NULL;
444     }
445
446     cfg_data = parse_config(cfg_blob);
447
448     if (!cfg_data) {
449         PrintError("Could not parse configuration\n");
450         return NULL;
451     }
452
453     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
454
455     if (!cores_cfg) {
456         PrintError("Could not find core configuration (new config format required)\n");
457         return NULL;
458     }
459
460     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
461
462     if (num_cores == 0) {
463         PrintError("No cores specified in configuration\n");
464         return NULL;
465     }
466
467     V3_Print("Configuring %d cores\n", num_cores);
468
469     vm = allocate_guest(num_cores);    
470
471     if (!vm) {
472         PrintError("Could not allocate %d core guest\n", vm->num_cores);
473         return NULL;
474     }
475
476     vm->cfg_data = cfg_data;
477
478     V3_Print("Preconfiguration\n");
479
480     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
481         PrintError("Error in preconfiguration\n");
482         return NULL;
483     }
484
485
486     V3_Print("Per core configuration\n");
487     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
488
489     // per core configuration
490     for (i = 0; i < vm->num_cores; i++) {
491         struct guest_info * info = &(vm->cores[i]);
492
493         info->cpu_id = i;
494         info->vm_info = vm;
495         info->core_cfg_data = per_core_cfg;
496
497         if (pre_config_core(info, per_core_cfg) == -1) {
498             PrintError("Error in core %d preconfiguration\n", i);
499             return NULL;
500         }
501
502         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
503     }
504
505
506     V3_Print("Post Configuration\n");
507
508     if (post_config_vm(vm, vm->cfg_data->cfg) == -1) {
509         PrintError("Error in postconfiguration\n");
510         return NULL;
511     }
512
513
514     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
515
516     // per core configuration
517     for (i = 0; i < vm->num_cores; i++) {
518         struct guest_info * info = &(vm->cores[i]);
519
520         post_config_core(info, per_core_cfg);
521
522         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
523     }
524
525     V3_Print("Configuration successfull\n");
526
527     return vm;
528 }
529
530
531
532
533
534 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
535     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
536
537     while (mem_region) {
538         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
539         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
540         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
541
542     
543         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
544             PrintError("Could not map memory region: %p-%p => %p\n", 
545                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
546             return -1;
547         }
548
549         mem_region = v3_cfg_next_branch(mem_region);
550     }
551
552     return 0;
553 }
554
555
556
557
558 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
559     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
560
561     
562     while (device) {
563         char * dev_class = v3_cfg_val(device, "class");
564
565         V3_Print("configuring device %s\n", dev_class);
566
567         if (v3_create_device(vm, dev_class, device) == -1) {
568             PrintError("Error creating device %s\n", dev_class);
569             return -1;
570         }
571         
572         device = v3_cfg_next_branch(device);
573     }
574
575     v3_print_dev_mgr(vm);
576
577     return 0;
578 }
579
580
581
582