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.


Add lock to vmm_queue
[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
32 #include <palacios/svm.h>
33 #include <palacios/vmx.h>
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 #include <palacios/vmm_host_events.h>
46 #include <palacios/vmm_socket.h>
47
48 #include "vmm_config_class.h"
49
50 // This is used to access the configuration file index table
51 struct file_hdr {
52     uint32_t index;
53     uint32_t size;
54     uint64_t offset;
55 };
56
57 struct file_idx_table {
58     uint64_t num_files;
59     struct file_hdr hdrs[0];
60 };
61
62
63
64
65 static int setup_memory_map(struct guest_info * info, struct v3_config * config_ptr);
66 static int setup_devices(struct guest_info * info, struct v3_config * config_ptr);
67
68
69 char * v3_cfg_val(v3_cfg_tree_t * tree, char * tag) {
70     char * attrib = (char *)v3_xml_attr(tree, tag);
71     v3_cfg_tree_t * child_entry = v3_xml_child(tree, tag);
72     char * val = NULL;
73
74     if ((child_entry != NULL) && (attrib != NULL)) {
75         PrintError("Duplicate Configuration parameters present for %s\n", tag);
76         return NULL;
77     }
78
79     val = (attrib == NULL) ? v3_xml_txt(child_entry): attrib;
80
81     return val; 
82 }
83
84 v3_cfg_tree_t * v3_cfg_subtree(v3_cfg_tree_t * tree, char * tag) {
85     return v3_xml_child(tree, tag);
86 }
87
88 v3_cfg_tree_t * v3_cfg_next_branch(v3_cfg_tree_t * tree) {
89     return v3_xml_next(tree);
90 }
91
92
93
94 struct v3_cfg_file * v3_cfg_get_file(struct guest_info * info, char * tag) {
95     struct v3_cfg_file * file = NULL;
96
97     file = (struct v3_cfg_file *)v3_htable_search(info->cfg_data->file_table, (addr_t)tag);
98
99     return file;
100 }
101
102
103 static uint_t file_hash_fn(addr_t key) {
104     char * name = (char *)key;
105     return v3_hash_buffer((uchar_t *)name, strlen(name));
106 }
107
108 static int file_eq_fn(addr_t key1, addr_t key2) {
109     char * name1 = (char *)key1;
110     char * name2 = (char *)key2;
111
112     return (strcmp(name1, name2) == 0);
113 }
114
115 static struct v3_config * parse_config(void * cfg_blob) {
116     struct v3_config * cfg = NULL;
117     int offset = 0;
118     uint_t xml_len = 0; 
119     struct file_idx_table * files = NULL;
120     v3_cfg_tree_t * file_tree = NULL;
121
122     V3_Print("cfg data at %p\n", cfg_blob);
123
124     if (memcmp(cfg_blob, "v3vee\0\0\0", 8) != 0) {
125         PrintError("Invalid Configuration Header\n");
126         return NULL;
127     }
128
129     offset += 8;
130
131     cfg = (struct v3_config *)V3_Malloc(sizeof(struct v3_config));
132     memset(cfg, 0, sizeof(struct v3_config));
133
134     cfg->blob = cfg_blob;
135     INIT_LIST_HEAD(&(cfg->file_list));
136     cfg->file_table = v3_create_htable(0, file_hash_fn, file_eq_fn);
137     
138     xml_len = *(uint32_t *)(cfg_blob + offset);
139     offset += 4;
140
141     cfg->cfg = (v3_cfg_tree_t *)v3_xml_parse((uint8_t *)(cfg_blob + offset));
142     offset += xml_len;
143    
144     offset += 8;
145
146     files = (struct file_idx_table *)(cfg_blob + offset);
147
148     V3_Print("Number of files in cfg: %d\n", (uint32_t)(files->num_files));
149
150     file_tree = v3_cfg_subtree(v3_cfg_subtree(cfg->cfg, "files"), "file");
151
152     while (file_tree) {
153         char * id = v3_cfg_val(file_tree, "id");
154         char * index = v3_cfg_val(file_tree, "index");
155         int idx = atoi(index);
156         struct file_hdr * hdr = &(files->hdrs[idx]);
157         struct v3_cfg_file * file = NULL;
158
159         file = (struct v3_cfg_file *)V3_Malloc(sizeof(struct v3_cfg_file));
160         
161         if (!file) {
162             PrintError("Could not allocate file structure\n");
163             return NULL;
164         }
165
166
167         V3_Print("File index=%d id=%s\n", idx, id);
168
169         strncpy(file->tag, id, 256);
170         file->size = hdr->size;
171         file->data = cfg_blob + hdr->offset;
172
173         V3_Print("Storing file data offset = %d, size=%d\n", (uint32_t)hdr->offset, hdr->size);
174         V3_Print("file data at %p\n", file->data);
175         list_add( &(file->file_node), &(cfg->file_list));
176
177         V3_Print("Keying file to name\n");
178         v3_htable_insert(cfg->file_table, (addr_t)(file->tag), (addr_t)(file));
179
180         V3_Print("Iterating to next file\n");
181
182         file_tree = v3_cfg_next_branch(file_tree);
183     }
184
185     V3_Print("Configuration parsed successfully\n");
186
187     return cfg;
188 }
189
190
191 static int pre_config_guest(struct guest_info * info, struct v3_config * config_ptr) {
192     extern v3_cpu_arch_t v3_cpu_types[];
193     char * memory_str = v3_cfg_val(config_ptr->cfg, "memory");
194     char * paging = v3_cfg_val(config_ptr->cfg, "paging");
195     char * schedule_hz_str = v3_cfg_val(config_ptr->cfg, "schedule_hz");
196     char * vm_class = v3_cfg_val(config_ptr->cfg, "class");
197     uint32_t sched_hz = 100;    // set the schedule frequency to 100 HZ
198     
199     if (!memory_str) {
200         PrintError("Memory is a required configuration parameter\n");
201         return -1;
202     }
203     
204     PrintDebug("Memory=%s\n", memory_str);
205
206     // Amount of ram the Guest will have, always in MB
207     info->mem_size = atoi(memory_str) * 1024 * 1024;
208     
209     if (strcasecmp(vm_class, "PC") == 0) {
210         info->vm_class = V3_PC_VM;
211     } else {
212         PrintError("Invalid VM class\n");
213         return -1;
214     }
215
216
217     /*
218      * Initialize the subsystem data strutures
219      */
220 #ifdef CONFIG_TELEMETRY
221     {
222         char * telemetry = v3_cfg_val(config_ptr->cfg, "telemetry");
223
224         // This should go first, because other subsystems will depend on the guest_info flag    
225         if ((telemetry) && (strcasecmp(telemetry, "enable") == 0)) {
226             info->enable_telemetry = 1;
227             v3_init_telemetry(info);
228         } else {
229             info->enable_telemetry = 0;
230         }
231     }
232 #endif
233
234     v3_init_hypercall_map(info);
235     v3_init_io_map(info);
236     v3_init_msr_map(info);
237     v3_init_cpuid_map(info);
238     v3_init_host_events(info);
239
240     // Initialize the memory map
241     if (v3_init_shadow_map(info) == -1) {
242         PrintError("Could not initialize shadow map\n");
243         return -1;
244     }
245     
246     if ((v3_cpu_types[info->cpu_id] == V3_SVM_REV3_CPU) && 
247         (paging) && (strcasecmp(paging, "nested") == 0)) {
248         PrintDebug("Guest Page Mode: NESTED_PAGING\n");
249         info->shdw_pg_mode = NESTED_PAGING;
250     } else {
251         PrintDebug("Guest Page Mode: SHADOW_PAGING\n");
252         v3_init_shadow_page_state(info);
253         info->shdw_pg_mode = SHADOW_PAGING;
254     }
255
256 #ifdef CONFIG_SYMBIOTIC
257     v3_init_sym_iface(info);
258 #endif
259
260     v3_init_time(info);
261     v3_init_interrupt_state(info);
262     v3_init_exception_state(info);
263     v3_init_dev_mgr(info);
264     v3_init_decoder(info);
265     
266 #ifdef CONFIG_SYMBIOTIC_SWAP
267     PrintDebug("initializing symbiotic swap\n");
268     v3_init_sym_swap(info);
269 #endif
270
271     if (schedule_hz_str) {
272         sched_hz = atoi(schedule_hz_str);
273     }
274
275     PrintDebug("CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(), 
276                (void *)(addr_t)sched_hz);
277
278     info->yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
279     
280     if (info->vm_class == V3_PC_VM) {
281         if (pre_config_pc(info, config_ptr) == -1) {
282             PrintError("PC Post configuration failure\n");
283             return -1;
284         }
285     } else {
286         PrintError("Invalid VM Class\n");
287         return -1;
288     }
289
290     return 0;
291 }
292
293
294 static int post_config_guest(struct guest_info * info, struct v3_config * config_ptr) {
295
296     // Configure the memory map for the guest
297     if (setup_memory_map(info, config_ptr) == -1) {
298         PrintError("Setting up guest memory map failed...\n");
299         return -1;
300     }
301     
302     //v3_hook_io_port(info, 1234, &IO_Read, NULL, info);
303   
304     if (setup_devices(info, config_ptr) == -1) {
305         PrintError("Failed to setup devices\n");
306         return -1;
307     }
308
309     //    v3_print_io_map(info);
310     v3_print_msr_map(info);
311
312     info->run_state = VM_STOPPED;
313
314     if (info->vm_class == V3_PC_VM) {
315         if (post_config_pc(info, config_ptr) == -1) {
316             PrintError("PC Post configuration failure\n");
317             return -1;
318         }
319     } else {
320         PrintError("Invalid VM Class\n");
321         return -1;
322     }
323
324
325     return 0;
326 }
327
328
329
330 int v3_config_guest(struct guest_info * info, void * cfg_blob) {
331     v3_cpu_arch_t cpu_type = v3_get_cpu_type(v3_get_cpu_id());
332
333     if (cpu_type == V3_INVALID_CPU) {
334         PrintError("Configuring guest on invalid CPU\n");
335         return -1;
336     }
337
338     info->cfg_data = parse_config(cfg_blob);
339
340     if (!info->cfg_data) {
341         PrintError("Could not parse configuration\n");
342         return -1;
343     }
344
345     V3_Print("Preconfiguration\n");
346
347     if (pre_config_guest(info, info->cfg_data) == -1) {
348         PrintError("Error in preconfiguration\n");
349         return -1;
350     }
351
352     V3_Print("Arch dependent configuration\n");
353
354     // init SVM/VMX
355 #ifdef CONFIG_SVM
356     if ((cpu_type == V3_SVM_CPU) || (cpu_type == V3_SVM_REV3_CPU)) {
357         if (v3_init_svm_vmcb(info, info->vm_class) == -1) {
358             PrintError("Error in SVM initialization\n");
359             return -1;
360         }
361     } 
362 #endif
363 #ifdef CONFIG_VMX
364     else if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) {
365         if (v3_init_vmx_vmcs(info, info->vm_class) == -1) {
366             PrintError("Error in VMX initialization\n");
367             return -1;
368         }
369     }
370 #endif
371     else {
372         PrintError("Invalid CPU Type\n");
373         return -1;
374     }
375
376     V3_Print("Post Configuration\n");
377
378     if (post_config_guest(info, info->cfg_data) == -1) {
379         PrintError("Error in postconfiguration\n");
380         return -1;
381     }
382
383     V3_Print("Configuration successfull\n");
384
385     return 0;
386 }
387
388
389
390
391
392 static int setup_memory_map(struct guest_info * info, struct v3_config * config_ptr) {
393     v3_cfg_tree_t * mem_region = v3_cfg_subtree(v3_cfg_subtree(config_ptr->cfg, "memmap"), "region");
394
395     while (mem_region) {
396         addr_t start_addr = atox(v3_cfg_val(mem_region, "start"));
397         addr_t end_addr = atox(v3_cfg_val(mem_region, "end"));
398         addr_t host_addr = atox(v3_cfg_val(mem_region, "host_addr"));
399
400     
401         if (v3_add_shadow_mem(info, start_addr, end_addr, host_addr) == -1) {
402             PrintError("Could not map memory region: %p-%p => %p\n", 
403                        (void *)start_addr, (void *)end_addr, (void *)host_addr);
404             return -1;
405         }
406
407         mem_region = v3_cfg_next_branch(mem_region);
408     }
409
410     return 0;
411 }
412
413
414
415
416
417
418
419
420
421 static int setup_devices(struct guest_info * info, struct v3_config * config_ptr) {
422     v3_cfg_tree_t * device = v3_cfg_subtree(v3_cfg_subtree(config_ptr->cfg, "devices"), "device");
423
424     
425     while (device) {
426         char * id = v3_cfg_val(device, "id");
427
428         V3_Print("configuring device %s\n", id);
429
430         if (v3_create_device(info, id, device) == -1) {
431             PrintError("Error creating device %s\n", id);
432             return -1;
433         }
434         
435         device = v3_cfg_next_branch(device);
436     }
437
438
439    v3_print_dev_mgr(info);
440
441     return 0;
442 }
443
444