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.


Functional 2 core linux guest
[palacios.git] / palacios / src / palacios / vmm_mem.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_mem.h>
21 #include <palacios/vmm.h>
22 #include <palacios/vmm_util.h>
23 #include <palacios/vmm_emulator.h>
24 #include <palacios/vm_guest.h>
25
26 #include <palacios/vmm_shadow_paging.h>
27 #include <palacios/vmm_direct_paging.h>
28
29
30
31
32 static int mem_offset_hypercall(struct guest_info * info, uint_t hcall_id, void * private_data) {
33     PrintDebug("V3Vee: Memory offset hypercall (offset=%p)\n", 
34                (void *)(info->vm_info->mem_map.base_region.host_addr));
35
36     info->vm_regs.rbx = info->vm_info->mem_map.base_region.host_addr;
37
38     return 0;
39 }
40
41 static int unhandled_err(struct guest_info * core, addr_t guest_va, addr_t guest_pa, 
42                          struct v3_mem_region * reg, pf_error_t access_info) {
43
44     PrintError("Unhandled memory access error\n");
45
46     v3_print_mem_map(core->vm_info);
47
48     v3_print_guest_state(core);
49
50     return -1;
51 }
52
53
54
55 int v3_init_mem_map(struct v3_vm_info * vm) {
56     struct v3_mem_map * map = &(vm->mem_map);
57     addr_t mem_pages = vm->mem_size >> 12;
58
59     memset(&(map->base_region), 0, sizeof(struct v3_mem_region));
60
61     map->mem_regions.rb_node = NULL;
62
63
64     // There is an underlying region that contains all of the guest memory
65     // PrintDebug("Mapping %d pages of memory (%u bytes)\n", (int)mem_pages, (uint_t)info->mem_size);
66
67     // 2MB page alignment needed for 2MB hardware nested paging
68     map->base_region.guest_start = 0;
69     map->base_region.guest_end = mem_pages * PAGE_SIZE_4KB;
70     map->base_region.host_addr = (addr_t)V3_AllocAlignedPages(mem_pages, PAGE_SIZE_2MB);
71
72     map->base_region.flags.read = 1;
73     map->base_region.flags.write = 1;
74     map->base_region.flags.exec = 1;
75     map->base_region.flags.base = 1;
76     map->base_region.flags.alloced = 1;
77     
78     map->base_region.unhandled = unhandled_err;
79
80     if ((void *)map->base_region.host_addr == NULL) {
81         PrintError("Could not allocate Guest memory\n");
82         return -1;
83     }
84         
85     //memset(V3_VAddr((void *)map->base_region.host_addr), 0xffffffff, map->base_region.guest_end);
86
87     v3_register_hypercall(vm, MEM_OFFSET_HCALL, mem_offset_hypercall, NULL);
88
89     return 0;
90 }
91
92
93 void v3_delete_mem_map(struct v3_vm_info * vm) {
94     struct rb_node * node = v3_rb_first(&(vm->mem_map.mem_regions));
95     struct v3_mem_region * reg;
96     struct rb_node * tmp_node = NULL;
97   
98     while (node) {
99         reg = rb_entry(node, struct v3_mem_region, tree_node);
100         tmp_node = node;
101         node = v3_rb_next(node);
102
103         v3_delete_mem_region(vm, reg);
104     }
105
106     V3_FreePage((void *)(vm->mem_map.base_region.host_addr));
107 }
108
109
110 struct v3_mem_region * v3_create_mem_region(struct v3_vm_info * vm, uint16_t core_id, 
111                                                addr_t guest_addr_start, addr_t guest_addr_end) {
112     
113     struct v3_mem_region * entry = (struct v3_mem_region *)V3_Malloc(sizeof(struct v3_mem_region));
114     memset(entry, 0, sizeof(struct v3_mem_region));
115
116     entry->guest_start = guest_addr_start;
117     entry->guest_end = guest_addr_end;
118     entry->core_id = core_id;
119     entry->unhandled = unhandled_err;
120
121     return entry;
122 }
123
124
125
126
127 int v3_add_shadow_mem( struct v3_vm_info * vm, uint16_t core_id,
128                        addr_t               guest_addr_start,
129                        addr_t               guest_addr_end,
130                        addr_t               host_addr)
131 {
132     struct v3_mem_region * entry = NULL;
133
134     entry = v3_create_mem_region(vm, core_id, 
135                                  guest_addr_start, 
136                                  guest_addr_end);
137
138     entry->host_addr = host_addr;
139
140
141     entry->flags.read = 1;
142     entry->flags.write = 1;
143     entry->flags.exec = 1;
144     entry->flags.alloced = 1;
145
146     if (v3_insert_mem_region(vm, entry) == -1) {
147         V3_Free(entry);
148         return -1;
149     }
150
151     return 0;
152 }
153
154
155
156 static inline 
157 struct v3_mem_region * __insert_mem_region(struct v3_vm_info * vm, 
158                                                  struct v3_mem_region * region) {
159     struct rb_node ** p = &(vm->mem_map.mem_regions.rb_node);
160     struct rb_node * parent = NULL;
161     struct v3_mem_region * tmp_region;
162
163     while (*p) {
164         parent = *p;
165         tmp_region = rb_entry(parent, struct v3_mem_region, tree_node);
166
167         if (region->guest_end <= tmp_region->guest_start) {
168             p = &(*p)->rb_left;
169         } else if (region->guest_start >= tmp_region->guest_end) {
170             p = &(*p)->rb_right;
171         } else {
172             if ((region->guest_end != tmp_region->guest_end) ||
173                 (region->guest_start != tmp_region->guest_start)) {
174                 PrintError("Trying to map a partial overlapped core specific page...\n");
175                 return tmp_region; // This is ugly... 
176             } else if (region->core_id == tmp_region->core_id) {
177                 return tmp_region;
178             } else if (region->core_id < tmp_region->core_id) {
179                 p = &(*p)->rb_left;
180             } else { 
181                 p = &(*p)->rb_right;
182             }
183         }
184     }
185
186     rb_link_node(&(region->tree_node), parent, p);
187   
188     return NULL;
189 }
190
191
192
193 int v3_insert_mem_region(struct v3_vm_info * vm, struct v3_mem_region * region) {
194     struct v3_mem_region * ret;
195     int i = 0;
196
197     if ((ret = __insert_mem_region(vm, region))) {
198         return -1;
199     }
200
201     v3_rb_insert_color(&(region->tree_node), &(vm->mem_map.mem_regions));
202
203
204
205     for (i = 0; i < vm->num_cores; i++) {
206         struct guest_info * info = &(vm->cores[i]);
207
208         // flush virtual page tables 
209         // 3 cases shadow, shadow passthrough, and nested
210
211         if (info->shdw_pg_mode == SHADOW_PAGING) {
212             v3_mem_mode_t mem_mode = v3_get_vm_mem_mode(info);
213             
214             if (mem_mode == PHYSICAL_MEM) {
215                 addr_t cur_addr;
216                 
217                 for (cur_addr = region->guest_start;
218                      cur_addr < region->guest_end;
219                      cur_addr += PAGE_SIZE_4KB) {
220                     v3_invalidate_passthrough_addr(info, cur_addr);
221                 }
222             } else {
223                 v3_invalidate_shadow_pts(info);
224             }
225             
226         } else if (info->shdw_pg_mode == NESTED_PAGING) {
227             addr_t cur_addr;
228             
229             for (cur_addr = region->guest_start;
230                  cur_addr < region->guest_end;
231                  cur_addr += PAGE_SIZE_4KB) {
232                 
233                 v3_invalidate_nested_addr(info, cur_addr);
234             }
235         }
236     }
237
238     return 0;
239 }
240                                                  
241
242
243
244 struct v3_mem_region * v3_get_mem_region(struct v3_vm_info * vm, uint16_t core_id, addr_t guest_addr) {
245     struct rb_node * n = vm->mem_map.mem_regions.rb_node;
246     struct v3_mem_region * reg = NULL;
247
248     while (n) {
249
250         reg = rb_entry(n, struct v3_mem_region, tree_node);
251
252         if (guest_addr < reg->guest_start) {
253             n = n->rb_left;
254         } else if (guest_addr >= reg->guest_end) {
255             n = n->rb_right;
256         } else {
257             if (reg->core_id == V3_MEM_CORE_ANY) {
258                 // found relevant region, it's available on all cores
259                 return reg;
260             } else if (core_id==reg->core_id) { 
261                 // found relevant region, it's available on the indicated core
262                 return reg;
263             } else if (core_id < reg->core_id) { 
264                 // go left, core too big
265                 n = n->rb_left;
266             } else if (core_id > reg->core_id) { 
267                 // go right, core too small
268                 n = n->rb_right;
269             } else {
270                 PrintDebug("v3_get_mem_region: Impossible!\n");
271                 return NULL;
272             }
273         }
274     }
275
276
277     // There is not registered region, so we check if its a valid address in the base region
278
279     if (guest_addr > vm->mem_map.base_region.guest_end) {
280         PrintError("Guest Address Exceeds Base Memory Size (ga=0x%p), (limit=0x%p) (core=0x%x)\n", 
281                    (void *)guest_addr, (void *)vm->mem_map.base_region.guest_end, core_id);
282         v3_print_mem_map(vm);
283
284         return NULL;
285     }
286     
287     
288     return &(vm->mem_map.base_region);
289 }
290
291
292 /* Search the "hooked" memory regions for a region that ends after the given address.  If the
293  * address is invalid, return NULL. Else, return the first region found or the base region if no
294  * region ends after the given address.
295  */
296 struct v3_mem_region * v3_get_next_mem_region( struct v3_vm_info * vm, uint16_t core_id, addr_t guest_addr) {
297     struct rb_node * n = vm->mem_map.mem_regions.rb_node;
298     struct v3_mem_region * reg = NULL;
299
300     // Keep going to the right in the tree while the address is greater than the current region's
301     // end address.
302     while (n) {
303         reg = rb_entry(n, struct v3_mem_region, tree_node);
304         if (guest_addr >= reg->guest_end) { // reg is [start,end)
305             n = n->rb_right;
306         } else {
307             // PAD this may be buggy since there is no guarantees that 
308             // the cores are in order
309             if ((core_id == reg->core_id) || (reg->core_id == V3_MEM_CORE_ANY)) {
310                 return reg;
311             } else {
312                 n = n->rb_right;
313             }
314         }
315     }
316     
317     // There is no registered region, so we check if it's a valid address in the base region
318     
319     if (guest_addr >= vm->mem_map.base_region.guest_end) {
320         PrintError("%s: Guest Address Exceeds Base Memory Size (ga=%p), (limit=%p)\n",
321                    __FUNCTION__, (void *)guest_addr, (void *)vm->mem_map.base_region.guest_end);
322         v3_print_mem_map(vm);
323         return NULL;
324     }
325     
326     return &(vm->mem_map.base_region);
327 }
328
329
330
331 void v3_delete_mem_region(struct v3_vm_info * vm, struct v3_mem_region * reg) {
332     int i = 0;
333
334     if (reg == NULL) {
335         return;
336     }
337
338     for (i = 0; i < vm->num_cores; i++) {
339         struct guest_info * info = &(vm->cores[i]);
340
341         // flush virtual page tables 
342         // 3 cases shadow, shadow passthrough, and nested
343
344         if (info->shdw_pg_mode == SHADOW_PAGING) {
345             v3_mem_mode_t mem_mode = v3_get_vm_mem_mode(info);
346             
347             if (mem_mode == PHYSICAL_MEM) {
348                 addr_t cur_addr;
349                 
350                 for (cur_addr = reg->guest_start;
351                      cur_addr < reg->guest_end;
352                      cur_addr += PAGE_SIZE_4KB) {
353                     v3_invalidate_passthrough_addr(info, cur_addr);
354                 }
355             } else {
356                 v3_invalidate_shadow_pts(info);
357             }
358             
359         } else if (info->shdw_pg_mode == NESTED_PAGING) {
360             addr_t cur_addr;
361             
362             for (cur_addr = reg->guest_start;
363                  cur_addr < reg->guest_end;
364                  cur_addr += PAGE_SIZE_4KB) {
365                 
366                 v3_invalidate_nested_addr(info, cur_addr);
367             }
368         }
369     }
370
371     v3_rb_erase(&(reg->tree_node), &(vm->mem_map.mem_regions));
372
373     V3_Free(reg);
374
375     // flush virtual page tables 
376     // 3 cases shadow, shadow passthrough, and nested
377
378 }
379
380
381
382 void v3_print_mem_map(struct v3_vm_info * vm) {
383     struct rb_node * node = v3_rb_first(&(vm->mem_map.mem_regions));
384     struct v3_mem_region * reg = &(vm->mem_map.base_region);
385     int i = 0;
386
387     V3_Print("Memory Layout (all cores):\n");
388     
389
390     V3_Print("Base Region (all cores):  0x%p - 0x%p -> 0x%p\n", 
391                (void *)(reg->guest_start), 
392                (void *)(reg->guest_end - 1), 
393                (void *)(reg->host_addr));
394     
395
396     // If the memory map is empty, don't print it
397     if (node == NULL) {
398         return;
399     }
400
401     do {
402         reg = rb_entry(node, struct v3_mem_region, tree_node);
403
404         V3_Print("%d:  0x%p - 0x%p -> 0x%p\n", i, 
405                    (void *)(reg->guest_start), 
406                    (void *)(reg->guest_end - 1), 
407                    (void *)(reg->host_addr));
408
409         V3_Print("\t(flags=0x%x) (core=0x%x) (unhandled = 0x%p)\n", 
410                  reg->flags.value, 
411                  reg->core_id,
412                  reg->unhandled);
413     
414         i++;
415     } while ((node = v3_rb_next(node)));
416 }
417