reactos/sdk/lib/drivers/wdf/shared/targets/general/km/fxiotargetkm.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

524 lines
15 KiB
C++

/*++
Copyright (c) Microsoft Corporation
Module Name:
FxIoTargetKm.cpp
Abstract:
This module implements the IO Target APIs
Author:
Environment:
kernel mode only
Revision History:
--*/
#include "../../fxtargetsshared.hpp"
extern "C" {
#if defined(EVENT_TRACING)
#include "FxIoTargetKm.tmh"
#endif
}
_Must_inspect_result_
NTSTATUS
FxIoTarget::FormatIoRequest(
__inout FxRequestBase* Request,
__in UCHAR MajorCode,
__in FxRequestBuffer* IoBuffer,
__in_opt PLONGLONG DeviceOffset,
_In_opt_ FxFileObject* FileObject
)
{
FxIoContext* pContext;
PVOID pBuffer;
NTSTATUS status;
ULONG ioLength;
BOOLEAN freeSysBuf;
BOOLEAN setBufferAndLength;
FxIrp* irp;
UNREFERENCED_PARAMETER(FileObject);
ASSERT(MajorCode == IRP_MJ_WRITE || MajorCode == IRP_MJ_READ);
freeSysBuf = FALSE;
pBuffer = NULL;
status = Request->ValidateTarget(this);
if (!NT_SUCCESS(status)) {
return status;
}
if (Request->HasContextType(FX_RCT_IO)) {
pContext = (FxIoContext*) Request->GetContext();
}
else {
pContext = new(GetDriverGlobals()) FxIoContext();
if (pContext == NULL) {
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"could not allocate context for request");
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Since we can error out and return, remember the allocation before
// we do anything so we can free it later.
//
Request->SetContext(pContext);
}
//
// Save away any references to IFxMemory pointers that are passed
//
pContext->StoreAndReferenceMemory(IoBuffer);
irp = Request->GetSubmitFxIrp();
irp->ClearNextStackLocation();
CopyFileObjectAndFlags(Request);
//
// Note that by convention "Set" methods of FxIrp apply to next stack
// location unless specified otherwise in the name.
//
irp->SetMajorFunction(MajorCode);
pContext->m_MajorFunction = MajorCode;
//
// Anytime we return here and we allocated the context above, the context
// will be freed when the FxRequest is freed or reformatted.
//
ioLength = IoBuffer->GetBufferLength();
pContext->CaptureState(irp);
switch (m_TargetIoType) {
case WdfDeviceIoBuffered:
irp->SetUserBuffer(NULL);
if (ioLength != 0) {
if ((pContext->m_BufferToFreeLength >= ioLength) &&
(pContext->m_BufferToFree != NULL)) {
irp->SetSystemBuffer(pContext->m_BufferToFree);
setBufferAndLength = FALSE;
}
else {
irp->SetSystemBuffer(FxPoolAllocate(GetDriverGlobals(),
NonPagedPool,
ioLength));
if (irp->GetSystemBuffer() == NULL) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not allocate common buffer");
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
setBufferAndLength = TRUE;
freeSysBuf = TRUE;
}
status = IoBuffer->GetBuffer(&pBuffer);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve io buffer, %!STATUS!", status);
break;
}
//
// If its a write, copy into the double buffer now, otherwise,
// no copy into the buffer is needed for a read.
//
if (MajorCode == IRP_MJ_WRITE) {
if (pBuffer != NULL) {
RtlCopyMemory(irp->GetSystemBuffer(),
pBuffer,
ioLength);
}
}
else {
irp->SetUserBuffer(pBuffer);
}
//
// On reads, copy back to the double buffer after the read has
// completed.
//
if (setBufferAndLength) {
pContext->SetBufferAndLength(irp->GetSystemBuffer(),
ioLength,
(MajorCode == IRP_MJ_READ) ? TRUE : FALSE);
freeSysBuf = FALSE; // FxIoContext will free the buffer.
}
else {
pContext->m_CopyBackToBuffer = MajorCode == IRP_MJ_READ ?
TRUE : FALSE;
}
}
else {
//
// This field was captured and will be restored by the context
// later.
//
irp->SetSystemBuffer(NULL);
}
break;
case WdfDeviceIoDirect:
{
BOOLEAN reuseMdl;
reuseMdl = FALSE;
if (pContext->m_MdlToFree != NULL) {
reuseMdl = TRUE;
}
status = IoBuffer->GetOrAllocateMdl(
GetDriverGlobals(),
irp->GetMdlAddressPointer(),
&pContext->m_MdlToFree,
&pContext->m_UnlockPages,
(MajorCode == IRP_MJ_READ) ? IoWriteAccess : IoReadAccess,
reuseMdl,
&pContext->m_MdlToFreeSize
);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve io buffer as a PMDL, %!STATUS!",
status);
break;
}
break;
}
case WdfDeviceIoNeither:
//
// Neither MDL nor buffered
//
status = IoBuffer->GetBuffer(&pBuffer);
if (NT_SUCCESS(status)) {
irp->SetUserBuffer(pBuffer);
}
else {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve io buffer as a PVOID, %!STATUS!",
status);
}
break;
case WdfDeviceIoUndefined:
default:
status = STATUS_INVALID_DEVICE_STATE;
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Trying to format closed WDFIOTARGET %p, %!STATUS!",
GetHandle(), status);
break;
}
//
// We are assuming the read and write parts of the Parameters union
// are at the same offset. If this is FALSE, WDFCASSERT will not allow
// this file to compile, so keep these WDFCASSERTs here as long as the
// assumption is being made.
//
WDFCASSERT(FIELD_OFFSET(IO_STACK_LOCATION, Parameters.Write.ByteOffset)
==
FIELD_OFFSET(IO_STACK_LOCATION, Parameters.Read.ByteOffset));
WDFCASSERT(FIELD_OFFSET(IO_STACK_LOCATION, Parameters.Write.Length)
==
FIELD_OFFSET(IO_STACK_LOCATION, Parameters.Read.Length));
if (NT_SUCCESS(status)) {
irp->SetNextParameterWriteLength(ioLength);
if (DeviceOffset != NULL) {
irp->SetNextParameterWriteByteOffsetQuadPart(*DeviceOffset);
}
else {
irp->SetNextParameterWriteByteOffsetQuadPart(0);
}
Request->VerifierSetFormatted();
}
else {
if (freeSysBuf) {
FxPoolFree(irp->GetSystemBuffer());
irp->SetSystemBuffer(NULL);
}
Request->ContextReleaseAndRestore();
}
return status;
}
_Must_inspect_result_
NTSTATUS
FxIoTarget::FormatIoctlRequest(
__in FxRequestBase* Request,
__in ULONG Ioctl,
__in BOOLEAN Internal,
__in FxRequestBuffer* InputBuffer,
__in FxRequestBuffer* OutputBuffer,
_In_opt_ FxFileObject* FileObject
)
{
FxIoContext* pContext;
NTSTATUS status;
PVOID pBuffer;
ULONG inLength, outLength;
BOOLEAN freeSysBuf;
BOOLEAN setBufferAndLength;
FxIrp* irp;
UNREFERENCED_PARAMETER(FileObject);
irp = Request->GetSubmitFxIrp();
freeSysBuf = FALSE;
status = Request->ValidateTarget(this);
if (!NT_SUCCESS(status)) {
return status;
}
if (Request->HasContextType(FX_RCT_IO)) {
pContext = (FxIoContext*) Request->GetContext();
}
else {
pContext = new(GetDriverGlobals()) FxIoContext();
if (pContext == NULL) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not allocate context for request");
return STATUS_INSUFFICIENT_RESOURCES;
}
Request->SetContext(pContext);
}
pContext->CaptureState(irp);
irp->ClearNextStackLocation();
//
// Save away any references to IFxMemory pointers that are passed
//
pContext->StoreAndReferenceMemory(InputBuffer);
pContext->StoreAndReferenceOtherMemory(OutputBuffer);
UCHAR majorFunction;
if (Internal) {
majorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
}
else {
majorFunction = IRP_MJ_DEVICE_CONTROL;
}
irp->SetMajorFunction(majorFunction);
pContext->m_MajorFunction = majorFunction;
CopyFileObjectAndFlags(Request);
inLength = InputBuffer->GetBufferLength();
outLength = OutputBuffer->GetBufferLength();
irp->SetParameterIoctlCode(Ioctl);
irp->SetParameterIoctlInputBufferLength(inLength);
irp->SetParameterIoctlOutputBufferLength(outLength);
//
// Anytime we return here and we allocated the context above, the context
// will be freed when the FxRequest is freed or reformatted.
//
switch (METHOD_FROM_CTL_CODE(Ioctl)) {
case METHOD_BUFFERED:
if (inLength != 0 || outLength != 0) {
ULONG allocationLength;
allocationLength = (inLength > outLength ? inLength : outLength);
if ((pContext->m_BufferToFreeLength >= allocationLength) &&
(pContext->m_BufferToFree != NULL)) {
irp->SetSystemBuffer(pContext->m_BufferToFree);
setBufferAndLength = FALSE;
}
else {
irp->SetSystemBuffer(FxPoolAllocate(GetDriverGlobals(),
NonPagedPool,
allocationLength));
if (irp->GetSystemBuffer() == NULL) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not allocate common buffer");
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
setBufferAndLength = TRUE;
freeSysBuf = TRUE;
}
status = InputBuffer->GetBuffer(&pBuffer);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve input buffer, %!STATUS!",
status);
break;
}
if (pBuffer != NULL) {
RtlCopyMemory(irp->GetSystemBuffer(),
pBuffer,
inLength);
}
status = OutputBuffer->GetBuffer(&pBuffer);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve output buffer, %!STATUS!",
status);
break;
}
irp->SetUserBuffer(pBuffer);
if (setBufferAndLength) {
pContext->SetBufferAndLength(irp->GetSystemBuffer(),
allocationLength,
outLength > 0 ? TRUE : FALSE);
freeSysBuf = FALSE; // FxIoContext will free the buffer.
} else {
pContext->m_CopyBackToBuffer = outLength > 0 ? TRUE : FALSE;
}
}
else {
//
// These fields were captured and will be restored by the context
// later.
//
irp->SetUserBuffer(NULL);
irp->SetSystemBuffer(NULL);
}
break;
case METHOD_DIRECT_TO_HARDWARE: // METHOD_IN_DIRECT
case METHOD_DIRECT_FROM_HARDWARE: // METHOD_OUT_DIRECT
{
BOOLEAN reuseMdl;
reuseMdl = FALSE;
status = InputBuffer->GetBuffer(&pBuffer);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve input buffer as a PVOID, %!STATUS!",
status);
break;
}
irp->SetSystemBuffer(pBuffer);
//
// NOTE: There is no need to compare the operation type since that
// applies only to the Pages locked in memory and not the MDL data
// structure itself per se.
// Also, note that if the size of the Outbuf need not be equal to the
// size of the MdlToFree as long as the number of page entries match.
//
if (pContext->m_MdlToFree != NULL) {
reuseMdl = TRUE;
}
status = OutputBuffer->GetOrAllocateMdl(
GetDriverGlobals(),
irp->GetMdlAddressPointer(),
&pContext->m_MdlToFree,
&pContext->m_UnlockPages,
(METHOD_FROM_CTL_CODE(Ioctl) == METHOD_DIRECT_TO_HARDWARE) ? IoReadAccess : IoWriteAccess,
reuseMdl,
&pContext->m_MdlToFreeSize
);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve output buffer as a PMDL, %!STATUS!",
status);
break;
}
break;
}
case METHOD_NEITHER:
status = OutputBuffer->GetBuffer(&pBuffer);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve output buffer as a PVOID, %!STATUS!",
status);
break;
}
irp->SetUserBuffer(pBuffer);
status = InputBuffer->GetBuffer(&pBuffer);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve input buffer as a PVOID, %!STATUS!",
status);
break;
}
irp->SetParameterIoctlType3InputBuffer(pBuffer);
break;
}
if (NT_SUCCESS(status)) {
Request->VerifierSetFormatted();
}
else {
if (freeSysBuf) {
FxPoolFree(irp->GetSystemBuffer());
irp->SetSystemBuffer(NULL);
}
Request->ContextReleaseAndRestore();
}
return status;
}