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 guest initialization to vm_guest.c, added guest_info hypercall
[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
46
47 #include <palacios/vmm_host_events.h>
48 #include <palacios/vmm_socket.h>
49
50 #include "vmm_config_class.h"
51
52 // This is used to access the configuration file index table
53 struct file_hdr {
54     uint32_t index;
55     uint32_t size;
56     uint64_t offset;
57 };
58
59 struct file_idx_table {
60     uint64_t num_files;
61     struct file_hdr hdrs[0];
62 };
63
64
65
66
67 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg);
68 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg);
69
70
71
72 char * v3_cfg_val(v3_cfg_tree_t * tree, char * tag) {
73     char * attrib = (char *)v3_xml_attr(tree, tag);
74     v3_cfg_tree_t * child_entry = v3_xml_child(tree, tag);
75     char * val = NULL;
76
77     if ((child_entry != NULL) && (attrib != NULL)) {
78         PrintError("Duplicate Configuration parameters present for %s\n", tag);
79         return NULL;
80     }
81
82     val = (attrib == NULL) ? v3_xml_txt(child_entry): attrib;
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
170         V3_Print("File index=%d id=%s\n", idx, id);
171
172         strncpy(file->tag, id, 256);
173         file->size = hdr->size;
174         file->data = cfg_blob + hdr->offset;
175
176         V3_Print("Storing file data offset = %d, size=%d\n", (uint32_t)hdr->offset, hdr->size);
177         V3_Print("file data at %p\n", file->data);
178         list_add( &(file->file_node), &(cfg->file_list));
179
180         V3_Print("Keying file to name\n");
181         v3_htable_insert(cfg->file_table, (addr_t)(file->tag), (addr_t)(file));
182
183         V3_Print("Iterating to next file\n");
184
185         file_tree = v3_cfg_next_branch(file_tree);
186     }
187
188     V3_Print("Configuration parsed successfully\n");
189
190     return cfg;
191 }
192
193 static int pre_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * vm_cfg) {
194
195
196     char * memory_str = v3_cfg_val(vm_cfg, "memory");
197     char * schedule_hz_str = v3_cfg_val(vm_cfg, "schedule_hz");
198     char * vm_class = v3_cfg_val(vm_cfg, "class");
199     uint32_t sched_hz = 100;    // set the schedule frequency to 100 HZ
200     
201     if (!memory_str) {
202         PrintError("Memory is a required configuration parameter\n");
203         return -1;
204     }
205     
206     PrintDebug("Memory=%s\n", memory_str);
207
208     // Amount of ram the Guest will have, always in MB
209     vm->mem_size = atoi(memory_str) * 1024 * 1024;
210     
211     if (strcasecmp(vm_class, "PC") == 0) {
212         vm->vm_class = V3_PC_VM;
213     } else {
214         PrintError("Invalid VM class\n");
215         return -1;
216     }
217
218
219 #ifdef CONFIG_TELEMETRY
220     {
221         char * telemetry = v3_cfg_val(vm_cfg, "telemetry");
222
223         // This should go first, because other subsystems will depend on the guest_info flag    
224         if ((telemetry) && (strcasecmp(telemetry, "enable") == 0)) {
225             vm->enable_telemetry = 1;
226         } else {
227             vm->enable_telemetry = 0;
228         }
229     }
230 #endif
231
232     if (v3_init_vm(vm) == -1) {
233         PrintError("Failed to initialize VM\n");
234         return -1;
235     }
236
237
238
239    if (schedule_hz_str) {
240         sched_hz = atoi(schedule_hz_str);
241     }
242
243     PrintDebug("CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(), 
244                (void *)(addr_t)sched_hz);
245
246     vm->yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
247     
248     return 0;
249 }
250
251 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
252     extern v3_cpu_arch_t v3_cpu_types[];
253     char * paging = v3_cfg_val(core_cfg, "paging");
254
255
256     
257     if ((v3_cpu_types[info->cpu_id] == V3_SVM_REV3_CPU) && 
258         (paging) && (strcasecmp(paging, "nested") == 0)) {
259         PrintDebug("Guest Page Mode: NESTED_PAGING\n");
260         info->shdw_pg_mode = NESTED_PAGING;
261     } else {
262         PrintDebug("Guest Page Mode: SHADOW_PAGING\n");
263
264         info->shdw_pg_mode = SHADOW_PAGING;
265     }
266
267
268     v3_init_core(info);
269
270
271     if (info->vm_info->vm_class == V3_PC_VM) {
272         if (pre_config_pc_core(info, core_cfg) == -1) {
273             PrintError("PC Post configuration failure\n");
274             return -1;
275         }
276     } else {
277         PrintError("Invalid VM Class\n");
278         return -1;
279     }
280
281     return 0;
282 }
283
284
285
286 static int post_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
287     
288     vm->run_state = VM_STOPPED;
289
290     // Configure the memory map for the guest
291     if (setup_memory_map(vm, cfg) == -1) {
292         PrintError("Setting up guest memory map failed...\n");
293         return -1;
294     }
295     
296     //v3_hook_io_port(info, 1234, &IO_Read, NULL, info);
297   
298     if (setup_devices(vm, cfg) == -1) {
299         PrintError("Failed to setup devices\n");
300         return -1;
301     }
302
303
304     //    v3_print_io_map(info);
305     v3_print_msr_map(vm);
306
307
308     if (vm->vm_class == V3_PC_VM) {
309         if (post_config_pc(vm, cfg) == -1) {
310             PrintError("PC Post configuration failure\n");
311             return -1;
312         }
313     } else {
314         PrintError("Invalid VM Class\n");
315         return -1;
316     }
317
318     return 0;
319 }
320
321
322
323 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
324
325
326  
327     if (info->vm_info->vm_class == V3_PC_VM) {
328         if (post_config_pc_core(info, cfg) == -1) {
329             PrintError("PC Post configuration failure\n");
330             return -1;
331         }
332     } else {
333         PrintError("Invalid VM Class\n");
334         return -1;
335     }
336
337
338     return 0;
339 }
340
341
342
343 static struct v3_vm_info * allocate_guest(int num_cores) {
344     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
345     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
346
347     memset(vm, 0, guest_state_size);
348
349     vm->num_cores = num_cores;
350
351     return vm;
352 }
353
354
355
356 struct v3_vm_info * v3_config_guest(void * cfg_blob) {
357     v3_cpu_arch_t cpu_type = v3_get_cpu_type(v3_get_cpu_id());
358     struct v3_config * cfg_data = NULL;
359     struct v3_vm_info * vm = NULL;
360     int num_cores = 0;
361     int i = 0;
362     v3_cfg_tree_t * cores_cfg = NULL;
363     v3_cfg_tree_t * per_core_cfg = NULL;
364
365     if (cpu_type == V3_INVALID_CPU) {
366         PrintError("Configuring guest on invalid CPU\n");
367         return NULL;
368     }
369
370     cfg_data = parse_config(cfg_blob);
371
372     if (!cfg_data) {
373         PrintError("Could not parse configuration\n");
374         return NULL;
375     }
376
377     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
378
379     if (!cores_cfg) {
380         PrintError("Could not find core configuration (new config format required)\n");
381         return NULL;
382     }
383
384     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
385
386     if (num_cores == 0) {
387         PrintError("No cores specified in configuration\n");
388         return NULL;
389     }
390
391     V3_Print("Configuring %d cores\n", num_cores);
392
393     vm = allocate_guest(num_cores);    
394
395     if (!vm) {
396         PrintError("Could not allocate %d core guest\n", vm->num_cores);
397         return NULL;
398     }
399
400     vm->cfg_data = cfg_data;
401
402     V3_Print("Preconfiguration\n");
403
404     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
405         PrintError("Error in preconfiguration\n");
406         return NULL;
407     }
408
409
410     V3_Print("Per core configuration\n");
411     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
412
413     // per core configuration
414     for (i = 0; i < vm->num_cores; i++) {
415         struct guest_info * info = &(vm->cores[i]);
416
417         
418         info->cpu_id = i;
419         info->vm_info = vm;
420
421         pre_config_core(info, per_core_cfg);
422
423         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
424     }
425
426
427     V3_Print("Post Configuration\n");
428
429     if (post_config_vm(vm, vm->cfg_data->cfg) == -1) {
430         PrintError("Error in postconfiguration\n");
431         return NULL;
432     }
433
434
435     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
436
437     // per core configuration
438     for (i = 0; i < vm->num_cores; i++) {
439         struct guest_info * info = &(vm->cores[i]);
440
441         post_config_core(info, per_core_cfg);
442
443         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
444     }
445
446     V3_Print("Configuration successfull\n");
447
448     return vm;
449 }
450
451
452
453
454
455 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
456     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
457
458     while (mem_region) {
459         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
460         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
461         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
462
463     
464         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
465             PrintError("Could not map memory region: %p-%p => %p\n", 
466                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
467             return -1;
468         }
469
470         mem_region = v3_cfg_next_branch(mem_region);
471     }
472
473     return 0;
474 }
475
476
477
478
479 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
480     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
481
482     
483     while (device) {
484         char * id = v3_cfg_val(device, "id");
485
486         V3_Print("configuring device %s\n", id);
487
488         if (v3_create_device(vm, id, device) == -1) {
489             PrintError("Error creating device %s\n", id);
490             return -1;
491         }
492         
493         device = v3_cfg_next_branch(device);
494     }
495
496     v3_print_dev_mgr(vm);
497
498     return 0;
499 }
500
501
502
503