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.


memory lookup refactorization
[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, 
193                             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         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 ((core_id == reg->core_id) || 
257                 (reg->core_id == V3_MEM_CORE_ANY)) {
258             return reg;
259             } else {
260                 n = n->rb_right;
261             }
262         }
263     }
264
265
266     // There is not registered region, so we check if its a valid address in the base region
267
268     if (guest_addr > vm->mem_map.base_region.guest_end) {
269         PrintError("Guest Address Exceeds Base Memory Size (ga=%p), (limit=%p)\n", 
270                    (void *)guest_addr, (void *)vm->mem_map.base_region.guest_end);
271         v3_print_mem_map(vm);
272
273         return NULL;
274     }
275     
276     return &(vm->mem_map.base_region);
277 }
278
279
280
281
282 void v3_delete_mem_region(struct v3_vm_info * vm, struct v3_mem_region * reg) {
283     int i = 0;
284
285     if (reg == NULL) {
286         return;
287     }
288
289     for (i = 0; i < vm->num_cores; i++) {
290         struct guest_info * info = &(vm->cores[i]);
291
292         // flush virtual page tables 
293         // 3 cases shadow, shadow passthrough, and nested
294
295         if (info->shdw_pg_mode == SHADOW_PAGING) {
296             v3_mem_mode_t mem_mode = v3_get_vm_mem_mode(info);
297             
298             if (mem_mode == PHYSICAL_MEM) {
299                 addr_t cur_addr;
300                 
301                 for (cur_addr = reg->guest_start;
302                      cur_addr < reg->guest_end;
303                      cur_addr += PAGE_SIZE_4KB) {
304                     v3_invalidate_passthrough_addr(info, cur_addr);
305                 }
306             } else {
307                 v3_invalidate_shadow_pts(info);
308             }
309             
310         } else if (info->shdw_pg_mode == NESTED_PAGING) {
311             addr_t cur_addr;
312             
313             for (cur_addr = reg->guest_start;
314                  cur_addr < reg->guest_end;
315                  cur_addr += PAGE_SIZE_4KB) {
316                 
317                 v3_invalidate_nested_addr(info, cur_addr);
318             }
319         }
320     }
321
322     v3_rb_erase(&(reg->tree_node), &(vm->mem_map.mem_regions));
323
324     V3_Free(reg);
325
326     // flush virtual page tables 
327     // 3 cases shadow, shadow passthrough, and nested
328
329 }
330
331
332
333 void v3_print_mem_map(struct v3_vm_info * vm) {
334     struct rb_node * node = v3_rb_first(&(vm->mem_map.mem_regions));
335     struct v3_mem_region * reg = &(vm->mem_map.base_region);
336     int i = 0;
337
338     V3_Print("Memory Layout:\n");
339     
340
341     V3_Print("Base Region:  0x%p - 0x%p -> 0x%p\n", 
342                (void *)(reg->guest_start), 
343                (void *)(reg->guest_end - 1), 
344                (void *)(reg->host_addr));
345     
346
347     // If the memory map is empty, don't print it
348     if (node == NULL) {
349         return;
350     }
351
352     do {
353         reg = rb_entry(node, struct v3_mem_region, tree_node);
354
355         V3_Print("%d:  0x%p - 0x%p -> 0x%p\n", i, 
356                    (void *)(reg->guest_start), 
357                    (void *)(reg->guest_end - 1), 
358                    (void *)(reg->host_addr));
359
360         V3_Print("\t(flags=%x) (unhandled = 0x%p)\n", 
361                    reg->flags.value,
362                    reg->unhandled);
363     
364         i++;
365     } while ((node = v3_rb_next(node)));
366 }
367