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 extension framework
[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_extensions(struct v3_vm_info * vm, v3_cfg_tree_t * cfg);
62 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg);
63
64
65
66 char * v3_cfg_val(v3_cfg_tree_t * tree, char * tag) {
67     char * attrib = (char *)v3_xml_attr(tree, tag);
68     v3_cfg_tree_t * child_entry = v3_xml_child(tree, tag);
69     char * val = NULL;
70
71     if ((child_entry != NULL) && (attrib != NULL)) {
72         PrintError("Duplicate Configuration parameters present for %s\n", tag);
73         return NULL;
74     }
75
76     if (attrib == NULL) {
77         val = v3_xml_txt(child_entry);
78         
79         if ( val[0] == 0 )
80                 val = NULL;
81     } else {
82         val = attrib;
83     }
84     
85     return val;
86 }
87
88 v3_cfg_tree_t * v3_cfg_subtree(v3_cfg_tree_t * tree, char * tag) {
89     return v3_xml_child(tree, tag);
90 }
91
92 v3_cfg_tree_t * v3_cfg_next_branch(v3_cfg_tree_t * tree) {
93     return v3_xml_next(tree);
94 }
95
96
97
98 struct v3_cfg_file * v3_cfg_get_file(struct v3_vm_info * vm, char * tag) {
99     struct v3_cfg_file * file = NULL;
100
101     file = (struct v3_cfg_file *)v3_htable_search(vm->cfg_data->file_table, (addr_t)tag);
102
103     return file;
104 }
105
106
107 static uint_t file_hash_fn(addr_t key) {
108     char * name = (char *)key;
109     return v3_hash_buffer((uchar_t *)name, strlen(name));
110 }
111
112 static int file_eq_fn(addr_t key1, addr_t key2) {
113     char * name1 = (char *)key1;
114     char * name2 = (char *)key2;
115
116     return (strcmp(name1, name2) == 0);
117 }
118
119 static struct v3_config * parse_config(void * cfg_blob) {
120     struct v3_config * cfg = NULL;
121     int offset = 0;
122     uint_t xml_len = 0; 
123     struct file_idx_table * files = NULL;
124     v3_cfg_tree_t * file_tree = NULL;
125
126     V3_Print("cfg data at %p\n", cfg_blob);
127
128     if (memcmp(cfg_blob, "v3vee\0\0\0", 8) != 0) {
129         PrintError("Invalid Configuration Header\n");
130         return NULL;
131     }
132
133     offset += 8;
134
135     cfg = (struct v3_config *)V3_Malloc(sizeof(struct v3_config));
136     memset(cfg, 0, sizeof(struct v3_config));
137
138     cfg->blob = cfg_blob;
139     INIT_LIST_HEAD(&(cfg->file_list));
140     cfg->file_table = v3_create_htable(0, file_hash_fn, file_eq_fn);
141     
142     xml_len = *(uint32_t *)(cfg_blob + offset);
143     offset += 4;
144
145     cfg->cfg = (v3_cfg_tree_t *)v3_xml_parse((uint8_t *)(cfg_blob + offset));
146     offset += xml_len;
147    
148     offset += 8;
149
150     files = (struct file_idx_table *)(cfg_blob + offset);
151
152     V3_Print("Number of files in cfg: %d\n", (uint32_t)(files->num_files));
153
154     file_tree = v3_cfg_subtree(v3_cfg_subtree(cfg->cfg, "files"), "file");
155
156     while (file_tree) {
157         char * id = v3_cfg_val(file_tree, "id");
158         char * index = v3_cfg_val(file_tree, "index");
159         int idx = atoi(index);
160         struct file_hdr * hdr = &(files->hdrs[idx]);
161         struct v3_cfg_file * file = NULL;
162
163         file = (struct v3_cfg_file *)V3_Malloc(sizeof(struct v3_cfg_file));
164         
165         if (!file) {
166             PrintError("Could not allocate file structure\n");
167             return NULL;
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
216
217 static int pre_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * vm_cfg) {
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
242     PrintDebug("Alignment for %lu bytes of memory computed as 0x%x\n", vm->mem_size, vm->mem_align);
243
244     if (strcasecmp(vm_class, "PC") == 0) {
245         vm->vm_class = V3_PC_VM;
246     } else {
247         PrintError("Invalid VM class\n");
248         return -1;
249     }
250
251 #ifdef CONFIG_TELEMETRY
252     {
253         char * telemetry = v3_cfg_val(vm_cfg, "telemetry");
254
255         // This should go first, because other subsystems will depend on the guest_info flag    
256         if ((telemetry) && (strcasecmp(telemetry, "enable") == 0)) {
257             vm->enable_telemetry = 1;
258         } else {
259             vm->enable_telemetry = 0;
260         }
261     }
262 #endif
263
264     if (v3_init_vm(vm) == -1) {
265         PrintError("Failed to initialize VM\n");
266         return -1;
267     }
268
269
270
271    if (schedule_hz_str) {
272         sched_hz = atoi(schedule_hz_str);
273     }
274
275     PrintDebug("CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(), 
276                (void *)(addr_t)sched_hz);
277
278     vm->yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
279     
280     return 0;
281 }
282
283
284 static int determine_paging_mode(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
285     extern v3_cpu_arch_t v3_cpu_types[];
286
287     v3_cfg_tree_t * vm_tree = info->vm_info->cfg_data->cfg;
288     v3_cfg_tree_t * pg_tree = v3_cfg_subtree(vm_tree, "paging");
289     char * pg_mode          = v3_cfg_val(pg_tree, "mode");
290     char * page_size        = v3_cfg_val(pg_tree, "page_size");
291     
292     PrintDebug("Paging mode specified as %s\n", pg_mode);
293
294     if (pg_mode) {
295         if ((strcasecmp(pg_mode, "nested") == 0)) {
296             // we assume symmetric cores, so if core 0 has nested paging they all do
297             if (v3_cpu_types[0] == V3_SVM_REV3_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 (info->shdw_pg_mode == NESTED_PAGING) {
316         PrintDebug("Guest Paging Mode: NESTED_PAGING\n");
317         if (strcasecmp(page_size, "4kb") == 0) { /* TODO: this may not be an ideal place for this */
318             info->vm_info->paging_size = PAGING_4KB;
319         } else if (strcasecmp(page_size, "2mb") == 0) {
320             info->vm_info->paging_size = PAGING_2MB;
321         } else {
322             PrintError("Invalid VM paging size: '%s'\n", page_size);
323             return -1;
324         }
325         PrintDebug("VM page size=%s\n", page_size);
326     } else if (info->shdw_pg_mode == SHADOW_PAGING) {
327         PrintDebug("Guest Paging Mode: SHADOW_PAGING\n");
328     } else {
329         PrintError("Guest paging mode incorrectly set.\n");
330         return -1;
331     }
332
333     if (v3_cfg_val(pg_tree, "large_pages") != NULL) {
334         if (strcasecmp(v3_cfg_val(pg_tree, "large_pages"), "true") == 0) {
335             info->use_large_pages = 1;
336             PrintDebug("Use of large pages in memory virtualization enabled.\n");
337         }
338     }
339     return 0;
340 }
341
342 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
343     if (determine_paging_mode(info, core_cfg) != 0) {
344         return -1;
345     }
346
347     v3_init_core(info);
348
349     if (info->vm_info->vm_class == V3_PC_VM) {
350         if (pre_config_pc_core(info, core_cfg) == -1) {
351             PrintError("PC Post configuration failure\n");
352             return -1;
353         }
354     } else {
355         PrintError("Invalid VM Class\n");
356         return -1;
357     }
358
359     return 0;
360 }
361
362
363
364 static int post_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
365     
366     vm->run_state = VM_STOPPED;
367
368     // Configure the memory map for the guest
369     if (setup_memory_map(vm, cfg) == -1) {
370         PrintError("Setting up guest memory map failed...\n");
371         return -1;
372     }
373
374     /* 
375      * Initialize configured extensions 
376      */
377     if (setup_extensions(vm, cfg) == -1) {
378         PrintError("Failed to setup extensions\n");
379         return -1;
380     }
381
382     /* 
383      * Initialize configured devices
384      */
385     if (setup_devices(vm, cfg) == -1) {
386         PrintError("Failed to setup devices\n");
387         return -1;
388     }
389
390
391     //    v3_print_io_map(info);
392     v3_print_msr_map(vm);
393
394
395     if (vm->vm_class == V3_PC_VM) {
396         if (post_config_pc(vm, cfg) == -1) {
397             PrintError("PC Post configuration failure\n");
398             return -1;
399         }
400     } else {
401         PrintError("Invalid VM Class\n");
402         return -1;
403     }
404
405     return 0;
406 }
407
408
409
410 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
411
412     info->core_run_state = CORE_STOPPED;
413  
414     if (info->vm_info->vm_class == V3_PC_VM) {
415         if (post_config_pc_core(info, cfg) == -1) {
416             PrintError("PC Post configuration failure\n");
417             return -1;
418         }
419     } else {
420         PrintError("Invalid VM Class\n");
421         return -1;
422     }
423
424
425     return 0;
426 }
427
428
429
430 static struct v3_vm_info * allocate_guest(int num_cores) {
431     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
432     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
433
434     memset(vm, 0, guest_state_size);
435
436     vm->num_cores = num_cores;
437
438     return vm;
439 }
440
441
442
443 struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
444     v3_cpu_arch_t cpu_type = v3_get_cpu_type(V3_Get_CPU());
445     struct v3_config * cfg_data = NULL;
446     struct v3_vm_info * vm = NULL;
447     int num_cores = 0;
448     int i = 0;
449     v3_cfg_tree_t * cores_cfg = NULL;
450     v3_cfg_tree_t * per_core_cfg = NULL;
451
452     if (cpu_type == V3_INVALID_CPU) {
453         PrintError("Configuring guest on invalid CPU\n");
454         return NULL;
455     }
456
457     cfg_data = parse_config(cfg_blob);
458
459     if (!cfg_data) {
460         PrintError("Could not parse configuration\n");
461         return NULL;
462     }
463
464     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
465
466     if (!cores_cfg) {
467         PrintError("Could not find core configuration (new config format required)\n");
468         return NULL;
469     }
470
471     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
472     if (num_cores == 0) {
473         PrintError("No cores specified in configuration\n");
474         return NULL;
475     }
476
477     V3_Print("Configuring %d cores\n", num_cores);
478
479     vm = allocate_guest(num_cores);    
480
481     if (!vm) {
482         PrintError("Could not allocate %d core guest\n", vm->num_cores);
483         return NULL;
484     }
485
486     vm->host_priv_data = priv_data;
487
488     vm->cfg_data = cfg_data;
489
490     V3_Print("Preconfiguration\n");
491
492     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
493         PrintError("Error in preconfiguration\n");
494         return NULL;
495     }
496
497     V3_Print("Per core configuration\n");
498     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
499
500     // per core configuration
501     for (i = 0; i < vm->num_cores; i++) {
502         struct guest_info * info = &(vm->cores[i]);
503
504         info->cpu_id = i;
505         info->vm_info = vm;
506         info->core_cfg_data = per_core_cfg;
507
508         if (pre_config_core(info, per_core_cfg) == -1) {
509             PrintError("Error in core %d preconfiguration\n", i);
510             return NULL;
511         }
512
513
514         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
515     }
516
517
518     V3_Print("Post Configuration\n");
519
520     if (post_config_vm(vm, vm->cfg_data->cfg) == -1) {
521         PrintError("Error in postconfiguration\n");
522         return NULL;
523     }
524
525
526     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
527
528     // per core configuration
529     for (i = 0; i < vm->num_cores; i++) {
530         struct guest_info * info = &(vm->cores[i]);
531
532         post_config_core(info, per_core_cfg);
533
534         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
535     }
536
537     V3_Print("Configuration successfull\n");
538
539     return vm;
540 }
541
542
543
544 int v3_free_config(struct v3_vm_info * vm) {
545    
546     v3_free_htable(vm->cfg_data->file_table, 1, 0);
547
548     v3_xml_free(vm->cfg_data->cfg);
549
550     V3_Free(vm->cfg_data);
551     return 0;
552 }
553
554
555
556 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
557     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
558
559     while (mem_region) {
560         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
561         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
562         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
563
564     
565         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
566             PrintError("Could not map memory region: %p-%p => %p\n", 
567                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
568             return -1;
569         }
570
571         mem_region = v3_cfg_next_branch(mem_region);
572     }
573
574     return 0;
575 }
576
577
578 static int setup_extensions(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
579     v3_cfg_tree_t * extension = v3_cfg_subtree(v3_cfg_subtree(cfg, "extensions"), "extension");
580
581     while (extension) {
582         char * ext_name = v3_cfg_val(extension, "name");
583
584         V3_Print("Configuring extension %s\n", ext_name);
585
586         if (v3_add_extension(vm, ext_name, extension) == -1) {
587             PrintError("Error adding extension %s\n", ext_name);
588             return -1;
589         }
590
591         extension = v3_cfg_next_branch(extension);
592     }
593
594     return 0;
595 }
596
597
598 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
599     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
600
601     
602     while (device) {
603         char * dev_class = v3_cfg_val(device, "class");
604
605         V3_Print("configuring device %s\n", dev_class);
606
607         if (v3_create_device(vm, dev_class, device) == -1) {
608             PrintError("Error creating device %s\n", dev_class);
609             return -1;
610         }
611         
612         device = v3_cfg_next_branch(device);
613     }
614
615     v3_print_dev_mgr(vm);
616
617     return 0;
618 }
619
620
621