Beispiel #1
0
        /// <summary>
        /// Creates a new page directory using only physical memory (used in Init)
        /// </summary>
        /// <param name="flags">The flags</param>
        /// <returns>The page directory</returns>
        public static PageDirectory *CreateNewDirectoryPhysically(PageFlags flags)
        {
            // Allocate a new block of physical memory to store our physical page in
            PageDirectory *directory = (PageDirectory *)Heap.AlignedAlloc(0x1000, sizeof(PageDirectory));

            directory->PhysicalDirectory = directory;
            if (directory == null)
            {
                Panic.DoPanic("directory == null");
            }

            // Allocate the tables
            for (int i = 0; i < 1024; i++)
            {
                PageTable *table = (PageTable *)PhysicalMemoryManager.Alloc();
                if (table == null)
                {
                    Panic.DoPanic("table == null");
                }

                Memory.Memclear(table, sizeof(PageTable));

                // Note: At this point, virtual address == physical address due to identity mapping
                directory->PhysicalTables[i] = (int)table | (int)flags;
                directory->VirtualTables[i]  = (int)table;
            }

            return(directory);
        }
Beispiel #2
0
        /// <summary>
        /// Starts a new process based on the given path and arguments
        /// </summary>
        /// <param name="path">The path</param>
        /// <param name="argv">The arguments</param>
        /// <param name="flags">Spawn flags</param>
        /// <returns>Errorcode or PID</returns>
        public static int StartProcess(string path, string[] argv, Task.SpawnFlags flags)
        {
            if (argv == null)
            {
                Panic.DoPanic("argv == null");
            }

            Node node = VFS.GetByAbsolutePath(path);

            if (node == null)
            {
                return(-(int)ErrorCode.ENOENT);
            }

            // Open and create buffer
            VFS.Open(node, (int)FileMode.O_RDONLY);
            byte[] buffer = new byte[node.Size];
            if (buffer == null)
            {
                Heap.Free(node);
                VFS.Close(node);
                return(-(int)ErrorCode.ENOMEM);
            }

            // Fill buffer contents
            VFS.Read(node, 0, node.Size, buffer);
            VFS.Close(node);

            // Pass execution to ELF loader
            int status = ELFLoader.Execute(buffer, node.Size, argv, flags);

            Heap.Free(buffer);
            Heap.Free(node);
            return(status);
        }
