1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 wdfpoolkm.cpp 8 9 Abstract: 10 11 This module implements the driver frameworks pool routines 12 functionality only applicable in kernel mode 13 14 Author: 15 16 17 18 19 Environment: 20 21 Kernel mode only 22 23 Revision History: 24 25 26 --*/ 27 28 #include "fxobjectpch.hpp" 29 30 // We use DoTraceMessage 31 extern "C" { 32 #if defined(EVENT_TRACING) 33 #include "wdfpoolkm.tmh" 34 #endif 35 } 36 37 // undo the previous masking 38 #undef IoAllocateMdl 39 #undef IoFreeMdl 40 41 __drv_maxIRQL(DISPATCH_LEVEL) 42 NTKERNELAPI 43 PMDL 44 STDCALL 45 IoAllocateMdl( 46 __in_opt __drv_aliasesMem PVOID VirtualAddress, 47 __in ULONG Length, 48 __in BOOLEAN SecondaryBuffer, 49 __in BOOLEAN ChargeQuota, 50 __inout_opt PIRP Irp 51 ); 52 53 __drv_maxIRQL(DISPATCH_LEVEL) 54 NTKERNELAPI 55 VOID 56 STDCALL 57 IoFreeMdl( 58 PMDL Mdl 59 ); 60 61 // 62 // Windows Driver Framework Pool Tracking 63 // 64 // This module implements a generic pool tracking mechanism 65 // if pool verifier mode is enabled. 66 // 67 // There can be multiple pools, each represented by a FX_POOL header. 68 // 69 // When the framework is supplied as a DLL, there is a global 70 // pool that represents allocations for the framework DLL itself. These 71 // allocations are pool allocations and object allocations. 72 // 73 // The driver's pool allocations are not currently tracked. If the driver needs 74 // to use pool outside of the framework objects, it calls the WDM 75 // ExAllocatePoolWithTag and ExFreePool(WithTag) APIs. 76 // 77 78 79 80 PMDL 81 FxMdlAllocateDebug( 82 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 83 __in FxObject* Owner, 84 __in PVOID VirtualAddress, 85 __in ULONG Length, 86 __in BOOLEAN SecondaryBuffer, 87 __in BOOLEAN ChargeQuota, 88 __in PVOID CallersAddress 89 ) 90 { 91 FxDriverGlobalsDebugExtension* pExtension; 92 FxAllocatedMdls* pAllocated, **ppNext; 93 ULONG i; 94 PMDL pMdl; 95 KIRQL irql; 96 97 pExtension = FxDriverGlobals->DebugExtension; 98 if (pExtension == NULL) { 99 return IoAllocateMdl(VirtualAddress, 100 Length, 101 SecondaryBuffer, 102 ChargeQuota, 103 NULL); 104 } 105 106 pAllocated = &pExtension->AllocatedMdls; 107 ppNext = NULL; 108 pMdl = NULL; 109 110 KeAcquireSpinLock(&pExtension->AllocatedMdlsLock, &irql); 111 112 while (pAllocated != NULL && pAllocated->Count == NUM_MDLS_IN_INFO) { 113 ppNext = &pAllocated->Next; 114 pAllocated = pAllocated->Next; 115 } 116 117 if (pAllocated == NULL) { 118 // 119 // No more entries, allocate a new table 120 // 121 pAllocated = (FxAllocatedMdls*) ExAllocatePoolWithTag( 122 NonPagedPool, sizeof(FxAllocatedMdls), FxDriverGlobals->Tag); 123 124 if (pAllocated != NULL) { 125 // 126 // Zero out the new buffer and link it in to the list 127 // 128 RtlZeroMemory(pAllocated, sizeof(*pAllocated)); 129 *ppNext = pAllocated; 130 } 131 else { 132 // 133 // Could not allocate a new table, return error 134 // 135 KeReleaseSpinLock(&pExtension->AllocatedMdlsLock, irql); 136 137 return NULL; 138 } 139 } 140 141 for (i = 0; i < NUM_MDLS_IN_INFO; i++) { 142 if (pAllocated->Info[i].Mdl != NULL) { 143 continue; 144 } 145 146 pMdl = IoAllocateMdl(VirtualAddress, 147 Length, 148 SecondaryBuffer, 149 ChargeQuota, 150 NULL); 151 152 if (pMdl != NULL) { 153 pAllocated->Info[i].Mdl = pMdl; 154 pAllocated->Info[i].Owner = Owner; 155 pAllocated->Info[i].Caller = CallersAddress; 156 pAllocated->Count++; 157 } 158 break; 159 } 160 161 KeReleaseSpinLock(&pExtension->AllocatedMdlsLock, irql); 162 163 return pMdl; 164 } 165 166 VOID 167 FxMdlFreeDebug( 168 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 169 __in PMDL Mdl 170 ) 171 { 172 FxDriverGlobalsDebugExtension* pExtension; 173 FxAllocatedMdls* pAllocated, **ppNext; 174 ULONG i; 175 KIRQL irql; 176 BOOLEAN found; 177 178 pExtension = FxDriverGlobals->DebugExtension; 179 if (pExtension == NULL) { 180 IoFreeMdl(Mdl); 181 return; 182 } 183 184 found = FALSE; 185 186 pAllocated = &pExtension->AllocatedMdls; 187 ppNext = NULL; 188 189 KeAcquireSpinLock(&pExtension->AllocatedMdlsLock, &irql); 190 191 while (pAllocated != NULL) { 192 for (i = 0; i < NUM_MDLS_IN_INFO; i++) { 193 if (pAllocated->Info[i].Mdl != Mdl) { 194 continue; 195 } 196 197 RtlZeroMemory(&pAllocated->Info[i], 198 sizeof(pAllocated->Info[i])); 199 200 pAllocated->Count--; 201 202 if (pAllocated->Count == 0 && 203 pAllocated != &pExtension->AllocatedMdls) { 204 // 205 // Remove the current table from the chain 206 // 207 *ppNext = pAllocated->Next; 208 209 // 210 // And free it 211 // 212 ExFreePool(pAllocated); 213 } 214 215 IoFreeMdl(Mdl); 216 found = TRUE; 217 break; 218 } 219 220 if (found) { 221 break; 222 } 223 224 ppNext = &pAllocated->Next; 225 pAllocated = pAllocated->Next; 226 } 227 228 KeReleaseSpinLock(&pExtension->AllocatedMdlsLock, irql); 229 230 if (found == FALSE) { 231 232 233 234 FxVerifierDbgBreakPoint(FxDriverGlobals); 235 } 236 } 237 238 VOID 239 FxMdlDump( 240 __in PFX_DRIVER_GLOBALS FxDriverGlobals 241 ) 242 { 243 FxAllocatedMdls *pCur; 244 BOOLEAN leak; 245 246 if (FxDriverGlobals->DebugExtension == NULL) { 247 return; 248 } 249 250 leak = FALSE; 251 252 for (pCur = &FxDriverGlobals->DebugExtension->AllocatedMdls; 253 pCur != NULL; 254 pCur = pCur->Next) { 255 ULONG i; 256 257 for (i = 0; i < NUM_MDLS_IN_INFO; i++) { 258 if (pCur->Info[i].Mdl != NULL) { 259 leak = TRUE; 260 261 DoTraceLevelMessage( 262 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 263 "PMDL 0x%p leaked, FxObject owner %p, Callers Address %p", 264 pCur->Info[i].Mdl, pCur->Info[i].Owner, 265 pCur->Info[i].Caller); 266 } 267 } 268 } 269 270 if (leak) { 271 FxVerifierDbgBreakPoint(FxDriverGlobals); 272 } 273 } 274 275