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.


added support for Intel EPT with(?) and without unrestricted guest support
[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 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 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     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             // we assume symmetric cores, so if core 0 has nested paging they all do
296             if ((v3_cpu_types[0] == V3_SVM_REV3_CPU) || 
297                 (v3_cpu_types[0] == V3_VMX_EPT_CPU) ||
298                 (v3_cpu_types[0] == V3_VMX_EPT_UG_CPU)) {
299                 info->shdw_pg_mode = NESTED_PAGING;
300             } else {
301                 PrintError("Nested paging not supported on this hardware. Defaulting to shadow paging\n");
302                 info->shdw_pg_mode = SHADOW_PAGING;
303             }
304         } else if ((strcasecmp(pg_mode, "shadow") == 0)) {
305             info->shdw_pg_mode = SHADOW_PAGING;
306         } else {
307             PrintError("Invalid paging mode (%s) specified in configuration. Defaulting to shadow paging\n", pg_mode);
308             info->shdw_pg_mode = SHADOW_PAGING;
309         }
310     } else {
311         PrintDebug("No paging type specified in configuration. Defaulting to shadow paging\n");
312         info->shdw_pg_mode = SHADOW_PAGING;
313     }
314
315
316     if (info->shdw_pg_mode == NESTED_PAGING) {
317         PrintDebug("Guest Paging Mode: NESTED_PAGING\n");
318         if (strcasecmp(page_size, "4kb") == 0) { /* TODO: this may not be an ideal place for this */
319             info->vm_info->paging_size = PAGING_4KB;
320         } else if (strcasecmp(page_size, "2mb") == 0) {
321             info->vm_info->paging_size = PAGING_2MB;
322         } else {
323             PrintError("Invalid VM paging size: '%s'\n", page_size);
324             return -1;
325         }
326         PrintDebug("VM page size=%s\n", page_size);
327     } else if (info->shdw_pg_mode == SHADOW_PAGING) {
328         PrintDebug("Guest Paging Mode: SHADOW_PAGING\n");
329     } else {
330         PrintError("Guest paging mode incorrectly set.\n");
331         return -1;
332     }
333
334     if (v3_cfg_val(pg_tree, "large_pages") != NULL) {
335         if (strcasecmp(v3_cfg_val(pg_tree, "large_pages"), "true") == 0) {
336             info->use_large_pages = 1;
337             PrintDebug("Use of large pages in memory virtualization enabled.\n");
338         }
339     }
340     return 0;
341 }
342
343 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
344     if (determine_paging_mode(info, core_cfg) != 0) {
345         return -1;
346     }
347
348     v3_init_core(info);
349
350     if (info->vm_info->vm_class == V3_PC_VM) {
351         if (pre_config_pc_core(info, core_cfg) == -1) {
352             PrintError("PC Post configuration failure\n");
353             return -1;
354         }
355     } else {
356         PrintError("Invalid VM Class\n");
357         return -1;
358     }
359
360     return 0;
361 }
362
363
364
365 static int post_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
366     
367     vm->run_state = VM_STOPPED;
368
369     // Configure the memory map for the guest
370     if (setup_memory_map(vm, cfg) == -1) {
371         PrintError("Setting up guest memory map failed...\n");
372         return -1;
373     }
374
375     /* 
376      * Initialize configured extensions 
377      */
378     if (setup_extensions(vm, cfg) == -1) {
379         PrintError("Failed to setup extensions\n");
380         return -1;
381     }
382
383     /* 
384      * Initialize configured devices
385      */
386     if (setup_devices(vm, cfg) == -1) {
387         PrintError("Failed to setup devices\n");
388         return -1;
389     }
390
391
392     //    v3_print_io_map(info);
393     v3_print_msr_map(vm);
394
395
396     if (vm->vm_class == V3_PC_VM) {
397         if (post_config_pc(vm, cfg) == -1) {
398             PrintError("PC Post configuration failure\n");
399             return -1;
400         }
401     } else {
402         PrintError("Invalid VM Class\n");
403         return -1;
404     }
405
406     return 0;
407 }
408
409
410
411 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
412
413     info->core_run_state = CORE_STOPPED;
414  
415     if (v3_init_core_extensions(info) == -1) {
416         PrintError("Error intializing extension core states\n");
417         return -1;
418     }
419
420     if (info->vm_info->vm_class == V3_PC_VM) {
421         if (post_config_pc_core(info, cfg) == -1) {
422             PrintError("PC Post configuration failure\n");
423             return -1;
424         }
425     } else {
426         PrintError("Invalid VM Class\n");
427         return -1;
428     }
429
430
431     return 0;
432 }
433
434
435
436 static struct v3_vm_info * allocate_guest(int num_cores) {
437     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
438     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
439
440     memset(vm, 0, guest_state_size);
441
442     vm->num_cores = num_cores;
443
444     return vm;
445 }
446
447
448
449 struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
450     v3_cpu_arch_t cpu_type = v3_get_cpu_type(V3_Get_CPU());
451     struct v3_config * cfg_data = NULL;
452     struct v3_vm_info * vm = NULL;
453     int num_cores = 0;
454     int i = 0;
455     v3_cfg_tree_t * cores_cfg = NULL;
456     v3_cfg_tree_t * per_core_cfg = NULL;
457
458     if (cpu_type == V3_INVALID_CPU) {
459         PrintError("Configuring guest on invalid CPU\n");
460         return NULL;
461     }
462
463     cfg_data = parse_config(cfg_blob);
464
465     if (!cfg_data) {
466         PrintError("Could not parse configuration\n");
467         return NULL;
468     }
469
470     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
471
472     if (!cores_cfg) {
473         PrintError("Could not find core configuration (new config format required)\n");
474         return NULL;
475     }
476
477     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
478     if (num_cores == 0) {
479         PrintError("No cores specified in configuration\n");
480         return NULL;
481     }
482
483     V3_Print("Configuring %d cores\n", num_cores);
484
485     vm = allocate_guest(num_cores);    
486
487     if (!vm) {
488         PrintError("Could not allocate %d core guest\n", vm->num_cores);
489         return NULL;
490     }
491
492     vm->host_priv_data = priv_data;
493
494     vm->cfg_data = cfg_data;
495
496     V3_Print("Preconfiguration\n");
497
498     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
499         PrintError("Error in preconfiguration\n");
500         return NULL;
501     }
502
503     V3_Print("Per core configuration\n");
504     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
505
506     // per core configuration
507     for (i = 0; i < vm->num_cores; i++) {
508         struct guest_info * info = &(vm->cores[i]);
509
510         info->cpu_id = i;
511         info->vm_info = vm;
512         info->core_cfg_data = per_core_cfg;
513
514         if (pre_config_core(info, per_core_cfg) == -1) {
515             PrintError("Error in core %d preconfiguration\n", i);
516             return NULL;
517         }
518
519
520         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
521     }
522
523
524     V3_Print("Post Configuration\n");
525
526     if (post_config_vm(vm, vm->cfg_data->cfg) == -1) {
527         PrintError("Error in postconfiguration\n");
528         return NULL;
529     }
530
531
532     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
533
534     // per core configuration
535     for (i = 0; i < vm->num_cores; i++) {
536         struct guest_info * info = &(vm->cores[i]);
537
538         post_config_core(info, per_core_cfg);
539
540         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
541     }
542
543     V3_Print("Configuration successfull\n");
544
545     return vm;
546 }
547
548
549
550 int v3_free_config(struct v3_vm_info * vm) {
551    
552     v3_free_htable(vm->cfg_data->file_table, 1, 0);
553
554     v3_xml_free(vm->cfg_data->cfg);
555
556     V3_Free(vm->cfg_data);
557     return 0;
558 }
559
560
561
562
563 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
564     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
565
566     while (mem_region) {
567         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
568         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
569         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
570
571     
572         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
573             PrintError("Could not map memory region: %p-%p => %p\n", 
574                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
575             return -1;
576         }
577
578         mem_region = v3_cfg_next_branch(mem_region);
579     }
580
581     return 0;
582 }
583
584
585 static int setup_extensions(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
586     v3_cfg_tree_t * extension = v3_cfg_subtree(v3_cfg_subtree(cfg, "extensions"), "extension");
587
588     while (extension) {
589         char * ext_name = v3_cfg_val(extension, "name");
590
591         V3_Print("Configuring extension %s\n", ext_name);
592
593         if (v3_add_extension(vm, ext_name, extension) == -1) {
594             PrintError("Error adding extension %s\n", ext_name);
595             return -1;
596         }
597
598         extension = v3_cfg_next_branch(extension);
599     }
600
601     return 0;
602 }
603
604
605 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
606     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
607
608     
609     while (device) {
610         char * dev_class = v3_cfg_val(device, "class");
611
612         V3_Print("configuring device %s\n", dev_class);
613
614         if (v3_create_device(vm, dev_class, device) == -1) {
615             PrintError("Error creating device %s\n", dev_class);
616             return -1;
617         }
618         
619         device = v3_cfg_next_branch(device);
620     }
621
622     v3_print_dev_mgr(vm);
623
624     return 0;
625 }
626
627
628