Beispiel #3
0
        /// <summary>
        /// Wait for drive to be finished
        /// </summary>
        /// <param name="port">Port IO base</param>
        private static void poll(uint port)
        {
            wait400ns(port);

            byte status;

            do
            {
                status = PortIO.In8((ushort)(port + ATA_REG_STATUS));
            }while ((status & ATA_STATUS_BSY) > 0);

            while ((status & ATA_STATUS_DRQ) == 0)
            {
                status = PortIO.In8((ushort)(port + ATA_REG_STATUS));

                if ((status & ATA_STATUS_DF) > 0)
                {
                    Panic.DoPanic("Device fault!");
                }

                if ((status & ATA_STATUS_ERR) > 0)
                {
                    Panic.DoPanic("ERR IN ATA!!");
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Do identify and read needed shizzle
        /// </summary>
        private void DoIdentify()
        {
            void *adr = Heap.Alloc(0x1000);

            int status = Identify(0, 1, adr);

            int statusCode = (status >> COMP_STATUS_SC_SHIFT) & COMP_STATUS_SC_MASK;

            if (statusCode != COMP_STATUS_SC_SUC)
            {
                Panic.DoPanic("[NVMe] Couldn't identifiy");
            }

            NVMe_ID_Ctrl *idCtrl = (NVMe_ID_Ctrl *)adr;

            mFirmwareRevision = new char[8];
            mSerialNumber     = new char[20];
            mModel            = new char[40];
            nNumNamespaces    = (int)idCtrl->Nn;

            Memory.Memcpy(Util.ObjectToVoidPtr(mFirmwareRevision), idCtrl->FirmwareRevision, 8);
            Memory.Memcpy(Util.ObjectToVoidPtr(mSerialNumber), idCtrl->SerialNumber, 20);
            Memory.Memcpy(Util.ObjectToVoidPtr(mModel), idCtrl->ModelNumber, 40);

            Heap.Free(adr);
        }
Beispiel #5
0
        /// <summary>
        /// Adds an IRQ to the table
        /// </summary>
        /// <param name="slot">The slot</param>
        /// <param name="pin">The pin</param>
        /// <param name="irq">The IRQ</param>
        private static void addIRQ(uint slot, uint pin, uint irq, uint polarity, uint trigger)
        {
            if (slot >= PCI_BUS_DEV_MAX || pin > PCI_PINS)
            {
                Panic.DoPanic("[PCI] Invalid IRQ added");
            }

            PciIRQEntry entry = new PciIRQEntry();

            entry.Irq = irq;

            entry.Flags = 0;
            if (polarity == 0 || polarity == 3)
            {
                entry.Flags |= IOApic.IOAPIC_REDIR_POLARITY_LOW;
            }
            else
            {
                entry.Flags |= IOApic.IOAPIC_REDIR_POLARITY_HIGH;
            }

            if (trigger == 0 || trigger == 3)
            {
                entry.Flags |= IOApic.IOAPIC_REDIR_TRIGGER_LEVEL;
            }
            else
            {
                entry.Flags |= IOApic.IOAPIC_REDIR_TRIGGER_EDGE;
            }

            m_irqTable[(slot * PCI_PINS) + pin] = entry;
        }
Beispiel #6
0
        /// <summary>
        /// Temporary kernel memory allocation before a real heap is set up
        /// </summary>
        /// <param name="size">The size</param>
        /// <param name="align">If the block should be aligned</param>
        /// <returns>A block of memory</returns>
        public static unsafe void *KAlloc(int size, bool align)
        {
#if HEAP_DEBUG
            if (useRealHeap)
            {
                Panic.DoPanic("[HEAP] KAlloc has been called after real heap started!");
            }
#endif

            if (PhysicalMemoryManager.IsInitialized)
            {
                return(PhysicalMemoryManager.AllocRange(size));
            }
            else
            {
                uint address = (uint)CurrentEnd;
                if (align)
                {
                    address = Paging.AlignUp(address);
                }

                // At least 4byte align
                if ((address & 3) != 0)
                {
                    address &= 3;
                    address += 4;
                }

                CurrentEnd = (void *)(address + size);

                return((void *)address);
            }
        }
Beispiel #7
0
        /// <summary>
        /// Translate ISA IRQ to a redirection entry
        /// </summary>
        /// <param name="irq">The ISA IRQ number</param>
        /// <returns>The override</returns>
        public static ISAOverride GetISARedirection(uint irq)
        {
            if (irq >= 16)
            {
                Panic.DoPanic("Requested an ISA redirection for IRQ >= 16");
            }

            return(m_intSourceOverrides[irq]);
        }
Beispiel #8
0
        /// <summary>
        /// Create queues (for now just 1..)
        /// </summary>
        private void CreateQueues()
        {
            var queue = CreateQueue(1);

            if (queue == null)
            {
                Panic.DoPanic("[NVMe] Couldn't make queue");
            }


            mIOQueue = queue;
        }
Beispiel #9
0
        /// <summary>
        /// Sets the IRQ routing
        /// </summary>
        private static void setIRQRouting()
        {
            m_irqTable = new PciIRQEntry[PCI_BUS_DEV_MAX * PCI_PINS];

            // Find root PCI device and handle it
            int status = Acpica.AcpiGetDevices("PNP0A03", onRootDevice, null, null);

            if (status != Acpica.AE_OK)
            {
                Panic.DoPanic("[PCI] Couldn't get root device");
            }
        }
Beispiel #10
0
        /// <summary>
        /// Gets the block from the pointer
        /// </summary>
        /// <param name="ptr">The pointer</param>
        /// <returns>The block</returns>
        private static unsafe Block *getBlockFromPtr(void *ptr)
        {
            Block *block = (Block *)((int)ptr - sizeof(Block));

#if HEAP_USE_MAGIC
            if (block->Magic != HEAP_MAGIC)
            {
                Panic.DoPanic("[HEAP] block->Magic != HEAP_MAGIC");
            }
#endif
            return(block);
        }
Beispiel #11
0
        /// <summary>
        /// Called as callback when a root device is found
        /// </summary>
        /// <param name="Object">The object</param>
        /// <param name="NestingLevel">Nesting level</param>
        /// <param name="Context">User context</param>
        /// <param name="ReturnValue">Return value if early returned</param>
        /// <returns>Status</returns>
        private static int onRootDevice(void *Object, uint NestingLevel, void *Context, void **ReturnValue)
        {
            // Get routing table
            AcpiObjects.Buffer buffer;
            buffer.Length = Acpica.ACPI_ALLOCATE_BUFFER;
            int status = Acpica.AcpiGetIrqRoutingTable(Object, &buffer);

            if (status != Acpica.AE_OK)
            {
                Panic.DoPanic("[PCI] Couldn't get ACPI IRQ Routing Table");
            }

            // The last entry will have Length 0
            Acpica.PCIRoutingTable *table = (Acpica.PCIRoutingTable *)buffer.Pointer;
            while (table->Length > 0)
            {
                // No reference source
                if (table->Source[0] == 0)
                {
                    uint slot = (uint)(table->Address >> 16);
                    addIRQ(slot, table->Pin, table->SourceIndex, 0, 0);
                }
                // Source is not null, that means we need to lookup the reference resource
                else
                {
                    void *handle = null;
                    status = Acpica.AcpiGetHandle(Object, Util.CharPtrToString(table->Source), &handle);
                    if (status != Acpica.AE_OK)
                    {
                        Panic.DoPanic("[PCI] Couldn't load references handle");
                    }

                    status = Acpica.AcpiWalkResources(handle, Acpica.METHOD_NAME__CRS, onIRQResource, table);
                    if (status != Acpica.AE_OK)
                    {
                        Panic.DoPanic("[PCI] Couldn't process resources for IRQ");
                    }
                }

                // Next entry
                table = (Acpica.PCIRoutingTable *)((byte *)table + table->Length);
            }

            // The object returned should be freed by us
            Acpica.AcpiOsFree(buffer.Pointer);

            return(Acpica.AE_OK);
        }
Beispiel #12
0
        /// <summary>
        /// Creates a block descriptor with given minimal size
        /// </summary>
        /// <param name="size">The minimal size</param>
        /// <returns>The block descriptor</returns>
        private static unsafe BlockDescriptor *createBlockDescriptor(int size)
        {
#if HEAP_DEBUG_DESCRIPTOR
            Console.WriteLine("[HEAP] Creating a new block descriptor");
#endif

            // Add size of Block and BlockDescriptor
            size += sizeof(Block) + sizeof(BlockDescriptor);

            // Allocate descriptor
            size = getRequiredPageCount(size) * 0x1000;
            BlockDescriptor *descriptor = (BlockDescriptor *)Paging.AllocateVirtual(size);

#if HEAP_DEBUG_DESCRIPTOR
            Console.Write("[HEAP] New descriptor is at 0x");
            Console.WriteHex((int)descriptor);
            Console.Write(", physical: 0x");
            Console.WriteHex((int)Paging.GetPhysicalFromVirtual(descriptor));
            Console.Write('\n');
#endif

            if (descriptor == null)
            {
                Panic.DoPanic("descriptor == null");
            }

            // Setup block
            Block *first = (Block *)((int)descriptor + sizeof(BlockDescriptor));
            first->Prev       = null;
            first->Next       = null;
            first->Size       = size - sizeof(BlockDescriptor);
            first->Used       = false;
            first->Descriptor = descriptor;
#if HEAP_USE_MAGIC
            first->Magic = HEAP_MAGIC;
#endif

            // Setup descriptor
            descriptor->FreeSpace = size - sizeof(BlockDescriptor);
            descriptor->First     = first;
            descriptor->FirstFree = first;
            descriptor->Next      = null;
#if HEAP_USE_MAGIC
            descriptor->Magic = HEAP_MAGIC;
#endif

            return(descriptor);
        }
Beispiel #13
0
        /// <summary>
        /// ISR handler
        /// </summary>
        /// <param name="regsPtr">Pointer to registers</param>
        public static unsafe void Handler(Regs *regsPtr)
        {
            int isrNum = regsPtr->IntNum;

            // If the kernel caused this, do a panic
            if (!Tasking.IsActive || Tasking.CurrentTask.PID == 0)
            {
                Panic.DoPanic(errorCodes[isrNum], regsPtr);
            }
            // Otherwise send a signal
            else
            {
#if ALWAYS_DO_PANIC
                Panic.DoPanic(errorCodes[isrNum], regsPtr);
#else
                Tasking.CurrentTask.ProcessSignal(isrToSignal[isrNum]);
#endif
            }
        }
Beispiel #14
0
        /// <summary>
        /// Frees a page directory
        /// </summary>
        /// <param name="directory">The directory</param>
        public static void FreeDirectory(PageDirectory *directory)
        {
            if (directory == CurrentDirectory)
            {
                Panic.DoPanic("Tried to free the current page directory");
            }

            if (directory == KernelDirectory)
            {
                Panic.DoPanic("Tried to free the kernel page directory");
            }

            // The directory was cloned, so it was allocated in one huge block
            PageDirectory *virt = CurrentDirectory;
            PageDirectory *phys = CurrentDirectoryPhysical;

            SetPageDirectory(KernelDirectory, KernelDirectory);
            Heap.Free(directory);
            SetPageDirectory(virt, phys);
        }
Beispiel #15
0
        /// <summary>
        /// Gets the physical address from a virtual address
        /// </summary>
        /// <param name="pageDir">The page directory to look into</param>
        /// <param name="virt">The virtual address</param>
        /// <returns>The physical address</returns>
        public static void *GetPhysicalFromVirtual(PageDirectory *pageDir, void *virt)
        {
            // Get indices
            int address   = (int)virt;
            int remaining = address % 0x1000;
            int frame     = address / 0x1000;

            // Find corresponding table to the virtual address
            PageTable *table = (PageTable *)pageDir->VirtualTables[frame / 1024];

            if (table == null)
            {
                Panic.DoPanic("table == null");
            }

            // Calculate page
            int page = table->Pages[frame & (1024 - 1)];

            return((void *)(GetFrameAddress(page) + remaining));
        }
Beispiel #16
0
        /// <summary>
        /// Clones a page directory and its tables
        /// </summary>
        /// <param name="source">The source page directory</param>
        /// <returns>The cloned page directory</returns>
        public static PageDirectory *CloneDirectory(PageDirectory *source)
        {
            // Note: sizeof(PageDirectory) is not neccesarily a page
            int pageDirSizeAligned = (int)AlignUp((uint)sizeof(PageDirectory));

            // One block for the page directory and the page tables
            int allocated = (int)Heap.AlignedAlloc(0x1000, pageDirSizeAligned + 1024 * sizeof(PageTable));

            if (allocated == 0)
            {
                Panic.DoPanic("Couldn't clone page directory because there is no memory left");
            }

            PageDirectory *destination = (PageDirectory *)allocated;

            destination->PhysicalDirectory = (PageDirectory *)GetPhysicalFromVirtual((void *)allocated);
            for (int i = 0; i < 1024; i++)
            {
                int sourceTable = source->VirtualTables[i];
                if (sourceTable == 0)
                {
                    Panic.DoPanic("sourceTable == 0?!");
                }

                // Get the pointer without the flags and the flags seperately
                PageTable *sourceTablePtr = (PageTable *)sourceTable;
                int        flags          = source->PhysicalTables[i] & 0xFFF;

                // Calculate addresses
                int        addressOffset    = pageDirSizeAligned + i * sizeof(PageTable);
                PageTable *newTable         = (PageTable *)(allocated + addressOffset);
                int        newTablePhysical = (int)GetPhysicalFromVirtual(newTable);

                // Copy table data and set pointers
                Memory.Memcpy(newTable, sourceTablePtr, sizeof(PageTable));
                destination->PhysicalTables[i] = newTablePhysical | flags;
                destination->VirtualTables[i]  = (int)newTable;
            }

            return(destination);
        }
Beispiel #17
0
        /// <summary>
        /// Read version
        /// </summary>
        private void ReadVersion()
        {
            uint version = mRegs->Version;

            if (version == 0x00010200)
            {
                mVersion = 102;
            }
            else if (version == 0x00010100)
            {
                mVersion = 101;
            }
            else if (version == 0x00010000)
            {
                mVersion = 100;
            }
            else
            {
                Panic.DoPanic("[NVMe] Wrong NVMe version");
            }
        }
Beispiel #18
0
        /// <summary>
        /// Gets a sufficient block descriptor for the required size
        /// </summary>
        /// <param name="size">The required size</param>
        /// <returns>The block descriptor</returns>
        private static unsafe BlockDescriptor *getSufficientDescriptor(BlockDescriptor *first, int size)
        {
            BlockDescriptor *descriptor = first;

            if (descriptor == null)
            {
                descriptor = firstDescriptor;
            }

            // Search for a big enough descriptor
            while (true)
            {
#if HEAP_USE_MAGIC
                if (descriptor->Magic != HEAP_MAGIC)
                {
                    Panic.DoPanic("descriptor->magic != HEAP_MAGIC");
                }
#endif

                if (descriptor != first && descriptor->FreeSpace >= size)
                {
                    return(descriptor);
                }

                if (descriptor->Next == null)
                {
                    break;
                }

                descriptor = descriptor->Next;
            }

            // Create next descriptor because there is no descriptor that is big enough
            BlockDescriptor *newDescriptor = createBlockDescriptor(size);
            descriptor->Next = newDescriptor;
            return(newDescriptor);
        }
Beispiel #19
0
        /// <summary>
        /// Enable NVMe controller
        /// </summary>
        private void EnableController()
        {
            mRegs->ControllerConfig  = (0) << CC_MPS_SHIFT;                             // 4KB
            mRegs->ControllerConfig |= CC_AMS_RR | CC_SHN_NO;                           // Round robin, no shutdown notifcation
            mRegs->ControllerConfig |= (6 << CC_IOSQES_SHIFT) | (4 << CC_IOCQES_SHIFT); // Setr Queue sizes
            mRegs->ControllerConfig |= CC_ENABLE | CC_CSS_NVM;                          // Enable and NVM

            // Wait till device is ready
            uint status  = mRegs->ControllerStatus;
            int  timeOut = 0;

            while ((status & CSTS_RDY) == 0)
            {
                Tasking.CurrentTask.CurrentThread.Sleep(0, 100);
                timeOut += 100;

                if (timeOut >= mTimeout)
                {
                    Panic.DoPanic("[NVMe] Could not enable controller in time");
                }

                status = mRegs->ControllerStatus;
            }
        }
Beispiel #20
0
        /// <summary>
        /// Initializes ACPI
        /// </summary>
        public static void Init()
        {
            int status = Acpica.AcpiInitializeSubsystem();

            if (status != Acpica.AE_OK)
            {
                Panic.DoPanic("[ACPI] Couldn't initialize ACPICA subsystem");
            }

            status = Acpica.AcpiInitializeTables(null, 16, false);
            if (status != Acpica.AE_OK)
            {
                Panic.DoPanic("[ACPI] Couldn't initialize tables");
            }

            status = Acpica.AcpiInstallAddressSpaceHandler((void *)Acpica.ACPI_ROOT_OBJECT, Acpica.ACPI_ADR_SPACE_SYSTEM_MEMORY, (void *)Acpica.ACPI_DEFAULT_HANDLER, null, null);
            if (status != Acpica.AE_OK)
            {
                Panic.DoPanic("[ACPI] Could not install address space handler for system memory");
            }

            status = Acpica.AcpiInstallAddressSpaceHandler((void *)Acpica.ACPI_ROOT_OBJECT, Acpica.ACPI_ADR_SPACE_SYSTEM_IO, (void *)Acpica.ACPI_DEFAULT_HANDLER, null, null);
            if (status != Acpica.AE_OK)
            {
                Panic.DoPanic("[ACPI] Could not install address space handler for system IO");
            }

            status = Acpica.AcpiInstallAddressSpaceHandler((void *)Acpica.ACPI_ROOT_OBJECT, Acpica.ACPI_ADR_SPACE_PCI_CONFIG, (void *)Acpica.ACPI_DEFAULT_HANDLER, null, null);
            if (status != Acpica.AE_OK)
            {
                Panic.DoPanic("[ACPI] Could not install address space handler for PCI");
            }

            status = Acpica.AcpiLoadTables();
            if (status != Acpica.AE_OK)
            {
                Panic.DoPanic("[ACPI] Couldn't load tables");
            }

            status = Acpica.AcpiEnableSubsystem(Acpica.ACPI_FULL_INITIALIZATION);
            if (status != Acpica.AE_OK)
            {
                Panic.DoPanic("[ACPI] Couldn't enable subsystems:");
            }

            status = Acpica.AcpiInitializeObjects(Acpica.ACPI_FULL_INITIALIZATION);
            if (status != Acpica.AE_OK)
            {
                Panic.DoPanic("[ACPI] Couldn't initialize objects");
            }

            // MADT table contains info about APIC, processors, ...
            Acpica.TableHeader *table;
            status = Acpica.AcpiGetTable("APIC", 1, &table);
            if (status != Acpica.AE_OK)
            {
                Panic.DoPanic("[ACPI] Couldn't find MADT table");
            }

            parseMADT((MADT *)table);

            // Set ACPI to APIC using the "_PIC" method, note that this method is not always present
            // so we "can" ignore the AE_NOT_FOUND error
            AcpiObjects.IntegerObject arg1;
            arg1.Type  = AcpiObjects.ObjectType.Integer;
            arg1.Value = 1;
            AcpiObjects.ObjectList args;
            args.Count   = 1;
            args.Pointer = &arg1;
            status       = Acpica.AcpiEvaluateObject((void *)Acpica.ACPI_ROOT_OBJECT, "_PIC", &args, null);
            if (status != Acpica.AE_NOT_FOUND && status != Acpica.AE_OK)
            {
                Panic.DoPanic("[ACPI] Couldn't call _PIC method");
            }

            // We are done here
            Console.WriteLine("[ACPI] Initialized");
        }
Beispiel #21
0
        /// <summary>
        /// Allocates an aligned piece of memory
        /// </summary>
        /// <param name="alignment">The alignment</param>
        /// <param name="size">The size</param>
        public static unsafe void *AlignedAlloc(int alignment, int size)
        {
#if HEAP_DEBUG
            if (size <= 0)
            {
                Panic.DoPanic("[HEAP] size <= 0");
            }

            if (alignment <= 0)
            {
                Panic.DoPanic("[HEAP] alignment <= 0");
            }
#endif

            if (useRealHeap)
            {
                // Find a descriptor that is big enough to hold the block header and its data
                // We need to look for something that can hold an aligned size if alignment is requested
                size += sizeof(Block);

                // Safe size
                if (size % alignment != 0)
                {
                    size  = size - (size % alignment);
                    size += alignment;
                }

                Block *          currentBlock  = null;
                Block *          previousBlock = null;
                BlockDescriptor *descriptor    = getSufficientDescriptor(null, size);

                if (descriptor == null)
                {
                    Panic.DoPanic("[HEAP] descriptor == null");
                }

retry:

                currentBlock  = descriptor->FirstFree;
                previousBlock = null;

                // Lock descriptor
                Mutex.InternalLock(&descriptor->Lock);

                // Search in the descriptor
                while (true)
                {
                    // Can fit in here
                    if (currentBlock->Used || currentBlock->Size < size)
                    {
                        goto nextBlock;
                    }

#if HEAP_USE_MAGIC
                    if (currentBlock->Magic != HEAP_MAGIC)
                    {
                        Panic.DoPanic("currentBlock->Magic != HEAP_MAGIC");
                    }
#endif

                    // Check if this block data would be aligned
                    int currentData = (int)currentBlock + sizeof(Block);
                    int remainder   = currentData % alignment;

                    // Not aligned
                    if (remainder != 0)
                    {
                        // Split the current block into two
                        // The first part is a padding
                        // The second part is the block we want for allocation
                        // This only happens if there is enough space left

                        // Size of gap
                        int gapSize = alignment - remainder;
                        int newSize = currentBlock->Size - gapSize;

                        // Would the new block be too small to fit our data into?
                        if (newSize < size)
                        {
                            goto nextBlock;
                        }

                        // Store old data
                        Block *newNext = currentBlock->Next;
                        bool   newUsed = currentBlock->Used;

                        // Move block forward
                        currentBlock             = (Block *)((int)currentBlock + gapSize);
                        currentBlock->Used       = newUsed;
                        currentBlock->Prev       = previousBlock;
                        currentBlock->Next       = newNext;
                        currentBlock->Size       = newSize;
                        currentBlock->Descriptor = descriptor;

                        // Increase size of previous block if needed
                        if (previousBlock != null)
                        {
                            previousBlock->Next  = currentBlock;
                            previousBlock->Size += gapSize;

                            // If the block is used and the gap is merged
                            // that means that the total free space in this descriptor decreases
                            if (currentBlock->Used)
                            {
                                descriptor->FreeSpace -= gapSize;
                            }
                        }
                        // There's space left to move this block and let the first block point to the new one
                        else if (gapSize >= sizeof(Block))
                        {
                            // Update first block
                            Block *first = descriptor->First;
                            descriptor->FreeSpace -= gapSize;

                            first->Used       = false;
                            first->Prev       = null;
                            first->Next       = currentBlock;
                            first->Size       = gapSize;
                            first->Descriptor = descriptor;
#if HEAP_USE_MAGIC
                            first->Magic = HEAP_MAGIC;
#endif
                            currentBlock->Prev = first;
                        }
                        // This is the first block that was moved
                        else
                        {
                            // Update header
                            descriptor->First     = currentBlock;
                            descriptor->FirstFree = currentBlock;
                        }
                    }

                    // Calculate leftover part for the next block
                    int leftover = currentBlock->Size - size;

                    // Update header
                    currentBlock->Used       = true;
                    currentBlock->Descriptor = descriptor;
                    currentBlock->Prev       = previousBlock;
#if HEAP_USE_MAGIC
                    currentBlock->Magic = HEAP_MAGIC;
#endif

                    // Update descriptor
                    descriptor->FreeSpace -= size;

                    // If we have something left over, create a new block
                    if (leftover > sizeof(Block) + 4)
                    {
                        // Update header
                        Block *afterBlock = (Block *)((int)currentBlock + size);
                        afterBlock->Size       = leftover;
                        afterBlock->Used       = false;
                        afterBlock->Next       = currentBlock->Next;
                        afterBlock->Prev       = currentBlock;
                        afterBlock->Descriptor = descriptor;

#if HEAP_USE_MAGIC
                        afterBlock->Magic = HEAP_MAGIC;
#endif

                        if (currentBlock->Next != null)
                        {
                            currentBlock->Next->Prev = afterBlock;
                        }

                        currentBlock->Next = afterBlock;
                        currentBlock->Size = size;

                        // Update descriptor
                        if ((int)currentBlock < (int)descriptor->FirstFree)
                        {
                            descriptor->FirstFree = currentBlock;
                        }
                    }

                    // Return block (skip header)
                    Mutex.InternalUnlock(&descriptor->Lock);
                    return((void *)((int)currentBlock + sizeof(Block)));

                    // Next block
nextBlock:
                    {
                        previousBlock = currentBlock;
                        currentBlock  = currentBlock->Next;
                        Mutex.InternalUnlock(&descriptor->Lock);
                        if (currentBlock == null)
                        {
                            // This was the last block in the descriptor
                            // Due to alignment issues we haven't found a good place
                            // Get another descriptor that has enough free space
                            descriptor = getSufficientDescriptor(descriptor, size);
                            goto retry;
                        }
                    }
                }
            }
            else
            {
                if (alignment == 0x1000)
                {
                    return(KAlloc(size, true));
                }
                else if (alignment == 4)
                {
                    return(KAlloc(size, false));
                }
                else
                {
                    Panic.DoPanic("[HEAP] Unsupported alignment in early allocation");
                    return(null);
                }
            }
        }
Beispiel #22
0
        /// <summary>
        /// Frees a piece of memory
        /// </summary>
        /// <param name="ptr">The pointer</param>
        public static unsafe void Free(void *ptr)
        {
#if HEAP_DEBUG
            if (ptr == null)
            {
                Panic.DoPanic("[HEAP] Free(null)");
            }
#endif

            Block *          block      = getBlockFromPtr(ptr);
            BlockDescriptor *descriptor = block->Descriptor;

#if HEAP_DEBUG
            if (!block->Used)
            {
                Panic.DoPanic("[HEAP] Tried to free a block that was already freed");
            }
#endif

            Mutex.InternalLock(&descriptor->Lock);

            // Not used anymore
            block->Used = false;
            block->Descriptor->FreeSpace += block->Size;
            if ((int)block->Descriptor->FirstFree > (int)block)
            {
                block->Descriptor->FirstFree = block;
            }

            // Merge forward
            if (block->Next != null && !block->Next->Used)
            {
                Block *next = block->Next;
                block->Size += next->Size;
                block->Next  = next->Next;

                if ((int)block->Descriptor->FirstFree > (int)next)
                {
                    block->Descriptor->FirstFree = next;
                }

                if (next->Next != null)
                {
                    next->Next->Prev = block;
                }
            }

            // Merge backwards
            if (block->Prev != null && !block->Prev->Used)
            {
                Block *prev = block->Prev;
                prev->Size += block->Size;
                prev->Next  = block->Next;

                if ((int)block->Descriptor->FirstFree > (int)prev)
                {
                    block->Descriptor->FirstFree = prev;
                }

                if (block->Next != null)
                {
                    block->Next->Prev = prev;
                }
            }

            Mutex.InternalUnlock(&descriptor->Lock);
        }