static public void Init() { // See note in Bootstrap about these CPU = Bootstrap.CPU; PIC = Bootstrap.PIC; //TODO: Since this is FCL, its "common". Otherwise it should be // system level and not accessible from Core. Need to think about this // for the future. Console.WriteLine("Finding PCI Devices"); PCI.Setup(); }
public static uint MemAlloc(uint aLength) { if (aLength == 0) { DebugAndHalt(" Request to retrieve block with size = 0 was halted!"); } var xInterruptsWereEnabled = CPU.DisableInterrupts(); try { EnsureIsInitialized(); var xCurrentTableIdx = mLastTableIndex; DataLookupTable *xCurrentTable = GlobalSystemInfo.GlobalInformationTable->FirstDataLookupTable; DataLookupTable *xPreviousTable = null; uint xResult; while (xCurrentTable != null) { DebugHex("Scanning DataLookupTable ", xCurrentTableIdx); //DebugHex("At address", (uint)xCurrentTable); if (ScanDataLookupTable(xCurrentTableIdx, xCurrentTable, aLength, out xResult)) { DebugHex("Returning handle", xResult); DebugHex("For dataobject size", aLength); if (xResult < CPU.GetEndOfKernel()) { DebugAndHalt("Wrong handle returned!"); } return(xResult); } xCurrentTableIdx++; xPreviousTable = xCurrentTable; xCurrentTable = xCurrentTable->Next; mLastTableIndex = xCurrentTableIdx; mLastEntryIndex = 0; } // no tables found, lets create a new one, and use that if (xPreviousTable == null) { // this check should theoretically be unnecessary, but lets keep it, to do some double-checking. DebugAndHalt("No PreviousTable found!"); } Debug("Creating new DataLookupTable"); var xLastItem = xPreviousTable->GetEntry(DataLookupTable.EntriesPerTable - 1); var xNextTablePointer = (DataLookupTable *)((uint)xLastItem->DataBlock + xLastItem->Size); // the memory hasn't been cleared yet, so lets do that now. ClearMemory(xNextTablePointer, GlobalSystemInfo.TotalDataLookupTableSize); xPreviousTable->Next = xNextTablePointer; xNextTablePointer->Previous = xPreviousTable; if (!ScanDataLookupTable(xCurrentTableIdx, xNextTablePointer, aLength, out xResult)) { // Something seriously weird happened: we could create a new DataLookupTable (with new entries) // but couldn't allocate a new handle from it. DebugAndHalt(" Something seriously weird happened: we could create a new DataLookupTable (with new entries), but couldn't allocate a new handle from it."); } DebugHex("Returning handle", xResult); DebugHex("For dataobject size", aLength); mLastTableIndex = xCurrentTableIdx; mLastEntryIndex = 0; return(xResult); } finally { if (xInterruptsWereEnabled) { CPU.EnableInterrupts(); } else { //Debug(" Not enabling interrupts, because they weren't enabled yet!"); } } }
private static void ClearMemory(void *aStartAddress, uint aLength) { //TODO: Move to memory. Internal access only... CPU.ZeroFill((uint)aStartAddress, aLength); }
public static void Initialize() { MultiBoot.Header *header = (MultiBoot.Header *)CPU.GetMultiBootInfo(); MultiBoot.Memory *memory = (MultiBoot.Memory *)header->mmap_address; uint memoryEntrySize = 0; uint memoryEntryCount = 0; if (header->mmap_length > 0) { memoryEntrySize = memory->size + 4; memoryEntryCount = header->mmap_length / memoryEntrySize; } // if (memoryEntrySize == 0 || memoryEntryCount == 0) throw some kind of kernel error, no memory map log.WriteLine("RAM > MMAP Entry: Size=" + memoryEntrySize + ", Count=" + memoryEntryCount); ulong endOfKernel = CPU.GetEndOfKernel(); ulong kernelSize = 0; ulong availableAddress = 0; ulong availableSize = 0; MultiBoot.Memory *memoryIterator = memory; for (uint memoryEntry = 0; memoryEntry < memoryEntryCount; memoryEntry++, memoryIterator++) { // Don't need these checks, if we're only grabbing the region the kernel is allocated in for now // if (memoryIterator->address + memoryIterator->length <= CONVENTIONAL_MEMORY_SIZE) continue; // if (memoryIterator->type != MultiBoot.Memory.TYPE_AVAILABLE) continue; if (endOfKernel >= memoryIterator->address) { if (endOfKernel <= (memoryIterator->address + memoryIterator->length)) { availableAddress = memoryIterator->address; availableSize = memoryIterator->length; kernelSize = endOfKernel - memoryIterator->address; availableAddress += kernelSize; availableSize -= kernelSize; break; } } } // if (availableSize == 0) throw some kind of kernel error, should not happen... kernel not found in available memory? // if (availableSize < PageSize + 1) throw some kind of kernel error, there isn't at least 1 smallest size page (plus tree byte) available after kernel log.WriteLine("RAM > MMAP Available: Address=" + ToHex(availableAddress, 64) + ", Length=" + ToHex(availableSize, 64) + ", Kernel=" + ToHex(kernelSize, 64)); ulong shiftMask = SmallestPageSize; log.WriteLine("ShiftMask BeforeLoop: " + shiftMask.ToString()); byte shiftMaskBit = 0; while ((shiftMask & ((ulong)1 << shiftMaskBit)) == 0) { log.WriteLine("ShiftMask: " + shiftMask.ToString()); shiftMask |= ((ulong)1 << shiftMaskBit); shiftMaskBit++; } ulong availableShift = availableSize & (~shiftMask); log.WriteLine("AvailableShift: " + availableShift.ToString()); PagesSize = SmallestPageSize; while (availableShift != 0) { availableShift >>= 1; availableShift &= ~shiftMask; TreeSize <<= 1; TreeSize |= 0x01; PagesSize <<= 1; OrderToSmallestPage += 1; } log.WriteLine("out:" + TreeSize.ToString() + ":" + PagesSize.ToString()); while ((TreeSize + PagesSize) > availableSize) { TreeSize >>= 1; PagesSize >>= 1; --OrderToSmallestPage; } log.WriteLine("RAM > Binary Heap: Order=" + ToHex((byte)OrderToSmallestPage, 8) + ", Size=" + ToHex(TreeSize, 64) + ", Paged=" + ToHex(PagesSize, 64)); TreeData = new byte[TreeSize]; // Replaced by putting directly in memory before paged memory, init to 0's to initialize correctly fixed(byte *treePtr = TreeData) Tree = treePtr; Pages = Tree + TreeSize; // After this point, the allocation tree is ready for use, slightly CPU inefficient initialization is okay, but alloc/dealloc must be fast // Code after this needs to be replaced with optimized ASM plugs log.WriteLine("RAM> Starts: Tree=" + ToHex((ulong)Tree, 64) + ", Pages=" + ToHex((ulong)Pages, 64)); // Let's find a page to handle 4000 bytes, should be 1 page, of the smallest size (4096) // For testing timing, make sure to remove all console outputs (averages around 100 per second unoptimized) int rtcSec = Cosmos.Hardware.RTC.Second; ulong offset = 0; byte *allocatedPage = null; log.WriteLine("RAM> Smallest Page Allocs Per Second: "); while (rtcSec == Cosmos.Hardware.RTC.Second) { ; } rtcSec = Cosmos.Hardware.RTC.Second; log.WriteLine("RAM> Smallest Page Allocs Per Second: "); int allocsPerSecond = 0; while (rtcSec == Cosmos.Hardware.RTC.Second) { offset = 0; allocatedPage = RequestPage(1, OrderToSmallestPage, Tree, ref offset); offset = 0; ReleasePage(allocatedPage, OrderToSmallestPage, Tree, ref offset); allocsPerSecond++; } log.WriteLine("RAM> Smallest Page Allocs Per Second: " + allocsPerSecond); /* * ulong offset1 = 0; * byte* allocatedPage1 = RequestPage(4000, OrderToSmallestPage, Tree, ref offset1); * ulong allocatedPageAddress1 = (ulong)allocatedPage1; * Console.WriteLine("Allocated 4000 bytes @ " + ToHex(allocatedPageAddress1, 64)); * * ulong offset2 = 0; * byte* allocatedPage2 = RequestPage(6000, OrderToSmallestPage, Tree, ref offset2); * ulong allocatedPageAddress2 = (ulong)allocatedPage2; * Console.WriteLine("Allocated 6000 bytes @ " + ToHex(allocatedPageAddress2, 64)); * * ulong offset3 = 0; * byte* allocatedPage3 = RequestPage(4000, OrderToSmallestPage, Tree, ref offset3); * ulong allocatedPageAddress3 = (ulong)allocatedPage3; * Console.WriteLine("Allocated 4000 bytes @ " + ToHex(allocatedPageAddress3, 64)); * * offset2 = 0; * if (ReleasePage(allocatedPage2, OrderToSmallestPage, Tree, ref offset2)) Console.WriteLine("Released 6000 bytes"); * * offset1 = 0; * if (ReleasePage(allocatedPage1, OrderToSmallestPage, Tree, ref offset1)) Console.WriteLine("Released 4000 bytes"); * * offset3 = 0; * if (ReleasePage(allocatedPage3, OrderToSmallestPage, Tree, ref offset3)) Console.WriteLine("Released 4000 bytes"); */ }