1 #include <geekos/vmm_mem.h>
2 #include <geekos/vmm.h>
3 #include <geekos/vmm_util.h>
5 extern struct vmm_os_hooks * os_hooks;
8 void init_mem_list(vmm_mem_list_t * list) {
10 list->long_mode = false;
12 list->num_regions = 0;
17 void free_mem_list(vmm_mem_list_t * list) {
18 mem_region_t * cursor = list->head;
19 mem_region_t * tmp = NULL;
23 cursor = cursor->next;
30 /*** FOR THE LOVE OF GOD WRITE SOME UNIT TESTS FOR THIS THING ***/
34 // Scan the current list, and extend an existing region if one exists
35 // Otherwise create a new region and merge it into the correct location in the list
37 // We scan to find the position at which to add the new region and insert it
38 // Then we clean up any region following the new region that overlaps
40 // JRL: This is pretty hairy...
41 int add_mem_list_pages(vmm_mem_list_t * list, addr_t addr, uint_t num_pages) {
43 uint_t num_new_pages = num_pages;
44 addr_t new_end = addr + (num_pages * PAGE_SIZE) - 1;
46 mem_region_t * cursor = get_mem_list_cursor(list, addr);
49 // PrintDebug("Adding: 0x%x - 0x%x\n", addr, num_pages * PAGE_SIZE);
52 // Make a new region at the head of the list
54 cursor = os_hooks->malloc(sizeof(mem_region_t));
58 cursor->num_pages = num_pages;
60 cursor->next = list->head;
64 cursor->next->prev = cursor;
69 addr_t cursor_end = cursor->addr + (cursor->num_pages * PAGE_SIZE) - 1;
71 if (addr > cursor_end + 1) {
72 // address falls after cursor region
74 mem_region_t * new_region = os_hooks->malloc(sizeof(mem_region_t));
76 new_region->prev = cursor;
77 new_region->next = cursor->next;
80 cursor->next->prev = new_region;
82 cursor->next = new_region;
84 new_region->addr = addr;
85 new_region->num_pages = num_pages;
90 } else if ((addr >= cursor->addr) &&
91 (addr <= cursor_end + 1)) {
92 // address falls inside the cursor region
95 // The region has already been added
96 if (new_end <= cursor_end) {
100 // We need to extend the old region
101 num_new_pages = (new_end - cursor_end) / PAGE_SIZE;
102 cursor->num_pages += num_new_pages;
108 // Clean up any overlaps that follow
109 while ((cursor->next) && (cursor->next->addr <= new_end + 1)) {
110 mem_region_t * overlap = cursor->next;
111 addr_t overlap_end = overlap->addr + (overlap->num_pages * PAGE_SIZE) - 1;
113 cursor->next = overlap->next;
115 overlap->next->prev = cursor;
118 if (overlap_end > new_end) {
119 uint_t extension = (overlap_end - new_end) / PAGE_SIZE;
121 cursor->num_pages += extension;
122 num_new_pages -= (overlap->num_pages - extension);
124 num_new_pages -= overlap->num_pages;
133 list->num_pages += num_new_pages;
139 /* this function returns a pointer to the location in the memory list that
140 * corresponds to addr.
142 * IF addr is in a region, a ptr to that region is returned
143 * IF addr is not in a region, a ptr to the previous region is returned
144 * IF addr is before all regions, returns NULL
145 * IF list is empty, returns NULL
147 mem_region_t * get_mem_list_cursor(vmm_mem_list_t * list, addr_t addr) {
148 mem_region_t * prev_region = list->head;
150 while (prev_region != NULL) {
151 if ( (addr >= prev_region->addr) &&
152 (addr < (prev_region->addr + (prev_region->num_pages * PAGE_SIZE) - 1)) ) {
154 } else if (addr < prev_region->addr) {
155 // If this region is the current head, then this should return NULL
156 return prev_region->prev;
157 } else if (addr >= (prev_region->addr + (prev_region->num_pages * PAGE_SIZE))) {
158 if (prev_region->next) {
159 prev_region = prev_region->next;
171 /* Returns the page address of page number 'index' in the memory list
172 * If index is out of bounds... returns -1 (an invalid page address)
174 addr_t get_mem_list_addr(vmm_mem_list_t * list, uint_t index) {
175 mem_region_t * reg = list->head;
178 // Memory List overrun
179 if (index > list->num_pages - 1) {
184 if (reg->num_pages <= index) {
188 return reg->addr + (i * PAGE_SIZE);
196 void init_mem_layout(vmm_mem_layout_t * layout) {
197 layout->num_pages = 0;
198 layout->num_regions = 0;
204 void free_mem_layout(vmm_mem_layout_t * layout) {
205 layout_region_t * cursor = layout->head;
206 layout_region_t * tmp = NULL;
210 cursor = cursor->next;
219 /* this function returns a pointer to the location in the layout list that
220 * corresponds to addr.
222 * IF addr is in a region, a ptr to that region is returned
223 * IF addr is not in a region, a ptr to the previous region is returned
224 * IF addr is before all regions, returns NULL
225 * IF list is empty, returns NULL
227 layout_region_t * get_layout_cursor(vmm_mem_layout_t * layout, addr_t addr) {
228 layout_region_t * prev_region = layout->head;
231 while (prev_region != NULL) {
232 if ( (addr >= prev_region->addr) &&
233 (addr < (prev_region->addr + (prev_region->num_pages * PAGE_SIZE))) ) {
235 } else if (addr < prev_region->addr) {
236 // If this region is the current head, then this should return NULL
237 return prev_region->prev;
238 } else if (addr >= (prev_region->addr + (prev_region->num_pages * PAGE_SIZE))) {
239 if (prev_region->next) {
240 prev_region = prev_region->next;
251 /* This is slightly different semantically from the mem list, in that we don't allow overlaps
252 * we could probably allow overlappig regions of the same type... but I'll let someone else deal with that
254 int add_mem_range(vmm_mem_layout_t * layout, layout_region_t * region) {
256 layout_region_t * cursor = get_layout_cursor(layout, region->addr);
258 if (cursor == NULL) {
260 if (layout->head->addr < region->addr + (region->num_pages * PAGE_SIZE) - 1) {
261 // overlaps not allowed
264 layout->head->prev = region;
268 region->next = layout->head;
269 layout->head = region;
271 layout->num_regions++;
272 layout->num_pages += region->num_pages;
273 } else if ((region->addr >= cursor->addr) &&
274 (region->addr <= cursor->addr + (cursor->num_pages * PAGE_SIZE) - 1)) {
275 // overlaps not allowed
277 } else if (region->addr > cursor->addr + (cursor->num_pages * PAGE_SIZE) - 1) {
278 // add region to layout
279 region->next = cursor->next;
280 region->prev = cursor;
283 region->next->prev = region;
285 cursor->next = region;
287 layout->num_regions++;
288 layout->num_pages += region->num_pages;
301 int add_shared_mem_range(vmm_mem_layout_t * layout, addr_t addr, uint_t num_pages, addr_t host_addr) {
302 layout_region_t * shared_region = os_hooks->malloc(sizeof(layout_region_t));
305 shared_region->next = NULL;
306 shared_region->prev = NULL;
307 shared_region->addr = addr;
308 shared_region->num_pages = num_pages;
309 shared_region->type = SHARED;
310 shared_region->host_addr = host_addr;
312 ret = add_mem_range(layout, shared_region);
315 VMMFree(shared_region);
321 int add_unmapped_mem_range(vmm_mem_layout_t * layout, addr_t addr, uint_t num_pages) {
322 layout_region_t * unmapped_region = os_hooks->malloc(sizeof(layout_region_t));
325 unmapped_region->next = NULL;
326 unmapped_region->prev = NULL;
327 unmapped_region->addr = addr;
328 unmapped_region->num_pages = num_pages;
329 unmapped_region->type = UNMAPPED;
330 unmapped_region->host_addr = 0;
332 ret = add_mem_range(layout, unmapped_region);
335 VMMFree(unmapped_region);
341 int add_guest_mem_range(vmm_mem_layout_t * layout, addr_t addr, uint_t num_pages) {
342 layout_region_t * guest_region = os_hooks->malloc(sizeof(layout_region_t));
345 guest_region->next = NULL;
346 guest_region->prev = NULL;
347 guest_region->addr = addr;
348 guest_region->num_pages = num_pages;
349 guest_region->type = GUEST;
350 guest_region->host_addr = 0;
352 ret = add_mem_range(layout, guest_region);
355 layout->num_guest_pages += num_pages;
357 VMMFree(guest_region);
365 /* Returns the page address of page number 'index' in the memory list
366 * If index is out of bounds... returns -1 (an invalid page address)
368 addr_t get_mem_layout_addr(vmm_mem_layout_t * layout, uint_t index) {
369 layout_region_t * reg = layout->head;
372 // Memory List overrun
373 if (index > layout->num_pages - 1) {
382 if (reg->num_pages <= index) {
386 return reg->addr + (i * PAGE_SIZE);
396 void print_mem_list(vmm_mem_list_t * list) {
397 mem_region_t * cur = list->head;
400 PrintDebug("Memory Region List (regions: %d) (pages: %d)\n", list->num_regions, list->num_pages);
403 PrintDebug("%d: 0x%x - 0x%x\n", i, cur->addr, cur->addr + (cur->num_pages * PAGE_SIZE) - 1);
412 void print_mem_layout(vmm_mem_layout_t * layout) {
413 layout_region_t * cur = layout->head;
416 PrintDebug("Memory Layout (regions: %d) (pages: %d)\n", layout->num_regions, layout->num_pages);
419 PrintDebug("%d: 0x%x - 0x%x\n", i, cur->addr, cur->addr + (cur->num_pages * PAGE_SIZE) - 1);
444 #include <geekos/vmm_paging.h>
448 struct vmm_os_hooks * os_hooks;
450 void * TestMalloc(uint_t size) {
454 void * TestAllocatePages(int size) {
455 return malloc(4096 * size);
459 void TestPrint(const char * fmt, ...) {
467 int mem_list_add_test_1( vmm_mem_list_t * list) {
471 PrintDebug("\n\nTesting Memory List\n");
475 offset = PAGE_SIZE * 6;
476 PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 10));
477 add_mem_list_pages(list, offset, 10);
478 print_mem_list(list);
482 PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + PAGE_SIZE * 4);
483 add_mem_list_pages(list, offset, 4);
484 print_mem_list(list);
486 offset = PAGE_SIZE * 20;
487 PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 1));
488 add_mem_list_pages(list, offset, 1);
489 print_mem_list(list);
491 offset = PAGE_SIZE * 21;
492 PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 3));
493 add_mem_list_pages(list, offset, 3);
494 print_mem_list(list);
497 offset = PAGE_SIZE * 10;
498 PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 30));
499 add_mem_list_pages(list, offset, 30);
500 print_mem_list(list);
503 offset = PAGE_SIZE * 5;
504 PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 1));
505 add_mem_list_pages(list, offset, 1);
506 print_mem_list(list);
514 int mem_layout_add_test_1(vmm_mem_layout_t *layout) {
518 PrintDebug("\n\nTesting Memory Layout\n");
520 init_mem_layout(layout);
522 offset = PAGE_SIZE * 6;
523 PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 10));
524 add_guest_mem_range(layout, offset, 10);
525 print_mem_layout(layout);
528 offset = PAGE_SIZE * 20;
529 PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 1));
530 add_guest_mem_range(layout, offset, 1);
531 print_mem_layout(layout);
534 offset = PAGE_SIZE * 16;
535 PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + PAGE_SIZE * 4);
536 add_guest_mem_range(layout, offset, 4);
537 print_mem_layout(layout);
540 offset = PAGE_SIZE * 10;
541 PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 30));
542 add_guest_mem_range(layout, offset, 30);
543 print_mem_layout(layout);
547 PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 1));
548 add_guest_mem_range(layout, offset, 1);
549 print_mem_layout(layout);
559 int main(int argc, char ** argv) {
560 struct vmm_os_hooks dummy_hooks;
561 os_hooks = &dummy_hooks;
563 vmm_mem_layout_t layout;
566 os_hooks->malloc = &TestMalloc;
567 os_hooks->free = &free;
568 os_hooks->print_debug = &TestPrint;
569 os_hooks->allocate_pages = &TestAllocatePages;
573 printf("mem_list_add_test_1: %d\n", mem_list_add_test_1(&list));
574 printf("layout_add_test_1: %d\n", mem_layout_add_test_1(&layout));
577 pde_t * pde = generate_guest_page_tables(&layout, &list);
578 PrintDebugPageTables(pde);