diff --git a/reactos/drivers/sac/driver/data.c b/reactos/drivers/sac/driver/data.c index 040a7b9f45f..6f23fea65b9 100644 --- a/reactos/drivers/sac/driver/data.c +++ b/reactos/drivers/sac/driver/data.c @@ -12,6 +12,8 @@ /* GLOBALS ********************************************************************/ +ULONG SACDebug; + /* FUNCTIONS ******************************************************************/ VOID diff --git a/reactos/drivers/sac/driver/memory.c b/reactos/drivers/sac/driver/memory.c index eadf646d68b..fb77febccf6 100644 --- a/reactos/drivers/sac/driver/memory.c +++ b/reactos/drivers/sac/driver/memory.c @@ -12,11 +12,43 @@ /* GLOBALS ********************************************************************/ +LONG TotalFrees, TotalBytesFreed, TotalAllocations, TotalBytesAllocated; +KSPIN_LOCK MemoryLock; +PSAC_MEMORY_LIST GlobalMemoryList; + /* FUNCTIONS ******************************************************************/ BOOLEAN InitializeMemoryManagement(VOID) { + PSAC_MEMORY_ENTRY Entry; + + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); + + GlobalMemoryList = ExAllocatePoolWithTagPriority( + NonPagedPool, + SAC_MEMORY_LIST_SIZE, + INITIAL_BLOCK_TAG, + HighPoolPriority); + if (GlobalMemoryList) + { + KeInitializeSpinLock(&MemoryLock); + + GlobalMemoryList->Signature = GLOBAL_MEMORY_SIGNATURE; + GlobalMemoryList->LocalDescriptor = + (PSAC_MEMORY_ENTRY)(GlobalMemoryList + 1); + GlobalMemoryList->Size = SAC_MEMORY_LIST_SIZE - sizeof(SAC_MEMORY_LIST); + + Entry = GlobalMemoryList->LocalDescriptor; + Entry->Signature = LOCAL_MEMORY_SIGNATURE; + Entry->Tag = FREE_POOL_TAG; + Entry->Size = GlobalMemoryList->Size - sizeof(SAC_MEMORY_ENTRY); + + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with TRUE.\n"); + return TRUE; + } + + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with FALSE. No pool.\n"); return FALSE; } @@ -25,7 +57,28 @@ FreeMemoryManagement( VOID ) { - + PSAC_MEMORY_LIST Next; + KIRQL OldIrql; + + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); + + KeAcquireSpinLock(&MemoryLock, &OldIrql); + while (GlobalMemoryList) + { + ASSERT(GlobalMemoryList->Signature == GLOBAL_MEMORY_SIGNATURE); + + KeReleaseSpinLock(&MemoryLock, OldIrql); + + Next = GlobalMemoryList->Next; + + ExFreePoolWithTag(GlobalMemoryList, 0); + + KeAcquireSpinLock(&MemoryLock, &OldIrql); + GlobalMemoryList = Next; + } + + KeReleaseSpinLock(&MemoryLock, OldIrql); + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting\n"); } PVOID @@ -36,7 +89,117 @@ MyAllocatePool( IN ULONG Line ) { - return NULL; + KIRQL OldIrql; + PSAC_MEMORY_LIST GlobalDescriptor, NewDescriptor; + PSAC_MEMORY_ENTRY LocalDescriptor, NextDescriptor; + ULONG GlobalSize, ActualSize; + PVOID Buffer; + + ASSERT("Tag != FREE_POOL_TAG"); + + SAC_DBG(SAC_DBG_MM, "Entering.\n"); + + OldIrql = KfAcquireSpinLock(&MemoryLock); + PoolSize = ALIGN_UP(PoolSize, ULONGLONG); + + GlobalDescriptor = GlobalMemoryList; + KeAcquireSpinLock(&MemoryLock, &OldIrql); + while (GlobalDescriptor) + { + ASSERT(GlobalMemoryList->Signature == GLOBAL_MEMORY_SIGNATURE); + + LocalDescriptor = GlobalDescriptor->LocalDescriptor; + + GlobalSize = GlobalDescriptor->Size; + while (GlobalSize) + { + ASSERT(LocalDescriptor->Signature == LOCAL_MEMORY_SIGNATURE); + + if ((LocalDescriptor->Tag == FREE_POOL_TAG) && + (LocalDescriptor->Size >= PoolSize)) + { + break; + } + + GlobalSize -= (LocalDescriptor->Size + sizeof(SAC_MEMORY_ENTRY)); + + LocalDescriptor = + (PSAC_MEMORY_ENTRY)((ULONG_PTR)LocalDescriptor + + LocalDescriptor->Size + + sizeof(SAC_MEMORY_ENTRY)); + } + + GlobalDescriptor = GlobalDescriptor->Next; + } + + if (!GlobalDescriptor) + { + KeReleaseSpinLock(&MemoryLock, OldIrql); + + ActualSize = min( + PAGE_SIZE, + PoolSize + sizeof(SAC_MEMORY_ENTRY) + sizeof(SAC_MEMORY_LIST)); + + SAC_DBG(SAC_DBG_MM, "Allocating new space.\n"); + + NewDescriptor = ExAllocatePoolWithTagPriority( + 0, + ActualSize, + ALLOC_BLOCK_TAG, + HighPoolPriority); + if (!NewDescriptor) + { + SAC_DBG(SAC_DBG_MM, "No more memory, returning NULL.\n"); + return NULL; + } + + KeAcquireSpinLock(&MemoryLock, &OldIrql); + + NewDescriptor->Signature = GLOBAL_MEMORY_SIGNATURE; + NewDescriptor->LocalDescriptor = (PSAC_MEMORY_ENTRY)(NewDescriptor + 1); + NewDescriptor->Size = ActualSize - 16; + NewDescriptor->Next = GlobalMemoryList; + + GlobalMemoryList = NewDescriptor; + + LocalDescriptor = NewDescriptor->LocalDescriptor; + LocalDescriptor->Signature = LOCAL_MEMORY_SIGNATURE; + LocalDescriptor->Tag = FREE_POOL_TAG; + LocalDescriptor->Size = + GlobalMemoryList->Size - sizeof(SAC_MEMORY_ENTRY); + } + + SAC_DBG(SAC_DBG_MM, "Found a good sized block.\n"); + ASSERT(LocalDescriptor->Tag == FREE_POOL_TAG); + ASSERT(LocalDescriptor->Signature == LOCAL_MEMORY_SIGNATURE); + + if (LocalDescriptor->Size > (PoolSize + sizeof(SAC_MEMORY_ENTRY))) + { + NextDescriptor = + (PSAC_MEMORY_ENTRY)((ULONG_PTR)LocalDescriptor + + PoolSize + + sizeof(SAC_MEMORY_ENTRY)); + if (NextDescriptor->Tag == FREE_POOL_TAG) + { + NextDescriptor->Tag = FREE_POOL_TAG; + NextDescriptor->Signature = LOCAL_MEMORY_SIGNATURE; + NextDescriptor->Size = + (LocalDescriptor->Size - PoolSize - sizeof(SAC_MEMORY_ENTRY)); + + LocalDescriptor->Size = PoolSize; + } + } + + LocalDescriptor->Tag = Tag; + KeReleaseSpinLock(&MemoryLock, OldIrql); + + InterlockedIncrement(&TotalAllocations); + InterlockedExchangeAdd(&TotalBytesAllocated, LocalDescriptor->Size); + SAC_DBG(1, "Returning block 0x%X.\n", LocalDescriptor); + + Buffer = LocalDescriptor + 1; + RtlZeroMemory(Buffer, PoolSize); + return Buffer; } VOID @@ -44,5 +207,100 @@ MyFreePool( IN PVOID *Block ) { + PSAC_MEMORY_ENTRY LocalDescriptor, NextDescriptor; + PSAC_MEMORY_ENTRY ThisDescriptor, FoundDescriptor; + ULONG GlobalSize, LocalSize; + PSAC_MEMORY_LIST GlobalDescriptor; + KIRQL OldIrql; + LocalDescriptor = (PVOID)((ULONG_PTR)(*Block) - sizeof(SAC_MEMORY_ENTRY)); + + SAC_DBG(SAC_DBG_MM, "Entering with block 0x%X.\n", LocalDescriptor); + + ASSERT(LocalDescriptor->Size > 0); + ASSERT(LocalDescriptor->Signature == LOCAL_MEMORY_SIGNATURE); + + InterlockedIncrement(&TotalFrees); + + InterlockedExchangeAdd(&TotalBytesFreed, LocalDescriptor->Size); + + GlobalDescriptor = GlobalMemoryList; + KeAcquireSpinLock(&MemoryLock, &OldIrql); + while (GlobalDescriptor) + { + ASSERT(GlobalMemoryList->Signature == GLOBAL_MEMORY_SIGNATURE); + + FoundDescriptor = NULL; + + ThisDescriptor = GlobalDescriptor->LocalDescriptor; + + GlobalSize = GlobalDescriptor->Size; + while (GlobalSize) + { + ASSERT(ThisDescriptor->Signature == LOCAL_MEMORY_SIGNATURE); + + if (ThisDescriptor == LocalDescriptor) break; + + GlobalSize -= (ThisDescriptor->Size + sizeof(SAC_MEMORY_ENTRY)); + + ThisDescriptor = + (PSAC_MEMORY_ENTRY)((ULONG_PTR)ThisDescriptor + + ThisDescriptor->Size + + sizeof(SAC_MEMORY_ENTRY)); + } + + if (ThisDescriptor == LocalDescriptor) break; + + GlobalDescriptor = GlobalDescriptor->Next; + } + + if (!GlobalDescriptor) + { + KeReleaseSpinLock(&MemoryLock, OldIrql); + SAC_DBG(SAC_DBG_MM, "Could not find block.\n"); + return; + } + + ASSERT(ThisDescriptor->Signature == LOCAL_MEMORY_SIGNATURE); + + if (LocalDescriptor->Tag == FREE_POOL_TAG) + { + KeReleaseSpinLock(&MemoryLock, OldIrql); + SAC_DBG(SAC_DBG_MM, "Attempted to free something twice.\n"); + return; + } + + LocalSize = LocalDescriptor->Size; + LocalDescriptor->Tag = FREE_POOL_TAG; + + if (GlobalSize > (LocalSize + sizeof(SAC_MEMORY_ENTRY))) + { + NextDescriptor = + (PSAC_MEMORY_ENTRY)((ULONG_PTR)LocalDescriptor + + LocalSize + + sizeof(SAC_MEMORY_ENTRY)); + if (NextDescriptor->Tag == FREE_POOL_TAG) + { + NextDescriptor->Tag = 0; + NextDescriptor->Signature = 0; + + LocalDescriptor->Size += + (NextDescriptor->Size + sizeof(SAC_MEMORY_ENTRY)); + } + } + + if ((FoundDescriptor) && (FoundDescriptor->Tag == FREE_POOL_TAG)) + { + LocalDescriptor->Signature = 0; + LocalDescriptor->Tag = 0; + + FoundDescriptor->Size += + (LocalDescriptor->Size + sizeof(SAC_MEMORY_ENTRY)); + } + + KeReleaseSpinLock(&MemoryLock, OldIrql); + *Block = NULL; + + SAC_DBG(SAC_DBG_MM, "exiting.\n"); + return; } diff --git a/reactos/drivers/sac/driver/sacdrv.h b/reactos/drivers/sac/driver/sacdrv.h index a8da32be5a6..6d2861e51fb 100644 --- a/reactos/drivers/sac/driver/sacdrv.h +++ b/reactos/drivers/sac/driver/sacdrv.h @@ -9,6 +9,46 @@ /* INCLUDES *******************************************************************/ #include +#define SAC_DBG_ENTRY_EXIT 0x01 +#define SAC_DBG_MM 0x1000 + +#define SAC_DBG(x, ...) \ + if (SACDebug & x) \ + { \ + DbgPrint("SAC %s: ", __FUNCTION__); \ + DbgPrint(__VA_ARGS__); \ + } + +//Rcp? - sacdrv.sys - SAC Driver (Headless) +//RcpA - sacdrv.sys - Internal memory mgr alloc block +//RcpI - sacdrv.sys - Internal memory mgr initial heap block +//RcpS - sacdrv.sys - Security related block +#define GENERIC_TAG '?pcR' +#define ALLOC_BLOCK_TAG 'ApcR' +#define INITIAL_BLOCK_TAG 'IpcR' +#define SECURITY_BLOCK_TAG 'SpcR' +#define FREE_POOL_TAG 'FpcR' + +#define LOCAL_MEMORY_SIGNATURE 'SSEL' +#define GLOBAL_MEMORY_SIGNATURE 'DAEH' + +#define SAC_MEMORY_LIST_SIZE (1 * 1024 * 1024) + +typedef struct _SAC_MEMORY_ENTRY +{ + ULONG Signature; + ULONG Tag; + ULONG Size; +} SAC_MEMORY_ENTRY, *PSAC_MEMORY_ENTRY; + +typedef struct _SAC_MEMORY_LIST +{ + ULONG Signature; + PSAC_MEMORY_ENTRY LocalDescriptor; + ULONG Size; + struct _SAC_MEMORY_LIST* Next; +} SAC_MEMORY_LIST, *PSAC_MEMORY_LIST; + typedef enum _SAC_CHANNEL_TYPE { VtUtf8, @@ -116,3 +156,6 @@ typedef struct _SAC_CHANNEL_ATTRIBUTES PKEVENT RedrawEvent; GUID ChannelId; } SAC_CHANNEL_ATTRIBUTES, *PSAC_CHANNEL_ATTRIBUTES; + +extern ULONG SACDebug; +