reactos/sdk/lib/drivers/wdf/umdf/fxlib/librarycommon/fxlibrarycommon.cpp
Victor Perevertkin 8a978a179f
[WDF] Add Windows Driver Framework files
Takern from Microsoft GitHub repo:
d9c6040fe9

Licensed under MIT
2020-11-03 00:06:26 +03:00

509 lines
15 KiB
C++

//
// Copyright (C) Microsoft. All rights reserved.
//
#include <ntverp.h>
#include <strsafe.h>
#include <driverspecs.h>
extern "C" {
#include "mx.h"
}
#include "fxmin.hpp"
#include <fxldrUm.h>
#include <wdfcxbase.h>
#include "wdf20.h"
#include "wdf215.h"
//
// This will cause inclusion of VfWdfFunctions table implementation from header
//
#define VF_FX_DYNAMICS_GENERATE_TABLE 1
#include "..\version\FxDynamics.h"
#include "..\version\vffxdynamics.h"
#include "FxLibraryCommon.h"
#include "FxTelemetry.hpp"
extern "C" {
//
// Global triage Info for dbgeng and 0x9F work
//
static WDFOBJECT_TRIAGE_INFO _WdfObjectTriageInfo = {0};
static WDFCONTEXT_TRIAGE_INFO _WdfContextTriageInfo = {0};
static WDFCONTEXTTYPE_TRIAGE_INFO _WdfContextTypeTriageInfo = {0};
static WDFQUEUE_TRIAGE_INFO _WdfQueueTriageInfo = {0};
static WDFIRPQUEUE_TRIAGE_INFO _WdfIrpQueueTriageInfo = {0};
static WDFREQUEST_TRIAGE_INFO _WdfRequestTriageInfo = {0};
static WDFDEVICE_TRIAGE_INFO _WdfDeviceTriageInfo = {0};
static WDFIRP_TRIAGE_INFO _WdfIrpTriageInfo = {0};
static WDFFWDPROGRESS_TRIAGE_INFO _WdfFwdProgressTriageInfo = {0};
WDF_TRIAGE_INFO g_WdfTriageInfo = {
//
// UMDF Version.
//
__WUDF_MAJOR_VERSION,
__WUDF_MINOR_VERSION,
//
// Table Version.
//
WDF_01_TRIAGE_INFO_MAJOR_VERSION,
WDF_01_TRIAGE_INFO_MINOR_VERSION,
//
// Reserved ptr (set to NULL).
//
NULL,
//
// WDF objects triage info.
//
&_WdfObjectTriageInfo,
&_WdfContextTriageInfo,
&_WdfContextTypeTriageInfo,
&_WdfQueueTriageInfo,
&_WdfFwdProgressTriageInfo,
&_WdfIrpQueueTriageInfo,
&_WdfRequestTriageInfo,
&_WdfDeviceTriageInfo,
&_WdfIrpTriageInfo,
};
} // extern "C"
VOID
GetTriageInfo(
VOID
)
{
// Object
_WdfObjectTriageInfo.RawObjectSize = sizeof(FxObject);
_WdfObjectTriageInfo.ObjectType = FIELD_OFFSET(FxObject, m_Type);
_WdfObjectTriageInfo.TotalObjectSize = FIELD_OFFSET(FxObject, m_ObjectSize);
_WdfObjectTriageInfo.ChildListHead = FIELD_OFFSET(FxObject, m_ChildListHead);
_WdfObjectTriageInfo.ChildEntry = FIELD_OFFSET(FxObject, m_ChildEntry);
_WdfObjectTriageInfo.Globals = FIELD_OFFSET(FxObject, m_Globals);
_WdfObjectTriageInfo.ParentObject = FIELD_OFFSET(FxObject, m_ParentObject);
// Context Triage Info
_WdfContextTriageInfo.HeaderSize = sizeof(FxContextHeader);
_WdfContextTriageInfo.NextHeader = FIELD_OFFSET(FxContextHeader, NextHeader);
_WdfContextTriageInfo.Object = FIELD_OFFSET(FxContextHeader, Object);
_WdfContextTriageInfo.TypeInfoPtr = FIELD_OFFSET(FxContextHeader, ContextTypeInfo);
_WdfContextTriageInfo.Context = FIELD_OFFSET(FxContextHeader, Context);
// Context type Triage info
_WdfContextTypeTriageInfo.TypeInfoSize = sizeof(WDF_OBJECT_CONTEXT_TYPE_INFO);
_WdfContextTypeTriageInfo.ContextSize = FIELD_OFFSET(WDF_OBJECT_CONTEXT_TYPE_INFO, ContextSize);
_WdfContextTypeTriageInfo.ContextName = FIELD_OFFSET(WDF_OBJECT_CONTEXT_TYPE_INFO, ContextName);
// WdfRequest Queue
_WdfQueueTriageInfo.QueueSize = sizeof(FxIoQueue);
_WdfQueueTriageInfo.IrpQueue1 = FIELD_OFFSET(FxIoQueue, m_Queue);
_WdfQueueTriageInfo.IrpQueue2 = FIELD_OFFSET(FxIoQueue, m_DriverCancelable);
_WdfQueueTriageInfo.RequestList1 = FIELD_OFFSET(FxIoQueue, m_Cancelled);
_WdfQueueTriageInfo.RequestList2 = FIELD_OFFSET(FxIoQueue, m_CanceledOnQueueList);
_WdfQueueTriageInfo.FwdProgressContext = FIELD_OFFSET(FxIoQueue, m_FwdProgContext);
_WdfQueueTriageInfo.PkgIo = FIELD_OFFSET(FxIoQueue, m_PkgIo);
// Forward Progress
_WdfFwdProgressTriageInfo.ReservedRequestList =
FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_ReservedRequestList);
_WdfFwdProgressTriageInfo.ReservedRequestInUseList =
FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_ReservedRequestInUseList);
_WdfFwdProgressTriageInfo.PendedIrpList =
FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_PendedIrpList);
// Irp Queue
_WdfIrpQueueTriageInfo.IrpQueueSize = sizeof(FxIrpQueue);
_WdfIrpQueueTriageInfo.IrpListHeader = FIELD_OFFSET(FxIrpQueue, m_Queue);
_WdfIrpQueueTriageInfo.IrpListEntry = 0;
_WdfIrpQueueTriageInfo.IrpContext = 0;
// WdfRequest
_WdfRequestTriageInfo.RequestSize = sizeof(FxRequest);
_WdfRequestTriageInfo.CsqContext = FIELD_OFFSET(FxRequest, m_CsqContext);
_WdfRequestTriageInfo.FxIrp = FIELD_OFFSET(FxRequest, m_Irp);
_WdfRequestTriageInfo.ListEntryQueueOwned =
FIELD_OFFSET(FxRequest, m_OwnerListEntry);
_WdfRequestTriageInfo.ListEntryQueueOwned2 =
FIELD_OFFSET(FxRequest, m_OwnerListEntry2);
_WdfRequestTriageInfo.RequestListEntry =
FIELD_OFFSET(FxRequest, m_ListEntry);
_WdfRequestTriageInfo.FwdProgressList =
FIELD_OFFSET(FxRequest, m_ForwardProgressList);
// WdfDevice
_WdfDeviceTriageInfo.DeviceInitSize = sizeof(WDFDEVICE_INIT);
_WdfDeviceTriageInfo.DeviceDriver = FIELD_OFFSET(FxDevice, m_Driver);
// FxIrp
_WdfIrpTriageInfo.FxIrpSize = sizeof(FxIrp);
_WdfIrpTriageInfo.IrpPtr = FIELD_OFFSET(FxIrp, m_Irp);
}
NTSTATUS
FxLibraryCommonCommission(
VOID
)
{
NTSTATUS status;
__Print((LITERAL(WDF_LIBRARY_COMMISSION) "\n"));
//
// Commission this version's DLL globals.
//
status = FxLibraryGlobalsCommission();
if (!NT_SUCCESS(status)) {
__Print(("FxLibraryGlobalsCommission failed %X\n", status));
return status;
}
//
// register for ETW tracing.
//
RegisterTelemetryProvider();
//
// Initialize internal WPP tracing.
//
status = FxTraceInitialize();
if (NT_SUCCESS(status)) {
FxLibraryGlobals.InternalTracingInitialized = TRUE;
}
else {
__Print(("Failed to initialize tracing for WDF\n"));
//
// Failure to initialize is not critical enough to fail driver load.
//
status = STATUS_SUCCESS;
}
return status;
}
NTSTATUS
FxLibraryCommonDecommission(
VOID
)
{
__Print((LITERAL(WDF_LIBRARY_DECOMMISSION) ": enter\n"));
//
// Uninitialize WPP tracing.
//
if (FxLibraryGlobals.InternalTracingInitialized) {
TraceUninitialize();
FxLibraryGlobals.InternalTracingInitialized = FALSE;
}
//
// Unregister telemetry provider.
//
UnregisterTelemetryProvider();
EventUnregisterMicrosoft_Windows_DriverFrameworks_UserMode_Performance();
//
// Decommission this version's DLL globals.
//
FxLibraryGlobalsDecommission();
//
// Note: This is the absolute last action from WDF library (dynamic or static).
// The image is likely to be deleted after returning.
//
__Print((LITERAL(WDF_LIBRARY_DECOMMISSION) ": exit\n"));
return STATUS_SUCCESS;
}
NTSTATUS
FxLibraryCommonRegisterClient(
PWDF_BIND_INFO Info,
PWDF_DRIVER_GLOBALS * WdfDriverGlobals,
PCLIENT_INFO ClientInfo
)
{
NTSTATUS status;
status = STATUS_INVALID_PARAMETER;
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) ": enter\n"));
ASSERT(Info != NULL && Info->FuncCount != 0);
ASSERT(WdfDriverGlobals != 0);
if (Info == NULL || WdfDriverGlobals == NULL || Info->FuncTable == NULL) {
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
": NULL parameter -- %s\n",
(Info == NULL) ? "PWDF_BIND_INFO" :
(WdfDriverGlobals == NULL) ? "PWDF_DRIVER_GLOBALS *" :
(Info->FuncTable == NULL) ? "PWDF_BIND_INFO->FuncTable" :
"unknown" ));
goto Done;
}
*WdfDriverGlobals = NULL;
ASSERT(Info->FuncCount <= WdfVersion.FuncCount);
//
// WdfVersion.Count is initialized in FxDynamics.h and is never changed.
// Prefast is unable to make that determination.
//
__assume(WdfVersion.FuncCount == sizeof(WDFFUNCTIONS)/sizeof(PVOID));
if (Info->FuncCount > WdfVersion.FuncCount) {
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
": version mismatch detected in function table count: client"
"has 0x%x, library has 0x%x\n",
Info->FuncCount, WdfVersion.FuncCount));
goto Done;
}
if (Info->FuncCount <= WdfFunctionTableNumEntries_V2_15) {
switch (Info->FuncCount) {
case WdfFunctionTableNumEntries_V2_15:
case WdfFunctionTableNumEntries_V2_0:
break;
default:
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
": Function table count 0x%x doesn't match any previously "
"released framework version table size\n",
Info->FuncCount));
goto Done;
}
}
else {
//
// Client version is same as framework version. Make
// sure table count is exact.
//
// Note that in order for build-to-build upgrade to work, the following
// check should be commented out during active development.
//
// DO CHANGE it to a real failure towards the tail end of release to
// prevent cases where a driver sneaks out into public after being built
// with a non-RTM version of WDF and has a function count less than the
// final count. An HCK test has been added to ensure such drivers are
// caught early. This check is an additional prevention.
//
if (Info->FuncCount != WdfFunctionTableNumEntries) {
__Print(("Framework function table size (%d) doesn't match "
"with client (%d). Rebuild the client driver.",
WdfFunctionTableNumEntries, Info->FuncCount));
ASSERT(FALSE);
goto Done;
}
}
//
// Allocate an new FxDriverGlobals area for this driver.
//
*WdfDriverGlobals = FxAllocateDriverGlobals();
if (*WdfDriverGlobals) {
BOOLEAN isFunctinTableHookingOn = FALSE;
BOOLEAN isPerformanceAnalysisOn = FALSE;
PFX_DRIVER_GLOBALS fxDriverGlobals = NULL;
//
// Check the registry to see if Enhanced verifier is on for this driver.
// if registry read fails, options value remains unchanged.
// store enhanced verifier options in driver globals
//
fxDriverGlobals = GetFxDriverGlobals(*WdfDriverGlobals);
GetEnhancedVerifierOptions(ClientInfo, &fxDriverGlobals->FxEnhancedVerifierOptions);
isFunctinTableHookingOn = IsFxVerifierFunctionTableHooking(fxDriverGlobals);
isPerformanceAnalysisOn = IsFxPerformanceAnalysis(fxDriverGlobals);
//
// Set-up the function table. Enhanced verifier and Performance analysis is off by default.
//
if (isFunctinTableHookingOn == FALSE && isPerformanceAnalysisOn == FALSE) {
//
// Set-up the function table
//
// Starting in 2.15 we reference a copy of the DDI table in WDF01000,
// prior to that we copy the entire table to local memory.
//
if (Info->FuncCount <= WdfFunctionTableNumEntries_V2_0) {
RtlCopyMemory( Info->FuncTable,
&WdfVersion.Functions,
Info->FuncCount * sizeof(PVOID) );
}
else {
//
// FuncTable arrives with a ptr to &WdfFunctions, so we update
// what WdfFunctions points to
//
*((WDFFUNC**) Info->FuncTable) = (WDFFUNC*) &WdfVersion.Functions;
}
}
else {
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
": Enhanced Verification is ON \n"));
if (Microsoft_Windows_DriverFrameworks_UserMode_PerformanceHandle == NULL)
{
EventRegisterMicrosoft_Windows_DriverFrameworks_UserMode_Performance();
}
//
// Enhanced verification is on. Return verifier function table
//
// Starting in 1.15 we reference a copy of the DDI table in WDF01000,
// prior to that we copy the entire table to local memory.
//
if (Info->FuncCount <= WdfFunctionTableNumEntries_V2_0) {
RtlCopyMemory( Info->FuncTable,
&VfWdfVersion.Functions,
Info->FuncCount * sizeof(PVOID) );
}
else {
//
// FuncTable arrives with a ptr to &WdfFunctions, so we update
// what WdfFunctions points to.
//
*((WDFFUNC**) Info->FuncTable) = (WDFFUNC*) &VfWdfVersion.Functions;
}
}
status = STATUS_SUCCESS;
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
": WdfFunctions %p\n", Info->FuncTable));
}
Done:
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
": exit: status %X\n", status));
if (!NT_SUCCESS(status)) {
FX_VERIFY(DRIVER(BadArgument, TODO),
TRAPMSG("Version mismatch detected in function table count. Recompile"
" driver with correct headers"));
}
return status;
}
NTSTATUS
FxLibraryCommonUnregisterClient(
PWDF_BIND_INFO Info,
PWDF_DRIVER_GLOBALS WdfDriverGlobals
)
{
NTSTATUS status;
__Print((LITERAL(WDF_LIBRARY_UNREGISTER_CLIENT) ": enter\n"));
ASSERT(Info != NULL);
ASSERT(WdfDriverGlobals != NULL);
if (Info != NULL && WdfDriverGlobals != NULL) {
PFX_DRIVER_GLOBALS pFxDriverGlobals;
status = STATUS_SUCCESS;
pFxDriverGlobals = GetFxDriverGlobals(WdfDriverGlobals);
//
// Destroy this FxDriver instance, if its still indicated.
//
if (pFxDriverGlobals->Driver != NULL) {
//
// Association support, we are a root with no parent
//
pFxDriverGlobals->Driver->DeleteObject();
FxDestroy(pFxDriverGlobals);
}
//
// Stop IFR logging
//
FxIFRStop(pFxDriverGlobals);
//
// This will free the client's FxDriverGlobals area
//
FxFreeDriverGlobals(WdfDriverGlobals);
}
else {
status = STATUS_UNSUCCESSFUL;
}
__Print((LITERAL(WDF_LIBRARY_UNREGISTER_CLIENT)
": exit: status %X\n", status));
return status;
}
VOID
GetEnhancedVerifierOptions(
PCLIENT_INFO ClientInfo,
PULONG Options
)
{
NTSTATUS status;
ULONG value;
FxAutoRegKey hWdf;
DECLARE_CONST_UNICODE_STRING(valueName, WDF_ENHANCED_VERIFIER_OPTIONS_VALUE_NAME);
*Options = 0;
if (ClientInfo == NULL ||
ClientInfo->Size != sizeof(CLIENT_INFO) ||
ClientInfo->RegistryPath == NULL ||
ClientInfo->RegistryPath->Length == 0 ||
ClientInfo->RegistryPath->Buffer == NULL ||
Options == NULL) {
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
": Invalid ClientInfo received from wudfldr \n"));
return;
}
status = FxRegKey::_OpenKey(NULL,
ClientInfo->RegistryPath,
&hWdf.m_Key,
KEY_READ);
if (!NT_SUCCESS(status)) {
return;
}
status = FxRegKey::_QueryULong(
hWdf.m_Key, &valueName, &value);
//
// Examine key values and set Options only on success.
//
if (NT_SUCCESS(status)) {
if (value) {
*Options = value;
}
}
}