reactos/sdk/lib/drivers/wdf/shared/object/handleapi.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

703 lines
18 KiB
C++

/*++
Copyright (c) Microsoft Corporation
Module Name:
HandleApi.cpp
Abstract:
This module implements the driver frameworks handle functions.
Author:
Environment:
Both kernel and user mode
Revision History:
--*/
#include "fxobjectpch.hpp"
extern "C" {
#if defined(EVENT_TRACING)
#include "HandleAPI.tmh"
#endif
}
size_t
FxGetContextSize(
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes
)
/*++
Routine Description:
Get a context size from an object's attributes settings.
Arguments:
Attributes - attributes which will describe the size requirements for the
associated context.
Return Value:
Size requirements for the associated context.
--*/
{
size_t contextSize = 0;
if (Attributes != NULL) {
if (Attributes->ContextTypeInfo != NULL) {
if (Attributes->ContextSizeOverride != 0) {
contextSize = Attributes->ContextSizeOverride;
}
else {
contextSize = Attributes->ContextTypeInfo->ContextSize;
}
}
}
return contextSize;
}
_Must_inspect_result_
NTSTATUS
FxCalculateObjectTotalSize2(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in USHORT RawObjectSize,
__in USHORT ExtraSize,
__in size_t ContextSize,
__out size_t* Total
)
/*++
Routine Description:
Calculates the size of an allocation for an FxObject that will contain the
object, its initial context and any addtional headers.
Arguments:
FxDriverGlobals - driver's globals
RawObjectSize - the size of the FxObject derived object
ExtraSize - additional size required by the derived object
ContextSize - Size requirements for the associated context (see FxGetContextSize() above).
Total - pointer which will receive the final size requirement
Return Value:
NT_SUCCESS on success, !NT_SUCCESS on failure
--*/
{
NTSTATUS status;
*Total = 0;
status = RtlSizeTAdd(
WDF_ALIGN_SIZE_UP(COMPUTE_OBJECT_SIZE(RawObjectSize, ExtraSize), MEMORY_ALLOCATION_ALIGNMENT),
FX_CONTEXT_HEADER_SIZE,
Total
);
if (NT_SUCCESS(status)) {
if (ContextSize != 0) {
size_t alignUp;
alignUp = ALIGN_UP(ContextSize, PVOID);
//
// overflow after aligning up to a pointer boundary;
//
if (alignUp < ContextSize) {
return STATUS_INTEGER_OVERFLOW;
}
status = RtlSizeTAdd(*Total, alignUp, Total);
}
}
if (NT_SUCCESS(status) && FxDriverGlobals->IsObjectDebugOn()) {
//
// Attempt to add in the debug extension
//
status = RtlSizeTAdd(*Total,
FxObjectDebugExtensionSize,
Total);
}
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGOBJECT,
"Size overflow, object size 0x%x, extra object size 0x%x, "
"context size 0x%I64x, %!STATUS!",
RawObjectSize, ExtraSize, ContextSize, status);
}
return status;
}
_Must_inspect_result_
NTSTATUS
FxCalculateObjectTotalSize(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in USHORT RawObjectSize,
__in USHORT ExtraSize,
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,
__out size_t* Total
)
{
return FxCalculateObjectTotalSize2(FxDriverGlobals,
RawObjectSize,
ExtraSize,
FxGetContextSize(Attributes),
Total);
}
PVOID
FxObjectHandleAlloc(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in POOL_TYPE PoolType,
__in size_t Size,
__in ULONG Tag,
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,
__in USHORT ExtraSize,
__in FxObjectType ObjectType
)
/*++
Routine Description:
Allocates an FxObject derived object, it's associated context, and any
framework required headers and footers.
Arguments:
FxDriverGlobals - caller's globals
PoolType - type of pool to be used in allocating the object's memory
Size - size of the object (as passed to operator new() by the compiler)
Tag - tag to use when allocating the object's memory
Attributes - attributes which describe the context to be associated with the
object
ExtraSize - any addtional storage required by the object itself
ObjectType - the type (internal or external) of object being allocated. An
internal object is a worker object which will never have an associated
type or be Commit()'ed into an external object handle that the client
driver will see.
Return Value:
A valid pointer on success, NULL otherwise
--*/
{
PVOID blob;
size_t totalSize;
NTSTATUS status;
if (Tag == 0) {
Tag = FxDriverGlobals->Tag;
ASSERT(Tag != 0);
}
if (ObjectType == FxObjectTypeInternal) {
//
// An internal object might need the debug extension size added to it,
// but that's it. No extra size, no FxContextHeader.
//
if (FxDriverGlobals->IsObjectDebugOn()) {
status = RtlSizeTAdd(Size,
FxObjectDebugExtensionSize,
&totalSize);
}
else {
totalSize = Size;
status = STATUS_SUCCESS;
}
}
else {
status = FxCalculateObjectTotalSize(FxDriverGlobals,
(USHORT) Size,
ExtraSize,
Attributes,
&totalSize);
}
if (!NT_SUCCESS(status)) {
return NULL;
}
blob = FxPoolAllocateWithTag(FxDriverGlobals, PoolType, totalSize, Tag);
if (blob != NULL) {
blob = FxObjectAndHandleHeaderInit(
FxDriverGlobals,
blob,
COMPUTE_OBJECT_SIZE((USHORT) Size, ExtraSize),
Attributes,
ObjectType
);
}
return blob;
}
VOID
FxContextHeaderInit(
__in FxContextHeader* Header,
__in FxObject* Object,
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes
)
/*++
Routine Description:
Initializes a context header which describes a typed context.
Arguments:
Header - the header to initialize
Object - the object on which the context is being associated with
Attributes - description of the typed context
--*/
{
RtlZeroMemory(Header, FX_CONTEXT_HEADER_SIZE);
Header->Object = Object;
if (Attributes != NULL) {
if (Attributes->ContextTypeInfo != NULL) {
size_t contextSize;
if (Attributes->ContextSizeOverride != 0) {
contextSize = Attributes->ContextSizeOverride;
}
else {
contextSize = Attributes->ContextTypeInfo->ContextSize;
}
//
// Zero initialize the entire context
//
RtlZeroMemory(&Header->Context[0], ALIGN_UP(contextSize, PVOID));
}
Header->ContextTypeInfo = Attributes->ContextTypeInfo;
}
}
PVOID
FxObjectAndHandleHeaderInit(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in PVOID AllocationStart,
__in USHORT ObjectSize,
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,
__in FxObjectType ObjectType
)
/*++
Routine Description:
Initialize the object and its associated context.
Arguments:
FxDriverGlobals - caller's globals
AllocationStart - start of the memory block allocated to represent the object.
This will not be the same as the pointer which represents the address of
the object itself in memory
ObjectSize - size of the object
Attributes - description of its context
ObjectType - type (internal or external) of object being initialized
Return Value:
The address of the object withing AllocationStart
--*/
{
FxObject* pObject;
if (FxDriverGlobals->IsObjectDebugOn()) {
FxObjectDebugExtension* pExtension;
pExtension = (FxObjectDebugExtension*) AllocationStart;
RtlZeroMemory(pExtension, FxObjectDebugExtensionSize);
pExtension->Signature = FxObjectDebugExtensionSignature;
pObject = (FxObject*) &pExtension->AllocationStart[0];
}
else {
pObject = (FxObject*) AllocationStart;
}
if (ObjectType == FxObjectTypeExternal) {
FxContextHeaderInit(
(FxContextHeader*) WDF_PTR_ADD_OFFSET(pObject, ObjectSize),
pObject,
Attributes
);
}
return pObject;
}
VOID
FxObjectHandleGetPtrQI(
__in FxObject* Object,
__out PVOID* PPObject,
__in WDFOBJECT Handle,
__in WDFTYPE Type,
__in WDFOBJECT_OFFSET Offset
)
/*++
Routine Description:
Worker function for FxObjectHandleGetPtrXxx which will call
FxObject::QueryInterface when the Type does not match the object's built in
Type.
Arguments:
Object - object to query
PPObject - pointer which will recieve the queried for object
Handle - handle which the caller passed to the framework
Type - required object type
Offset - offset of the handle within the object. Nearly all handles will have
a zero object.
--*/
{
FxQueryInterfaceParams params = { PPObject, Type, Offset };
NTSTATUS status;
*PPObject = NULL;
status = Object->QueryInterface(&params);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
Object->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
"Object Type Mismatch, Handle 0x%p, Type 0x%x, "
"Obj 0x%p, SB 0x%x",
Handle, Type, Object, Object->GetType());
FxVerifierBugCheck(Object->GetDriverGlobals(),
WDF_INVALID_HANDLE,
(ULONG_PTR) Handle,
Type);
/* NOTREACHED */
return;
}
}
_Must_inspect_result_
NTSTATUS
FxObjectAllocateContext(
__in FxObject* Object,
__in PWDF_OBJECT_ATTRIBUTES Attributes,
__in BOOLEAN AllowCallbacksOnly,
__deref_opt_out PVOID* Context
)
/*++
Routine Description:
Allocates an additional context on the object if it is in the correct state.
Arguments:
Object - object on which to add a context
Attributes - attributes which describe the type and size of the new context
AllowEmptyContext -TRUE to allow logic to allocate the context's header only.
Context - optional pointer which will recieve the new context
Return Value:
STATUS_SUCCESS upon success, STATUS_OBJECT_NAME_EXISTS if the context type
is already attached to the handle, and !NT_SUCCESS on failure
--*/
{
PFX_DRIVER_GLOBALS fxDriverGlobals;
NTSTATUS status;
FxContextHeader * header;
size_t size;
BOOLEAN relRef;
ULONG flags;
fxDriverGlobals = Object->GetDriverGlobals();
header = NULL;
relRef = FALSE;
//
// Init validation flags.
//
flags = FX_VALIDATE_OPTION_ATTRIBUTES_REQUIRED;
if (fxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) {
flags |= FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED;
}
//
// Basic validations.
//
status = FxValidateObjectAttributes(fxDriverGlobals, Attributes, flags);
if (!NT_SUCCESS(status)) {
goto Done;
}
//
// Check for context type!
//
if (Attributes->ContextTypeInfo == NULL && AllowCallbacksOnly == FALSE) {
status = STATUS_OBJECT_NAME_INVALID;
DoTraceLevelMessage(
fxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGHANDLE,
"Attributes %p ContextTypeInfo is NULL, %!STATUS!",
Attributes, status);
goto Done;
}
Object->ADDREF(&status);
relRef = TRUE;
//
// By passing 0's for raw object size and extra size, we can compute the
// size of only the header and its contents.
//
status = FxCalculateObjectTotalSize(fxDriverGlobals, 0, 0, Attributes, &size);
if (!NT_SUCCESS(status)) {
goto Done;
}
header = (FxContextHeader*)
FxPoolAllocate(fxDriverGlobals, NonPagedPool, size);
if (header == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Done;
}
FxContextHeaderInit(header, Object, Attributes);
status = Object->AddContext(header, Context, Attributes);
//
// STATUS_OBJECT_NAME_EXISTS will not fail NT_SUCCESS, so check
// explicitly for STATUS_SUCCESS.
//
if (status != STATUS_SUCCESS) {
FxPoolFree(header);
}
Done:
if (relRef) {
Object->RELEASE(&status);
}
return status;
}
// extern "C" all APIs
extern "C" {
_Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)
WDFAPI
NTSTATUS
STDCALL
WDFEXPORT(WdfObjectAllocateContext)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
WDFOBJECT Handle,
__in
PWDF_OBJECT_ATTRIBUTES Attributes,
__deref_opt_out
PVOID* Context
)
/*++
Routine Description:
Allocates an additional context on the handle if the object is in the
correct state
Arguments:
Handle - handle on which to add a context
Attributes - attributes which describe the type and size of the new context
Context - optional pointer which will recieve the new context
Return Value:
STATUS_SUCCESS upon success, STATUS_OBJECT_NAME_EXISTS if the context type
is already attached to the handle, and !NT_SUCCESS on failure
--*/
{
DDI_ENTRY_IMPERSONATION_OK();
NTSTATUS status;
FxObject* object;
WDFOBJECT_OFFSET offset;
FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), Handle);
//
// No need to call FxObjectHandleGetPtr( , , FX_TYPE_OBJECT) because
// we assume that the object handle will point back to an FxObject. (The
// call to FxObjectHandleGetPtr will just make needless virtual call into
// FxObject anyways).
//
offset = 0;
object = FxObject::_GetObjectFromHandle(Handle, &offset);
if (offset != 0) {
status = STATUS_OBJECT_PATH_INVALID;
DoTraceLevelMessage(
object->GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGHANDLE,
"WDFHANDLE %p cannot have contexts added to it, %!STATUS!",
Handle, status);
goto Done;
}
//
// Internal helper function does the rest of the work.
//
status = FxObjectAllocateContext(object, Attributes, FALSE, Context);
Done:
return status;
}
__drv_maxIRQL(DISPATCH_LEVEL+1)
WDFAPI
PVOID
FASTCALL
WDFEXPORT(WdfObjectGetTypedContextWorker)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
WDFOBJECT Handle,
__in
PCWDF_OBJECT_CONTEXT_TYPE_INFO TypeInfo
)
/*++
Routine Description:
Retrieves the requested type from a handle
Arguments:
Handle - the handle to retrieve the context from
TypeInfo - global constant pointer which describes the type. Since the pointer
value is unique in all of kernel space, we will perform a pointer compare
instead of a deep structure compare
Return Value:
A valid context pointere or NULL. NULL is not a failure, querying for a type
not associated with the handle is a legitimate operation.
--*/
{
DDI_ENTRY_IMPERSONATION_OK();
FxContextHeader* pHeader;
FxObject* pObject;
PFX_DRIVER_GLOBALS pFxDriverGlobals;
WDFOBJECT_OFFSET offset;
FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), Handle);
//
// Do not call FxObjectHandleGetPtr( , , FX_TYPE_OBJECT) because this is a
// hot spot / workhorse function that should be as efficient as possible.
//
// A call to FxObjectHandleGetPtr would :
// 1) invoke a virtual call to QueryInterface
//
// 2) ASSERT that the ref count of the object is > zero. Since this is one
// of the few functions that can be called in EvtObjectDestroy where the
// ref count is zero, that is not a good side affect.
//
offset = 0;
pObject = FxObject::_GetObjectFromHandle(Handle, &offset);
//
// Use the object's globals, not the caller's
//
pFxDriverGlobals = pObject->GetDriverGlobals();
FxPointerNotNull(pFxDriverGlobals, TypeInfo);
pHeader = pObject->GetContextHeader();
for ( ; pHeader != NULL; pHeader = pHeader->NextHeader) {
if (pHeader->ContextTypeInfo == TypeInfo) {
return &pHeader->Context[0];
}
}
PCHAR pGivenName;
if (TypeInfo->ContextName != NULL) {
pGivenName = TypeInfo->ContextName;
}
else {
pGivenName = "<no typename given>";
}
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGHANDLE,
"Attempting to get context type %s from WDFOBJECT 0x%p",
pGivenName, Handle);
return NULL;
}
__drv_maxIRQL(DISPATCH_LEVEL+1)
WDFAPI
WDFOBJECT
FASTCALL
WDFEXPORT(WdfObjectContextGetObject)(
__in
PWDF_DRIVER_GLOBALS,
__in
PVOID ContextPointer
)
/*++
Routine Description:
Reverse of WdfObjectGetTypedContextWorker. Function will return the handle
associated with the provided context pointer.
Arguments:
ContextPointer - context pointer from which to retrieve the owning handle
Return Value:
A valid WDF handle
--*/
{
DDI_ENTRY_IMPERSONATION_OK();
FxContextHeader* pHeader;
FxObject* pObject;
//
// The context could be one of the chained contexts on the object and not
// the first one, so it is easiest to go back to the object and build the
// handle value from the FxObject*.
//
#pragma prefast(push);
#pragma prefast(disable:__WARNING_BUFFER_UNDERFLOW, "No way to express that passed in ptr is at an offset");
pHeader = CONTAINING_RECORD(ContextPointer, FxContextHeader, Context);
pObject = pHeader->Object;
#pragma prefast(pop);
return (WDFOBJECT) pObject->GetObjectHandle();
}
} // extern "C"