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.


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