// print buddy system status //void dump_print(struct mem_zone * zone); //void dump_print_dot(struct mem_zone * zone); //---###--- public static void buddy_system_init(mem_zone *zone, page *start_page, uint start_addr, uint page_num) { uint i; page * page = null; free_area *area = null; // init memory zone zone->page_num = page_num; zone->page_size = BUDDY_PAGE_SIZE; zone->first_page = start_page; zone->start_addr = start_addr; zone->end_addr = start_addr + (page_num * BUDDY_PAGE_SIZE); // TODO: init zone->lock // init each area for (i = 0; i < BUDDY_MAX_ORDER; i++) { area = zone->free_area + i; INIT_LIST_HEAD(&area->free_list); area->nr_free = 0; } memset((byte *)start_page, 0, page_num * (uint)sizeof(page)); // init and free each page for (i = 0; i < page_num; i++) { page = zone->first_page + i; INIT_LIST_HEAD(&page->lru); // TODO: init page->lock buddy_free_pages(zone, page); } }
static uint buddy_num_free_page(mem_zone *zone) { byte i; uint ret; for (i = 0, ret = 0; i < BUDDY_MAX_ORDER; i++) { ret += zone->free_area[i].nr_free * (1U << i); } return(ret); }
//////////////////////////////////////////////// public static void *page_to_virt(mem_zone *zone, page *page) { uint page_idx = 0; uint address = 0; page_idx = (uint)(page - zone->first_page); address = zone->start_addr + (page_idx * BUDDY_PAGE_SIZE); return((void *)address); }
public static page *buddy_get_pages(mem_zone *zone, byte order) { page *page = null; if (order >= BUDDY_MAX_ORDER) { BUDDY_BUG("error"); return(null); } //TODO: lock zone->lock page = __alloc_page(order, zone); //TODO: unlock zone->lock return(page); }
/// <summary> /// Split the combined page to get the page of the desired size /// </summary> static void expand(mem_zone *zone, page *page, byte low_order, byte high_order, free_area *area) { uint size = (1U << high_order); while (high_order > low_order) { area--; high_order--; size >>= 1; list_add(&page[size].lru, &area->free_list); area->nr_free++; // set page order set_page_order_buddy(&page[size], high_order); } }
public static page *virt_to_page(mem_zone *zone, void *ptr) { uint page_idx = 0; page *page = null; uint address = (uint)ptr; if ((address < zone->start_addr) || (address > zone->end_addr)) { //printf("start_addr=0x%lx, end_addr=0x%lx, address=0x%lx\n", // zone->start_addr, zone->end_addr, address); BUDDY_BUG("error"); return(null); } page_idx = (address - zone->start_addr) >> BUDDY_PAGE_SHIFT; page = zone->first_page + page_idx; return(page); }
public static void buddy_free_pages(mem_zone *zone, page *page) { byte order = compound_order(page); uint buddy_idx = 0, combinded_idx = 0; uint page_idx = (uint)(page - zone->first_page); //TODO: lock zone->lock if (PageCompound(page)) { if (destroy_compound_pages(page, order)) { BUDDY_BUG("error"); } } while (order < BUDDY_MAX_ORDER - 1) { page *buddy; // find and delete buddy to combine buddy_idx = __find_buddy_index(page_idx, order); buddy = page + (buddy_idx - page_idx); if (!page_is_buddy(buddy, order)) { break; } list_del(&buddy->lru); zone->free_area[order].nr_free--; // remove buddy's flag and order rmv_page_order_buddy(buddy); // update page and page_idx after combined combinded_idx = __find_combined_index(page_idx, order); page = page + (combinded_idx - page_idx); page_idx = combinded_idx; order++; } set_page_order_buddy(page, order); list_add(&page->lru, &zone->free_area[order].free_list); zone->free_area[order].nr_free++; //TODO: unlock zone->lock }
public static Page *buddy_get_pages(mem_zone *zone, byte order) { BUDDY_TRACE("buddy_get_pages, Order: {0:X8}", order); Page *page = null; if (order >= BUDDY_MAX_ORDER) { BUDDY_BUG("buddy_get_pages: order >= BUDDY_MAX_ORDER, {0}", order); return(null); } //TODO: lock zone->lock page = __alloc_page(order, zone); //TODO: unlock zone->lock if (page == null) { BUDDY_TRACE("Out of Memory?"); } return(page); }
static page *__alloc_page(byte order, mem_zone *zone) { page * page = null; free_area *area = null; byte current_order = 0; for (current_order = order; current_order < BUDDY_MAX_ORDER; current_order++) { area = zone->free_area + current_order; if (list_empty(&area->free_list)) { continue; } // remove closest size page //page = list_entry(area->free_list.next, struct page, lru); page = (page *)&((page *)area->free_list.next)->lru; list_del(&page->lru); rmv_page_order_buddy(page); area->nr_free--; // expand to lower order expand(zone, page, order, current_order, area); // compound page if (order > 0) { prepare_compound_pages(page, order); } else // single page { page->order = 0; } return(page); } return(null); }