From 08d017171d4230c054f3d43f8e2c21da486c1ae9 Mon Sep 17 00:00:00 2001 From: Dibyamartanda Samanta Date: Sun, 18 Aug 2024 11:11:36 +0200 Subject: [PATCH] [NTOSKRNL:CC] Implement Extarnal Cache Directives Implemented:: CcDeductDirtyPagesFromExternalCache CcAddDirtyPagesToExternalCache:: Exported CcAddExternalCache CcRegisterExternalCache:: Exported CcRemoveExternalCache CcUnregisterExternalCache :: Exported --- NTOSKRNL/CC/ccexternalcache.cpp | 210 ++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 NTOSKRNL/CC/ccexternalcache.cpp diff --git a/NTOSKRNL/CC/ccexternalcache.cpp b/NTOSKRNL/CC/ccexternalcache.cpp new file mode 100644 index 0000000..25286ac --- /dev/null +++ b/NTOSKRNL/CC/ccexternalcache.cpp @@ -0,0 +1,210 @@ +/* + * PROJECT: Alcyone System Kernel + * LICENSE: BSD Clause 3 + * PURPOSE: Cache Controller:: External Cache Compatibility Layer + * NT KERNEL: 5.11.9360 + * COPYRIGHT: 2023-2029 Dibymartanda Samanta <> + */ + + NOTE::Alcyone will not notify,in case of Empty External Cache at the moment, feature is planned for threadpool revamp + +/* Move Typedef later cctypes.hpp */ +typedef struct alignas(24) _DIRTY_PAGE_STATISTICS { + ULONGLONG DirtyPages; // 0x0 + ULONGLONG DirtyPagesLastScan; // 0x8 + ULONG DirtyPagesScheduledLastScan; // 0x10 +} DIRTY_PAGE_STATISTICS, *PDIRTY_PAGE_STATISTICS; // 0x18 bytes (sizeof) + +typedef struct alignas(30) _CC_EXTERNAL_CACHE_INFO { + VOID (*Callback)(VOID* arg1, ULONGLONG arg2, ULONG arg3); // 0x0 + struct _DIRTY_PAGE_STATISTICS DirtyPageStatistics; // 0x8 + struct _LIST_ENTRY Links; // 0x20 +} CC_EXTERNAL_CACHE_INFO, *PCC_EXTERNAL_CACHE_INFO; // 0x30 bytes (sizeof) + +VOID +NTAPI +CcDeductDirtyPagesFromExternalCache( + IN PCC_EXTERNAL_CACHE_INFO ExternalCacheContext, + IN ULONG Pages + ) +{ + KIRQL OldIrql ={0}; + ULONG PagesToDeduct = {0}; + + + if (Pages > 0) + { + /* Acquire the master lock */ + KeAcquireQueuedSpinLock(LockQueueMasterLock, &OldIrql); + + /* Calculate the number of pages to deduct */ + PagesToDeduct = min(Pages, ExternalCacheContext->DirtyPageStatistics.DirtyPages); + + /* Deduct the pages from the external cache context */ + ExternalCacheContext->DirtyPageStatistics.DirtyPages -= PagesToDeduct; + + /* Deduct the pages from the global statistics */ + CcTotalDirtyPages -= PagesToDeduct; + + /* Release the master lock */ + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); + } + + /* Check if there are any deferred writes and post them if necessary */ + if (!IsListEmpty(&CcDeferredWrites)) + { + CcPostDeferredWrites(); + } +} + +VOID +NTAPI +CcAddExternalCache( + IN PCC_EXTERNAL_CACHE_INFO CacheInfo + ) +{ + + + KLOCK_QUEUE_HANDLE LockHandle ={0}; + + /* Acquire the external cache list lock */ + KeAcquireInStackQueuedSpinLock(&CcExternalCacheListLock,&LockHandle); + + /* Insert the new cache info at the end of the list */ + InsertTailList(&CcExternalCacheList, &CacheInfo->Links); + + /* Increment the number of external caches */ + if (_InterlockedIncrement(&CcNumberOfExternalCaches) <= 0) + { + /* Overflow occurred, bug check */ + KeBugCheckEx(CACHE_MANAGER,0,STATUS_INTEGER_OVERFLOW,0,0); + } + + /* Release the external cache list lock */ + KeReleaseInStackQueuedSpinLock(&LockHandle); +} + +VOID +NTAPI +CcRemoveExternalCache( + IN PCC_EXTERNAL_CACHE_INFO CacheInfo + ) +{ + + + + KLOCK_QUEUE_HANDLE LockHandle ={0}; + + /* Acquire the external cache list lock */ + KeAcquireInStackQueuedSpinLock(&CcExternalCacheListLock,&LockHandle); + + /* Remove the entry from the list */ + RemoveTailList(&CacheInfo->Links.Blink); + + /* Decrement the number of external caches */ + if (_InterlockedDecrement(&CcNumberOfExternalCaches) < 0) + { + /* Underflow occurred, bug check */ + KeBugCheckEx(CACHE_MANAGER,0,STATUS_INTEGER_OVERFLOW,0,0); + } + + /* Release the external cache list lock */ + KeReleaseInStackQueuedSpinLock(&LockHandle); +} + + +/*Exported */ +VOID +NTAPI +CcAddDirtyPagesToExternalCache( + IN PCC_EXTERNAL_CACHE_INFO ExternalCacheContext, + IN ULONG Pages + ) +{ + KIRQL OldIrql ={0}; + + + /* Only proceed if there are pages to add */ + if (Pages == 0) + { + return; + } + + /* Acquire the master lock */ + KeAcquireQueuedSpinLock(LockQueueMasterLock, &OldIrql); + + /* If this is the first dirty page, schedule a lazy write scan */ + if (ExternalCacheContext->DirtyPageStatistics.DirtyPages == 0) + { + CcScheduleLazyWriteScan(FALSE, NULL); + } + + /* Increment the dirty page count */ + ExternalCacheContext->DirtyPageStatistics.DirtyPages += Pages; + + /* Charge the dirty pages */ + CcChargeDirtyPages(NULL, NULL, NULL, Pages); + + /* Release the master lock */ + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); +} + +VOID +NTAPI +CcUnregisterExternalCache( + IN PCC_EXTERNAL_CACHE_INFO ExternalCacheContext + ) +{ + + + /* Remove the external cache from the list */ + CcRemoveExternalCache(ExternalCacheContext); + + /* Deduct any remaining dirty pages */ + if (ExternalCacheContext->DirtyPageStatistics.DirtyPages > 0) + { + CcDeductDirtyPagesFromExternalCache(ExternalCacheContext,ExternalCacheContext->DirtyPageStatistics.DirtyPages); + } + + /* Free the external cache context */ + ExFreePoolWithTag(ExternalCacheContext, CC_EXTERNAL_CACHE_INFO_TAG); +} + +NTSTATUS +NTAPI +CcRegisterExternalCache( + IN PCC_EXTERNAL_CACHE_CALLBACK Callback, + OUT PVOID *ExternalCacheContext + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + PCC_EXTERNAL_CACHE_INFO CacheInfo; + + + /* Ensure the Cache Manager is initialized */ + if (!CcInitializationComplete) + { + KeBugCheckEx(CACHE_MANAGER,0,STATUS_UNSUCCESSFUL,0,0); + } + + /* Allocate memory for the external cache info structure */ + CacheInfo = ExAllocatePoolWithTag(NonPagedPool, + sizeof(CC_EXTERNAL_CACHE_INFO), + CC_EXTERNAL_CACHE_INFO_TAG); + if (CacheInfo == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Initialize the cache info structure */ + RtlZeroMemory(CacheInfo, sizeof(CC_EXTERNAL_CACHE_INFO)); + CacheInfo->Callback = Callback; + + /* Add the external cache to the list */ + CcAddExternalCache(CacheInfo); + + /* Return the cache info as the context */ + *ExternalCacheContext = CacheInfo; + + return Status; +}