ReactOS  0.4.15-dev-3308-g9455def
fxrequestbufferkm.cpp
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) Microsoft. All rights reserved.
4 
5 Module Name:
6 
7  FxRequestBufferKm.cpp
8 
9 Abstract:
10 
11  This module implements a memory union object
12 
13 Author:
14 
15 
16 
17 Environment:
18 
19  Kernel mode only
20 
21 Revision History:
22 
23 --*/
24 
25 #include "fxsupportpch.hpp"
26 
27 extern "C" {
28 // #include "FxRequestBufferKm.tmh"
29 }
30 
34  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
36  __inout PMDL* MdlToFree,
37  __inout PBOOLEAN UnlockWhenFreed,
39  __in BOOLEAN ReuseMdl,
40  __inout_opt size_t* SizeOfMdl
41  )
42 /*++
43 
44 Routine Description:
45 
46  This function attempts to reuse the passed-in MDL (if any) or allocates
47  a new MDL if reuse flag isn't passed-in or if the existing MDL isn't
48  big enough.
49 
50 Arguments:
51 
52 Return Value:
53  FxDriverGlobals - Driver globals
54 
55  Mdl - on return it contains the MDL allocated/reused
56 
57  MdlToFree - pointer to any MDL
58  * to be reused, if the size is <= current size, or
59  * freed and set to newly allocated MDL
60 
61  UnlockWhenFreed - whether to unlock pages when freeing MDL
62  (if FALSE, MDL may represent just MDL buffer but the pages
63  might have already been unlocked)
64 
65  Operation - Operation to pass to MmLockPages
66 
67  ReuseMdl - whether to reuse *MdlToFree
68  Please note that this can be FALSE even when MDL is supplied
69 
70  SizeOfMdl - on input contains size of *MdlToFree,
71  on return contains size of *Mdl
72 
73 Remarks:
74 
75  *MdlToFree is modified only when this function frees the passed in MDL
76  Otherwise it leaves it untouched. Caller is responsible for storing
77  properly initialized value and/or freeing what's stored in the value.
78 
79  --*/
80 {
81  PVOID pBuf;
83  ULONG length;
84  BOOLEAN oldUnlockValue;
85 
86  pBuf = NULL;
87 
88  oldUnlockValue = *UnlockWhenFreed;
89 
90  //
91  // Format functions that use this helper call
92  // FxRequestBase::ValidateTarget which calls ContextReleaseAndRestore
93  // which unlocks any locked pages.
94  //
95  // Hence pages must already be unlocked now. Let's assert that.
96  //
97  // This condition needs to be true since we unconditionally set
98  // *UnlockWhenFreed to FALSE just below.
99  //
100  ASSERT (oldUnlockValue == FALSE);
101 
102  *UnlockWhenFreed = FALSE;
103 
104  //
105  // Even if ReuseMdl is not true, SizeOfMdl may be supplied to store
106  // the size of allocated MDL to be used later
107  //
108  ASSERT(ReuseMdl ? (SizeOfMdl != NULL && *MdlToFree != NULL) : TRUE);
109 
110  switch (DataType) {
112  *Mdl = NULL;
113  //
114  // We should not set *MdlToFree to NULL as *MdlToFree might have a valid
115  // MDL which we should not overwrite with NULL without freeing it
116  //
117  return STATUS_SUCCESS;
118 
120  if (u.Memory.Offsets != NULL) {
121  pBuf = WDF_PTR_ADD_OFFSET(u.Memory.Memory->GetBuffer(),
122  u.Memory.Offsets->BufferOffset);
123  }
124  else {
125  pBuf = u.Memory.Memory->GetBuffer();
126  }
127  // || ||
128  // \/ \/ fall through
129 
131  if (pBuf == NULL) {
132  pBuf = u.Buffer.Buffer;
133  }
134 
136  status = GetOrAllocateMdlWorker(FxDriverGlobals,
137  Mdl,
138  &ReuseMdl,
139  length,
140  pBuf,
141  SizeOfMdl,
142  oldUnlockValue,
143  MdlToFree
144  );
145  if (!NT_SUCCESS(status)) {
147  FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
148  "Couldn't allocate memory for MDL of length 0x%x %!STATUS!", length, status);
149  return status;
150  }
151 
152  //
153  // If we are reusing the MDL we need to initialize it with current
154  // buffer.
155  //
156  if (ReuseMdl == TRUE) {
157  Mx::MxInitializeMdl(*Mdl, pBuf, length);
158  }
159 
161 
162  if (!NT_SUCCESS(status)) {
164  FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
165  "Couldn't lock pages for MDL 0x%p %!STATUS!", *Mdl, status);
166 
167  //
168  // Free MDL only if it was not reused.
169  //
170  if (ReuseMdl == FALSE) {
171  FxMdlFree(FxDriverGlobals, *Mdl);
172  }
173 
174  *Mdl = NULL;
175  return status;
176  }
177 
178  *UnlockWhenFreed = TRUE;
179  *MdlToFree = *Mdl;
180 
181  return STATUS_SUCCESS;
182 
183  case FxRequestBufferMdl:
184  *Mdl = u.Mdl.Mdl;
185  //
186  // We should not set *MdlToFree to NULL as *MdlToFree might have a valid
187  // MDL which we should not overwrite with NULL without freeing it
188  //
189  return STATUS_SUCCESS;
190 
192  if (u.RefMdl.Offsets == NULL ||
193  (u.RefMdl.Offsets->BufferOffset == 0 && u.RefMdl.Offsets->BufferLength == 0)) {
194  *Mdl = u.RefMdl.Mdl;
195  //
196  // We should not set *MdlToFree to NULL as *MdlToFree might have a valid
197  // MDL which we should not overwrite with NULL without freeing it
198  //
199  }
200  else {
201  //
202  // Do not use MmGetSystemAddressForMdlSafe because StartVa could be
203  // in UM while MappedVa (obviously) is in KM. Since
204  // IoBuildPartial Mdl basically uses
205  // pBuf - MmGetMdlVirtualAddress(SrcMdl) to compute offset, if one
206  // VA is in UM (e.g. MmGetMdlVirtualAddress(SrcMdl)), you get the
207  // (drastically) wrong offset.
208  //
209  pBuf = Mx::MxGetMdlVirtualAddress(u.RefMdl.Mdl);
210  ASSERT(pBuf != NULL);
211 
212  pBuf = WDF_PTR_ADD_OFFSET(pBuf, u.RefMdl.Offsets->BufferOffset);
213 
214  //
215  // GetBufferLength will compute the correct length with the given offsets
216  //
218  status = GetOrAllocateMdlWorker(FxDriverGlobals,
219  Mdl,
220  &ReuseMdl,
221  length,
222  pBuf,
223  SizeOfMdl,
224  oldUnlockValue,
225  MdlToFree
226  );
227  if (!NT_SUCCESS(status)) {
229  FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
230  "Couldn't allocate memory for MDL of length 0x%x %!STATUS!", length, status);
231  return status;
232  }
233 
235  u.RefMdl.Mdl,
236  *Mdl,
237  pBuf,
238  length
239  );
240 
241  *MdlToFree = *Mdl;
242  }
243 
244  return STATUS_SUCCESS;
245 
246  default:
247  *Mdl = NULL;
248  //
249  // We should not set *MdlToFree to NULL as *MdlToFree might have a valid
250  // MDL which we should not overwrite with NULL without freeing it
251  //
253  }
254 }
255 
256 VOID
259  __in PWDFMEMORY_OFFSET Offsets
260  )
261 {
262  PMDL pMdl;
263 
264  pMdl = Memory->GetMdl();
265  if (pMdl != NULL) {
267  u.RefMdl.Memory = Memory;
268  u.RefMdl.Offsets = Offsets;
269  u.RefMdl.Mdl = pMdl;
270  }
271  else {
273  u.Memory.Memory = Memory;
274  u.Memory.Offsets = Offsets;
275  }
276 }
277 
static __inline PVOID MxGetMdlVirtualAddress(_In_ PMDL Mdl)
Definition: mxgeneralkm.h:654
VOID SetMemory(__in IFxMemory *Memory, __in PWDFMEMORY_OFFSET Offsets)
ULONG GetBufferLength(VOID)
#define WDF_PTR_ADD_OFFSET(_ptr, _offset)
Definition: wdfcore.h:144
#define TRUE
Definition: types.h:120
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
LONG NTSTATUS
Definition: precomp.h:26
static __inline VOID MxInitializeMdl(_In_ PMDL MemoryDescriptorList, _In_ PVOID BaseVa, _In_ SIZE_T Length)
Definition: mxgeneralkm.h:643
#define TRACINGAPIERROR
Definition: dbgtrace.h:60
PWDFMEMORY_OFFSET Offsets
#define __inout_opt
Definition: dbghelp.h:53
#define FALSE
Definition: types.h:117
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
unsigned char BOOLEAN
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _In_ _Strict_type_match_ POOL_TYPE _In_opt_ ULONG _In_ _Out_ WDFMEMORY * Memory
Definition: wdfmemory.h:169
NTSTATUS FxProbeAndLockWithAccess(__in PMDL Mdl, __in KPROCESSOR_MODE AccessMode, __in LOCK_OPERATION Operation)
Definition: probeandlock.c:74
#define ASSERT(a)
Definition: mode.c:44
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
static __inline VOID MxBuildPartialMdl(_In_ PMDL SourceMdl, _Inout_ PMDL TargetMdl, _In_ PVOID VirtualAddress, _In_ ULONG Length)
Definition: mxgeneralkm.h:663
char * PBOOLEAN
Definition: retypes.h:11
static ULONG SizeOfMdl(VOID)
Definition: NtReadFile.c:36
VOID __inline FxMdlFree(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in PMDL Mdl)
Definition: fxmdl.h:60
#define __inout
Definition: dbghelp.h:50
#define _Must_inspect_result_
Definition: ms_sal.h:558
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
union FxRequestBuffer::@4571 u
enum _LOCK_OPERATION LOCK_OPERATION
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, "Enter, WDFDEVICE %p", Device)
FxRequestBufferType DataType
#define NULL
Definition: types.h:112
_In_ WDFDEVICE _In_ PVOID _In_opt_ PMDL Mdl
#define __deref_out_opt
Definition: dbghelp.h:29
NTSTATUS GetOrAllocateMdlWorker(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __deref_out PMDL *Mdl, __in BOOLEAN *ReuseMdl, __in LONG Length, __in PVOID Buffer, __inout size_t *SizeOfMdl, __in BOOLEAN UnlockWhenFreed, __deref_out_opt PMDL *MdlToFree)
_Must_inspect_result_ NTSTATUS GetOrAllocateMdl(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __deref_out_opt PMDL *Mdl, __inout PMDL *MdlToFree, __inout PBOOLEAN UnlockWhenFreed, __in LOCK_OPERATION Operation, __in BOOLEAN ReuseMdl=FALSE, __inout_opt size_t *SizeOfMdl=NULL)
unsigned int ULONG
Definition: retypes.h:1
_In_ FLT_SET_CONTEXT_OPERATION Operation
Definition: fltkernel.h:1467
#define STATUS_SUCCESS
Definition: shellext.h:65
#define __in
Definition: dbghelp.h:35
static SERVICE_STATUS status
Definition: service.c:31
Definition: ps.c:97