#include #include #include struct dlist_node mm_free_page_list; void mm_init() { init_list(&mm_free_page_list); } //presupposes mm_free_page_list is a properly initialized list void insert_page(struct page *p) { if (list_empty(&mm_free_page_list) || p->address < container(mm_free_page_list.next, struct page, list)->address) { insert_after(&mm_free_page_list, &p->list); } else if (p->address > container(mm_free_page_list.prev, struct page, list)->address) { insert_before(&mm_free_page_list, &p->list); } else { struct page *it; for_each_list(it, &mm_free_page_list, struct page, list) { if (p->address < it->address) { insert_before(&it->list, &p->list); return; } } print("Error: failed to insert page\n"); } } void mm_add_free_region(void *start, void *end) { unsigned int num_pages, usable_pages; struct page *p; void *page; //make sure both start and end address are aligned to the size of a page if ((unsigned int)start % MM_PAGE_SIZE != 0) start = (char*)start + (MM_PAGE_SIZE - ((unsigned int)start % MM_PAGE_SIZE)); if (((unsigned int)end + 1) % MM_PAGE_SIZE != 0) end = (char*)end - ((unsigned int)end + 1) % MM_PAGE_SIZE; if ((char *)end + 1 - (char *)start < MM_PAGE_SIZE<<1) { print("Error: Supplied memory area(%x,%x) is smaller than the page size (%d)\n", (unsigned int)start, (unsigned int)end, MM_PAGE_SIZE); return; } //reserve enough pages at the front of this chunk of memory to hold the //page structs, then build the structs and add them to the list //TODO we're potentially losing memory here because we're calculating //the number of page structs we need even for those pages that will contain only page structs num_pages = ((char *)end + 1 - (char *)start) / MM_PAGE_SIZE; usable_pages = num_pages - num_pages * sizeof(struct page) / MM_PAGE_SIZE; if (num_pages * sizeof(struct page) % MM_PAGE_SIZE) usable_pages--; p = (struct page *)start; for (page = ((char *)start) + (num_pages - usable_pages)*MM_PAGE_SIZE; page < end; page = (void *)(((char *)page) + MM_PAGE_SIZE)) { p->address = page; insert_page(p); p++; } } struct page* mm_get_free_pages(unsigned int power) { unsigned int num_pages = 1<list.next, struct page, list); it2->list.next != &mm_free_page_list && curr_pages < num_pages; it2 = container(it2->list.next, struct page, list)) { if ((char*)it2->address != (char*)container(it2->list.prev, struct page, list)->address + MM_PAGE_SIZE) { it = it2; //fast-forward 'it' to start of next contiguous section of pages break; } else { curr_pages++; } } if (curr_pages == num_pages) { remove_splice(&it->list, it2->list.prev); return it; } } return (struct page*)0; } int mm_put_free_pages(struct page *p) { struct page *it; for_each_list(it, &mm_free_page_list, struct page, list) { if (p->address < it->address) { insert_splice_before(&it->list, &p->list, p->list.prev); return 0; } } return 1; }