reactos/sdk/lib/drivers/wdf/shared/support/km/fxrequestbufferkm.cpp
Victor Perevertkin 1f377076d7
[WDF] Fix KMDF so it can compile with ReactOS SDK
Not all files are included, but these are necessary to compile cdrom driver.
So far it can only be statically linked with drivers, a proper
implementation requires wdfldr helper driver
2020-11-03 00:06:27 +03:00

277 lines
7.8 KiB
C++

/*++
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_
NTSTATUS
FxRequestBuffer::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;
}
}
VOID
FxRequestBuffer::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;
}
}