public unsafe Page *AllocatePages(uint pages, AllocatePageOptions options = default) { if (pages > _FreePages) { Panic.Error("Out of Memory"); return(null); } Page *page; if (AddressSpaceKind == AddressSpaceKind.Virtual || options.Continuous) { page = AllocatePagesContinuous(pages, options); } else { page = AllocatePagesNormal(pages, options); } if (page == null) { KernelMessage.WriteLine("DebugName: {0}", DebugName); KernelMessage.WriteLine("Free pages: {0:X8}, Requested: {1:X8}", FreePages, pages); Panic.Error("Out of Memory"); } KernelMessage.Path(DebugName, "SimpleAlloc: Request {0} Pages, Addr {1:X8}", pages, GetAddress(page)); return(page); }
static void BUDDY_BUG(string msg, uint value = 0) { //printf("BUDDY_BUG in %s, %d.\n", f, line); //System.Console.WriteLine(msg); KernelMessage.Path("Allocator", msg, value); //assert(0); }
/// <summary> /// Releases a page to the free list /// </summary> public void Free(Page *page) { var oldFree = _FreePages; string debugName = null; if (page->DebugTag != null) { debugName = (string)Intrinsic.GetObjectFromAddress((Pointer)(uint)page->DebugTag); } UninterruptableMonitor.Enter(this); try { var debugCount = list_head.list_count((list_head *)page); // DEBUG SelfCheck("SCF1", debugCount); Page *temp = page; uint result = 0; do { result++; if (temp->Status == PageStatus.Free) { //Panic.Error("Double Free"); SelfCheck("SCF3", debugCount); KernelMessage.WriteLine("Double Free. Pages {0} Iteration {1}", debugCount, result); Debug.Break(); } temp->Status = PageStatus.Free; var oldTemp = temp; temp = (Page *)temp->Lru.next; Native.Nop(); _FreePages++; list_head.list_move_tail((list_head *)oldTemp, FreeList); }while (temp != page && result != debugCount); //list_head.list_headless_splice_tail((list_head*)page, FreeList); SelfCheck("SCF2", debugCount); } finally { UninterruptableMonitor.Exit(this); } var freedPages = _FreePages - oldFree; if (KConfig.Log.PageAllocation && TraceOptions.Enabled && freedPages >= TraceOptions.MinPages) { KernelMessage.Path(DebugName, "Freed Pages: {1}. Addr: {2:X8}. Now available: {3} --> {4}. Allocations={5} DebugName={0}.", debugName, freedPages, GetAddress(page), oldFree, _FreePages, (uint)Requests); } _Releases++; }
public void Setup(MemoryRegion region, AddressSpaceKind addrKind) { TraceOptions = new PageFrameAllocatorTraceOptions(); _AddressSpaceKind = addrKind; _Region = region; FistPageNum = region.Start / PageSize; _TotalPages = region.Size / PageSize; kmap = AllocRawMemory(_TotalPages * (uint)sizeof(Page)); PageArray = (Page *)kmap.Start; var firstSelfPageNum = KMath.DivFloor(kmap.Start, 4096); var selfPages = KMath.DivFloor(kmap.Size, 4096); KernelMessage.WriteLine("Page Frame Array allocated {0} pages, beginning with page {1} at {2:X8}", selfPages, firstSelfPageNum, (uint)PageArray); PageTable.KernelTable.SetWritable(kmap.Start, kmap.Size); kmap.Clear(); var addr = FistPageNum * 4096; for (uint i = 0; i < _TotalPages; i++) { //KernelMessage.WriteLine(i); PageArray[i].Address = addr; //if (i != 0) // PageArray[i - 1].Next = &PageArray[i]; addr += 4096; } KernelMessage.WriteLine("Setup free memory"); SetupFreeMemory(); KernelMessage.WriteLine("Build linked lists"); BuildLinkedLists(); KernelMessage.WriteLine("Build linked lists done"); _FreePages = 0; for (uint i = 0; i < _TotalPages; i++) { if (PageArray[i].Status == PageStatus.Free) { _FreePages++; } } //Assert.True(list_head.list_count(FreeList) == _FreePages, "list_head.list_count(FreeList) == _FreePages"); var debugCheckCount = list_head.list_count(FreeList); if (debugCheckCount != _FreePages) { KernelMessage.WriteLine("debugCheckCount {0} != {1}", debugCheckCount, _FreePages); Debug.Break(); } KernelMessage.Path(DebugName, "Pages Free: {0}", FreePages); }
private void CheckAllocation(Page *page, uint pages) { //return; var count = list_head.list_count((list_head *)page); //Assert.True(count == pages); if (count != pages) { KernelMessage.Path(DebugName, "Pages {0} != {1}, num={2} addr={3:X8} ptr={4:X8}", pages, count, GetPageNum(page), GetAddress(page), (uint)page); Debug.Break(); } }
protected override MemoryRegion AllocRawMemory(uint size) { var kmap = KernelMemoryMapManager.Allocate(size, BootInfoMemoryType.PageFrameAllocator, AddressSpaceKind.Both); KernelMessage.Path(DebugName, "AllocRawMemory: Done. Current maps:"); KernelMemoryMapManager.PrintMapArrays(); PageTable.KernelTable.Map(kmap.Start, kmap.Start, kmap.Size, flush: true); PageTable.KernelTable.SetWritable(kmap.Start, kmap.Size); var region = new MemoryRegion(kmap.Start, kmap.Size); region.Clear(); return(region); }
public static void Setup() { var addr = Initial_FindFreePage(); KernelMessage.Path("KernelMemoryMapManager", "Initial Page: {0:X}", addr); PageTable.KernelTable.Map(addr, addr, flush: true); // 80KB should be enough // TODO: Check if really 80KB are available after this address. InitialMap = new KernelMemoryMap(addr, 0x1000 * 20, BootInfoMemoryType.KernelMemoryMap, AddressSpaceKind.Both); PageTable.KernelTable.Map(InitialMap.Start, InitialMap.Start, InitialMap.Size, flush: true); PageTable.KernelTable.SetWritable(InitialMap.Start, InitialMap.Size); Header = (KernelMemoryMapHeader *)InitialMap.Start; var arrayOffset1 = 0x1000; var arrayOffset2 = 0x2000; var arrayOffset3 = 0x3000; Header->SystemUsable = new KernelMemoryMapArray((KernelMemoryMap *)(InitialMap.Start + arrayOffset1), 50); Header->Used = new KernelMemoryMapArray((KernelMemoryMap *)(InitialMap.Start + arrayOffset2), 100); Header->KernelReserved = new KernelMemoryMapArray((KernelMemoryMap *)(InitialMap.Start + arrayOffset3), 100); for (uint i = 0; i < BootInfo.Header->MemoryMapLength; i++) { var map = BootInfo.Header->MemoryMapArray[i]; var kmap = new KernelMemoryMap(map.Start, map.Size, map.Type, map.AddressSpaceKind); if (kmap.Type == BootInfoMemoryType.SystemUsable) { Header->SystemUsable.Add(kmap); } else { if (kmap.Type == BootInfoMemoryType.KernelReserved) { Header->KernelReserved.Add(kmap); } else { Header->Used.Add(kmap); } } } Header->Used.Add(InitialMap); KernelMessage.Path("KernelMemoryMapManager", "Filling Lists Done. SystemUsable: {0}, CustomReserved: {1}, Used: {2}", Header->SystemUsable.Count, Header->KernelReserved.Count, Header->Used.Count); PrintMapArrays(); //Debug_FillAvailableMemory(); }
/// <summary> /// Video Stage /// </summary> public static unsafe void InitFrameBuffer() { if (!BootInfo.Header->FBPresent || BootInfo.Header->VBEMode < 0x100) { KernelMessage.Path("fb", "not present"); return; } KernelMessage.WriteLine("InitFrameBuffer"); Fb = new FrameBuffer(BootInfo.Header->FbInfo.FbAddr, BootInfo.Header->FbInfo.FbWidth, BootInfo.Header->FbInfo.FbHeight, BootInfo.Header->FbInfo.FbPitch, 8); Fb.Init(); FrameBufferTextScreen = new FrameBufferTextScreenDevice(Fb); Console.SetOutputDevice(FrameBufferTextScreen); }
public static KernelMemoryMap Allocate(USize size, BootInfoMemoryType type, AddressSpaceKind addressSpaceKind) { var cnt = Header->Used.Count; for (uint i = 0; i < cnt; i++) { var map = Header->Used.Items[i]; if (CheckPageIsUsableAfterMap(map, size, addressSpaceKind)) { var newMap = new KernelMemoryMap(map.Start + map.Size, size, type, addressSpaceKind); Header->Used.Add(newMap); KernelMessage.Path("KernelMemoryMapManager", "Allocated: at {0:X8}, size {1:X8}, type {2}", newMap.Start, size, (uint)type); return(newMap); } } return(KernelMemoryMap.Empty); }
public Page *AllocatePages(uint pages, AllocatePageOptions options = default) { Page *page = AllocateInternal(pages, options); if (page == null) { //KernelMessage.WriteLine("DebugName: {0}", DebugName); KernelMessage.WriteLine("Free pages: {0:X8}, Requested: {1:X8}", FreePages, pages); Panic.Error("Out of Memory"); } if (FreePages < 1000) { KernelMessage.Path(DebugName, "WARNING: Low pages. Available: {0}", FreePages); } return(page); }
/// <summary> /// Video Stage /// </summary> public static unsafe void InitFrameBuffer() { if (!BootInfo.Header->FBPresent || BootInfo.Header->VBEMode < 0x100) { KernelMessage.Path("fb", "not present"); return; } KernelMessage.WriteLine("InitFrameBuffer"); Fb = new FrameBuffer(ref BootInfo.Header->FbInfo); for (uint at = Fb.Addr; at < Fb.Addr + Fb.MemorySize; at += 4096) { PageTable.KernelTable.MapVirtualAddressToPhysical(at, at); } PageTable.KernelTable.Flush(); FrameBufferTextScreen = new FrameBufferTextScreenDevice(Fb); Console.SetOutputDevice(FrameBufferTextScreen); }
private void SelfCheck(string checkName, uint debugVal = 0) { return; var page = (Page *)FreeList; var count = list_head.list_count(FreeList); if (count != _FreePages) { this.DumpPages(); this.DumpStats(); this.DumpPage(page); KernelMessage.WriteLine("SelfCheck: {0} DebugVal={1}", checkName, debugVal); KernelMessage.Path(DebugName, "FreeListCount {0} != {1}, num={2} addr={3:X8} ptr={4:X8}", _FreePages, count, GetPageNum(page), GetAddress(page), (uint)page); Debug.Break(); } else { //Serial.Write(Serial.COM1, (byte)'!'); } }
private Page *AllocateInternal(uint pages, AllocatePageOptions options = default) { if (KConfig.Log.PageAllocation && TraceOptions.Enabled && pages >= TraceOptions.MinPages) { KernelMessage.Path(DebugName, "Requesting Pages: {1}. Available: {2} DebugName={0}", options.DebugName, pages, _FreePages); } if (pages == 256) { Debug.Nop(); } UninterruptableMonitor.Enter(this); try { SelfCheck("SC1"); if (pages > 1 && (AddressSpaceKind == AddressSpaceKind.Virtual || options.Continuous)) { if (!MoveToFreeContinuous(pages)) { // Compact //KernelMessage.Path(DebugName, "Compacting Linked List"); //this.DumpPages(); BuildLinkedLists(); if (!MoveToFreeContinuous(pages)) { this.DumpPages(); KernelMessage.WriteLine("Requesting {0} pages failed", pages); Panic.Error("Requesting pages failed: out of memory"); } } } // --- var head = FreeList; var headPage = (Page *)head; FreeList = head->next; list_head.list_del_init(head); headPage->Status = PageStatus.Used; if (KConfig.Log.PageAllocation) { if (options.DebugName != null) { headPage->DebugTag = (uint)Intrinsic.GetObjectAddress(options.DebugName); } else { headPage->DebugTag = null; } } _FreePages--; // --- for (var i = 1; i < pages; i++) { var tmpNextFree = FreeList->next; list_head.list_move_tail(FreeList, head); var p = (Page *)FreeList; if (p->Status == PageStatus.Used) { this.DumpPages(); this.DumpPage(p); KernelMessage.Path(DebugName, "Double Alloc pages={0} allocs={1} free={2} ptr={3:X8}", pages, (uint)_Requests, _FreePages, (uint)p); Panic.Error("Double Alloc"); } p->Status = PageStatus.Used; FreeList = tmpNextFree; _FreePages--; } if (KConfig.Log.PageAllocation && TraceOptions.Enabled && pages >= TraceOptions.MinPages) { KernelMessage.Path(DebugName, "Allocation done. Addr: {0:X8} Available: {1}", GetAddress(headPage), _FreePages); } _Requests++; CheckAllocation(headPage, pages); SelfCheck("SC2"); return(headPage); } finally { UninterruptableMonitor.Exit(this); } }