mirror of
https://github.com/reactos/reactos.git
synced 2024-11-03 13:25:57 +00:00
1f377076d7
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
703 lines
18 KiB
C++
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(¶ms);
|
|
|
|
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"
|