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.


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