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.


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