//////////////////////////////////////////////// /// <summary> /// Destroy the combined page /// </summary> static bool destroy_compound_pages(Page *page, byte order) { int bad = 0; uint i; uint nr_pages = (1U << order); __ClearPageHead(page); for (i = 1; i < nr_pages; i++) { Page *p = page + i; if (!PageTail(p) || p->FirstPage != page) { bad++; BUDDY_BUG("destroy_compound_pages: error"); } __ClearPageTail(p); } return(bad != 0); }
private bool MoveToFreeContinuous(uint pages) { Page *tryHead = (Page *)FreeList; var loopedPages = 0; Page *tmpHead = tryHead; var found = false; for (int i = 0; i < pages; i++) { if (loopedPages >= _FreePages) { return(false); } loopedPages++; var next = (Page *)tmpHead->Lru.next; if (GetPageNum(next) - GetPageNum(tmpHead) != 1) { tryHead = next; tmpHead = next; i = -1; // Reset loop continue; } tmpHead = next; if (i == pages - 1) { found = true; } } if (found) { FreeList = (list_head *)tryHead; return(true); } else { return(false); } }
public void Initialize(MemoryRegion region, Page *pages, AddressSpaceKind addressSpaceKind) { _Requests = 0; _Releases = 0; KernelMessage.WriteLine("Init SimplePageAllocator"); AddressSpaceKind = addressSpaceKind; _Region = region; Pages = pages; FirstPageNum = region.Start / 4096; _FreePages = region.Size / 4096; _TotalPages = region.Size / 4096; var addr = region.Start; for (var i = 0; i < _TotalPages; i++) { Pages[i].Address = addr; addr += 4096; } }
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("buddy_free_pages: 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_head.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_head.list_add(&page->Lru, &zone->free_area[order].free_list); zone->free_area[order].nr_free++; //TODO: unlock zone->lock }
public Page *NextCompoundPage(Page *page) { if (page == null) { return(null); } var next = NextPage(page); if (next == null) { return(null); } if (BuddyAllocatorImplementation.PageHead(page)) { if (BuddyAllocatorImplementation.PageTail(next)) { return(next); } else { return(null); } } else if (BuddyAllocatorImplementation.PageTail(page)) { if (BuddyAllocatorImplementation.PageTail(next)) { return(next); } else { return(null); } } else { return(null); } }
/// <summary> /// Releases a page to the free list /// </summary> public void Free(Page *page) { lock (this) { var head = page; if (head->Status == PageStatus.Reserved) { Panic.Error("Cannot free reserved page"); } //if (head->Free) if (head->Status == PageStatus.Free) { Panic.Error("Double Free?"); return; } var num = head->PagesUsed; //KernelMessage.Write("F:{0};", num); var p = head; for (var n = 0; n < num; n++) { if (p->Free) { Panic.Error("Already Free Page in Compound Page"); return; } p->Status = PageStatus.Free; p->PagesUsed = 0; p->Head = null; p->Tail = null; p = NextPage(p); _FreePages++; } NextTryPage = head; } }
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_head.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_head.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); }
private unsafe Page *AllocatePagesNormal(uint pages, AllocatePageOptions options = default) { Page *prevHead = null; Page *firstHead = null; var pagesFound = 0; for (var i = 0; i < _TotalPages; i++) { var page = &Pages[i]; if (!InUse(page)) { if (firstHead == null) { firstHead = page; } if (prevHead != null) { SetNext(prevHead, page); } SetInUse(page); pagesFound++; _FreePages--; if (pagesFound >= pages) { return(firstHead); } prevHead = page; } } return(null); }
public uint GetPageIndex(Page *page) { var addr = GetAddress(page); return((addr - Region.Start) / 4096); }
public Page *NextPage(Page *page) { var pageIdx = GetPageIndex(page) + 1; return(GetPageByIndex(pageIdx)); }
public uint GetAddress(Page *page) { return((uint)BuddyAllocatorImplementation.page_to_virt(ZonePtr, page)); }
public uint GetPageNum(Page *page) { return((uint)BuddyAllocatorImplementation.page_to_virt(ZonePtr, page) >> BuddyAllocatorImplementation.BUDDY_PAGE_SHIFT); }
public void Free(Page *page) { BuddyAllocatorImplementation.buddy_free_pages(ZonePtr, page); }
public Page *AllocatePages(uint pages, AllocatePageOptions options = default) { lock (this) { if (pages == 0) { KernelMessage.WriteLine("Requesting zero pages"); return(null); } else if (pages > 1 && KConfig.Log.PageAllocation) { KernelMessage.WriteLine("Requesting {0} pages", pages); } //KernelMessage.WriteLine("Request {0} pages...", num); uint statBlocks = 0; uint statFreeBlocks = 0; int statMaxBlockPages = 0; uint statRangeChecks = 0; uint cnt = 0; if (NextTryPage == null) { NextTryPage = PageArray; } Page *p = NextTryPage; while (true) { statBlocks++; if (p == null) { p = PageArray; } if (p->Status == PageStatus.Free) { statFreeBlocks++; var head = p; // Found free Page. Check now free range. for (var i = 0; i < pages; i++) { statRangeChecks++; statMaxBlockPages = Math.Max(statMaxBlockPages, i); if (p == null) { break; // Reached end. Our Range is incomplete } if (p->Status != PageStatus.Free) // Used -> so we can abort the search { break; } if (i == pages - 1) { // all loops successful. So we found our range. if (p == null) { Panic.Error("Tail is null"); } head->Tail = p; head->PagesUsed = pages; p = head; for (var n = 0; n < pages; n++) { if (p->Status != PageStatus.Free) { Panic.Error("Page is not Free. PageFrame Array corrupted?"); } p->Status = PageStatus.Used; p->Head = head; p->Tail = head->Tail; p = NextPage(p); _FreePages--; } // correct version: NextTryPage = p; // TODO: HACK! Currently, we have somewhere a buffer overrun? Fix that! //NextTryPage = p + 1; //var t = head->Tail; //var a = t->Address; //var anum = (uint)a; ////(uint)head->Tail->Address + 4096 - 1 //KernelMessage.Write("<"); //KernelMessage.WriteLine("Allocated from {0:X8} to {1:X8}, Status={2}", (uint)head->Address, anum, (uint)head->Status); //KernelMessage.Write(">"); //if (head->PhysicalAddress == 0x01CA4000) //{ // KernelMessage.WriteLine("DEBUG-MARKER 2"); // DumpPage(head); //} return(head); } p = NextPage(p); } } if (p->Tail != null) { p = p->Tail; } p = NextPage(p); if (++cnt > _TotalPages) { break; } } KernelMessage.WriteLine("Blocks={0} FreeBlocks={1} MaxBlockPages={2} RangeChecks={3} cnt={4}", statBlocks, statFreeBlocks, (uint)statMaxBlockPages, statRangeChecks, cnt); this.DumpPages(); Panic.Error("PageFrameAllocator: Could not allocate " + pages + " Pages."); return(null); } }
public bool ContainsPage(Page *page) { return(_Region.Contains(page->Address)); }
public unsafe Page *NextPage(Page *page) { return(GetPageByIndex(GetPageIndex(page) + 1)); }
public bool ContainsPage(Page *page) { var addr = GetAddress(page); return(Region.Contains(addr)); }
public static void Free(Page *page) { Default.Free(page); }
private void DumpPage(Page *p) { KernelMessage.WriteLine("pNum {0}, phys {1:X8} status {2} struct {3:X8} structPage {4}", GetPageNum(p), GetAddress(p), p->Flags, (uint)p, (uint)p / 4096); }
public static unsafe Addr MapVirtualPages(Page *pages, uint count, ulong flags, Pgprot_t protection) { throw new NotImplementedException(); }
public static Page *NextCompoundPage(Page *page) { return(Default.NextCompoundPage(page)); }
public static Addr GetAddress(Page *page) { return(Default.GetAddress(page)); }
public static unsafe Addr MapVirtualPages(Page *pages, uint count, ulong flags, Pgprot_t protection) { return(Addr.Zero); }
public uint GetPageIndex(Page *page) { return(GetPageNum(page) - FistPageNum); }
public Page *NextCompoundPage(Page *page) { //KernelMessage.WriteLine("NextCompoundPage: {0:X8}, {1:X8}", GetAddress(page), (uint)page->FirstPage); return(page->FirstPage); }
/// <summary> /// Allocate a physical page from the free list /// </summary> /// <returns>The page</returns> Page *Allocate(uint num) { KernelMessage.Write("Request {0} pages...", num); var cnt = 0; if (lastAllocatedPage == null) { lastAllocatedPage = PageArray; } Page *p = lastAllocatedPage->Next; while (true) { if (p == null) { p = PageArray; } if (p->Status == PageStatus.Free) { var head = p; // Found free Page. Check now free range. for (var i = 0; i < num; i++) { if (p == null) { break; // Reached end. SorRange is incomplete } if (p->Status != PageStatus.Free) // Used -> so we can abort the searach { break; } if (i == num - 1) { // all loops successful. So we found our range. head->Tail = p; head->PagesUsed = num; p = head; for (var n = 0; n < num; n++) { p->Status = PageStatus.Used; p->Head = head; p->Tail = head->Tail; p = p->Next; PagesUsed++; } lastAllocatedPage = p; KernelMessage.WriteLine("Allocated from {0:X8} to {1:X8}", (uint)head->PhysicalAddress, (uint)head->Tail->PhysicalAddress); return(head); } p = p->Next; } } if (p->Tail != null) { p = p->Tail; } p = p->Next; if (++cnt > PageCount) { break; } } Panic.Error("PageFrameAllocator: No free Page found"); return(null); }
public uint GetAddress(Page *page) { return(page->Address); }
public void Free(Page *page) { Free(page->PhysicalAddress); }
public uint GetPageNum(Page *page) { return(GetAddress(page) / 4096); }