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.


Generalization of constraints on page allocation and implementation/use
[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 #include <palacios/vmm_debug.h>
26
27 #include <palacios/vmm_shadow_paging.h>
28 #include <palacios/vmm_direct_paging.h>
29
30 #include <interfaces/vmm_numa.h>
31
32 #ifdef V3_CONFIG_SWAPPING
33 #include <palacios/vmm_swapping.h>
34 #endif
35
36 uint64_t v3_mem_block_size = V3_CONFIG_MEM_BLOCK_SIZE;
37
38
39
40
41 struct v3_mem_region * v3_get_base_region(struct v3_vm_info * vm, addr_t gpa) {
42    
43     //PrintDebug(VM_NONE, VCORE_NONE, "get_base_region called"); 
44     struct v3_mem_map * map = &(vm->mem_map);
45     uint32_t block_index = gpa / v3_mem_block_size;
46     struct v3_mem_region *reg;
47     if ((gpa >= (map->num_base_regions * v3_mem_block_size)) ||
48         (block_index >= map->num_base_regions)) {
49         PrintError(vm, VCORE_NONE, "Guest Address Exceeds Base Memory Size (ga=0x%p), (limit=0x%p)\n", 
50                    (void *)gpa, (void *)vm->mem_size);
51         v3_print_mem_map(vm);
52
53         return NULL;
54     }
55
56     reg = &(map->base_regions[block_index]);
57
58 #ifdef V3_CONFIG_SWAPPING
59     if(vm->swap_state.enable_swapping) {
60         if (reg->flags.swapped) {
61             if (v3_swap_in_region(vm,reg)) { 
62                 PrintError(vm, VCORE_NONE, "Unable to swap in region GPA=%p..%p!!!\n",(void*)reg->guest_start,(void*)reg->guest_end);
63                 v3_print_mem_map(vm);
64                 return NULL;
65             }
66         }
67     }
68     v3_touch_region(vm,reg);
69 #endif
70
71     return reg;
72 }
73
74
75
76 static int mem_offset_hypercall(struct guest_info * info, uint_t hcall_id, void * private_data) {
77     /*
78     PrintDebug(info->vm_info, info,"V3Vee: Memory offset hypercall (offset=%p)\n", 
79                (void *)(info->vm_info->mem_map.base_region.host_addr));
80
81     info->vm_regs.rbx = info->vm_info->mem_map.base_region.host_addr;
82     */
83     return -1;
84 }
85
86 static int unhandled_err(struct guest_info * core, addr_t guest_va, addr_t guest_pa, 
87                          struct v3_mem_region * reg, pf_error_t access_info) {
88
89     PrintError(core->vm_info, core, "Unhandled memory access error (gpa=%p, gva=%p, error_code=%d)\n",
90                (void *)guest_pa, (void *)guest_va, *(uint32_t *)&access_info);
91
92     v3_print_mem_map(core->vm_info);
93
94     v3_print_guest_state(core);
95
96     return -1;
97 }
98
99 static int gpa_to_node_from_cfg(struct v3_vm_info * vm, addr_t gpa) {
100     v3_cfg_tree_t * layout_cfg = v3_cfg_subtree(vm->cfg_data->cfg, "mem_layout");
101     v3_cfg_tree_t * region_desc = v3_cfg_subtree(layout_cfg, "region");
102
103     while (region_desc) {
104         char * start_addr_str = v3_cfg_val(region_desc, "start_addr");
105         char * end_addr_str = v3_cfg_val(region_desc, "end_addr");
106         char * node_id_str = v3_cfg_val(region_desc, "node");
107
108         addr_t start_addr = 0;
109         addr_t end_addr = 0;
110         int node_id = 0;
111         
112         if ((!start_addr_str) || (!end_addr_str) || (!node_id_str)) {
113             PrintError(vm, VCORE_NONE, "Invalid memory layout in configuration\n");
114             return -1;
115         }
116         
117         start_addr = atox(start_addr_str);
118         end_addr = atox(end_addr_str);
119         node_id = atoi(node_id_str);
120
121         if ((gpa >= start_addr) && (gpa < end_addr)) {
122             return node_id;
123         }
124
125         region_desc = v3_cfg_next_branch(region_desc);
126     }
127
128     return -1;
129 }
130
131 //
132 // This code parallels that in vmm_shadow_paging.c:v3_init_shdw_impl() 
133 // and vmm_config.c:determine_paging_mode.   The determination of which
134 // paging mode will be used is determined much later than the allocation of
135 // the guest memory regions, so we need to do this here to decide if they
136 // need to be below 4 GB or not.
137 static int will_use_shadow_paging(struct v3_vm_info *vm)
138 {
139     v3_cfg_tree_t * pg_cfg = v3_cfg_subtree(vm->cfg_data->cfg, "paging");
140     char * pg_mode = v3_cfg_val(pg_cfg, "mode");
141    
142     if (pg_mode == NULL) { 
143         return 1; // did not ask, get shadow
144     } else {
145         if (strcasecmp(pg_mode, "nested") == 0) {
146             extern v3_cpu_arch_t v3_mach_type;
147             if ((v3_mach_type == V3_SVM_REV3_CPU) || 
148                 (v3_mach_type == V3_VMX_EPT_CPU) ||
149                 (v3_mach_type == V3_VMX_EPT_UG_CPU)) {
150                 return 0; // ask for nested, get nested
151             } else { 
152                 return 1; // ask for nested, get shadow
153             }
154         } else if (strcasecmp(pg_mode, "shadow") != 0) { 
155             return 1;     // ask for shadow, get shadow
156         } else {
157             return 1;     // ask for something else, get shadow
158         }
159     }
160 }
161
162 #define CEIL_DIV(x,y) (((x)/(y)) + !!((x)%(y)))
163
164
165 int v3_init_mem_map(struct v3_vm_info * vm) {
166     struct v3_mem_map * map = &(vm->mem_map);
167     addr_t block_pages = v3_mem_block_size >> 12;
168     int i = 0;
169     uint64_t num_base_regions_host_mem;
170
171     map->num_base_regions = CEIL_DIV(vm->mem_size, v3_mem_block_size); 
172
173     num_base_regions_host_mem=map->num_base_regions;  // without swapping
174
175     PrintDebug(VM_NONE, VCORE_NONE, "v3_init_mem_map: num_base_regions:%d",map->num_base_regions);
176
177     map->mem_regions.rb_node = NULL;
178
179 #ifdef V3_CONFIG_SWAPPING
180     if (vm->swap_state.enable_swapping) {
181         num_base_regions_host_mem = CEIL_DIV(vm->swap_state.host_mem_size, v3_mem_block_size);
182     } 
183 #endif
184
185     PrintDebug(VM_NONE, VCORE_NONE, "v3_init_mem_map: %llu base regions will be allocated of %llu base regions in guest\n",
186                (uint64_t)num_base_regions_host_mem, (uint64_t)map->num_base_regions);
187     
188     map->base_regions = V3_VMalloc(sizeof(struct v3_mem_region) * map->num_base_regions);
189     if (map->base_regions == NULL) {
190         PrintError(vm, VCORE_NONE, "Could not allocate base region array\n");
191         return -1;
192     }
193
194     memset(map->base_regions, 0, sizeof(struct v3_mem_region) * map->num_base_regions);
195
196     for (i = 0; i < map->num_base_regions; i++) {
197   
198
199         struct v3_mem_region * region = &(map->base_regions[i]);
200         int node_id = -1;
201
202         // 2MB page alignment needed for 2MB hardware nested paging
203         // If swapping is enabled, the host memory will be allocated to low address regions at initialization
204         region->guest_start = v3_mem_block_size * i;
205         region->guest_end = region->guest_start + v3_mem_block_size;
206
207         // We assume that the xml config was smart enough to align the layout to the block size
208         // If they didn't we're going to ignore their settings 
209         //     and use whatever node the first byte of the block is assigned to
210         node_id = gpa_to_node_from_cfg(vm, region->guest_start);
211         
212
213         if (i < num_base_regions_host_mem) {
214             //The regions within num_base_regions_in_mem are allocated in host memory
215             V3_Print(vm, VCORE_NONE, "Allocating block %d on node %d\n", i, node_id);
216
217 #ifdef V3_CONFIG_SWAPPING
218             // nothing to do - memset will have done it.
219 #endif
220     
221             region->host_addr = (addr_t)V3_AllocPagesExtended(block_pages,
222                                                               PAGE_SIZE_4KB,
223                                                               node_id,
224                                                               0, 0); // no constraints 
225             
226             if ((void *)region->host_addr == NULL) { 
227                 PrintError(vm, VCORE_NONE, "Could not allocate guest memory\n");
228                 return -1;
229             }
230             
231             // Clear the memory...
232             memset(V3_VAddr((void *)region->host_addr), 0, v3_mem_block_size);
233
234         } else {
235
236 #ifdef V3_CONFIG_SWAPPING
237             if(vm->swap_state.enable_swapping) {        
238                 // The regions beyond num_base_regions_in_mem are allocated on disk to start
239                 region->flags.swapped = 1;
240                 region->host_addr=(addr_t) 0;
241                 // other flags / state correctly set up by zeroing the region earlier
242             }
243 #endif
244
245         }
246
247         
248         // Note assigned numa ID could be different than our request... 
249         // Also note that when swapping is used, the numa info will
250         // reflect the numa id of address 0x0 for unallocated regions
251         //
252         region->numa_id = v3_numa_hpa_to_node(region->host_addr);
253
254         region->flags.read = 1;
255         region->flags.write = 1;
256         region->flags.exec = 1;
257         region->flags.base = 1;
258         region->flags.alloced = 1;
259         region->flags.limit32 = will_use_shadow_paging(vm);
260         
261         region->unhandled = unhandled_err;
262     }
263
264     v3_register_hypercall(vm, MEM_OFFSET_HCALL, mem_offset_hypercall, NULL);
265
266     return 0;
267 }
268
269
270 void v3_delete_mem_map(struct v3_vm_info * vm) {
271     struct v3_mem_map * map = &(vm->mem_map);
272     struct rb_node * node = v3_rb_first(&(map->mem_regions));
273     struct v3_mem_region * reg;
274     struct rb_node * tmp_node = NULL;
275     addr_t block_pages = v3_mem_block_size >> 12;
276     int i = 0;
277
278     while (node) {
279         reg = rb_entry(node, struct v3_mem_region, tree_node);
280         tmp_node = node;
281         node = v3_rb_next(node);
282
283         v3_delete_mem_region(vm, reg);
284     }
285
286     for (i = 0; i < map->num_base_regions; i++) {
287         struct v3_mem_region * region = &(map->base_regions[i]);
288 #ifdef V3_CONFIG_SWAPPING
289         if (vm->swap_state.enable_swapping) { 
290             if (!region->flags.swapped) { 
291                 V3_FreePages((void *)(region->host_addr), block_pages);
292             } // otherwise this is not allocated space
293         }
294 #else
295         V3_FreePages((void *)(region->host_addr), block_pages);
296 #endif
297     }
298
299     V3_VFree(map->base_regions);
300 }
301
302
303 struct v3_mem_region * v3_create_mem_region(struct v3_vm_info * vm, uint16_t core_id, 
304                                                addr_t guest_addr_start, addr_t guest_addr_end) {
305     struct v3_mem_region * entry = NULL;
306
307     if (guest_addr_start >= guest_addr_end) {
308         PrintError(vm, VCORE_NONE, "Region start is after region end\n");
309         return NULL;
310     }
311
312     entry = (struct v3_mem_region *)V3_Malloc(sizeof(struct v3_mem_region));
313
314     if (!entry) {
315         PrintError(vm, VCORE_NONE, "Cannot allocate in creating a memory region\n");
316         return NULL;
317     }
318
319     memset(entry, 0, sizeof(struct v3_mem_region));
320
321     entry->guest_start = guest_addr_start;
322     entry->guest_end = guest_addr_end;
323     entry->core_id = core_id;
324     entry->unhandled = unhandled_err;
325
326     return entry;
327 }
328
329
330
331
332 int v3_add_shadow_mem( struct v3_vm_info * vm, uint16_t core_id,
333                        addr_t               guest_addr_start,
334                        addr_t               guest_addr_end,
335                        addr_t               host_addr)
336 {
337     struct v3_mem_region * entry = NULL;
338
339     entry = v3_create_mem_region(vm, core_id, 
340                                  guest_addr_start, 
341                                  guest_addr_end);
342
343     entry->host_addr = host_addr;
344
345     entry->flags.read = 1;
346     entry->flags.write = 1;
347     entry->flags.exec = 1;
348     entry->flags.alloced = 1;
349
350     if (v3_insert_mem_region(vm, entry) == -1) {
351         V3_Free(entry);
352         return -1;
353     }
354
355     return 0;
356 }
357
358
359
360 static inline 
361 struct v3_mem_region * __insert_mem_region(struct v3_vm_info * vm, 
362                                            struct v3_mem_region * region) {
363     struct rb_node ** p = &(vm->mem_map.mem_regions.rb_node);
364     struct rb_node * parent = NULL;
365     struct v3_mem_region * tmp_region;
366
367     while (*p) {
368         parent = *p;
369         tmp_region = rb_entry(parent, struct v3_mem_region, tree_node);
370
371         if (region->guest_end <= tmp_region->guest_start) {
372             p = &(*p)->rb_left;
373         } else if (region->guest_start >= tmp_region->guest_end) {
374             p = &(*p)->rb_right;
375         } else {
376             if ((region->guest_end != tmp_region->guest_end) ||
377                 (region->guest_start != tmp_region->guest_start)) {
378                 PrintError(vm, VCORE_NONE, "Trying to map a partial overlapped core specific page...\n");
379                 return tmp_region; // This is ugly... 
380             } else if (region->core_id == tmp_region->core_id) {
381                 PrintError(vm, VCORE_NONE, "Trying to map a core-overlapping page\n");
382                 return tmp_region;
383             } else if (region->core_id < tmp_region->core_id) {
384                 p = &(*p)->rb_left;
385             } else { 
386                 p = &(*p)->rb_right;
387             }
388         }
389     }
390
391     rb_link_node(&(region->tree_node), parent, p);
392   
393     return NULL;
394 }
395
396
397
398 int v3_insert_mem_region(struct v3_vm_info * vm, struct v3_mem_region * region) {
399     struct v3_mem_region * ret;
400     int i = 0;
401     int rc;
402
403     if ((ret = __insert_mem_region(vm, region))) {
404         PrintError(vm, VCORE_NONE, "Internal insert failed returned region is from 0x%p to 0x%p on vcore %d\n", (void*)(ret->guest_start), (void*)(ret->guest_end), ret->core_id);
405         return -1;
406     }
407
408     v3_rb_insert_color(&(region->tree_node), &(vm->mem_map.mem_regions));
409
410
411     rc = 0;
412
413     for (i = 0; i < vm->num_cores; i++) {
414         struct guest_info * info = &(vm->cores[i]);
415
416         // flush virtual page tables 
417         // 3 cases shadow, shadow passthrough, and nested
418
419         if (info->shdw_pg_mode == SHADOW_PAGING) {
420             v3_mem_mode_t mem_mode = v3_get_vm_mem_mode(info);
421             
422             if (mem_mode == PHYSICAL_MEM) {
423               rc |= v3_invalidate_passthrough_addr_range(info, region->guest_start, region->guest_end-1,NULL,NULL);
424             } else {
425                 rc |= v3_invalidate_shadow_pts(info);
426             }
427             
428         } else if (info->shdw_pg_mode == NESTED_PAGING) {
429           rc |= v3_invalidate_nested_addr_range(info, region->guest_start, region->guest_end-1,NULL,NULL);
430         }
431     }
432
433     return rc;
434 }
435                                                  
436
437
438
439 struct v3_mem_region * v3_get_mem_region(struct v3_vm_info * vm, uint16_t core_id, addr_t guest_addr) {
440     struct rb_node * n = vm->mem_map.mem_regions.rb_node;
441     struct v3_mem_region * reg = NULL;
442
443     while (n) {
444
445         reg = rb_entry(n, struct v3_mem_region, tree_node);
446
447         if (guest_addr < reg->guest_start) {
448             n = n->rb_left;
449         } else if (guest_addr >= reg->guest_end) {
450             n = n->rb_right;
451         } else {
452             if (reg->core_id == V3_MEM_CORE_ANY) {
453                 // found relevant region, it's available on all cores
454                 return reg;
455             } else if (core_id == reg->core_id) { 
456                 // found relevant region, it's available on the indicated core
457                 return reg;
458             } else if (core_id < reg->core_id) { 
459                 // go left, core too big
460                 n = n->rb_left;
461             } else if (core_id > reg->core_id) { 
462                 // go right, core too small
463                 n = n->rb_right;
464             } else {
465                 PrintDebug(vm, VCORE_NONE, "v3_get_mem_region: Impossible!\n");
466                 return NULL;
467             }
468         }
469     }
470
471
472     // There is not registered region, so we check if its a valid address in the base region
473
474     return v3_get_base_region(vm, guest_addr);
475 }
476
477
478
479 /* This returns the next memory region based on a given address. 
480  * If the address falls inside a sub region, that region is returned. 
481  * If the address falls outside a sub region, the next sub region is returned
482  * NOTE that we have to be careful about core_ids here...
483  */
484 static struct v3_mem_region * get_next_mem_region( struct v3_vm_info * vm, uint16_t core_id, addr_t guest_addr) {
485     struct rb_node * n = vm->mem_map.mem_regions.rb_node;
486     struct v3_mem_region * reg = NULL;
487     struct v3_mem_region * parent = NULL;
488
489     if (n == NULL) {
490         return NULL;
491     }
492
493     while (n) {
494
495         reg = rb_entry(n, struct v3_mem_region, tree_node);
496
497         if (guest_addr < reg->guest_start) {
498             n = n->rb_left;
499         } else if (guest_addr >= reg->guest_end) {
500             n = n->rb_right;
501         } else {
502             if (reg->core_id == V3_MEM_CORE_ANY) {
503                 // found relevant region, it's available on all cores
504                 return reg;
505             } else if (core_id == reg->core_id) { 
506                 // found relevant region, it's available on the indicated core
507                 return reg;
508             } else if (core_id < reg->core_id) { 
509                 // go left, core too big
510                 n = n->rb_left;
511             } else if (core_id > reg->core_id) { 
512                 // go right, core too small
513                 n = n->rb_right;
514             } else {
515                 PrintError(vm, VCORE_NONE, "v3_get_mem_region: Impossible!\n");
516                 return NULL;
517             }
518         }
519
520         if ((reg->core_id == core_id) || (reg->core_id == V3_MEM_CORE_ANY)) {
521             parent = reg;
522         }
523     }
524
525
526     if (parent->guest_start > guest_addr) {
527         return parent;
528     } else if (parent->guest_end < guest_addr) {
529         struct rb_node * node = &(parent->tree_node);
530
531         while ((node = v3_rb_next(node)) != NULL) {
532             struct v3_mem_region * next_reg = rb_entry(node, struct v3_mem_region, tree_node);
533
534             if ((next_reg->core_id == V3_MEM_CORE_ANY) ||
535                 (next_reg->core_id == core_id)) {
536
537                 // This check is not strictly necessary, but it makes it clearer
538                 if (next_reg->guest_start > guest_addr) {
539                     return next_reg;
540                 }
541             }
542         }
543     }
544
545     return NULL;
546 }
547
548
549
550
551 /* Given an address region of memory, find if there are any regions that overlap with it. 
552  * This checks that the range lies in a single region, and returns that region if it does, 
553  * this can be either the base region or a sub region. 
554  * IF there are multiple regions in the range then it returns NULL
555  */
556 static struct v3_mem_region * get_overlapping_region(struct v3_vm_info * vm, uint16_t core_id, 
557                                                      addr_t start_gpa, addr_t end_gpa) {
558     struct v3_mem_region * start_region = v3_get_mem_region(vm, core_id, start_gpa);
559
560     if (start_region == NULL) {
561         PrintError(vm, VCORE_NONE, "No overlapping region for core=%d, start_gpa=%p\n", core_id, (void*)start_gpa);
562         v3_print_mem_map(vm);
563         return NULL;
564     }
565
566
567     if (start_region->guest_end < end_gpa) {
568         // Region ends before range
569         return NULL;
570     } else if (start_region->flags.base == 0) {
571         // sub region overlaps range
572         return start_region;
573     } else {
574         // Base region, now we have to scan forward for the next sub region
575         struct v3_mem_region * next_reg = get_next_mem_region(vm, core_id, start_gpa);
576         
577         if (next_reg == NULL) {
578             // no sub regions after start_addr, base region is ok
579             return start_region;
580         } else if (next_reg->guest_start >= end_gpa) {
581             // Next sub region begins outside range
582             return start_region;
583         } else {
584             return NULL;
585         }
586     }
587
588
589     // Should never get here
590     return NULL;
591 }
592
593
594
595
596
597 void v3_delete_mem_region(struct v3_vm_info * vm, struct v3_mem_region * reg) {
598     int i = 0;
599     int rc;
600
601     if (reg == NULL) {
602         return;
603     }
604
605
606     v3_rb_erase(&(reg->tree_node), &(vm->mem_map.mem_regions));
607
608
609
610     // If the guest isn't running then there shouldn't be anything to invalidate. 
611     // Page tables should __always__ be created on demand during execution
612     // NOTE: This is a sanity check, and can be removed if that assumption changes
613     if (vm->run_state != VM_RUNNING) {
614         V3_Free(reg);
615         return;
616     }
617
618     rc = 0;
619
620     for (i = 0; i < vm->num_cores; i++) {
621         struct guest_info * info = &(vm->cores[i]);
622
623         // flush virtual page tables 
624         // 3 cases shadow, shadow passthrough, and nested
625
626         if (info->shdw_pg_mode == SHADOW_PAGING) {
627             v3_mem_mode_t mem_mode = v3_get_vm_mem_mode(info);
628             
629             if (mem_mode == PHYSICAL_MEM) {
630               rc |= v3_invalidate_passthrough_addr_range(info,reg->guest_start, reg->guest_end-1,NULL,NULL);
631             } else {
632               rc |= v3_invalidate_shadow_pts(info);
633             }
634             
635         } else if (info->shdw_pg_mode == NESTED_PAGING) {
636           rc |= v3_invalidate_nested_addr_range(info,reg->guest_start, reg->guest_end-1,NULL,NULL);
637         }
638     }
639
640     V3_Free(reg);
641
642     // flush virtual page tables 
643     // 3 cases shadow, shadow passthrough, and nested
644
645     if (rc) { PrintError(vm, VCORE_NONE, "Error in deleting memory region\n"); }
646 }
647
648 // Determine if a given address can be handled by a large page of the requested size
649 uint32_t v3_get_max_page_size(struct guest_info * core, addr_t page_addr, v3_cpu_mode_t mode) {
650     addr_t pg_start = 0;
651     addr_t pg_end = 0; 
652     uint32_t page_size = PAGE_SIZE_4KB;
653     struct v3_mem_region * reg = NULL;
654     
655     switch (mode) {
656         case PROTECTED:
657             if (core->use_large_pages == 1) {
658                 pg_start = PAGE_ADDR_4MB(page_addr);
659                 pg_end = (pg_start + PAGE_SIZE_4MB);
660
661                 reg = get_overlapping_region(core->vm_info, core->vcpu_id, pg_start, pg_end); 
662
663                 if ((reg) && ((reg->host_addr % PAGE_SIZE_4MB) == 0)) {
664                     page_size = PAGE_SIZE_4MB;
665                 }
666             }
667             break;
668         case PROTECTED_PAE:
669             if (core->use_large_pages == 1) {
670                 pg_start = PAGE_ADDR_2MB(page_addr);
671                 pg_end = (pg_start + PAGE_SIZE_2MB);
672
673                 reg = get_overlapping_region(core->vm_info, core->vcpu_id, pg_start, pg_end);
674
675                 if ((reg) && ((reg->host_addr % PAGE_SIZE_2MB) == 0)) {
676                     page_size = PAGE_SIZE_2MB;
677                 }
678             }
679             break;
680         case LONG:
681         case LONG_32_COMPAT:
682         case LONG_16_COMPAT:
683             if (core->use_giant_pages == 1) {
684                 pg_start = PAGE_ADDR_1GB(page_addr);
685                 pg_end = (pg_start + PAGE_SIZE_1GB);
686                 
687                 reg = get_overlapping_region(core->vm_info, core->vcpu_id, pg_start, pg_end);
688                 
689                 if ((reg) && ((reg->host_addr % PAGE_SIZE_1GB) == 0)) {
690                     page_size = PAGE_SIZE_1GB;
691                     break;
692                 }
693             }
694
695             if (core->use_large_pages == 1) {
696                 pg_start = PAGE_ADDR_2MB(page_addr);
697                 pg_end = (pg_start + PAGE_SIZE_2MB);
698
699                 reg = get_overlapping_region(core->vm_info, core->vcpu_id, pg_start, pg_end);
700                 
701                 if ((reg) && ((reg->host_addr % PAGE_SIZE_2MB) == 0)) {
702                     page_size = PAGE_SIZE_2MB;
703                 }
704             }
705             break;
706         default:
707             PrintError(core->vm_info, core, "Invalid CPU mode: %s\n", v3_cpu_mode_to_str(v3_get_vm_cpu_mode(core)));
708             return -1;
709     }
710
711     return page_size;
712 }
713
714
715
716 void v3_print_mem_map(struct v3_vm_info * vm) {
717     struct v3_mem_map * map = &(vm->mem_map);
718     struct rb_node * node = v3_rb_first(&(vm->mem_map.mem_regions));
719     struct v3_mem_region * reg = NULL;
720     int i = 0;
721
722     V3_Print(vm, VCORE_NONE, "Memory Layout (all cores):\n");
723     
724     V3_Print(vm, VCORE_NONE, "Base Memory: (%d regions)\n", map->num_base_regions);
725
726     for (i = 0; i < map->num_base_regions; i++) {
727         reg = &(map->base_regions[i]);
728
729         V3_Print(vm, VCORE_NONE, "Base Region[%d] (all cores):  0x%p - 0x%p -> 0x%p\n", 
730                  i, 
731                  (void *)(reg->guest_start), 
732                  (void *)(reg->guest_end - 1), 
733                  (void *)(reg->host_addr));
734     
735     }
736
737     // If the memory map is empty, don't print it
738     if (node == NULL) {
739         return;
740     }
741
742     do {
743         reg = rb_entry(node, struct v3_mem_region, tree_node);
744
745         V3_Print(vm, VCORE_NONE, "%d:  0x%p - 0x%p -> 0x%p\n", i, 
746                    (void *)(reg->guest_start), 
747                    (void *)(reg->guest_end - 1), 
748                    (void *)(reg->host_addr));
749
750         V3_Print(vm, VCORE_NONE, "\t(flags=0x%x) (core=0x%x) (unhandled = 0x%p)\n", 
751                  reg->flags.value, 
752                  reg->core_id,
753                  reg->unhandled);
754     
755         i++;
756     } while ((node = v3_rb_next(node)));
757 }
758
759
760 void v3_init_mem()
761 {
762     char *arg = v3_lookup_option("mem_block_size");
763
764     if (arg) { 
765         v3_mem_block_size = atoi(arg);
766         V3_Print(VM_NONE,VCORE_NONE,"memory block size set to %llu bytes\n",v3_mem_block_size);
767     } else {
768         V3_Print(VM_NONE,VCORE_NONE,"default memory block size of %llu bytes is in use\n",v3_mem_block_size);
769     }
770 }
771
772 void v3_deinit_mem()
773 {
774     // currently nothing
775 }