reactos/boot/environ/lib/mm/blkalloc.c
2018-03-18 16:10:41 +01:00

298 lines
7.5 KiB
C

/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/mm/blkalloc.c
* PURPOSE: Boot Library Memory Manager Block Allocator
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
PVOID* MmBlockAllocatorTable;
ULONG MmBlockAllocatorTableEntries;
BOOLEAN MmBlockAllocatorInitialized;
typedef struct _BL_BLOCK_DESCRIPTOR
{
LIST_ENTRY ListHead;
ULONG Unknown;
BL_MEMORY_TYPE Type;
ULONG Attributes;
ULONG Unknown2;
ULONG Count;
ULONG Count2;
ULONG Size;
ULONG BlockId;
ULONG ReferenceCount;
} BL_BLOCK_DESCRIPTOR, *PBL_BLOCK_DESCRIPTOR;
typedef struct _BL_BLOCK_ENTRY
{
LIST_ENTRY ListEntry;
ULONG Todo;
} BL_BLOCK_ENTRY, *PBL_BLOCK_ENTRY;
/* FUNCTIONS *****************************************************************/
BOOLEAN
MmBapCompareBlockAllocatorTableEntry (
_In_ PVOID Entry,
_In_ PVOID Argument1,
_In_ PVOID Argument2,
_In_ PVOID Argument3,
_In_ PVOID Argument4
)
{
PBL_BLOCK_DESCRIPTOR BlockInfo = (PBL_BLOCK_DESCRIPTOR)Entry;
ULONG BlockId = PtrToUlong(Argument1);
/* Check if the block ID matches */
return BlockInfo->BlockId == BlockId;
}
PBL_BLOCK_DESCRIPTOR
MmBapFindBlockInformation (
ULONG BlockId
)
{
ULONG EntryId;
/* Find the block that matches */
EntryId = BlockId;
return BlTblFindEntry(MmBlockAllocatorTable,
MmBlockAllocatorTableEntries,
&EntryId,
MmBapCompareBlockAllocatorTableEntry,
UlongToPtr(EntryId),
NULL,
NULL,
NULL);
}
NTSTATUS
MmBapFreeBlockAllocatorDescriptor (
_In_ PBL_BLOCK_DESCRIPTOR BlockInfo,
_In_ PBL_BLOCK_ENTRY BlockEntry
)
{
/* @TODO FIXME: Later */
EfiPrintf(L"Block free not yet implemented\r\n");
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
BlpMmDeleteBlockAllocator (
_In_ ULONG BlockId
)
{
NTSTATUS Status, LocalStatus;
PBL_BLOCK_DESCRIPTOR BlockInfo;
PLIST_ENTRY ListHead, NextEntry;
PBL_BLOCK_ENTRY BlockEntry;
/* Nothing to delete if we're not initialized */
if (!MmBlockAllocatorInitialized)
{
return STATUS_UNSUCCESSFUL;
}
/* Find the block descriptor */
BlockInfo = MmBapFindBlockInformation(BlockId);
if (BlockInfo)
{
/* Assume success for now */
Status = STATUS_SUCCESS;
/* Do we have at least one reference? */
if (BlockInfo->ReferenceCount)
{
/* Iterate over the allocated blocks */
ListHead = &BlockInfo->ListHead;
NextEntry = ListHead->Flink;
while (NextEntry != ListHead)
{
/* Free each one */
BlockEntry = CONTAINING_RECORD(NextEntry,
BL_BLOCK_ENTRY,
ListEntry);
LocalStatus = MmBapFreeBlockAllocatorDescriptor(BlockInfo,
BlockEntry);
if (!NT_SUCCESS(LocalStatus))
{
/* Remember status on failure only */
Status = LocalStatus;
}
}
/* Drop a reference */
BlockInfo->ReferenceCount--;
}
else
{
/* There aren't any references, so why are we being called? */
Status = STATUS_INVALID_PARAMETER;
}
}
else
{
/* No block exists with this ID */
Status = STATUS_UNSUCCESSFUL;
}
/* Return back */
return Status;
}
NTSTATUS
MmBapFreeBlockAllocatorTableEntry (
_In_ PVOID Entry,
_In_ ULONG Index
)
{
PBL_BLOCK_DESCRIPTOR BlockInfo = (PBL_BLOCK_DESCRIPTOR)Entry;
NTSTATUS Status, LocalStatus;
/* Assume success */
Status = STATUS_SUCCESS;
/* Check if there was at least one reference */
if (BlockInfo->ReferenceCount > 1)
{
/* Try to delete the allocator */
LocalStatus = BlpMmDeleteBlockAllocator(BlockInfo->BlockId);
if (!NT_SUCCESS(LocalStatus))
{
/* Remember status on failure only */
Status = LocalStatus;
}
}
/* Now destroy the allocator's descriptor */
LocalStatus = BlMmFreeHeap(BlockInfo);
if (!NT_SUCCESS(LocalStatus))
{
/* Remember status on failure only */
Status = LocalStatus;
}
/* Free the entry, and return failure, if any */
MmBlockAllocatorTable[Index] = NULL;
return Status;
}
NTSTATUS
MmBapPurgeBlockAllocatorTableEntry (
_In_ PVOID Entry
)
{
PBL_BLOCK_DESCRIPTOR BlockInfo = (PBL_BLOCK_DESCRIPTOR)Entry;
NTSTATUS Status;
/* Check if there's a reference on the block descriptor */
if (BlockInfo->ReferenceCount)
{
/* Don't allow purging */
Status = STATUS_UNSUCCESSFUL;
}
else
{
/* Free the entry */
Status = MmBapFreeBlockAllocatorTableEntry(BlockInfo,
BlockInfo->BlockId);
}
/* Return purge status */
return Status;
}
NTSTATUS
BlpMmCreateBlockAllocator (
VOID
)
{
PBL_BLOCK_DESCRIPTOR BlockInfo;
ULONG BlockId;
NTSTATUS Status;
/* If the block allocator isn't initialized, bail out */
BlockId = -1;
if (!MmBlockAllocatorInitialized)
{
goto Quickie;
}
/* Allocate a block descriptor and zero it out */
BlockInfo = BlMmAllocateHeap(sizeof(*BlockInfo));
if (!BlockInfo)
{
goto Quickie;
}
RtlZeroMemory(BlockInfo, sizeof(*BlockInfo));
/* Setup the block descriptor */
BlockInfo->Attributes = 0;
BlockInfo->Type = BlLoaderBlockMemory;
BlockInfo->Unknown = 1;
BlockInfo->Unknown2 = 1;
BlockInfo->Size = PAGE_SIZE;
BlockInfo->Count = 128;
BlockInfo->Count2 = 128;
InitializeListHead(&BlockInfo->ListHead);
/* Add it to the list of block descriptors */
Status = BlTblSetEntry(&MmBlockAllocatorTable,
&MmBlockAllocatorTableEntries,
BlockInfo,
&BlockId,
MmBapPurgeBlockAllocatorTableEntry);
if (NT_SUCCESS(Status))
{
/* Add the initial reference and store the block ID */
BlockInfo->ReferenceCount = 1;
BlockInfo->BlockId = BlockId;
}
Quickie:
/* On failure, free the block descriptor */
if (BlockId == -1)
{
BlMmFreeHeap(BlockInfo);
}
/* Return the block descriptor ID, or -1 on failure */
return BlockId;
}
NTSTATUS
MmBaInitialize (
VOID
)
{
NTSTATUS Status;
ULONG Size;
/* Allocate 8 table entries */
MmBlockAllocatorTableEntries = 8;
Size = sizeof(BL_BLOCK_DESCRIPTOR) * MmBlockAllocatorTableEntries;
MmBlockAllocatorTable = BlMmAllocateHeap(Size);
if (MmBlockAllocatorTable)
{
/* Zero them out -- we're all done */
Status = STATUS_SUCCESS;
RtlZeroMemory(MmBlockAllocatorTable, Size);
MmBlockAllocatorInitialized = 1;
}
else
{
/* Bail out since we're out of memory */
Status = STATUS_NO_MEMORY;
MmBlockAllocatorInitialized = 0;
}
/* Return initialization status */
return Status;
}