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.


Final changes to paging configuration format. Nested and shadow paging
[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 = atoi(memory_str) * 1024 * 1024;
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
212 #ifdef CONFIG_TELEMETRY
213     {
214         char * telemetry = v3_cfg_val(vm_cfg, "telemetry");
215
216         // This should go first, because other subsystems will depend on the guest_info flag    
217         if ((telemetry) && (strcasecmp(telemetry, "enable") == 0)) {
218             vm->enable_telemetry = 1;
219         } else {
220             vm->enable_telemetry = 0;
221         }
222     }
223 #endif
224
225     if (v3_init_vm(vm) == -1) {
226         PrintError("Failed to initialize VM\n");
227         return -1;
228     }
229
230
231
232    if (schedule_hz_str) {
233         sched_hz = atoi(schedule_hz_str);
234     }
235
236     PrintDebug("CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(), 
237                (void *)(addr_t)sched_hz);
238
239     vm->yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
240     
241     return 0;
242 }
243
244 static int determine_paging_mode(struct guest_info *info, v3_cfg_tree_t * core_cfg)
245 {
246     extern v3_cpu_arch_t v3_cpu_types[];
247
248     v3_cfg_tree_t *vm_tree = info->vm_info->cfg_data->cfg;
249     v3_cfg_tree_t *pg_tree = v3_cfg_subtree(vm_tree, "paging");
250     char *pg_mode = v3_cfg_val(pg_tree, "mode");
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 mode specified in configuration.\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     } else if (info->shdw_pg_mode == SHADOW_PAGING) {
276         PrintDebug("Guest Paging Mode: SHADOW_PAGING\n");
277     } else {
278         PrintError("Guest paging mode incorrectly set.\n");
279         return -1;
280     }
281     return 0;
282 }
283
284 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
285
286     if (determine_paging_mode(info, core_cfg))
287         return -1;
288
289     v3_init_core(info);
290
291     if (info->vm_info->vm_class == V3_PC_VM) {
292         if (pre_config_pc_core(info, core_cfg) == -1) {
293             PrintError("PC Post configuration failure\n");
294             return -1;
295         }
296     } else {
297         PrintError("Invalid VM Class\n");
298         return -1;
299     }
300
301     return 0;
302 }
303
304
305
306 static int post_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
307     
308     vm->run_state = VM_STOPPED;
309
310     // Configure the memory map for the guest
311     if (setup_memory_map(vm, cfg) == -1) {
312         PrintError("Setting up guest memory map failed...\n");
313         return -1;
314     }
315     
316     //v3_hook_io_port(info, 1234, &IO_Read, NULL, info);
317   
318     if (setup_devices(vm, cfg) == -1) {
319         PrintError("Failed to setup devices\n");
320         return -1;
321     }
322
323
324     //    v3_print_io_map(info);
325     v3_print_msr_map(vm);
326
327
328     if (vm->vm_class == V3_PC_VM) {
329         if (post_config_pc(vm, 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     if (v3_inject_mptable(vm)==-1) { 
339         PrintError("Failed to inject mptable during configuration\n");
340         return -1;
341     }
342
343     return 0;
344 }
345
346
347
348 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
349
350
351  
352     if (info->vm_info->vm_class == V3_PC_VM) {
353         if (post_config_pc_core(info, cfg) == -1) {
354             PrintError("PC Post configuration failure\n");
355             return -1;
356         }
357     } else {
358         PrintError("Invalid VM Class\n");
359         return -1;
360     }
361
362
363     return 0;
364 }
365
366
367
368 static struct v3_vm_info * allocate_guest(int num_cores) {
369     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
370     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
371
372     memset(vm, 0, guest_state_size);
373
374     vm->num_cores = num_cores;
375
376     return vm;
377 }
378
379
380
381 struct v3_vm_info * v3_config_guest(void * cfg_blob) {
382     v3_cpu_arch_t cpu_type = v3_get_cpu_type(v3_get_cpu_id());
383     struct v3_config * cfg_data = NULL;
384     struct v3_vm_info * vm = NULL;
385     int num_cores = 0;
386     int i = 0;
387     v3_cfg_tree_t * cores_cfg = NULL;
388     v3_cfg_tree_t * per_core_cfg = NULL;
389
390     if (cpu_type == V3_INVALID_CPU) {
391         PrintError("Configuring guest on invalid CPU\n");
392         return NULL;
393     }
394
395     cfg_data = parse_config(cfg_blob);
396
397     if (!cfg_data) {
398         PrintError("Could not parse configuration\n");
399         return NULL;
400     }
401
402     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
403
404     if (!cores_cfg) {
405         PrintError("Could not find core configuration (new config format required)\n");
406         return NULL;
407     }
408
409     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
410
411     if (num_cores == 0) {
412         PrintError("No cores specified in configuration\n");
413         return NULL;
414     }
415
416     V3_Print("Configuring %d cores\n", num_cores);
417
418     vm = allocate_guest(num_cores);    
419
420     if (!vm) {
421         PrintError("Could not allocate %d core guest\n", vm->num_cores);
422         return NULL;
423     }
424
425     vm->cfg_data = cfg_data;
426
427     V3_Print("Preconfiguration\n");
428
429     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
430         PrintError("Error in preconfiguration\n");
431         return NULL;
432     }
433
434
435     V3_Print("Per core configuration\n");
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         info->cpu_id = i;
443         info->vm_info = vm;
444
445         if (pre_config_core(info, per_core_cfg) == -1) {
446             PrintError("Error in core %d preconfiguration\n", i);
447             return NULL;
448         }
449
450         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
451     }
452
453
454     V3_Print("Post Configuration\n");
455
456     if (post_config_vm(vm, vm->cfg_data->cfg) == -1) {
457         PrintError("Error in postconfiguration\n");
458         return NULL;
459     }
460
461
462     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
463
464     // per core configuration
465     for (i = 0; i < vm->num_cores; i++) {
466         struct guest_info * info = &(vm->cores[i]);
467
468         post_config_core(info, per_core_cfg);
469
470         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
471     }
472
473     V3_Print("Configuration successfull\n");
474
475     return vm;
476 }
477
478
479
480
481
482 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
483     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
484
485     while (mem_region) {
486         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
487         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
488         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
489
490     
491         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
492             PrintError("Could not map memory region: %p-%p => %p\n", 
493                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
494             return -1;
495         }
496
497         mem_region = v3_cfg_next_branch(mem_region);
498     }
499
500     return 0;
501 }
502
503
504
505
506 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
507     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
508
509     
510     while (device) {
511         char * id = v3_cfg_val(device, "id");
512
513         V3_Print("configuring device %s\n", id);
514
515         if (v3_create_device(vm, id, device) == -1) {
516             PrintError("Error creating device %s\n", id);
517             return -1;
518         }
519         
520         device = v3_cfg_next_branch(device);
521     }
522
523     v3_print_dev_mgr(vm);
524
525     return 0;
526 }
527
528
529
530