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