|  |  |  | @@ -19,37 +19,43 @@ | 
		
	
		
			
				|  |  |  |  |  */ | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #include <list.h> | 
		
	
		
			
				|  |  |  |  | #include <mm.h> | 
		
	
		
			
				|  |  |  |  | #include <frames.h> | 
		
	
		
			
				|  |  |  |  | #include <print.h> | 
		
	
		
			
				|  |  |  |  | #include <types.h> | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | struct dlist_node mm_free_page_list; | 
		
	
		
			
				|  |  |  |  | struct dlist_node free_frames_list; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | void mm_init() { | 
		
	
		
			
				|  |  |  |  | 	init_list(&mm_free_page_list); | 
		
	
		
			
				|  |  |  |  | void frames_init() { | 
		
	
		
			
				|  |  |  |  | 	init_list(&free_frames_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); | 
		
	
		
			
				|  |  |  |  | /*
 | 
		
	
		
			
				|  |  |  |  |  * Adds a page frame struct to the list of free page frames. Presupposes | 
		
	
		
			
				|  |  |  |  |  * free_frames_list is a properly initialized list. | 
		
	
		
			
				|  |  |  |  |  */ | 
		
	
		
			
				|  |  |  |  | static void insert_page_frame(struct frame *p) { | 
		
	
		
			
				|  |  |  |  | 	if (list_empty(&free_frames_list) || p->address < container(free_frames_list.next, struct frame, list)->address) { | 
		
	
		
			
				|  |  |  |  | 		insert_after(&free_frames_list, &p->list); | 
		
	
		
			
				|  |  |  |  | 	} else if (p->address > container(free_frames_list.prev, struct frame, list)->address) { | 
		
	
		
			
				|  |  |  |  | 		insert_before(&free_frames_list, &p->list); | 
		
	
		
			
				|  |  |  |  | 	} else { | 
		
	
		
			
				|  |  |  |  | 		struct page *it; | 
		
	
		
			
				|  |  |  |  | 		for_each_list(it, &mm_free_page_list, struct page, list) { | 
		
	
		
			
				|  |  |  |  | 		struct frame *it; | 
		
	
		
			
				|  |  |  |  | 		for_each_list(it, &free_frames_list, struct frame, list) { | 
		
	
		
			
				|  |  |  |  | 			if (p->address < it->address) { | 
		
	
		
			
				|  |  |  |  | 				insert_before(&it->list, &p->list); | 
		
	
		
			
				|  |  |  |  | 				return; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		print("Error: failed to insert page\n"); | 
		
	
		
			
				|  |  |  |  | 		print("Error: failed to insert page frame\n"); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | void mm_add_free_region(void *start, void *end) { | 
		
	
		
			
				|  |  |  |  | /*
 | 
		
	
		
			
				|  |  |  |  |  * Called to add a segment of memory to the frame allocation pool. | 
		
	
		
			
				|  |  |  |  |  */ | 
		
	
		
			
				|  |  |  |  | static void add_physical_memory(void *start, void *end) { | 
		
	
		
			
				|  |  |  |  | 	unsigned int num_pages, usable_pages; | 
		
	
		
			
				|  |  |  |  | 	struct page *p; | 
		
	
		
			
				|  |  |  |  | 	struct frame *p; | 
		
	
		
			
				|  |  |  |  | 	void *page; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	//If region starts at 0x0, make it start at next page to not screw up null pointer detection, etc.
 | 
		
	
	
		
			
				
					
					|  |  |  | @@ -73,40 +79,44 @@ void mm_add_free_region(void *start, void *end) { | 
		
	
		
			
				|  |  |  |  | 	//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 = num_pages - num_pages * sizeof(struct frame) / MM_PAGE_SIZE; | 
		
	
		
			
				|  |  |  |  | 	if (num_pages * sizeof(struct frame) % MM_PAGE_SIZE) | 
		
	
		
			
				|  |  |  |  | 		usable_pages--; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	p = (struct page *)start; | 
		
	
		
			
				|  |  |  |  | 	p = (struct frame *)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); | 
		
	
		
			
				|  |  |  |  | 		insert_page_frame(p); | 
		
	
		
			
				|  |  |  |  | 		p++; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | struct page* mm_get_free_pages(unsigned int power) { | 
		
	
		
			
				|  |  |  |  | /*
 | 
		
	
		
			
				|  |  |  |  |  * Attempt to get 2^power contiguous page frames. Returns the frame struct of | 
		
	
		
			
				|  |  |  |  |  * the first frame on success or a null pointer on failure. | 
		
	
		
			
				|  |  |  |  |  */ | 
		
	
		
			
				|  |  |  |  | struct frame* get_free_frames(unsigned int power) { | 
		
	
		
			
				|  |  |  |  | 	unsigned int num_pages = 1<<power; | 
		
	
		
			
				|  |  |  |  | 	struct page *it; | 
		
	
		
			
				|  |  |  |  | 	struct frame *it; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	if (list_empty(&mm_free_page_list)) { | 
		
	
		
			
				|  |  |  |  | 	if (list_empty(&free_frames_list)) { | 
		
	
		
			
				|  |  |  |  | 		print("Error: Out of memory\n"); | 
		
	
		
			
				|  |  |  |  | 		return (struct page*)0; | 
		
	
		
			
				|  |  |  |  | 		return (struct frame*)0; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	if (!num_pages) { | 
		
	
		
			
				|  |  |  |  | 		print("Error: mm_get_free_pages must be called with power from 0 to 31, inclusive (power=%d)\n", power); | 
		
	
		
			
				|  |  |  |  | 		return (struct page*)0; | 
		
	
		
			
				|  |  |  |  | 		return (struct frame*)0; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	for_each_list(it, &mm_free_page_list, struct page, list) { | 
		
	
		
			
				|  |  |  |  | 	for_each_list(it, &free_frames_list, struct frame, list) { | 
		
	
		
			
				|  |  |  |  | 		unsigned int curr_pages = 1; | 
		
	
		
			
				|  |  |  |  | 		struct page *it2; | 
		
	
		
			
				|  |  |  |  | 		for (it2 = container(it->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 
 | 
		
	
		
			
				|  |  |  |  | 		struct frame *it2; | 
		
	
		
			
				|  |  |  |  | 		for (it2 = container(it->list.next, struct frame, list); | 
		
	
		
			
				|  |  |  |  | 					it2->list.next != &free_frames_list && curr_pages < num_pages; | 
		
	
		
			
				|  |  |  |  | 					it2 = container(it2->list.next, struct frame, list)) { | 
		
	
		
			
				|  |  |  |  | 			if ((char*)it2->address != (char*)container(it2->list.prev, struct frame, list)->address + MM_PAGE_SIZE) { | 
		
	
		
			
				|  |  |  |  | 				it = it2; //fast-forward 'it' to start of next contiguous section of pages
 | 
		
	
		
			
				|  |  |  |  | 				break; | 
		
	
		
			
				|  |  |  |  | 			} else { | 
		
	
		
			
				|  |  |  |  | 				curr_pages++; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -117,14 +127,17 @@ struct page* mm_get_free_pages(unsigned int power) { | 
		
	
		
			
				|  |  |  |  | 			return it; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	return (struct page*)0; | 
		
	
		
			
				|  |  |  |  | 	return (struct frame*)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 pages allocated to the pool of unused pages. | 
		
	
		
			
				|  |  |  |  |  */ | 
		
	
		
			
				|  |  |  |  | int put_free_frames(struct frame *f) { | 
		
	
		
			
				|  |  |  |  | 	struct frame *it; | 
		
	
		
			
				|  |  |  |  | 	for_each_list(it, &free_frames_list, struct frame, list) { | 
		
	
		
			
				|  |  |  |  | 		if (f->address < it->address) { | 
		
	
		
			
				|  |  |  |  | 			insert_splice_before(&it->list, &f->list, f->list.prev); | 
		
	
		
			
				|  |  |  |  | 			return 0; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} |