Something went wrong. Try again.
Reactos
Something went wrong. Try again.
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278/*++
Copyright (c) Microsoft. All rights reserved.
Module Name:
FxRequestBufferKm.cpp
Abstract:
This module implements a memory union object
Author:
Environment:
Kernel mode only
Revision History:
--*/
#include "fxsupportpch.hpp"
extern "C" {// #include "FxRequestBufferKm.tmh"}
_Must_inspect_result_NTSTATUSFxRequestBuffer::GetOrAllocateMdl( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __deref_out_opt PMDL* Mdl, __inout PMDL* MdlToFree, __inout PBOOLEAN UnlockWhenFreed, __in LOCK_OPERATION Operation, __in BOOLEAN ReuseMdl, __inout_opt size_t* SizeOfMdl )/*++
Routine Description:
This function attempts to reuse the passed-in MDL (if any) or allocates a new MDL if reuse flag isn't passed-in or if the existing MDL isn't big enough.
Arguments:
Return Value: FxDriverGlobals - Driver globals
Mdl - on return it contains the MDL allocated/reused
MdlToFree - pointer to any MDL * to be reused, if the size is <= current size, or * freed and set to newly allocated MDL
UnlockWhenFreed - whether to unlock pages when freeing MDL (if FALSE, MDL may represent just MDL buffer but the pages might have already been unlocked)
Operation - Operation to pass to MmLockPages
ReuseMdl - whether to reuse *MdlToFree Please note that this can be FALSE even when MDL is supplied
SizeOfMdl - on input contains size of *MdlToFree, on return contains size of *Mdl
Remarks:
*MdlToFree is modified only when this function frees the passed in MDL Otherwise it leaves it untouched. Caller is responsible for storing properly initialized value and/or freeing what's stored in the value.
--*/{ PVOID pBuf; NTSTATUS status; ULONG length; BOOLEAN oldUnlockValue;
pBuf = NULL;
oldUnlockValue = *UnlockWhenFreed;
// // Format functions that use this helper call // FxRequestBase::ValidateTarget which calls ContextReleaseAndRestore // which unlocks any locked pages. // // Hence pages must already be unlocked now. Let's assert that. // // This condition needs to be true since we unconditionally set // *UnlockWhenFreed to FALSE just below. // ASSERT (oldUnlockValue == FALSE);
*UnlockWhenFreed = FALSE;
// // Even if ReuseMdl is not true, SizeOfMdl may be supplied to store // the size of allocated MDL to be used later // ASSERT(ReuseMdl ? (SizeOfMdl != NULL && *MdlToFree != NULL) : TRUE);
switch (DataType) { case FxRequestBufferUnspecified: *Mdl = NULL; // // We should not set *MdlToFree to NULL as *MdlToFree might have a valid // MDL which we should not overwrite with NULL without freeing it // return STATUS_SUCCESS;
case FxRequestBufferMemory: if (u.Memory.Offsets != NULL) { pBuf = WDF_PTR_ADD_OFFSET(u.Memory.Memory->GetBuffer(), u.Memory.Offsets->BufferOffset); } else { pBuf = u.Memory.Memory->GetBuffer(); } // || || // \/ \/ fall through
case FxRequestBufferBuffer: if (pBuf == NULL) { pBuf = u.Buffer.Buffer; }
length = GetBufferLength(); status = GetOrAllocateMdlWorker(FxDriverGlobals, Mdl, &ReuseMdl, length, pBuf, SizeOfMdl, oldUnlockValue, MdlToFree ); if (!NT_SUCCESS(status)) { DoTraceLevelMessage( FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, "Couldn't allocate memory for MDL of length 0x%x %!STATUS!", length, status); return status; }
// // If we are reusing the MDL we need to initialize it with current // buffer. // if (ReuseMdl == TRUE) { Mx::MxInitializeMdl(*Mdl, pBuf, length); }
status = FxProbeAndLockWithAccess(*Mdl, KernelMode, Operation);
if (!NT_SUCCESS(status)) { DoTraceLevelMessage( FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, "Couldn't lock pages for MDL 0x%p %!STATUS!", *Mdl, status);
// // Free MDL only if it was not reused. // if (ReuseMdl == FALSE) { FxMdlFree(FxDriverGlobals, *Mdl); }
*Mdl = NULL; return status; }
*UnlockWhenFreed = TRUE; *MdlToFree = *Mdl;
return STATUS_SUCCESS;
case FxRequestBufferMdl: *Mdl = u.Mdl.Mdl; // // We should not set *MdlToFree to NULL as *MdlToFree might have a valid // MDL which we should not overwrite with NULL without freeing it // return STATUS_SUCCESS;
case FxRequestBufferReferencedMdl: if (u.RefMdl.Offsets == NULL || (u.RefMdl.Offsets->BufferOffset == 0 && u.RefMdl.Offsets->BufferLength == 0)) { *Mdl = u.RefMdl.Mdl; // // We should not set *MdlToFree to NULL as *MdlToFree might have a valid // MDL which we should not overwrite with NULL without freeing it // } else { // // Do not use MmGetSystemAddressForMdlSafe because StartVa could be // in UM while MappedVa (obviously) is in KM. Since // IoBuildPartial Mdl basically uses // pBuf - MmGetMdlVirtualAddress(SrcMdl) to compute offset, if one // VA is in UM (e.g. MmGetMdlVirtualAddress(SrcMdl)), you get the // (drastically) wrong offset. // pBuf = Mx::MxGetMdlVirtualAddress(u.RefMdl.Mdl); ASSERT(pBuf != NULL);
pBuf = WDF_PTR_ADD_OFFSET(pBuf, u.RefMdl.Offsets->BufferOffset);
// // GetBufferLength will compute the correct length with the given offsets // length = GetBufferLength(); status = GetOrAllocateMdlWorker(FxDriverGlobals, Mdl, &ReuseMdl, length, pBuf, SizeOfMdl, oldUnlockValue, MdlToFree ); if (!NT_SUCCESS(status)) { DoTraceLevelMessage( FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, "Couldn't allocate memory for MDL of length 0x%x %!STATUS!", length, status); return status; }
Mx::MxBuildPartialMdl( u.RefMdl.Mdl, *Mdl, pBuf, length );
*MdlToFree = *Mdl; }
return STATUS_SUCCESS;
default: *Mdl = NULL; // // We should not set *MdlToFree to NULL as *MdlToFree might have a valid // MDL which we should not overwrite with NULL without freeing it // return STATUS_INVALID_PARAMETER; }}
VOIDFxRequestBuffer::SetMemory( __in IFxMemory* Memory, __in PWDFMEMORY_OFFSET Offsets ){ PMDL pMdl;
pMdl = Memory->GetMdl(); if (pMdl != NULL) { DataType = FxRequestBufferReferencedMdl; u.RefMdl.Memory = Memory; u.RefMdl.Offsets = Offsets; u.RefMdl.Mdl = pMdl; } else { DataType = FxRequestBufferMemory; u.Memory.Memory = Memory; u.Memory.Offsets = Offsets; }}