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.


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