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.


build fixes to merge the Palacios configuration parameters with Linux parameters.
[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
42 #include "vmm_config_class.h"
43
44 // This is used to access the configuration file index table
45 struct file_hdr {
46     uint32_t index;
47     uint32_t size;
48     uint64_t offset;
49 };
50
51 struct file_idx_table {
52     uint64_t num_files;
53     struct file_hdr hdrs[0];
54 };
55
56
57
58
59 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg);
60 static int setup_extensions(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         V3_Print("File index=%d id=%s\n", idx, id);
170
171         strncpy(file->tag, id, 256);
172         file->size = hdr->size;
173         file->data = cfg_blob + hdr->offset;
174
175         V3_Print("Storing file data offset = %d, size=%d\n", (uint32_t)hdr->offset, hdr->size);
176         V3_Print("file data at %p\n", file->data);
177         list_add( &(file->file_node), &(cfg->file_list));
178
179         V3_Print("Keying file to name\n");
180         v3_htable_insert(cfg->file_table, (addr_t)(file->tag), (addr_t)(file));
181
182         V3_Print("Iterating to next file\n");
183
184         file_tree = v3_cfg_next_branch(file_tree);
185     }
186
187     V3_Print("Configuration parsed successfully\n");
188
189     return cfg;
190 }
191
192
193 static inline uint32_t get_alignment(char * align_str) {
194     // default is 4KB alignment
195     uint32_t alignment = PAGE_SIZE_4KB;
196
197     if (align_str != NULL) {
198         if (strcasecmp(align_str, "2MB") == 0) {
199             alignment = PAGE_SIZE_2MB;
200         } else if (strcasecmp(align_str, "4MB") == 0) {
201             alignment = PAGE_SIZE_4MB;
202         }
203     }
204     
205 #ifndef V3_CONFIG_ALIGNED_PG_ALLOC
206     if (alignment != PAGE_SIZE_4KB) {
207         PrintError("Aligned page allocations are not supported in this host (requested alignment=%d)\n", alignment);
208         PrintError("Ignoring alignment request\n");
209     }
210 #endif 
211
212     return alignment;
213 }
214
215
216 static int pre_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * vm_cfg) {
217     char * memory_str = v3_cfg_val(vm_cfg, "memory");
218     char * schedule_hz_str = v3_cfg_val(vm_cfg, "schedule_hz");
219     char * vm_class = v3_cfg_val(vm_cfg, "class");
220     char * align_str = v3_cfg_val(v3_cfg_subtree(vm_cfg, "memory"), "alignment");
221     uint32_t sched_hz = 100;    // set the schedule frequency to 100 HZ
222
223
224     if (!memory_str) {
225         PrintError("Memory is a required configuration parameter\n");
226         return -1;
227     }
228     
229     PrintDebug("Memory=%s\n", memory_str);
230     if (align_str) {
231          PrintDebug("Alignment=%s\n", align_str);
232     } else {
233          PrintDebug("Alignment defaulted to 4KB.\n");
234     }
235
236     // Amount of ram the Guest will have, always in MB
237     vm->mem_size = (addr_t)atoi(memory_str) * 1024 * 1024;
238     vm->mem_align = get_alignment(align_str);
239
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 V3_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
283 static int determine_paging_mode(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
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     
290     PrintDebug("Paging mode specified as %s\n", pg_mode);
291
292     if (pg_mode) {
293         if ((strcasecmp(pg_mode, "nested") == 0)) {
294             // we assume symmetric cores, so if core 0 has nested paging they all do
295             if ((v3_cpu_types[0] == V3_SVM_REV3_CPU) || 
296                 (v3_cpu_types[0] == V3_VMX_EPT_CPU) ||
297                 (v3_cpu_types[0] == V3_VMX_EPT_UG_CPU)) {
298                 info->shdw_pg_mode = NESTED_PAGING;
299             } else {
300                 PrintError("Nested paging not supported on this hardware. Defaulting to shadow paging\n");
301                 info->shdw_pg_mode = SHADOW_PAGING;
302             }
303         } else if ((strcasecmp(pg_mode, "shadow") == 0)) {
304             info->shdw_pg_mode = SHADOW_PAGING;
305         } else {
306             PrintError("Invalid paging mode (%s) specified in configuration. Defaulting to shadow paging\n", pg_mode);
307             info->shdw_pg_mode = SHADOW_PAGING;
308         }
309     } else {
310         PrintDebug("No paging type specified in configuration. Defaulting to shadow paging\n");
311         info->shdw_pg_mode = SHADOW_PAGING;
312     }
313
314
315     if (v3_cfg_val(pg_tree, "large_pages") != NULL) {
316         if (strcasecmp(v3_cfg_val(pg_tree, "large_pages"), "true") == 0) {
317             info->use_large_pages = 1;
318             PrintDebug("Use of large pages in memory virtualization enabled.\n");
319         }
320     }
321     return 0;
322 }
323
324 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
325     if (determine_paging_mode(info, core_cfg) != 0) {
326         return -1;
327     }
328
329     v3_init_core(info);
330
331     if (info->vm_info->vm_class == V3_PC_VM) {
332         if (pre_config_pc_core(info, core_cfg) == -1) {
333             PrintError("PC Post configuration failure\n");
334             return -1;
335         }
336     } else {
337         PrintError("Invalid VM Class\n");
338         return -1;
339     }
340
341     return 0;
342 }
343
344
345
346 static int post_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
347     
348     vm->run_state = VM_STOPPED;
349
350     // Configure the memory map for the guest
351     if (setup_memory_map(vm, cfg) == -1) {
352         PrintError("Setting up guest memory map failed...\n");
353         return -1;
354     }
355
356     /* 
357      * Initialize configured extensions 
358      */
359     if (setup_extensions(vm, cfg) == -1) {
360         PrintError("Failed to setup extensions\n");
361         return -1;
362     }
363
364     /* 
365      * Initialize configured devices
366      */
367     if (setup_devices(vm, cfg) == -1) {
368         PrintError("Failed to setup devices\n");
369         return -1;
370     }
371
372
373     //    v3_print_io_map(info);
374     v3_print_msr_map(vm);
375
376
377     if (vm->vm_class == V3_PC_VM) {
378         if (post_config_pc(vm, cfg) == -1) {
379             PrintError("PC Post configuration failure\n");
380             return -1;
381         }
382     } else {
383         PrintError("Invalid VM Class\n");
384         return -1;
385     }
386
387     return 0;
388 }
389
390
391
392 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
393
394     info->core_run_state = CORE_STOPPED;
395  
396     if (v3_init_core_extensions(info) == -1) {
397         PrintError("Error intializing extension core states\n");
398         return -1;
399     }
400
401     if (info->vm_info->vm_class == V3_PC_VM) {
402         if (post_config_pc_core(info, cfg) == -1) {
403             PrintError("PC Post configuration failure\n");
404             return -1;
405         }
406     } else {
407         PrintError("Invalid VM Class\n");
408         return -1;
409     }
410
411
412     return 0;
413 }
414
415
416
417 static struct v3_vm_info * allocate_guest(int num_cores) {
418     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
419     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
420
421     memset(vm, 0, guest_state_size);
422
423     vm->num_cores = num_cores;
424
425     return vm;
426 }
427
428
429
430 struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
431     v3_cpu_arch_t cpu_type = v3_get_cpu_type(V3_Get_CPU());
432     struct v3_config * cfg_data = NULL;
433     struct v3_vm_info * vm = NULL;
434     int num_cores = 0;
435     int i = 0;
436     v3_cfg_tree_t * cores_cfg = NULL;
437     v3_cfg_tree_t * per_core_cfg = NULL;
438
439     if (cpu_type == V3_INVALID_CPU) {
440         PrintError("Configuring guest on invalid CPU\n");
441         return NULL;
442     }
443
444     cfg_data = parse_config(cfg_blob);
445
446     if (!cfg_data) {
447         PrintError("Could not parse configuration\n");
448         return NULL;
449     }
450
451     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
452
453     if (!cores_cfg) {
454         PrintError("Could not find core configuration (new config format required)\n");
455         return NULL;
456     }
457
458     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
459     if (num_cores == 0) {
460         PrintError("No cores specified in configuration\n");
461         return NULL;
462     }
463
464     V3_Print("Configuring %d cores\n", num_cores);
465
466     vm = allocate_guest(num_cores);    
467
468     if (!vm) {
469         PrintError("Could not allocate %d core guest\n", vm->num_cores);
470         return NULL;
471     }
472
473     vm->host_priv_data = priv_data;
474
475     vm->cfg_data = cfg_data;
476
477     V3_Print("Preconfiguration\n");
478
479     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
480         PrintError("Error in preconfiguration\n");
481         return NULL;
482     }
483
484     V3_Print("Per core configuration\n");
485     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
486
487     // per core configuration
488     for (i = 0; i < vm->num_cores; i++) {
489         struct guest_info * info = &(vm->cores[i]);
490
491         info->cpu_id = i;
492         info->vm_info = vm;
493         info->core_cfg_data = per_core_cfg;
494
495         if (pre_config_core(info, per_core_cfg) == -1) {
496             PrintError("Error in core %d preconfiguration\n", i);
497             return NULL;
498         }
499
500
501         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
502     }
503
504
505     V3_Print("Post Configuration\n");
506
507     if (post_config_vm(vm, vm->cfg_data->cfg) == -1) {
508         PrintError("Error in postconfiguration\n");
509         return NULL;
510     }
511
512
513     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
514
515     // per core configuration
516     for (i = 0; i < vm->num_cores; i++) {
517         struct guest_info * info = &(vm->cores[i]);
518
519         post_config_core(info, per_core_cfg);
520
521         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
522     }
523
524     V3_Print("Configuration successfull\n");
525
526     return vm;
527 }
528
529
530
531 int v3_free_config(struct v3_vm_info * vm) {
532    
533     v3_free_htable(vm->cfg_data->file_table, 1, 0);
534
535     v3_xml_free(vm->cfg_data->cfg);
536
537     V3_Free(vm->cfg_data);
538     return 0;
539 }
540
541
542
543
544 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
545     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
546
547     while (mem_region) {
548         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
549         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
550         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
551
552     
553         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
554             PrintError("Could not map memory region: %p-%p => %p\n", 
555                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
556             return -1;
557         }
558
559         mem_region = v3_cfg_next_branch(mem_region);
560     }
561
562     return 0;
563 }
564
565
566 static int setup_extensions(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
567     v3_cfg_tree_t * extension = v3_cfg_subtree(v3_cfg_subtree(cfg, "extensions"), "extension");
568
569     while (extension) {
570         char * ext_name = v3_cfg_val(extension, "name");
571
572         V3_Print("Configuring extension %s\n", ext_name);
573
574         if (v3_add_extension(vm, ext_name, extension) == -1) {
575             PrintError("Error adding extension %s\n", ext_name);
576             return -1;
577         }
578
579         extension = v3_cfg_next_branch(extension);
580     }
581
582     return 0;
583 }
584
585
586 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
587     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
588
589     
590     while (device) {
591         char * dev_class = v3_cfg_val(device, "class");
592
593         V3_Print("configuring device %s\n", dev_class);
594
595         if (v3_create_device(vm, dev_class, device) == -1) {
596             PrintError("Error creating device %s\n", dev_class);
597             return -1;
598         }
599         
600         device = v3_cfg_next_branch(device);
601     }
602
603     v3_print_dev_mgr(vm);
604
605     return 0;
606 }
607
608
609