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 initial global shutdown functionality
[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         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     PrintDebug("Alignment for %lu bytes of memory computed as 0x%x\n", vm->mem_size, vm->mem_align);
241
242     if (strcasecmp(vm_class, "PC") == 0) {
243         vm->vm_class = V3_PC_VM;
244     } else {
245         PrintError("Invalid VM class\n");
246         return -1;
247     }
248
249 #ifdef CONFIG_TELEMETRY
250     {
251         char * telemetry = v3_cfg_val(vm_cfg, "telemetry");
252
253         // This should go first, because other subsystems will depend on the guest_info flag    
254         if ((telemetry) && (strcasecmp(telemetry, "enable") == 0)) {
255             vm->enable_telemetry = 1;
256         } else {
257             vm->enable_telemetry = 0;
258         }
259     }
260 #endif
261
262     if (v3_init_vm(vm) == -1) {
263         PrintError("Failed to initialize VM\n");
264         return -1;
265     }
266
267
268
269    if (schedule_hz_str) {
270         sched_hz = atoi(schedule_hz_str);
271     }
272
273     PrintDebug("CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(), 
274                (void *)(addr_t)sched_hz);
275
276     vm->yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
277     
278     return 0;
279 }
280
281
282 static int determine_paging_mode(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
283     extern v3_cpu_arch_t v3_cpu_types[];
284
285     v3_cfg_tree_t * vm_tree = info->vm_info->cfg_data->cfg;
286     v3_cfg_tree_t * pg_tree = v3_cfg_subtree(vm_tree, "paging");
287     char * pg_mode          = v3_cfg_val(pg_tree, "mode");
288     char * page_size        = v3_cfg_val(pg_tree, "page_size");
289     
290     PrintDebug("Paging mode specified as %s\n", pg_mode);
291
292     if (pg_mode) {
293         if ((strcasecmp(pg_mode, "nested") == 0)) {
294             if (v3_cpu_types[info->cpu_id] == V3_SVM_REV3_CPU) {
295                 info->shdw_pg_mode = NESTED_PAGING;
296             } else {
297                 PrintError("Nested paging not supported on this hardware. Defaulting to shadow paging\n");
298                 info->shdw_pg_mode = SHADOW_PAGING;
299             }
300         } else if ((strcasecmp(pg_mode, "shadow") == 0)) {
301             info->shdw_pg_mode = SHADOW_PAGING;
302         } else {
303             PrintError("Invalid paging mode (%s) specified in configuration. Defaulting to shadow paging\n", pg_mode);
304             info->shdw_pg_mode = SHADOW_PAGING;
305         }
306     } else {
307         PrintDebug("No paging type specified in configuration. Defaulting to shadow paging\n");
308         info->shdw_pg_mode = SHADOW_PAGING;
309     }
310
311
312     if (info->shdw_pg_mode == NESTED_PAGING) {
313         PrintDebug("Guest Paging Mode: NESTED_PAGING\n");
314         if (strcasecmp(page_size, "4kb") == 0) { /* TODO: this may not be an ideal place for this */
315             info->vm_info->paging_size = PAGING_4KB;
316         } else if (strcasecmp(page_size, "2mb") == 0) {
317             info->vm_info->paging_size = PAGING_2MB;
318         } else {
319             PrintError("Invalid VM paging size: '%s'\n", page_size);
320             return -1;
321         }
322         PrintDebug("VM page size=%s\n", page_size);
323     } else if (info->shdw_pg_mode == SHADOW_PAGING) {
324         PrintDebug("Guest Paging Mode: SHADOW_PAGING\n");
325     } else {
326         PrintError("Guest paging mode incorrectly set.\n");
327         return -1;
328     }
329
330     if (v3_cfg_val(pg_tree, "large_pages") != NULL) {
331         if (strcasecmp(v3_cfg_val(pg_tree, "large_pages"), "true") == 0) {
332             info->use_large_pages = 1;
333             PrintDebug("Use of large pages in memory virtualization enabled.\n");
334         }
335     }
336     return 0;
337 }
338
339 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
340
341     if (determine_paging_mode(info, core_cfg))
342         return -1;
343
344     v3_init_core(info);
345
346     if (info->vm_info->vm_class == V3_PC_VM) {
347         if (pre_config_pc_core(info, core_cfg) == -1) {
348             PrintError("PC Post configuration failure\n");
349             return -1;
350         }
351     } else {
352         PrintError("Invalid VM Class\n");
353         return -1;
354     }
355
356     return 0;
357 }
358
359
360
361 static int post_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
362     
363     vm->run_state = VM_STOPPED;
364
365     // Configure the memory map for the guest
366     if (setup_memory_map(vm, cfg) == -1) {
367         PrintError("Setting up guest memory map failed...\n");
368         return -1;
369     }
370     
371     //v3_hook_io_port(info, 1234, &IO_Read, NULL, info);
372   
373     if (setup_devices(vm, cfg) == -1) {
374         PrintError("Failed to setup devices\n");
375         return -1;
376     }
377
378
379     //    v3_print_io_map(info);
380     v3_print_msr_map(vm);
381
382
383     if (vm->vm_class == V3_PC_VM) {
384         if (post_config_pc(vm, cfg) == -1) {
385             PrintError("PC Post configuration failure\n");
386             return -1;
387         }
388     } else {
389         PrintError("Invalid VM Class\n");
390         return -1;
391     }
392
393     return 0;
394 }
395
396
397
398 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
399
400     info->core_run_state = CORE_STOPPED;
401  
402     if (info->vm_info->vm_class == V3_PC_VM) {
403         if (post_config_pc_core(info, cfg) == -1) {
404             PrintError("PC Post configuration failure\n");
405             return -1;
406         }
407     } else {
408         PrintError("Invalid VM Class\n");
409         return -1;
410     }
411
412
413     return 0;
414 }
415
416
417
418 static struct v3_vm_info * allocate_guest(int num_cores) {
419     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
420     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
421
422     memset(vm, 0, guest_state_size);
423
424     vm->num_cores = num_cores;
425
426     return vm;
427 }
428
429
430
431 struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
432     v3_cpu_arch_t cpu_type = v3_get_cpu_type(V3_Get_CPU());
433     struct v3_config * cfg_data = NULL;
434     struct v3_vm_info * vm = NULL;
435     int num_cores = 0;
436     int i = 0;
437     v3_cfg_tree_t * cores_cfg = NULL;
438     v3_cfg_tree_t * per_core_cfg = NULL;
439
440     if (cpu_type == V3_INVALID_CPU) {
441         PrintError("Configuring guest on invalid CPU\n");
442         return NULL;
443     }
444
445     cfg_data = parse_config(cfg_blob);
446
447     if (!cfg_data) {
448         PrintError("Could not parse configuration\n");
449         return NULL;
450     }
451
452     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
453
454     if (!cores_cfg) {
455         PrintError("Could not find core configuration (new config format required)\n");
456         return NULL;
457     }
458
459     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
460
461     if (num_cores == 0) {
462         PrintError("No cores specified in configuration\n");
463         return NULL;
464     }
465
466     V3_Print("Configuring %d cores\n", num_cores);
467
468     vm = allocate_guest(num_cores);    
469
470     if (!vm) {
471         PrintError("Could not allocate %d core guest\n", vm->num_cores);
472         return NULL;
473     }
474
475     vm->host_priv_data = priv_data;
476
477     vm->cfg_data = cfg_data;
478
479     V3_Print("Preconfiguration\n");
480
481     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
482         PrintError("Error in preconfiguration\n");
483         return NULL;
484     }
485
486
487     V3_Print("Per core configuration\n");
488     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
489
490     // per core configuration
491     for (i = 0; i < vm->num_cores; i++) {
492         struct guest_info * info = &(vm->cores[i]);
493
494         info->cpu_id = i;
495         info->vm_info = vm;
496         info->core_cfg_data = per_core_cfg;
497
498         if (pre_config_core(info, per_core_cfg) == -1) {
499             PrintError("Error in core %d preconfiguration\n", i);
500             return NULL;
501         }
502
503         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
504     }
505
506
507     V3_Print("Post Configuration\n");
508
509     if (post_config_vm(vm, vm->cfg_data->cfg) == -1) {
510         PrintError("Error in postconfiguration\n");
511         return NULL;
512     }
513
514
515     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
516
517     // per core configuration
518     for (i = 0; i < vm->num_cores; i++) {
519         struct guest_info * info = &(vm->cores[i]);
520
521         post_config_core(info, per_core_cfg);
522
523         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
524     }
525
526     V3_Print("Configuration successfull\n");
527
528     return vm;
529 }
530
531
532
533 int v3_free_config(struct v3_vm_info * vm) {
534    
535     v3_free_htable(vm->cfg_data->file_table, 1, 0);
536
537     v3_xml_free(vm->cfg_data->cfg);
538
539     V3_Free(vm->cfg_data);
540     return 0;
541 }
542
543
544
545 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
546     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
547
548     while (mem_region) {
549         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
550         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
551         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
552
553     
554         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
555             PrintError("Could not map memory region: %p-%p => %p\n", 
556                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
557             return -1;
558         }
559
560         mem_region = v3_cfg_next_branch(mem_region);
561     }
562
563     return 0;
564 }
565
566
567
568
569 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
570     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
571
572     
573     while (device) {
574         char * dev_class = v3_cfg_val(device, "class");
575
576         V3_Print("configuring device %s\n", dev_class);
577
578         if (v3_create_device(vm, dev_class, device) == -1) {
579             PrintError("Error creating device %s\n", dev_class);
580             return -1;
581         }
582         
583         device = v3_cfg_next_branch(device);
584     }
585
586     v3_print_dev_mgr(vm);
587
588     return 0;
589 }
590
591
592
593