1 /* 2 * PROJECT: ReactOS Drivers 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: drivers/sac/driver/memory.c 5 * PURPOSE: Driver for the Server Administration Console (SAC) for EMS 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "sacdrv.h" 12 13 /* GLOBALS ********************************************************************/ 14 15 LONG TotalFrees, TotalBytesFreed, TotalAllocations, TotalBytesAllocated; 16 KSPIN_LOCK MemoryLock; 17 PSAC_MEMORY_LIST GlobalMemoryList; 18 19 /* FUNCTIONS ******************************************************************/ 20 21 BOOLEAN 22 NTAPI 23 InitializeMemoryManagement(VOID) 24 { 25 PSAC_MEMORY_ENTRY Entry; 26 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 27 28 /* Allocate a nonpaged heap for us to use */ 29 GlobalMemoryList = ExAllocatePoolWithTagPriority(NonPagedPool, 30 SAC_MEMORY_LIST_SIZE, 31 INITIAL_BLOCK_TAG, 32 HighPoolPriority); 33 if (GlobalMemoryList) 34 { 35 /* Initialize a lock for it */ 36 KeInitializeSpinLock(&MemoryLock); 37 38 /* Initialize the head of the list */ 39 GlobalMemoryList->Signature = GLOBAL_MEMORY_SIGNATURE; 40 GlobalMemoryList->LocalDescriptor = (PSAC_MEMORY_ENTRY)(GlobalMemoryList + 1); 41 GlobalMemoryList->Size = SAC_MEMORY_LIST_SIZE - sizeof(SAC_MEMORY_LIST); 42 GlobalMemoryList->Next = NULL; 43 44 /* Initialize the first free entry */ 45 Entry = GlobalMemoryList->LocalDescriptor; 46 Entry->Signature = LOCAL_MEMORY_SIGNATURE; 47 Entry->Tag = FREE_POOL_TAG; 48 Entry->Size = GlobalMemoryList->Size - sizeof(SAC_MEMORY_ENTRY); 49 50 /* All done */ 51 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with TRUE.\n"); 52 return TRUE; 53 } 54 55 /* No pool available to manage our heap */ 56 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with FALSE. No pool.\n"); 57 return FALSE; 58 } 59 60 VOID 61 NTAPI 62 FreeMemoryManagement(VOID) 63 { 64 PSAC_MEMORY_LIST Next; 65 KIRQL OldIrql; 66 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 67 68 /* Acquire the memory lock while freeing the list(s) */ 69 KeAcquireSpinLock(&MemoryLock, &OldIrql); 70 while (GlobalMemoryList) 71 { 72 ASSERT(GlobalMemoryList->Signature == GLOBAL_MEMORY_SIGNATURE); 73 74 /* While outside of the lock, save the next list and free this one */ 75 KeReleaseSpinLock(&MemoryLock, OldIrql); 76 Next = GlobalMemoryList->Next; 77 ExFreePoolWithTag(GlobalMemoryList, 0); 78 79 /* Reacquire the lock and see if there was another list to free */ 80 KeAcquireSpinLock(&MemoryLock, &OldIrql); 81 GlobalMemoryList = Next; 82 } 83 84 /* All done */ 85 KeReleaseSpinLock(&MemoryLock, OldIrql); 86 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting\n"); 87 } 88 89 PVOID 90 NTAPI 91 MyAllocatePool(IN SIZE_T PoolSize, 92 IN ULONG Tag, 93 IN PCHAR File, 94 IN ULONG Line) 95 { 96 PVOID p; 97 p = ExAllocatePoolWithTag(NonPagedPool, PoolSize, 'HACK'); 98 RtlZeroMemory(p, PoolSize); 99 SAC_DBG(SAC_DBG_MM, "Returning block 0x%X.\n", p); 100 return p; 101 #if 0 102 KIRQL OldIrql; 103 PSAC_MEMORY_LIST GlobalDescriptor, NewDescriptor; 104 PSAC_MEMORY_ENTRY LocalDescriptor, NextDescriptor; 105 ULONG GlobalSize, ActualSize; 106 PVOID Buffer; 107 108 ASSERT(Tag != FREE_POOL_TAG); 109 SAC_DBG(SAC_DBG_MM, "Entering.\n"); 110 111 /* Acquire the memory allocation lock and align the size request */ 112 KeAcquireSpinLock(&MemoryLock, &OldIrql); 113 PoolSize = ALIGN_UP(PoolSize, ULONGLONG); 114 115 #if _USE_SAC_HEAP_ALLOCATOR_ 116 GlobalDescriptor = GlobalMemoryList; 117 KeAcquireSpinLock(&MemoryLock, &OldIrql); 118 while (GlobalDescriptor) 119 { 120 ASSERT(GlobalMemoryList->Signature == GLOBAL_MEMORY_SIGNATURE); 121 122 LocalDescriptor = GlobalDescriptor->LocalDescriptor; 123 124 GlobalSize = GlobalDescriptor->Size; 125 while (GlobalSize) 126 { 127 ASSERT(LocalDescriptor->Signature == LOCAL_MEMORY_SIGNATURE); 128 129 if ((LocalDescriptor->Tag == FREE_POOL_TAG) && 130 (LocalDescriptor->Size >= PoolSize)) 131 { 132 break; 133 } 134 135 GlobalSize -= (LocalDescriptor->Size + sizeof(SAC_MEMORY_ENTRY)); 136 137 LocalDescriptor = 138 (PSAC_MEMORY_ENTRY)((ULONG_PTR)LocalDescriptor + 139 LocalDescriptor->Size + 140 sizeof(SAC_MEMORY_ENTRY)); 141 } 142 143 GlobalDescriptor = GlobalDescriptor->Next; 144 } 145 146 if (!GlobalDescriptor) 147 { 148 KeReleaseSpinLock(&MemoryLock, OldIrql); 149 150 ActualSize = min( 151 PAGE_SIZE, 152 PoolSize + sizeof(SAC_MEMORY_ENTRY) + sizeof(SAC_MEMORY_LIST)); 153 154 SAC_DBG(SAC_DBG_MM, "Allocating new space.\n"); 155 156 NewDescriptor = ExAllocatePoolWithTagPriority(NonPagedPool, 157 ActualSize, 158 ALLOC_BLOCK_TAG, 159 HighPoolPriority); 160 if (!NewDescriptor) 161 { 162 SAC_DBG(SAC_DBG_MM, "No more memory, returning NULL.\n"); 163 return NULL; 164 } 165 166 KeAcquireSpinLock(&MemoryLock, &OldIrql); 167 168 NewDescriptor->Signature = GLOBAL_MEMORY_SIGNATURE; 169 NewDescriptor->LocalDescriptor = (PSAC_MEMORY_ENTRY)(NewDescriptor + 1); 170 NewDescriptor->Size = ActualSize - 16; 171 NewDescriptor->Next = GlobalMemoryList; 172 173 GlobalMemoryList = NewDescriptor; 174 175 LocalDescriptor = NewDescriptor->LocalDescriptor; 176 LocalDescriptor->Signature = LOCAL_MEMORY_SIGNATURE; 177 LocalDescriptor->Tag = FREE_POOL_TAG; 178 LocalDescriptor->Size = 179 GlobalMemoryList->Size - sizeof(SAC_MEMORY_ENTRY); 180 } 181 182 SAC_DBG(SAC_DBG_MM, "Found a good sized block.\n"); 183 ASSERT(LocalDescriptor->Tag == FREE_POOL_TAG); 184 ASSERT(LocalDescriptor->Signature == LOCAL_MEMORY_SIGNATURE); 185 186 if (LocalDescriptor->Size > (PoolSize + sizeof(SAC_MEMORY_ENTRY))) 187 { 188 NextDescriptor = 189 (PSAC_MEMORY_ENTRY)((ULONG_PTR)LocalDescriptor + 190 PoolSize + 191 sizeof(SAC_MEMORY_ENTRY)); 192 if (NextDescriptor->Tag == FREE_POOL_TAG) 193 { 194 NextDescriptor->Tag = FREE_POOL_TAG; 195 NextDescriptor->Signature = LOCAL_MEMORY_SIGNATURE; 196 NextDescriptor->Size = 197 (LocalDescriptor->Size - PoolSize - sizeof(SAC_MEMORY_ENTRY)); 198 199 LocalDescriptor->Size = PoolSize; 200 } 201 } 202 #else 203 /* Shut the compiler up */ 204 NewDescriptor = GlobalDescriptor = NULL; 205 GlobalSize = (ULONG)NewDescriptor; 206 ActualSize = GlobalSize; 207 NextDescriptor = (PVOID)ActualSize; 208 NewDescriptor = (PVOID)NextDescriptor; 209 210 /* Use the NT pool allocator */ 211 LocalDescriptor = ExAllocatePoolWithTag(NonPagedPool, 212 PoolSize + sizeof(*LocalDescriptor), 213 Tag); 214 LocalDescriptor->Size = PoolSize; 215 #endif 216 /* Set the tag, and release the lock */ 217 LocalDescriptor->Tag = Tag; 218 KeReleaseSpinLock(&MemoryLock, OldIrql); 219 220 /* Update our performance counters */ 221 InterlockedIncrement(&TotalAllocations); 222 InterlockedExchangeAdd(&TotalBytesAllocated, LocalDescriptor->Size); 223 224 /* Return the buffer and zero it */ 225 SAC_DBG(SAC_DBG_MM, "Returning block 0x%X.\n", LocalDescriptor); 226 Buffer = LocalDescriptor + 1; 227 RtlZeroMemory(Buffer, PoolSize); 228 return Buffer; 229 #endif 230 } 231 232 VOID 233 NTAPI 234 MyFreePool(IN PVOID *Block) 235 { 236 #if 0 237 PSAC_MEMORY_ENTRY NextDescriptor; 238 PSAC_MEMORY_ENTRY ThisDescriptor, FoundDescriptor; 239 PSAC_MEMORY_ENTRY LocalDescriptor = (PVOID)((ULONG_PTR)(*Block) - sizeof(SAC_MEMORY_ENTRY)); 240 ULONG GlobalSize, LocalSize; 241 PSAC_MEMORY_LIST GlobalDescriptor; 242 KIRQL OldIrql; 243 SAC_DBG(SAC_DBG_MM, "Entering with block 0x%X.\n", LocalDescriptor); 244 245 /* Make sure this was a valid entry */ 246 ASSERT(LocalDescriptor->Size > 0); 247 ASSERT(LocalDescriptor->Signature == LOCAL_MEMORY_SIGNATURE); 248 249 /* Update performance counters */ 250 InterlockedIncrement(&TotalFrees); 251 InterlockedExchangeAdd(&TotalBytesFreed, LocalDescriptor->Size); 252 253 /* Acquire the memory allocation lock */ 254 GlobalDescriptor = GlobalMemoryList; 255 KeAcquireSpinLock(&MemoryLock, &OldIrql); 256 257 #if _USE_SAC_HEAP_ALLOCATOR_ 258 while (GlobalDescriptor) 259 { 260 ASSERT(GlobalMemoryList->Signature == GLOBAL_MEMORY_SIGNATURE); 261 262 FoundDescriptor = NULL; 263 264 ThisDescriptor = GlobalDescriptor->LocalDescriptor; 265 266 GlobalSize = GlobalDescriptor->Size; 267 while (GlobalSize) 268 { 269 ASSERT(ThisDescriptor->Signature == LOCAL_MEMORY_SIGNATURE); 270 271 if (ThisDescriptor == LocalDescriptor) break; 272 273 GlobalSize -= (ThisDescriptor->Size + sizeof(SAC_MEMORY_ENTRY)); 274 275 ThisDescriptor = 276 (PSAC_MEMORY_ENTRY)((ULONG_PTR)ThisDescriptor + 277 ThisDescriptor->Size + 278 sizeof(SAC_MEMORY_ENTRY)); 279 } 280 281 if (ThisDescriptor == LocalDescriptor) break; 282 283 GlobalDescriptor = GlobalDescriptor->Next; 284 } 285 286 if (!GlobalDescriptor) 287 { 288 KeReleaseSpinLock(&MemoryLock, OldIrql); 289 SAC_DBG(SAC_DBG_MM, "Could not find block.\n"); 290 return; 291 } 292 293 ASSERT(ThisDescriptor->Signature == LOCAL_MEMORY_SIGNATURE); 294 295 if (LocalDescriptor->Tag == FREE_POOL_TAG) 296 { 297 KeReleaseSpinLock(&MemoryLock, OldIrql); 298 SAC_DBG(SAC_DBG_MM, "Attempted to free something twice.\n"); 299 return; 300 } 301 302 LocalSize = LocalDescriptor->Size; 303 LocalDescriptor->Tag = FREE_POOL_TAG; 304 305 if (GlobalSize > (LocalSize + sizeof(SAC_MEMORY_ENTRY))) 306 { 307 NextDescriptor = 308 (PSAC_MEMORY_ENTRY)((ULONG_PTR)LocalDescriptor + 309 LocalSize + 310 sizeof(SAC_MEMORY_ENTRY)); 311 if (NextDescriptor->Tag == FREE_POOL_TAG) 312 { 313 NextDescriptor->Tag = 0; 314 NextDescriptor->Signature = 0; 315 316 LocalDescriptor->Size += 317 (NextDescriptor->Size + sizeof(SAC_MEMORY_ENTRY)); 318 } 319 } 320 321 if ((FoundDescriptor) && (FoundDescriptor->Tag == FREE_POOL_TAG)) 322 { 323 LocalDescriptor->Signature = 0; 324 LocalDescriptor->Tag = 0; 325 326 FoundDescriptor->Size += 327 (LocalDescriptor->Size + sizeof(SAC_MEMORY_ENTRY)); 328 } 329 #else 330 /* Shut the compiler up */ 331 LocalSize = GlobalSize = 0; 332 ThisDescriptor = (PVOID)LocalSize; 333 NextDescriptor = (PVOID)GlobalSize; 334 GlobalDescriptor = (PVOID)ThisDescriptor; 335 FoundDescriptor = (PVOID)GlobalDescriptor; 336 GlobalDescriptor = (PVOID)NextDescriptor; 337 NextDescriptor = (PVOID)FoundDescriptor; 338 339 /* Use the NT pool allocator*/ 340 ExFreePool(LocalDescriptor); 341 #endif 342 343 /* Release the lock, delete the address, and return */ 344 KeReleaseSpinLock(&MemoryLock, OldIrql); 345 #endif 346 SAC_DBG(SAC_DBG_MM, "exiting: 0x%p.\n", *Block); 347 ExFreePoolWithTag(*Block, 'HACK'); 348 *Block = NULL; 349 } 350