_Must_inspect_result_ PVOID FxRequestSystemBuffer::GetBuffer( VOID ) /*++ Routine Description: Returns the system buffer that has been cached away by the call to SetBuffer() Arguments: None Return Value: Valid memory or NULL on error --*/ { FxDevice* pDevice; FxIrp* irp = GetRequest()->GetFxIrp(); WDF_DEVICE_IO_TYPE ioType; switch (irp->GetMajorFunction()) { case IRP_MJ_DEVICE_CONTROL: case IRP_MJ_INTERNAL_DEVICE_CONTROL: return m_Buffer; case IRP_MJ_READ: case IRP_MJ_WRITE: pDevice = FxDevice::GetFxDevice(irp->GetDeviceObject()); ioType = pDevice->GetIoType(); switch (ioType) { case WdfDeviceIoBuffered: return m_Buffer; case WdfDeviceIoDirect: // // FxRequest::GetMemoryObject has already called MmGetSystemAddressForMdlSafe // and returned success, so we know that we can safely call // MmGetSystemAddressForMdlSafe again to get a valid VA pointer. // return Mx::MxGetSystemAddressForMdlSafe(m_Mdl, NormalPagePriority); case WdfDeviceIoNeither: return m_Buffer; default: ASSERT(FALSE); return NULL; } default: ASSERT(FALSE); return NULL; } }
FORCEINLINE VOID FxIoContext::ReleaseAndRestore( __in FxRequestBase* Request ) { FxIrp* irp = NULL; irp = Request->GetSubmitFxIrp(); if (m_RestoreState) { irp->SetSystemBuffer(m_OriginalSystemBuffer); irp->SetUserBuffer(m_OriginalUserBuffer); irp->SetMdlAddress(m_OriginalMdl); irp->SetFlags(m_OriginalFlags); m_OriginalSystemBuffer = NULL; m_OriginalUserBuffer = NULL; m_OriginalMdl = NULL; m_OriginalFlags = NULL; m_RestoreState = FALSE; } // // If there was a buffer present don't free the buffer here so that // it can be reused for any request with the same size. // Similarly if there was an MDL to be freed unlock the pages but dont free // the Mdl so that it can be reused. // if (m_MdlToFree != NULL) { if (m_UnlockPages) { MmUnlockPages(m_MdlToFree); m_UnlockPages = FALSE; } m_DriverGlobals = Request->GetDriverGlobals(); } // // Release the 2ndary buffer if we have an outstanding reference // if (m_OtherMemory != NULL) { m_OtherMemory->RELEASE(this); m_OtherMemory = NULL; } // // Release the other buffer and all __super related fields // __super::ReleaseAndRestore(Request); }
FORCEINLINE VOID FxIoContext::CopyParameters( __in FxRequestBase* Request ) { switch (m_MajorFunction) { case IRP_MJ_WRITE: m_CompletionParams.Parameters.Write.Length = m_CompletionParams.IoStatus.Information; break; case IRP_MJ_READ: m_CompletionParams.Parameters.Read.Length = m_CompletionParams.IoStatus.Information; break; case IRP_MJ_DEVICE_CONTROL: case IRP_MJ_INTERNAL_DEVICE_CONTROL: m_CompletionParams.Parameters.Ioctl.Output.Length = m_CompletionParams.IoStatus.Information; break; default: ASSERT(FALSE); } if (m_BufferToFree == NULL) { return; } if (m_CopyBackToBuffer) { FxIrp* irp = Request->GetSubmitFxIrp(); if (irp->GetUserBuffer() != NULL) { // // UserBuffer contains the caller's original output buffer. // Copy the results back into the original buffer. // if (m_MajorFunction == IRP_MJ_DEVICE_CONTROL || m_MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) { ASSERT(irp->GetInformation() <= m_BufferToFreeLength); } RtlCopyMemory(irp->GetUserBuffer(), m_BufferToFree, irp->GetInformation()); m_CopyBackToBuffer = FALSE; } } }
_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; NTSTATUS status; ULONG ioLength; FxIrp* irp; PVOID buffer; UNREFERENCED_PARAMETER(FileObject); ASSERT(MajorCode == IRP_MJ_WRITE || MajorCode == IRP_MJ_READ); 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); // // Setup irp stack // irp = Request->GetSubmitFxIrp(); irp->ClearNextStackLocation(); // // copy File object and flags // CopyFileObjectAndFlags(Request); irp->SetMajorFunction(MajorCode); pContext->m_MajorFunction = MajorCode; ioLength = IoBuffer->GetBufferLength(); status = IoBuffer->GetBuffer(&buffer); if (!NT_SUCCESS(status)) { DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Could not retrieve i/o buffer, %!STATUS!", status); goto exit; } // // Since we don't support buffer transformations (buffered->Direct->Neither) // we are analogous to "Neither" method in KMDF // in which case we just set the Irp buffer to the buffer that is passed in // if (IRP_MJ_READ == MajorCode) { pContext->SwapIrpBuffer(Request, 0, NULL, ioLength, buffer); irp->GetIoIrp()->SetReadParametersForNextStackLocation( ioLength, DeviceOffset, 0 ); } else if (IRP_MJ_WRITE == MajorCode) { pContext->SwapIrpBuffer(Request, ioLength, buffer, 0, NULL); irp->GetIoIrp()->SetWriteParametersForNextStackLocation( ioLength, DeviceOffset, 0 ); } /* else if (WdfRequestQueryInformation == RequestType) { pContext->SwapIrpBuffer(pRequest, 0, NULL, ioLength, buffer); } else if (WdfRequestSetInformation == RequestType) { pContext->SwapIrpBuffer(pRequest, ioLength, buffer, 0, NULL); } */ else { pContext->SwapIrpBuffer(Request, 0, NULL, 0, NULL); } exit: if (NT_SUCCESS(status)) { Request->VerifierSetFormatted(); } else { 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; ULONG inLength, outLength; FxIrp* irp; PVOID inputBuffer; PVOID outputBuffer; UNREFERENCED_PARAMETER(FileObject); irp = Request->GetSubmitFxIrp(); 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); } inLength = InputBuffer->GetBufferLength(); outLength = OutputBuffer->GetBufferLength(); // // Capture irp buffers in context and set driver-provided buffers in the irp // status = InputBuffer->GetBuffer(&inputBuffer); if (!NT_SUCCESS(status)) { DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Could not retrieve input buffer, %!STATUS!", status); goto exit; } status = OutputBuffer->GetBuffer(&outputBuffer); if (!NT_SUCCESS(status)) { DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Could not retrieve output buffer, %!STATUS!", status); goto exit; } // // Save away any references to IFxMemory pointers that are passed // pContext->StoreAndReferenceMemory(InputBuffer); pContext->StoreAndReferenceOtherMemory(OutputBuffer); pContext->m_MajorFunction = IRP_MJ_DEVICE_CONTROL; // // Format next stack location // irp->ClearNextStackLocation(); irp->SetMajorFunction(IRP_MJ_DEVICE_CONTROL); // // copy File object and flags // CopyFileObjectAndFlags(Request); irp->GetIoIrp()->SetDeviceIoControlParametersForNextStackLocation( Ioctl, inLength, outLength ); pContext->SwapIrpBuffer(Request, InputBuffer->GetBufferLength(), inputBuffer, OutputBuffer->GetBufferLength(), outputBuffer); exit: if (NT_SUCCESS(status)) { Request->VerifierSetFormatted(); } else { Request->ContextReleaseAndRestore(); } return status;; }
// // This inserts a request into the I/O processing pipeline // _Must_inspect_result_ NTSTATUS FxPkgIo::EnqueueRequest( __in CfxDevice* Device, __inout FxRequest* pRequest ) { NTSTATUS status; FxIoQueue* pQueue; FxIrp* Irp = NULL; FxRequestCompletionState oldState; PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); SHORT origVerifierFlags = 0; // // Request is owned by the driver, and has a reference count of == 1 // (or > 1 if EvtIoInCallerContext callback took an additional reference), // with a FxPkgIoInProcessRequestComplete callback registered. // ASSERT(pRequest->GetRefCnt() >= 1); Irp = pRequest->GetFxIrp(); DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, "WDFREQUEST 0x%p", pRequest->GetObjectHandle()); status = VerifyEnqueueRequestUpdateFlags(FxDriverGlobals, pRequest, &origVerifierFlags); if (!NT_SUCCESS(status)) { return status; } // // Get the associated queue // pQueue = (FxIoQueue*) pRequest->GetInternalContext(); if (NULL == pQueue) { pQueue = m_DispatchTable[Irp->GetMajorFunction()]; if (pQueue == NULL) { // // No queue configured yet, fail request unless the driver is a filter. // if (m_Filter) { goto Forward; } status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, "No queue configured for WDFDEVICE 0x%p, " "failing WDFREQUEST 0x%p %!STATUS!", Device->GetHandle(), pRequest->GetObjectHandle(), status); FxVerifierDbgBreakPoint(FxDriverGlobals); // // Return it back to the driver to decide the outcome // goto Error; } } // // If the queue is a default-queue and driver is a filter then before // calling the queue we should make sure the queue can dispatch // requests to the driver. If the queue cannot dispatch request, // we should forward it down to the lower driver ourself. if (m_Filter && pQueue == m_DefaultQueue && pQueue->IsIoEventHandlerRegistered((WDF_REQUEST_TYPE)Irp->GetMajorFunction()) == FALSE) { // // Default queue doesn't have callback events registered to // handle this request. So forward it down. // goto Forward; } pQueue->AddRef(); // Must add a reference before releasing the callback and its reference pRequest->ADDREF(FXREQUEST_STATE_TAG); // Release the callback oldState = pRequest->SetCompletionState(FxRequestCompletionStateNone); ASSERT(oldState != FxRequestCompletionStateNone); UNREFERENCED_PARAMETER(oldState); status = pQueue->QueueRequestFromForward(pRequest); pQueue->Release(); // // If not successfull, must place the request back // to the state it was in on entry so that the driver // can decide what to do next with it // if (!NT_SUCCESS(status)) { // // If the request comes back to us, it should still // have a reference count of 1 // oldState = pRequest->SetCompletionState(FxRequestCompletionStateIoPkg); ASSERT(oldState == FxRequestCompletionStateNone); UNREFERENCED_PARAMETER(oldState); // // Release the reference count on the request since // the callback will hold the only one that gets // decremented when the request is completed // pRequest->RELEASE(FXREQUEST_STATE_TAG); goto Error; } else { // // On success, can not touch the request since it // may have already been completed // } return status; Forward: // // Cannot send-and-forget a request with a formatted IO context. // if (pRequest->HasContext()) { status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage( FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, "Cannot send-and-forget WDFREQUEST 0x%p with formatted IO" " context for filter WDFDEVICE 0x%p, %!STATUS!", pRequest->GetObjectHandle(), Device->GetHandle(), status ); FxVerifierDbgBreakPoint(FxDriverGlobals); goto Error; } // // This will skip the current stack location and perform // early dispose on the request. // pRequest->PreProcessSendAndForget(); (VOID)Irp->CallDriver(Device->GetAttachedDevice()); // // This will delete the request and free the memory back // to the device lookaside list. // pRequest->PostProcessSendAndForget(); // // Return a success status in this code path even if the previous call // to send the request to the lower driver failed. The status code returned // by this function should reflect the status of enqueuing the request and // not the status returned by the lower driver. // return STATUS_SUCCESS; Error: // // If not successful, we must set the original verifier flags. // VerifyEnqueueRequestRestoreFlags(FxDriverGlobals, pRequest, origVerifierFlags); return status; }