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

740 lines
19 KiB
C++

/*++
Copyright (c) Microsoft Corporation
Module Name:
FxResourceCollection.cpp
Abstract:
This module implements a base object for derived collection classes and
the derived collection classes.
Author:
Environment:
Both kernel and user mode
Revision History:
--*/
#include "fxsupportpch.hpp"
extern "C" {
#if defined(EVENT_TRACING)
#include "FxResourceCollection.tmh"
#endif
}
BOOLEAN
FxResourceCollection::RemoveAndDelete(
__in ULONG Index
)
/*++
Routine Description:
Removes an entry from the collection and then deletes it if found. The
caller must have removal permissions to perform this action.
Arguments:
Index - zero based index into the collection at which to perform the removal
Return Value:
TRUE if the item was found and deleted, FALSE otherwise
--*/
{
FxObject* pObject;
FxCollectionEntry* pEntry;
KIRQL irql;
if (IsRemoveAllowed() == FALSE) {
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
"Removes not allowed on handle %p, remove at index %d"
"failed", GetObjectHandle(), Index);
FxVerifierDbgBreakPoint(GetDriverGlobals());
return FALSE;
}
pObject = NULL;
Lock(&irql);
pEntry = FindEntry(Index);
if (pEntry != NULL) {
//
// Mark the list as changed so when we go to create a WDM resource list we
// know if a new list is needed.
//
MarkChanged();
pObject = pEntry->m_Object;
//
// Remove the entry
//
RemoveEntry(pEntry);
}
Unlock(irql);
if (pObject != NULL) {
//
// Delete the object since we created it
//
pObject->DeleteObject();
pObject = NULL;
return TRUE;
}
else {
return FALSE;
}
}
_Must_inspect_result_
NTSTATUS
FxResourceCollection::AddAt(
__in ULONG Index,
__in FxObject* Object
)
/*++
Routine Description:
Adds an object into the collection at the specified index.
Arguments:
Index - zero baesd index in which to insert into the list. WDF_INSERT_AT_END
is a special value which indicates that the insertion is an append.
Object - object to add
Return Value:
NTSTATUS
--*/
{
FxCollectionEntry *pNew;
PLIST_ENTRY ple;
NTSTATUS status;
KIRQL irql;
if (IsAddAllowed() == FALSE) {
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
"Adds not allowed on handle %p, add at index %d"
"failed", GetObjectHandle(), Index);
FxVerifierDbgBreakPoint(GetDriverGlobals());
return STATUS_ACCESS_DENIED;
}
Lock(&irql);
ple = NULL;
status = STATUS_SUCCESS;
pNew = AllocateEntry(GetDriverGlobals());
if (pNew != NULL) {
//
// Inserting at the current count (i.e. one past the end) is the same
// as append.
//
if (Index == WDF_INSERT_AT_END || Index == Count()) {
ple = &m_ListHead;
}
else {
FxCollectionEntry* cur, *end;
ULONG i;
for (cur = Start(), end = End(), i = 0;
cur != end;
cur = cur->Next(), i++) {
if (i == Index) {
ple = &cur->m_ListEntry;
break;
}
}
if (ple == NULL) {
delete pNew;
status = STATUS_ARRAY_BOUNDS_EXCEEDED;
}
}
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(status)) {
PLIST_ENTRY blink;
// ple now points to the list entry which we will insert our node
// *before*
blink = ple->Blink;
// Link the previous with the new entry
blink->Flink = &pNew->m_ListEntry;
pNew->m_ListEntry.Blink = blink;
// Link the current with the new entry
pNew->m_ListEntry.Flink = ple;
ple->Blink = &pNew->m_ListEntry;
AddEntry(pNew, Object);
//
// Mark the list as changed so when we go to create a WDM resource list
// we know if a new list is needed.
//
MarkChanged();
}
Unlock(irql);
if (!NT_SUCCESS(status)) {
Object->DeleteFromFailedCreate();
}
return status;
}
_Must_inspect_result_
NTSTATUS
FxIoResList::BuildFromWdmList(
__deref_in PIO_RESOURCE_LIST* WdmResourceList
)
/*++
Routine Description:
Builds up the collection with FxResourceIo objects based on the passed in
WDM io resource list
Arguments:
WdmResourceList - list which specifies the io resource objects to create
Return Value:
NTSTATUS
--*/
{
PIO_RESOURCE_DESCRIPTOR pWdmDescriptor;
ULONG i, count;
NTSTATUS status;
pWdmDescriptor = &(*WdmResourceList)->Descriptors[0];
count = (*WdmResourceList)->Count;
status = STATUS_SUCCESS;
for (i = 0; i < count; i++) {
//
// Now create a new resource object for each resource
// in our list.
//
FxResourceIo *pResource;
pResource = new(GetDriverGlobals())
FxResourceIo(GetDriverGlobals(), pWdmDescriptor);
if (pResource == NULL) {
//
// We failed, clean up, and exit. Since we are only
// keeping references on the master collection, if
// we free this, everything else will go away too.
//
status = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(status)) {
status = pResource->AssignParentObject(this);
//
// See notes in previous AssignParentObject as to why
// we are asserting.
//
ASSERT(NT_SUCCESS(status));
UNREFERENCED_PARAMETER(status);
status = Add(pResource) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
}
if (!NT_SUCCESS(status)) {
break;
}
pWdmDescriptor++;
}
if (NT_SUCCESS(status)) {
status = m_OwningList->Add(this) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(status)) {
*WdmResourceList = (PIO_RESOURCE_LIST) pWdmDescriptor;
}
return status;
}
_Must_inspect_result_
NTSTATUS
FxCmResList::BuildFromWdmList(
__in PCM_RESOURCE_LIST WdmResourceList,
__in UCHAR AccessFlags
)
/*++
Routine Description:
Builds up the collection with FxResourceCm objects based on the passed in
WDM io resource list.
Arguments:
WdmResourceList - list which specifies the io resource objects to create
AccessFlags - permissions to be associated with the list
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
//
// Predispose to success
//
status = STATUS_SUCCESS;
Clear();
m_AccessFlags = AccessFlags;
if (WdmResourceList != NULL) {
PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;
ULONG count, i;
//
// We only expect to see one full resource descriptor.
//
ASSERT(WdmResourceList->Count == 1);
count = WdmResourceList->List[0].PartialResourceList.Count;
pDescriptor = WdmResourceList->List[0].PartialResourceList.PartialDescriptors;
for(i = 0; i < count; i++, pDescriptor++) {
FxResourceCm *pResource;
pResource = new(GetDriverGlobals())
FxResourceCm(GetDriverGlobals(), pDescriptor);
if (pResource == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(status)) {
status = pResource->AssignParentObject(this);
//
// Since we control our own lifetime here, the assign should
// always work.
//
ASSERT(NT_SUCCESS(status));
status = Add(pResource) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
}
if (!NT_SUCCESS(status)) {
Clear();
break;
}
}
}
return status;
}
_Must_inspect_result_
PCM_RESOURCE_LIST
FxCmResList::CreateWdmList(
__in __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE PoolType
)
/*++
Routine Description:
Allocates and initializes a WDM CM resource list based off of the current
contents of this collection.
Arguments:
PoolType - the pool type from which to allocate the resource list
Return Value:
a new resource list upon success, NULL upon failure
--*/
{
PCM_RESOURCE_LIST pWdmResourceList;
ULONG size;
PFX_DRIVER_GLOBALS pFxDriverGlobals;
pWdmResourceList = NULL;
pFxDriverGlobals = GetDriverGlobals();
if (Count()) {
//
// NOTE: This function assumes all resources are on the same bus
// and therefore there is only one FULL_RESOURCE_DESCRIPTOR.
//
size = sizeof(CM_RESOURCE_LIST) +
(sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (Count() - 1));
pWdmResourceList = (PCM_RESOURCE_LIST)
MxMemory::MxAllocatePoolWithTag(PoolType, size, pFxDriverGlobals->Tag);
if (pWdmResourceList != NULL) {
PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;
FxCollectionEntry *cur, *end;
RtlZeroMemory(pWdmResourceList, size);
pWdmResourceList->Count = 1; // We only return one full descriptor
pWdmResourceList->List[0].PartialResourceList.Version = 1;
pWdmResourceList->List[0].PartialResourceList.Revision = 1;
pWdmResourceList->List[0].PartialResourceList.Count = Count();
pDescriptor =
pWdmResourceList->List[0].PartialResourceList.PartialDescriptors;
end = End();
for (cur = Start(); cur != end; cur = cur->Next()) {
FxResourceCm *pResource;
pResource = (FxResourceCm*) cur->m_Object;
RtlCopyMemory(pDescriptor,
&pResource->m_Descriptor,
sizeof(pResource->m_Descriptor));
pDescriptor++;
}
}
}
return pWdmResourceList;
}
ULONG
FxCmResList::GetCount(
VOID
)
{
ULONG count;
KIRQL irql;
Lock(&irql);
count = Count();
Unlock(irql);
return count;
}
PCM_PARTIAL_RESOURCE_DESCRIPTOR
FxCmResList::GetDescriptor(
__in ULONG Index
)
{
FxResourceCm* pObject;
KIRQL irql;
Lock(&irql);
pObject = (FxResourceCm*) GetItem(Index);
Unlock(irql);
if (pObject == NULL) {
return NULL;
}
else {
//
// Copy the current descriptor to the clone and return it
//
RtlCopyMemory(&pObject->m_DescriptorClone,
&pObject->m_Descriptor,
sizeof(pObject->m_Descriptor));
return &pObject->m_DescriptorClone;
}
}
_Must_inspect_result_
FxIoResReqList*
FxIoResReqList::_CreateFromWdmList(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in PIO_RESOURCE_REQUIREMENTS_LIST WdmRequirementsList,
__in UCHAR AccessFlags
)
/*++
Routine Description:
Allocates and populates an FxIoResReqList based on the WDM resource
requirements list.
Arguments:
WdmRequirementsList - a list of IO_RESOURCE_LISTs which will indicate how
to fill in the returned collection object
AccessFlags - permissions to associate with the newly created object
Return Value:
a new object upon success, NULL upon failure
--*/
{
FxIoResReqList* pIoResReqList;
ULONG i;
pIoResReqList = new(FxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES)
FxIoResReqList(FxDriverGlobals, AccessFlags);
if (pIoResReqList != NULL) {
PIO_RESOURCE_LIST pWdmResourceList;
NTSTATUS status;
if (WdmRequirementsList == NULL) {
return pIoResReqList;
}
status = STATUS_SUCCESS;
pWdmResourceList = &WdmRequirementsList->List[0];
pIoResReqList->m_InterfaceType = WdmRequirementsList->InterfaceType;
pIoResReqList->m_SlotNumber = WdmRequirementsList->SlotNumber;
for (i = 0; i < WdmRequirementsList->AlternativeLists; i++) {
FxIoResList *pResList;
pResList = new(FxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES)
FxIoResList(FxDriverGlobals, pIoResReqList);
if (pResList != NULL) {
status = pResList->AssignParentObject(pIoResReqList);
//
// Since we control our own lifetime, assigning the parent should
// never fail.
//
ASSERT(NT_SUCCESS(status));
status = pResList->BuildFromWdmList(&pWdmResourceList);
}
else {
//
// We failed to allocate a child collection. Clean up
// and break out of the loop.
//
status = STATUS_INSUFFICIENT_RESOURCES;
}
if (!NT_SUCCESS(status)) {
break;
}
}
if (!NT_SUCCESS(status)) {
//
// Cleanup and return a NULL object
//
pIoResReqList->DeleteObject();
pIoResReqList = NULL;
}
}
return pIoResReqList;
}
_Must_inspect_result_
PIO_RESOURCE_REQUIREMENTS_LIST
FxIoResReqList::CreateWdmList(
VOID
)
/*++
Routine Description:
Creates a WDM io resource requirements list based off of the current
contents of the collection
Arguments:
None
Return Value:
new WDM io resource requirements list allocated out of paged pool upon success,
NULL upon failure or an empty list
--*/
{
PIO_RESOURCE_REQUIREMENTS_LIST pRequirementsList;
FxCollectionEntry *cur, *end;
NTSTATUS status;
ULONG totalDescriptors;
ULONG size;
ULONG count;
ULONG tmp;
PFX_DRIVER_GLOBALS pFxDriverGlobals;
totalDescriptors = 0;
pRequirementsList = NULL;
count = Count();
pFxDriverGlobals = GetDriverGlobals();
if (count > 0) {
//
// The collection object should contain a set of child collections
// with each of the various requirement lists. Use the number of
// these collections to determine the size of our requirements
// list.
//
end = End();
for (cur = Start(); cur != end; cur = cur->Next()) {
status = RtlULongAdd(totalDescriptors,
((FxIoResList *) cur->m_Object)->Count(),
&totalDescriptors);
if (!NT_SUCCESS(status)) {
goto Overflow;
}
}
//
// We now have enough information to determine how much memory we
// need to allocate for our requirements list.
//
// size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
// (sizeof(IO_RESOURCE_LIST) * (count - 1)) +
// (sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescriptors) -
// (sizeof(IO_RESOURCE_DESCRIPTOR) * count);
//
// sizeof(IO_RESOURCE_DESCRIPTOR) * count is subtracted off because
// each IO_RESOURCE_LIST has an embedded IO_RESOURCE_DESCRIPTOR in it
// and we don't want to overallocated.
//
//
// To handle overflow each mathematical operation is split out into an
// overflow safe call.
//
size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
// sizeof(IO_RESOURCE_LIST) * (count - 1)
status = RtlULongMult(sizeof(IO_RESOURCE_LIST), count - 1, &tmp);
if (!NT_SUCCESS(status)) {
goto Overflow;
}
status = RtlULongAdd(size, tmp, &size);
if (!NT_SUCCESS(status)) {
goto Overflow;
}
// (sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescriptors)
status = RtlULongMult(sizeof(IO_RESOURCE_DESCRIPTOR),
totalDescriptors,
&tmp);
if (!NT_SUCCESS(status)) {
goto Overflow;
}
status = RtlULongAdd(size, tmp, &size);
if (!NT_SUCCESS(status)) {
goto Overflow;
}
// - sizeof(IO_RESOURCE_DESCRIPTOR) * Count() (note the subtraction!)
status = RtlULongMult(sizeof(IO_RESOURCE_DESCRIPTOR), count, &tmp);
if (!NT_SUCCESS(status)) {
goto Overflow;
}
// Sub, not Add!
status = RtlULongSub(size, tmp, &size);
if (!NT_SUCCESS(status)) {
goto Overflow;
}
pRequirementsList = (PIO_RESOURCE_REQUIREMENTS_LIST)
MxMemory::MxAllocatePoolWithTag(PagedPool, size, pFxDriverGlobals->Tag);
if (pRequirementsList != NULL) {
PIO_RESOURCE_LIST pList;
FxResourceIo *pResource;
pList = pRequirementsList->List;
//
// Start by zero initializing our structure
//
RtlZeroMemory(pRequirementsList, size);
//
// InterfaceType and BusNumber are unused for WDM, but InterfaceType
// is used by the arbiters.
//
pRequirementsList->InterfaceType = m_InterfaceType;
pRequirementsList->SlotNumber = m_SlotNumber;
//
// Now populate the requirements list with the resources from
// our collections.
//
pRequirementsList->ListSize = size;
pRequirementsList->AlternativeLists = Count();
end = End();
for (cur = Start(); cur != end; cur = cur->Next()) {
FxIoResList* pIoResList;
PIO_RESOURCE_DESCRIPTOR pDescriptor;
FxCollectionEntry *pIoResCur, *pIoResEnd;
pIoResList = (FxIoResList*) cur->m_Object;
pList->Version = 1;
pList->Revision = 1;
pList->Count = pIoResList->Count();
pDescriptor = pList->Descriptors;
pIoResEnd = pIoResList->End();
for (pIoResCur = pIoResList->Start();
pIoResCur != pIoResEnd;
pIoResCur = pIoResCur->Next()) {
pResource = (FxResourceIo *) pIoResCur->m_Object;
RtlCopyMemory(pDescriptor,
&pResource->m_Descriptor,
sizeof(pResource->m_Descriptor));
pDescriptor++;
}
pList = (PIO_RESOURCE_LIST) pDescriptor;
}
}
}
return pRequirementsList;
Overflow:
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
"Integer overflow occured when computing size of "
"IO_RESOURCE_REQUIREMENTS_LIST");
return NULL;
}