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.


New Shadow paging implementation to allow pluggable shadow paging implementations
[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     v3_cfg_tree_t * paging_cfg = v3_cfg_subtree(core_cfg, "paging");
254     char * paging = v3_cfg_val(paging_cfg, "mode");
255
256
257     
258     if ((v3_cpu_types[info->cpu_id] == V3_SVM_REV3_CPU) && 
259         (paging) && (strcasecmp(paging, "nested") == 0)) {
260         PrintDebug("Guest Page Mode: NESTED_PAGING\n");
261         info->shdw_pg_mode = NESTED_PAGING;
262     } else {
263         PrintDebug("Guest Page Mode: SHADOW_PAGING\n");
264
265         info->shdw_pg_mode = SHADOW_PAGING;
266     }
267
268
269     v3_init_core(info);
270
271
272     if (info->vm_info->vm_class == V3_PC_VM) {
273         if (pre_config_pc_core(info, core_cfg) == -1) {
274             PrintError("PC Post configuration failure\n");
275             return -1;
276         }
277     } else {
278         PrintError("Invalid VM Class\n");
279         return -1;
280     }
281
282     return 0;
283 }
284
285
286
287 static int post_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
288     
289     vm->run_state = VM_STOPPED;
290
291     // Configure the memory map for the guest
292     if (setup_memory_map(vm, cfg) == -1) {
293         PrintError("Setting up guest memory map failed...\n");
294         return -1;
295     }
296     
297     //v3_hook_io_port(info, 1234, &IO_Read, NULL, info);
298   
299     if (setup_devices(vm, cfg) == -1) {
300         PrintError("Failed to setup devices\n");
301         return -1;
302     }
303
304
305     //    v3_print_io_map(info);
306     v3_print_msr_map(vm);
307
308
309     if (vm->vm_class == V3_PC_VM) {
310         if (post_config_pc(vm, cfg) == -1) {
311             PrintError("PC Post configuration failure\n");
312             return -1;
313         }
314     } else {
315         PrintError("Invalid VM Class\n");
316         return -1;
317     }
318
319     return 0;
320 }
321
322
323
324 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
325
326
327  
328     if (info->vm_info->vm_class == V3_PC_VM) {
329         if (post_config_pc_core(info, cfg) == -1) {
330             PrintError("PC Post configuration failure\n");
331             return -1;
332         }
333     } else {
334         PrintError("Invalid VM Class\n");
335         return -1;
336     }
337
338
339     return 0;
340 }
341
342
343
344 static struct v3_vm_info * allocate_guest(int num_cores) {
345     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
346     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
347
348     memset(vm, 0, guest_state_size);
349
350     vm->num_cores = num_cores;
351
352     return vm;
353 }
354
355
356
357 struct v3_vm_info * v3_config_guest(void * cfg_blob) {
358     v3_cpu_arch_t cpu_type = v3_get_cpu_type(v3_get_cpu_id());
359     struct v3_config * cfg_data = NULL;
360     struct v3_vm_info * vm = NULL;
361     int num_cores = 0;
362     int i = 0;
363     v3_cfg_tree_t * cores_cfg = NULL;
364     v3_cfg_tree_t * per_core_cfg = NULL;
365
366     if (cpu_type == V3_INVALID_CPU) {
367         PrintError("Configuring guest on invalid CPU\n");
368         return NULL;
369     }
370
371     cfg_data = parse_config(cfg_blob);
372
373     if (!cfg_data) {
374         PrintError("Could not parse configuration\n");
375         return NULL;
376     }
377
378     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
379
380     if (!cores_cfg) {
381         PrintError("Could not find core configuration (new config format required)\n");
382         return NULL;
383     }
384
385     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
386
387     if (num_cores == 0) {
388         PrintError("No cores specified in configuration\n");
389         return NULL;
390     }
391
392     V3_Print("Configuring %d cores\n", num_cores);
393
394     vm = allocate_guest(num_cores);    
395
396     if (!vm) {
397         PrintError("Could not allocate %d core guest\n", vm->num_cores);
398         return NULL;
399     }
400
401     vm->cfg_data = cfg_data;
402
403     V3_Print("Preconfiguration\n");
404
405     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
406         PrintError("Error in preconfiguration\n");
407         return NULL;
408     }
409
410
411     V3_Print("Per core configuration\n");
412     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
413
414     // per core configuration
415     for (i = 0; i < vm->num_cores; i++) {
416         struct guest_info * info = &(vm->cores[i]);
417
418         
419         info->cpu_id = i;
420         info->vm_info = vm;
421
422         pre_config_core(info, per_core_cfg);
423
424         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
425     }
426
427
428     V3_Print("Post Configuration\n");
429
430     if (post_config_vm(vm, vm->cfg_data->cfg) == -1) {
431         PrintError("Error in postconfiguration\n");
432         return NULL;
433     }
434
435
436     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
437
438     // per core configuration
439     for (i = 0; i < vm->num_cores; i++) {
440         struct guest_info * info = &(vm->cores[i]);
441
442         post_config_core(info, per_core_cfg);
443
444         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
445     }
446
447     V3_Print("Configuration successfull\n");
448
449     return vm;
450 }
451
452
453
454
455
456 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
457     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
458
459     while (mem_region) {
460         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
461         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
462         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
463
464     
465         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
466             PrintError("Could not map memory region: %p-%p => %p\n", 
467                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
468             return -1;
469         }
470
471         mem_region = v3_cfg_next_branch(mem_region);
472     }
473
474     return 0;
475 }
476
477
478
479
480 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
481     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
482
483     
484     while (device) {
485         char * id = v3_cfg_val(device, "id");
486
487         V3_Print("configuring device %s\n", id);
488
489         if (v3_create_device(vm, id, device) == -1) {
490             PrintError("Error creating device %s\n", id);
491             return -1;
492         }
493         
494         device = v3_cfg_next_branch(device);
495     }
496
497     v3_print_dev_mgr(vm);
498
499     return 0;
500 }
501
502
503
504