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.


Now correctly boots 2, 4, 8 core kitten
[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
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
293
294 void v3_delete_mem_region(struct v3_vm_info * vm, struct v3_mem_region * reg) {
295     int i = 0;
296
297     if (reg == NULL) {
298         return;
299     }
300
301     for (i = 0; i < vm->num_cores; i++) {
302         struct guest_info * info = &(vm->cores[i]);
303
304         // flush virtual page tables 
305         // 3 cases shadow, shadow passthrough, and nested
306
307         if (info->shdw_pg_mode == SHADOW_PAGING) {
308             v3_mem_mode_t mem_mode = v3_get_vm_mem_mode(info);
309             
310             if (mem_mode == PHYSICAL_MEM) {
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                     v3_invalidate_passthrough_addr(info, cur_addr);
317                 }
318             } else {
319                 v3_invalidate_shadow_pts(info);
320             }
321             
322         } else if (info->shdw_pg_mode == NESTED_PAGING) {
323             addr_t cur_addr;
324             
325             for (cur_addr = reg->guest_start;
326                  cur_addr < reg->guest_end;
327                  cur_addr += PAGE_SIZE_4KB) {
328                 
329                 v3_invalidate_nested_addr(info, cur_addr);
330             }
331         }
332     }
333
334     v3_rb_erase(&(reg->tree_node), &(vm->mem_map.mem_regions));
335
336     V3_Free(reg);
337
338     // flush virtual page tables 
339     // 3 cases shadow, shadow passthrough, and nested
340
341 }
342
343
344
345 void v3_print_mem_map(struct v3_vm_info * vm) {
346     struct rb_node * node = v3_rb_first(&(vm->mem_map.mem_regions));
347     struct v3_mem_region * reg = &(vm->mem_map.base_region);
348     int i = 0;
349
350     V3_Print("Memory Layout (all cores):\n");
351     
352
353     V3_Print("Base Region (all cores):  0x%p - 0x%p -> 0x%p\n", 
354                (void *)(reg->guest_start), 
355                (void *)(reg->guest_end - 1), 
356                (void *)(reg->host_addr));
357     
358
359     // If the memory map is empty, don't print it
360     if (node == NULL) {
361         return;
362     }
363
364     do {
365         reg = rb_entry(node, struct v3_mem_region, tree_node);
366
367         V3_Print("%d:  0x%p - 0x%p -> 0x%p\n", i, 
368                    (void *)(reg->guest_start), 
369                    (void *)(reg->guest_end - 1), 
370                    (void *)(reg->host_addr));
371
372         V3_Print("\t(flags=0x%x) (core=0x%x) (unhandled = 0x%p)\n", 
373                  reg->flags.value, 
374                  reg->core_id,
375                  reg->unhandled);
376     
377         i++;
378     } while ((node = v3_rb_next(node)));
379 }
380