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.


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