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