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.


moved vmx/svm arch maps to global setup
[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     {
231         char * telemetry = v3_cfg_val(vm_cfg, "telemetry");
232
233         // This should go first, because other subsystems will depend on the guest_info flag    
234         if ((telemetry) && (strcasecmp(telemetry, "enable") == 0)) {
235             vm->enable_telemetry = 1;
236         } else {
237             vm->enable_telemetry = 0;
238         }
239     }
240 #endif
241
242     v3_init_hypercall_map(vm);
243     v3_init_io_map(vm);
244     v3_init_msr_map(vm);
245     v3_init_cpuid_map(vm);
246     v3_init_host_events(vm);
247     v3_init_intr_routers(vm);
248
249     // Initialize the memory map
250     if (v3_init_mem_map(vm) == -1) {
251         PrintError("Could not initialize shadow map\n");
252         return -1;
253     }
254
255 #ifdef CONFIG_SYMBIOTIC
256     v3_init_sym_iface(vm);
257 #endif
258
259     v3_init_dev_mgr(vm);
260
261
262 #ifdef CONFIG_SYMBIOTIC_SWAP
263     PrintDebug("initializing symbiotic swap\n");
264     v3_init_sym_swap(vm);
265 #endif
266
267
268         // init SVM/VMX
269 #ifdef CONFIG_SVM
270         if ((cpu_type == V3_SVM_CPU) || (cpu_type == V3_SVM_REV3_CPU)) {
271             v3_init_svm_io_map(vm);
272             v3_init_svm_msr_map(vm);
273         }
274 #endif
275 #ifdef CONFIG_VMX
276         else if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) {
277             v3_init_vmx_io_map(vm);
278             v3_init_vmx_msr_map(vm);
279         }
280 #endif
281         else {
282             PrintError("Invalid CPU Type\n");
283             return -1;
284         }
285
286    if (schedule_hz_str) {
287         sched_hz = atoi(schedule_hz_str);
288     }
289
290     PrintDebug("CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(), 
291                (void *)(addr_t)sched_hz);
292
293     vm->yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
294     
295     return 0;
296 }
297
298 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
299     extern v3_cpu_arch_t v3_cpu_types[];
300     char * paging = v3_cfg_val(core_cfg, "paging");
301
302     /*
303      * Initialize the subsystem data strutures
304      */
305 #ifdef CONFIG_TELEMETRY
306     if (info->vm_info->enable_telemetry) {
307         v3_init_telemetry(info);
308     }
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, 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