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.


Clear guest memory to 0 at init time.
[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 (gpa=%p, gva=%p, error_code=%d)\n",
45                (void *)guest_pa, (void *)guest_va, *(uint32_t *)&access_info);
46
47     v3_print_mem_map(core->vm_info);
48
49     v3_print_guest_state(core);
50
51     return -1;
52 }
53
54 int v3_init_mem_map(struct v3_vm_info * vm) {
55     struct v3_mem_map * map = &(vm->mem_map);
56     addr_t mem_pages = vm->mem_size >> 12;
57
58     memset(&(map->base_region), 0, sizeof(struct v3_mem_region));
59
60     map->mem_regions.rb_node = NULL;
61
62     // There is an underlying region that contains all of the guest memory
63     // PrintDebug("Mapping %d pages of memory (%u bytes)\n", (int)mem_pages, (uint_t)info->mem_size);
64
65     // 2MB page alignment needed for 2MB hardware nested paging
66     map->base_region.guest_start = 0;
67     map->base_region.guest_end = mem_pages * PAGE_SIZE_4KB;
68
69 #ifdef V3_CONFIG_ALIGNED_PG_ALLOC
70     map->base_region.host_addr = (addr_t)V3_AllocAlignedPages(mem_pages, vm->mem_align);
71 #else
72     map->base_region.host_addr = (addr_t)V3_AllocPages(mem_pages);
73 #endif
74
75     // Clear the memory...
76     memset(V3_VAddr((void *)map->base_region.host_addr), 0, mem_pages * PAGE_SIZE_4KB);
77
78
79     map->base_region.flags.read = 1;
80     map->base_region.flags.write = 1;
81     map->base_region.flags.exec = 1;
82     map->base_region.flags.base = 1;
83     map->base_region.flags.alloced = 1;
84     
85     map->base_region.unhandled = unhandled_err;
86
87     if ((void *)map->base_region.host_addr == NULL) {
88         PrintError("Could not allocate Guest memory\n");
89         return -1;
90     }
91         
92     //memset(V3_VAddr((void *)map->base_region.host_addr), 0xffffffff, map->base_region.guest_end);
93
94     v3_register_hypercall(vm, MEM_OFFSET_HCALL, mem_offset_hypercall, NULL);
95
96     return 0;
97 }
98
99
100 void v3_delete_mem_map(struct v3_vm_info * vm) {
101     struct rb_node * node = v3_rb_first(&(vm->mem_map.mem_regions));
102     struct v3_mem_region * reg;
103     struct rb_node * tmp_node = NULL;
104     addr_t mem_pages = vm->mem_size >> 12;
105   
106     while (node) {
107         reg = rb_entry(node, struct v3_mem_region, tree_node);
108         tmp_node = node;
109         node = v3_rb_next(node);
110
111         v3_delete_mem_region(vm, reg);
112     }
113
114     V3_FreePages((void *)(vm->mem_map.base_region.host_addr), mem_pages);
115 }
116
117
118 struct v3_mem_region * v3_create_mem_region(struct v3_vm_info * vm, uint16_t core_id, 
119                                                addr_t guest_addr_start, addr_t guest_addr_end) {
120     
121     struct v3_mem_region * entry = (struct v3_mem_region *)V3_Malloc(sizeof(struct v3_mem_region));
122     memset(entry, 0, sizeof(struct v3_mem_region));
123
124     entry->guest_start = guest_addr_start;
125     entry->guest_end = guest_addr_end;
126     entry->core_id = core_id;
127     entry->unhandled = unhandled_err;
128
129     return entry;
130 }
131
132
133
134
135 int v3_add_shadow_mem( struct v3_vm_info * vm, uint16_t core_id,
136                        addr_t               guest_addr_start,
137                        addr_t               guest_addr_end,
138                        addr_t               host_addr)
139 {
140     struct v3_mem_region * entry = NULL;
141
142     entry = v3_create_mem_region(vm, core_id, 
143                                  guest_addr_start, 
144                                  guest_addr_end);
145
146     entry->host_addr = host_addr;
147
148     entry->flags.read = 1;
149     entry->flags.write = 1;
150     entry->flags.exec = 1;
151     entry->flags.alloced = 1;
152
153     if (v3_insert_mem_region(vm, entry) == -1) {
154         V3_Free(entry);
155         return -1;
156     }
157
158     return 0;
159 }
160
161
162
163 static inline 
164 struct v3_mem_region * __insert_mem_region(struct v3_vm_info * vm, 
165                                            struct v3_mem_region * region) {
166     struct rb_node ** p = &(vm->mem_map.mem_regions.rb_node);
167     struct rb_node * parent = NULL;
168     struct v3_mem_region * tmp_region;
169
170     while (*p) {
171         parent = *p;
172         tmp_region = rb_entry(parent, struct v3_mem_region, tree_node);
173
174         if (region->guest_end <= tmp_region->guest_start) {
175             p = &(*p)->rb_left;
176         } else if (region->guest_start >= tmp_region->guest_end) {
177             p = &(*p)->rb_right;
178         } else {
179             if ((region->guest_end != tmp_region->guest_end) ||
180                 (region->guest_start != tmp_region->guest_start)) {
181                 PrintError("Trying to map a partial overlapped core specific page...\n");
182                 return tmp_region; // This is ugly... 
183             } else if (region->core_id == tmp_region->core_id) {
184                 return tmp_region;
185             } else if (region->core_id < tmp_region->core_id) {
186                 p = &(*p)->rb_left;
187             } else { 
188                 p = &(*p)->rb_right;
189             }
190         }
191     }
192
193     rb_link_node(&(region->tree_node), parent, p);
194   
195     return NULL;
196 }
197
198
199
200 int v3_insert_mem_region(struct v3_vm_info * vm, struct v3_mem_region * region) {
201     struct v3_mem_region * ret;
202     int i = 0;
203
204     if ((ret = __insert_mem_region(vm, region))) {
205         return -1;
206     }
207
208     v3_rb_insert_color(&(region->tree_node), &(vm->mem_map.mem_regions));
209
210
211
212     for (i = 0; i < vm->num_cores; i++) {
213         struct guest_info * info = &(vm->cores[i]);
214
215         // flush virtual page tables 
216         // 3 cases shadow, shadow passthrough, and nested
217
218         if (info->shdw_pg_mode == SHADOW_PAGING) {
219             v3_mem_mode_t mem_mode = v3_get_vm_mem_mode(info);
220             
221             if (mem_mode == PHYSICAL_MEM) {
222                 addr_t cur_addr;
223                 
224                 for (cur_addr = region->guest_start;
225                      cur_addr < region->guest_end;
226                      cur_addr += PAGE_SIZE_4KB) {
227                     v3_invalidate_passthrough_addr(info, cur_addr);
228                 }
229             } else {
230                 v3_invalidate_shadow_pts(info);
231             }
232             
233         } else if (info->shdw_pg_mode == NESTED_PAGING) {
234             addr_t cur_addr;
235             
236             for (cur_addr = region->guest_start;
237                  cur_addr < region->guest_end;
238                  cur_addr += PAGE_SIZE_4KB) {
239                 
240                 v3_invalidate_nested_addr(info, cur_addr);
241             }
242         }
243     }
244
245     return 0;
246 }
247                                                  
248
249
250
251 struct v3_mem_region * v3_get_mem_region(struct v3_vm_info * vm, uint16_t core_id, addr_t guest_addr) {
252     struct rb_node * n = vm->mem_map.mem_regions.rb_node;
253     struct v3_mem_region * reg = NULL;
254
255     while (n) {
256
257         reg = rb_entry(n, struct v3_mem_region, tree_node);
258
259         if (guest_addr < reg->guest_start) {
260             n = n->rb_left;
261         } else if (guest_addr >= reg->guest_end) {
262             n = n->rb_right;
263         } else {
264             if (reg->core_id == V3_MEM_CORE_ANY) {
265                 // found relevant region, it's available on all cores
266                 return reg;
267             } else if (core_id == reg->core_id) { 
268                 // found relevant region, it's available on the indicated core
269                 return reg;
270             } else if (core_id < reg->core_id) { 
271                 // go left, core too big
272                 n = n->rb_left;
273             } else if (core_id > reg->core_id) { 
274                 // go right, core too small
275                 n = n->rb_right;
276             } else {
277                 PrintDebug("v3_get_mem_region: Impossible!\n");
278                 return NULL;
279             }
280         }
281     }
282
283
284     // There is not registered region, so we check if its a valid address in the base region
285
286     if (guest_addr > vm->mem_map.base_region.guest_end) {
287         PrintError("Guest Address Exceeds Base Memory Size (ga=0x%p), (limit=0x%p) (core=0x%x)\n", 
288                    (void *)guest_addr, (void *)vm->mem_map.base_region.guest_end, core_id);
289         v3_print_mem_map(vm);
290
291         return NULL;
292     }
293
294     return &(vm->mem_map.base_region);
295 }
296
297
298
299 /* This returns the next memory region based on a given address. 
300  * If the address falls inside a sub region, that region is returned. 
301  * If the address falls outside a sub region, the next sub region is returned
302  * NOTE that we have to be careful about core_ids here...
303  */
304 static struct v3_mem_region * get_next_mem_region( struct v3_vm_info * vm, uint16_t core_id, addr_t guest_addr) {
305     struct rb_node * n = vm->mem_map.mem_regions.rb_node;
306     struct v3_mem_region * reg = NULL;
307     struct v3_mem_region * parent = NULL;
308
309     if (n == NULL) {
310         return NULL;
311     }
312
313     while (n) {
314
315         reg = rb_entry(n, struct v3_mem_region, tree_node);
316
317         if (guest_addr < reg->guest_start) {
318             n = n->rb_left;
319         } else if (guest_addr >= reg->guest_end) {
320             n = n->rb_right;
321         } else {
322             if (reg->core_id == V3_MEM_CORE_ANY) {
323                 // found relevant region, it's available on all cores
324                 return reg;
325             } else if (core_id == reg->core_id) { 
326                 // found relevant region, it's available on the indicated core
327                 return reg;
328             } else if (core_id < reg->core_id) { 
329                 // go left, core too big
330                 n = n->rb_left;
331             } else if (core_id > reg->core_id) { 
332                 // go right, core too small
333                 n = n->rb_right;
334             } else {
335                 PrintError("v3_get_mem_region: Impossible!\n");
336                 return NULL;
337             }
338         }
339
340         if ((reg->core_id == core_id) || (reg->core_id == V3_MEM_CORE_ANY)) {
341             parent = reg;
342         }
343     }
344
345
346     if (parent->guest_start > guest_addr) {
347         return parent;
348     } else if (parent->guest_end < guest_addr) {
349         struct rb_node * node = &(parent->tree_node);
350
351         while ((node = v3_rb_next(node)) != NULL) {
352             struct v3_mem_region * next_reg = rb_entry(node, struct v3_mem_region, tree_node);
353
354             if ((next_reg->core_id == V3_MEM_CORE_ANY) ||
355                 (next_reg->core_id == core_id)) {
356
357                 // This check is not strictly necessary, but it makes it clearer
358                 if (next_reg->guest_start > guest_addr) {
359                     return next_reg;
360                 }
361             }
362         }
363     }
364
365     return NULL;
366 }
367
368
369
370
371 /* Given an address region of memory, find if there are any regions that overlap with it. 
372  * This checks that the range lies in a single region, and returns that region if it does, 
373  * this can be either the base region or a sub region. 
374  * IF there are multiple regions in the range then it returns NULL
375  */
376 static struct v3_mem_region * get_overlapping_region(struct v3_vm_info * vm, uint16_t core_id, 
377                                                      addr_t start_gpa, addr_t end_gpa) {
378     struct v3_mem_region * start_region = v3_get_mem_region(vm, core_id, start_gpa);
379
380     if (start_region == NULL) {
381         PrintError("Invalid memory region\n");
382         return NULL;
383     }
384
385
386     if (start_region->guest_end < end_gpa) {
387         // Region ends before range
388         return NULL;
389     } else if (start_region->flags.base == 0) {
390         // sub region overlaps range
391         return start_region;
392     } else {
393         // Base region, now we have to scan forward for the next sub region
394         struct v3_mem_region * next_reg = get_next_mem_region(vm, core_id, start_gpa);
395         
396         if (next_reg == NULL) {
397             // no sub regions after start_addr, base region is ok
398             return start_region;
399         } else if (next_reg->guest_start >= end_gpa) {
400             // Next sub region begins outside range
401             return start_region;
402         } else {
403             return NULL;
404         }
405     }
406
407
408     // Should never get here
409     return NULL;
410 }
411
412
413
414
415
416 void v3_delete_mem_region(struct v3_vm_info * vm, struct v3_mem_region * reg) {
417     int i = 0;
418
419     if (reg == NULL) {
420         return;
421     }
422
423
424     v3_rb_erase(&(reg->tree_node), &(vm->mem_map.mem_regions));
425
426
427
428     // If the guest isn't running then there shouldn't be anything to invalidate. 
429     // Page tables should __always__ be created on demand during execution
430     // NOTE: This is a sanity check, and can be removed if that assumption changes
431     if (vm->run_state != VM_RUNNING) {
432         V3_Free(reg);
433         return;
434     }
435
436     for (i = 0; i < vm->num_cores; i++) {
437         struct guest_info * info = &(vm->cores[i]);
438
439         // flush virtual page tables 
440         // 3 cases shadow, shadow passthrough, and nested
441
442         if (info->shdw_pg_mode == SHADOW_PAGING) {
443             v3_mem_mode_t mem_mode = v3_get_vm_mem_mode(info);
444             
445             if (mem_mode == PHYSICAL_MEM) {
446                 addr_t cur_addr;
447                 
448                 for (cur_addr = reg->guest_start;
449                      cur_addr < reg->guest_end;
450                      cur_addr += PAGE_SIZE_4KB) {
451                     v3_invalidate_passthrough_addr(info, cur_addr);
452                 }
453             } else {
454                 v3_invalidate_shadow_pts(info);
455             }
456             
457         } else if (info->shdw_pg_mode == NESTED_PAGING) {
458             addr_t cur_addr;
459             
460             for (cur_addr = reg->guest_start;
461                  cur_addr < reg->guest_end;
462                  cur_addr += PAGE_SIZE_4KB) {
463                 
464                 v3_invalidate_nested_addr(info, cur_addr);
465             }
466         }
467     }
468
469     V3_Free(reg);
470
471     // flush virtual page tables 
472     // 3 cases shadow, shadow passthrough, and nested
473
474 }
475
476 // Determine if a given address can be handled by a large page of the requested size
477 uint32_t v3_get_max_page_size(struct guest_info * core, addr_t page_addr, v3_cpu_mode_t mode) {
478     addr_t pg_start = 0;
479     addr_t pg_end = 0; 
480     uint32_t page_size = PAGE_SIZE_4KB;
481     struct v3_mem_region * reg = NULL;
482     
483     switch (mode) {
484         case PROTECTED:
485             if (core->use_large_pages == 1) {
486                 pg_start = PAGE_ADDR_4MB(page_addr);
487                 pg_end = (pg_start + PAGE_SIZE_4MB);
488
489                 reg = get_overlapping_region(core->vm_info, core->vcpu_id, pg_start, pg_end); 
490
491                 if ((reg) && ((reg->host_addr % PAGE_SIZE_4MB) == 0)) {
492                     page_size = PAGE_SIZE_4MB;
493                 }
494             }
495             break;
496         case PROTECTED_PAE:
497             if (core->use_large_pages == 1) {
498                 pg_start = PAGE_ADDR_2MB(page_addr);
499                 pg_end = (pg_start + PAGE_SIZE_2MB);
500
501                 reg = get_overlapping_region(core->vm_info, core->vcpu_id, pg_start, pg_end);
502
503                 if ((reg) && ((reg->host_addr % PAGE_SIZE_2MB) == 0)) {
504                     page_size = PAGE_SIZE_2MB;
505                 }
506             }
507             break;
508         case LONG:
509         case LONG_32_COMPAT:
510         case LONG_16_COMPAT:
511             if (core->use_giant_pages == 1) {
512                 pg_start = PAGE_ADDR_1GB(page_addr);
513                 pg_end = (pg_start + PAGE_SIZE_1GB);
514                 
515                 reg = get_overlapping_region(core->vm_info, core->vcpu_id, pg_start, pg_end);
516                 
517                 if ((reg) && ((reg->host_addr % PAGE_SIZE_1GB) == 0)) {
518                     page_size = PAGE_SIZE_1GB;
519                     break;
520                 }
521             }
522
523             if (core->use_large_pages == 1) {
524                 pg_start = PAGE_ADDR_2MB(page_addr);
525                 pg_end = (pg_start + PAGE_SIZE_2MB);
526
527                 reg = get_overlapping_region(core->vm_info, core->vcpu_id, pg_start, pg_end);
528                 
529                 if ((reg) && ((reg->host_addr % PAGE_SIZE_2MB) == 0)) {
530                     page_size = PAGE_SIZE_2MB;
531                 }
532             }
533             break;
534         default:
535             PrintError("Invalid CPU mode: %s\n", v3_cpu_mode_to_str(v3_get_vm_cpu_mode(core)));
536             return -1;
537     }
538
539     return page_size;
540 }
541
542
543
544 void v3_print_mem_map(struct v3_vm_info * vm) {
545     struct rb_node * node = v3_rb_first(&(vm->mem_map.mem_regions));
546     struct v3_mem_region * reg = &(vm->mem_map.base_region);
547     int i = 0;
548
549     V3_Print("Memory Layout (all cores):\n");
550     
551
552     V3_Print("Base Region (all cores):  0x%p - 0x%p -> 0x%p\n", 
553                (void *)(reg->guest_start), 
554                (void *)(reg->guest_end - 1), 
555                (void *)(reg->host_addr));
556     
557
558     // If the memory map is empty, don't print it
559     if (node == NULL) {
560         return;
561     }
562
563     do {
564         reg = rb_entry(node, struct v3_mem_region, tree_node);
565
566         V3_Print("%d:  0x%p - 0x%p -> 0x%p\n", i, 
567                    (void *)(reg->guest_start), 
568                    (void *)(reg->guest_end - 1), 
569                    (void *)(reg->host_addr));
570
571         V3_Print("\t(flags=0x%x) (core=0x%x) (unhandled = 0x%p)\n", 
572                  reg->flags.value, 
573                  reg->core_id,
574                  reg->unhandled);
575     
576         i++;
577     } while ((node = v3_rb_next(node)));
578 }
579