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