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.


updates to enable functionality necessary for SEABIOS to run
[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_sprintf.h>
34
35
36
37
38
39 #include <palacios/vmm_host_events.h>
40 #include <palacios/vmm_perftune.h>
41
42 #include "vmm_config_class.h"
43
44
45 /* The Palacios cookie encodes "v3vee" followed by a 
46    3 byte version code.   There are currently two versions:
47
48     \0\0\0 => original (no checksum)
49     \0\0\1 => checksum
50 */
51 #define COOKIE_LEN 8
52 #define COOKIE_V0 "v3vee\0\0\0"
53 #define COOKIE_V1 "v3vee\0\0\1"
54
55
56
57
58 // This is used to access the configuration file index table
59 struct file_hdr_v0 {
60     uint32_t index;
61     uint32_t size;
62     uint64_t offset;
63 };
64
65 struct file_hdr_v1 {
66     uint32_t index;
67     uint32_t size;
68     uint64_t offset;
69     ulong_t  hash;
70 };
71
72
73 struct file_idx_table_v0 {
74     uint64_t num_files;
75     struct file_hdr_v0 hdrs[0];
76 };
77
78 struct file_idx_table_v1 {
79     uint64_t num_files;
80     struct file_hdr_v1 hdrs[0];
81 };
82
83
84
85
86 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg);
87 static int setup_extensions(struct v3_vm_info * vm, v3_cfg_tree_t * cfg);
88 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg);
89
90
91
92 char * v3_cfg_val(v3_cfg_tree_t * tree, char * tag) {
93     char * attrib = (char *)v3_xml_attr(tree, tag);
94     v3_cfg_tree_t * child_entry = v3_xml_child(tree, tag);
95     char * val = NULL;
96
97     if ((child_entry != NULL) && (attrib != NULL)) {
98         PrintError(VM_NONE, VCORE_NONE, "Duplicate Configuration parameters present for %s\n", tag);
99         return NULL;
100     }
101
102     if (attrib == NULL) {
103         val = v3_xml_txt(child_entry);
104         
105         if ( val[0] == 0 )
106                 val = NULL;
107     } else {
108         val = attrib;
109     }
110     
111     return val;
112 }
113
114 v3_cfg_tree_t * v3_cfg_subtree(v3_cfg_tree_t * tree, char * tag) {
115     return v3_xml_child(tree, tag);
116 }
117
118 v3_cfg_tree_t * v3_cfg_next_branch(v3_cfg_tree_t * tree) {
119     return v3_xml_next(tree);
120 }
121
122
123
124 struct v3_cfg_file * v3_cfg_get_file(struct v3_vm_info * vm, char * tag) {
125     struct v3_cfg_file * file = NULL;
126
127     file = (struct v3_cfg_file *)v3_htable_search(vm->cfg_data->file_table, (addr_t)tag);
128
129     return file;
130 }
131
132
133 static uint_t file_hash_fn(addr_t key) {
134     char * name = (char *)key;
135     return v3_hash_buffer((uchar_t *)name, strlen(name));
136 }
137
138 static int file_eq_fn(addr_t key1, addr_t key2) {
139     char * name1 = (char *)key1;
140     char * name2 = (char *)key2;
141
142     return (strcmp(name1, name2) == 0);
143 }
144
145 static struct v3_config * parse_config(void * cfg_blob) {
146     struct v3_config * cfg = NULL;
147     int offset = 0;
148     uint_t xml_len = 0; 
149     struct file_idx_table_v0 * files_v0 = NULL;
150     struct file_idx_table_v1 * files_v1 = NULL;
151     v3_cfg_tree_t * file_tree = NULL;
152     int version=-1;
153
154     V3_Print(VM_NONE, VCORE_NONE, "cfg data at %p\n", cfg_blob);
155
156     if (memcmp(cfg_blob, COOKIE_V0, COOKIE_LEN) == 0) {
157         version = 0;
158     } else if (memcmp(cfg_blob, COOKIE_V1, COOKIE_LEN) == 0) { 
159         version = 1;
160     } else {
161         PrintError(VM_NONE, VCORE_NONE, "Invalid Configuration Header Or Unknown Version\n");
162         return NULL;
163     } 
164
165     V3_Print(VM_NONE, VCORE_NONE, "Handling Palacios Image Format, Version 0x%x\n",version);
166
167     offset += COOKIE_LEN;
168
169     cfg = (struct v3_config *)V3_Malloc(sizeof(struct v3_config));
170
171     if (!cfg) {
172         PrintError(VM_NONE, VCORE_NONE, "Unable to allocate while parsing\n");
173         return NULL;
174     }
175
176     memset(cfg, 0, sizeof(struct v3_config));
177
178     cfg->blob = cfg_blob;
179     INIT_LIST_HEAD(&(cfg->file_list));
180     cfg->file_table = v3_create_htable(0, file_hash_fn, file_eq_fn);
181
182     if (!(cfg->file_table)) {
183         PrintError(VM_NONE, VCORE_NONE, "Unable to allocate hash table while parsing\n");
184         V3_Free(cfg);
185         return NULL;
186     }
187     
188     xml_len = *(uint32_t *)(cfg_blob + offset);
189     offset += 4;
190
191     cfg->cfg = (v3_cfg_tree_t *)v3_xml_parse((uint8_t *)(cfg_blob + offset));
192     offset += xml_len;
193    
194     offset += 8;
195
196     // This is hideous, but the file formats are still very close
197     if (version==0) { 
198         files_v0 = (struct file_idx_table_v0 *)(cfg_blob + offset);
199         V3_Print(VM_NONE, VCORE_NONE, "Number of files in cfg: %d\n", (uint32_t)(files_v0->num_files));
200     } else {
201         files_v1 = (struct file_idx_table_v1 *)(cfg_blob + offset);
202         V3_Print(VM_NONE, VCORE_NONE, "Number of files in cfg: %d\n", (uint32_t)(files_v1->num_files));
203     }
204
205
206     file_tree = v3_cfg_subtree(v3_cfg_subtree(cfg->cfg, "files"), "file");
207
208     while (file_tree) {
209         char * id = v3_cfg_val(file_tree, "id");
210         char * index = v3_cfg_val(file_tree, "index");
211         int idx = atoi(index);
212         struct v3_cfg_file * file = NULL;
213
214         file = (struct v3_cfg_file *)V3_Malloc(sizeof(struct v3_cfg_file));
215         
216         if (!file) {
217             PrintError(VM_NONE, VCORE_NONE, "Could not allocate file structure\n");
218             v3_free_htable(cfg->file_table,0,0);
219             V3_Free(cfg);
220             return NULL;
221         }
222
223         V3_Print(VM_NONE, VCORE_NONE, "File index=%d id=%s\n", idx, id);
224
225         strncpy(file->tag, id, V3_MAX_TAG_LEN);
226
227         if (version==0) { 
228             struct file_hdr_v0 * hdr = &(files_v0->hdrs[idx]);
229
230             file->size = hdr->size;
231             file->data = cfg_blob + hdr->offset;
232             file->hash = 0;
233             
234             V3_Print(VM_NONE, VCORE_NONE, "Storing file data offset = %d, size=%d\n", (uint32_t)hdr->offset, hdr->size);
235             V3_Print(VM_NONE, VCORE_NONE, "file data at %p\n", file->data);
236
237         } else if (version==1) { 
238             struct file_hdr_v1 * hdr = &(files_v1->hdrs[idx]);
239             unsigned long hash;
240
241             file->size = hdr->size;
242             file->data = cfg_blob + hdr->offset;
243             file->hash = hdr->hash;
244
245             V3_Print(VM_NONE, VCORE_NONE, "Storing file data offset = %d, size=%d\n", (uint32_t)hdr->offset, hdr->size);
246             V3_Print(VM_NONE, VCORE_NONE, "file data at %p\n", file->data);
247             V3_Print(VM_NONE, VCORE_NONE, "Checking file data integrity...\n");
248             if ((hash = v3_hash_buffer(file->data, file->size)) != file->hash) {
249                 PrintError(VM_NONE, VCORE_NONE, "File data corrupted! (orig hash=0x%lx, new=0x%lx\n",
250                            file->hash, hash);
251                 return NULL;
252             }
253             V3_Print(VM_NONE, VCORE_NONE, "File data OK\n");
254             
255         }
256             
257             
258         list_add( &(file->file_node), &(cfg->file_list));
259
260         V3_Print(VM_NONE, VCORE_NONE, "Keying file to name\n");
261         v3_htable_insert(cfg->file_table, (addr_t)(file->tag), (addr_t)(file));
262
263         V3_Print(VM_NONE, VCORE_NONE, "Iterating to next file\n");
264
265         file_tree = v3_cfg_next_branch(file_tree);
266     }
267
268     V3_Print(VM_NONE, VCORE_NONE, "Configuration parsed successfully\n");
269
270     return cfg;
271 }
272
273
274 static inline uint32_t get_alignment(char * align_str) {
275     // default is 4KB alignment
276     uint32_t alignment = PAGE_SIZE_4KB;
277
278     if (align_str != NULL) {
279         if (strcasecmp(align_str, "2MB") == 0) {
280             alignment = PAGE_SIZE_2MB;
281         } else if (strcasecmp(align_str, "4MB") == 0) {
282             alignment = PAGE_SIZE_4MB;
283         }
284     }
285     
286 #ifndef V3_CONFIG_ALIGNED_PG_ALLOC
287     if (alignment != PAGE_SIZE_4KB) {
288         PrintError(VM_NONE, VCORE_NONE, "Aligned page allocations are not supported in this host (requested alignment=%d)\n", alignment);
289         PrintError(VM_NONE, VCORE_NONE, "Ignoring alignment request\n");
290     }
291 #endif 
292
293     return alignment;
294 }
295
296
297 static int pre_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * vm_cfg) {
298     char * memory_str = v3_cfg_val(vm_cfg, "memory");
299     char * schedule_hz_str = v3_cfg_val(vm_cfg, "schedule_hz");
300     char * vm_class = v3_cfg_val(vm_cfg, "class");
301     char * align_str = v3_cfg_val(v3_cfg_subtree(vm_cfg, "memory"), "alignment");
302     uint32_t sched_hz = 100;    // set the schedule frequency to 100 HZ
303
304
305     if (!memory_str) {
306         PrintError(VM_NONE, VCORE_NONE, "Memory is a required configuration parameter\n");
307         return -1;
308     }
309     
310     PrintDebug(VM_NONE, VCORE_NONE, "Memory=%s\n", memory_str);
311     if (align_str) {
312          PrintDebug(VM_NONE, VCORE_NONE, "Alignment=%s\n", align_str);
313     } else {
314          PrintDebug(VM_NONE, VCORE_NONE, "Alignment defaulted to 4KB.\n");
315     }
316
317     // Amount of ram the Guest will have, always in MB
318     vm->mem_size = (addr_t)atoi(memory_str) * 1024 * 1024;
319     vm->mem_align = get_alignment(align_str);
320
321
322     PrintDebug(VM_NONE, VCORE_NONE, "Alignment for %lu bytes of memory computed as 0x%x\n", vm->mem_size, vm->mem_align);
323
324     if (strcasecmp(vm_class, "PC") == 0) {
325         vm->vm_class = V3_PC_VM;
326     } else {
327         PrintError(VM_NONE, VCORE_NONE, "Invalid VM class\n");
328         return -1;
329     }
330
331 #ifdef V3_CONFIG_TELEMETRY
332     {
333         char * telemetry = v3_cfg_val(vm_cfg, "telemetry");
334
335         // This should go first, because other subsystems will depend on the guest_info flag    
336         if ((telemetry) && (strcasecmp(telemetry, "enable") == 0)) {
337             vm->enable_telemetry = 1;
338         } else {
339             vm->enable_telemetry = 0;
340         }
341     }
342 #endif
343
344     if (v3_init_vm(vm) == -1) {
345         PrintError(VM_NONE, VCORE_NONE, "Failed to initialize VM\n");
346         return -1;
347     }
348
349
350
351    if (schedule_hz_str) {
352         sched_hz = atoi(schedule_hz_str);
353     }
354
355     PrintDebug(VM_NONE, VCORE_NONE, "CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(), 
356                (void *)(addr_t)sched_hz);
357
358     vm->yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
359     
360     return 0;
361 }
362
363
364 static int determine_paging_mode(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
365     extern v3_cpu_arch_t v3_mach_type;
366
367     v3_cfg_tree_t * vm_tree = info->vm_info->cfg_data->cfg;
368     v3_cfg_tree_t * pg_tree = v3_cfg_subtree(vm_tree, "paging");
369     char * pg_mode          = v3_cfg_val(pg_tree, "mode");
370     
371     PrintDebug(info->vm_info, info, "Paging mode specified as %s\n", pg_mode);
372
373     if (pg_mode) {
374         if ((strcasecmp(pg_mode, "nested") == 0)) {
375             // we assume symmetric cores, so if core 0 has nested paging they all do
376             if ((v3_mach_type == V3_SVM_REV3_CPU) || 
377                 (v3_mach_type == V3_VMX_EPT_CPU) ||
378                 (v3_mach_type == V3_VMX_EPT_UG_CPU)) {
379                 
380                 V3_Print(info->vm_info, info, "Setting paging mode to NESTED\n");
381                 info->shdw_pg_mode = NESTED_PAGING;
382             } else {
383                 PrintError(info->vm_info, info, "Nested paging not supported on this hardware. Defaulting to shadow paging\n");
384                 info->shdw_pg_mode = SHADOW_PAGING;
385             }
386         } else if ((strcasecmp(pg_mode, "shadow") == 0)) {
387             V3_Print(info->vm_info, info, "Setting paging mode to SHADOW\n");
388             info->shdw_pg_mode = SHADOW_PAGING;
389         } else {
390             PrintError(info->vm_info, info, "Invalid paging mode (%s) specified in configuration. Defaulting to shadow paging\n", pg_mode);
391             info->shdw_pg_mode = SHADOW_PAGING;
392         }
393     } else {
394         V3_Print(info->vm_info, info, "No paging type specified in configuration. Defaulting to shadow paging\n");
395         info->shdw_pg_mode = SHADOW_PAGING;
396     }
397
398
399     if (v3_cfg_val(pg_tree, "large_pages") != NULL) {
400         if (strcasecmp(v3_cfg_val(pg_tree, "large_pages"), "true") == 0) {
401             info->use_large_pages = 1;
402             PrintDebug(info->vm_info, info, "Use of large pages in memory virtualization enabled.\n");
403         }
404     }
405     return 0;
406 }
407
408 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
409     if (determine_paging_mode(info, core_cfg) != 0) {
410         return -1;
411     }
412
413     if (v3_init_core(info) == -1) {
414         PrintError(info->vm_info, info, "Error Initializing Core\n");
415         return -1;
416     }
417
418     if (info->vm_info->vm_class == V3_PC_VM) {
419         if (pre_config_pc_core(info, core_cfg) == -1) {
420             PrintError(info->vm_info, info, "PC Post configuration failure\n");
421             return -1;
422         }
423     } else {
424         PrintError(info->vm_info, info, "Invalid VM Class\n");
425         return -1;
426     }
427
428     return 0;
429 }
430
431
432
433 static int post_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
434     
435
436
437     // Configure the memory map for the guest
438     if (setup_memory_map(vm, cfg) == -1) {
439         PrintError(vm, VCORE_NONE,"Setting up guest memory map failed...\n");
440         return -1;
441     }
442
443
444     if (vm->vm_class == V3_PC_VM) {
445         if (post_config_pc(vm, cfg) == -1) {
446             PrintError(vm, VCORE_NONE,"PC Post configuration failure\n");
447             return -1;
448         }
449     } else {
450         PrintError(vm, VCORE_NONE,"Invalid VM Class\n");
451         return -1;
452     }
453
454
455
456     // Initialize fw_cfg state for VMM<->VM SEABIOS communication
457     if (v3_fw_cfg_init(vm) == -1) {
458         PrintError(vm, VCORE_NONE, "Error initializing Firmware Config (fw_cfg) state\n");
459         return -1;
460     }
461
462     /* 
463      * Initialize configured devices
464      */
465     if (setup_devices(vm, cfg) == -1) {
466         PrintError(vm, VCORE_NONE,"Failed to setup devices\n");
467         return -1;
468     }
469
470
471     //    v3_print_io_map(info);
472     v3_print_msr_map(vm);
473
474
475
476
477     /* 
478      * Initialize configured extensions 
479      */
480     if (setup_extensions(vm, cfg) == -1) {
481         PrintError(vm, VCORE_NONE,"Failed to setup extensions\n");
482         return -1;
483     }
484
485     if (v3_setup_performance_tuning(vm, cfg) == -1) { 
486         PrintError(vm, VCORE_NONE,"Failed to configure performance tuning parameters\n");
487         return -1;
488     }
489
490
491     vm->run_state = VM_STOPPED;
492
493     return 0;
494 }
495
496
497
498 static int post_config_core(struct guest_info * info, v3_cfg_tree_t * cfg) {
499
500  
501     if (v3_init_core_extensions(info) == -1) {
502         PrintError(info->vm_info, info, "Error intializing extension core states\n");
503         return -1;
504     }
505
506     if (info->vm_info->vm_class == V3_PC_VM) {
507         if (post_config_pc_core(info, cfg) == -1) {
508             PrintError(info->vm_info, info, "PC Post configuration failure\n");
509             return -1;
510         }
511     } else {
512         PrintError(info->vm_info, info, "Invalid VM Class\n");
513         return -1;
514     }
515
516
517     return 0;
518 }
519
520
521
522 static struct v3_vm_info * allocate_guest(int num_cores) {
523     int guest_state_size = sizeof(struct v3_vm_info) + (sizeof(struct guest_info) * num_cores);
524     struct v3_vm_info * vm = V3_Malloc(guest_state_size);
525
526     if (!vm) {
527         PrintError(VM_NONE, VCORE_NONE, "Unable to allocate space for guest data structures\n");
528         return NULL;
529     }
530
531     int i = 0;
532
533     memset(vm, 0, guest_state_size);
534
535     vm->num_cores = num_cores;
536
537     for (i = 0; i < num_cores; i++) {
538         vm->cores[i].core_run_state = CORE_INVALID;
539     }
540
541     vm->run_state = VM_INVALID;
542
543     return vm;
544 }
545
546
547
548 struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
549     extern v3_cpu_arch_t v3_mach_type;
550     struct v3_config * cfg_data = NULL;
551     struct v3_vm_info * vm = NULL;
552     int num_cores = 0;
553     int i = 0;
554     v3_cfg_tree_t * cores_cfg = NULL;
555     v3_cfg_tree_t * per_core_cfg = NULL;
556
557     if (v3_mach_type == V3_INVALID_CPU) {
558         PrintError(VM_NONE, VCORE_NONE, "Configuring guest on invalid CPU\n");
559         return NULL;
560     }
561
562     cfg_data = parse_config(cfg_blob);
563
564     if (!cfg_data) {
565         PrintError(VM_NONE, VCORE_NONE, "Could not parse configuration\n");
566         return NULL;
567     }
568
569     cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
570
571     if (!cores_cfg) {
572         PrintError(VM_NONE, VCORE_NONE, "Could not find core configuration (new config format required)\n");
573         return NULL;
574     }
575
576     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
577     if (num_cores == 0) {
578         PrintError(VM_NONE, VCORE_NONE, "No cores specified in configuration\n");
579         return NULL;
580     }
581
582     V3_Print(VM_NONE, VCORE_NONE, "Configuring %d cores\n", num_cores);
583
584     vm = allocate_guest(num_cores);    
585
586     if (!vm) {
587         PrintError(VM_NONE, VCORE_NONE, "Could not allocate %d core guest\n", vm->num_cores);
588         return NULL;
589     }
590
591     vm->host_priv_data = priv_data;
592
593     vm->cfg_data = cfg_data;
594
595     V3_Print(vm, VCORE_NONE, "Preconfiguration\n");
596
597     if (pre_config_vm(vm, vm->cfg_data->cfg) == -1) {
598         PrintError(vm, VCORE_NONE, "Error in preconfiguration\n");
599         return NULL;
600     }
601
602     V3_Print(vm, VCORE_NONE, "Per core configuration\n");
603     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
604
605     // per core configuration
606     for (i = 0; i < vm->num_cores; i++) {
607         struct guest_info * info = &(vm->cores[i]);
608
609         info->vcpu_id = i;
610         info->vm_info = vm;
611         info->core_cfg_data = per_core_cfg;
612
613         if (pre_config_core(info, per_core_cfg) == -1) {
614             PrintError(vm, VCORE_NONE, "Error in core %d preconfiguration\n", i);
615             return NULL;
616         }
617
618
619         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
620     }
621
622
623     V3_Print(vm, VCORE_NONE, "Post Configuration\n");
624
625     if (post_config_vm(vm, vm->cfg_data->cfg) == -1) {
626         PrintError(vm, VCORE_NONE, "Error in postconfiguration\n");
627         return NULL;
628     }
629
630
631     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
632
633     // per core configuration
634     for (i = 0; i < vm->num_cores; i++) {
635         struct guest_info * info = &(vm->cores[i]);
636
637         post_config_core(info, per_core_cfg);
638
639         per_core_cfg = v3_cfg_next_branch(per_core_cfg);
640     }
641
642     V3_Print(vm, VCORE_NONE, "Configuration successfull\n");
643
644     return vm;
645 }
646
647
648
649 int v3_free_config(struct v3_vm_info * vm) {
650    
651     v3_free_htable(vm->cfg_data->file_table, 1, 0);
652
653     v3_xml_free(vm->cfg_data->cfg);
654
655     V3_Free(vm->cfg_data);
656     return 0;
657 }
658
659
660
661
662 static int setup_memory_map(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
663     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(cfg, "memmap"), "region");
664
665     while (mem_region) {
666         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
667         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
668         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
669
670     
671         if (v3_add_shadow_mem(vm, V3_MEM_CORE_ANY, start_addr, end_addr, host_addr) == -1) {
672             PrintError(vm, VCORE_NONE,"Could not map memory region: %p-%p => %p\n", 
673                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
674             return -1;
675         }
676
677         mem_region = v3_cfg_next_branch(mem_region);
678     }
679
680     return 0;
681 }
682
683
684 static int setup_extensions(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
685     v3_cfg_tree_t * extension = v3_cfg_subtree(v3_cfg_subtree(cfg, "extensions"), "extension");
686
687     while (extension) {
688         char * ext_name = v3_cfg_val(extension, "name");
689
690         if (!ext_name) {
691             PrintError(vm, VCORE_NONE, "Extension has no name\n");
692             return -1;
693         }
694
695         V3_Print(vm, VCORE_NONE, "Configuring extension %s\n", ext_name);
696
697         if (v3_add_extension(vm, ext_name, extension) == -1) {
698             PrintError(vm, VCORE_NONE, "Error adding extension %s\n", ext_name);
699             return -1;
700         }
701
702         extension = v3_cfg_next_branch(extension);
703     }
704
705     return 0;
706 }
707
708
709 static int setup_devices(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
710     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(cfg, "devices"), "device");
711
712     
713     while (device) {
714         char * dev_class = v3_cfg_val(device, "class");
715
716         V3_Print(vm, VCORE_NONE, "configuring device %s\n", dev_class);
717
718         if (v3_create_device(vm, dev_class, device) == -1) {
719             PrintError(vm, VCORE_NONE, "Error creating device %s\n", dev_class);
720             return -1;
721         }
722         
723         device = v3_cfg_next_branch(device);
724     }
725
726     v3_print_dev_mgr(vm);
727
728     return 0;
729 }
730
731
732