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.


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