mirror of
https://github.com/reactos/reactos.git
synced 2024-11-10 00:34:39 +00:00
c2d0d784c7
- Create a branch to do a proper merge of USB work from a trunk base instead of from cmake-bringup - In the future, DO NOT under any circumstances branch another branch. This leads to merge problems! svn path=/branches/usb-bringup-trunk/; revision=55018
1221 lines
40 KiB
C
1221 lines
40 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* COPYRIGHT: GPL - See COPYING in the top level directory
|
|
* FILE: ntoskrnl/io/pnpmgr/pnpres.c
|
|
* PURPOSE: Resource handling code
|
|
* PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
|
|
* ReactOS Portable Systems Group
|
|
*/
|
|
|
|
#include <ntoskrnl.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
static
|
|
BOOLEAN
|
|
IopCheckDescriptorForConflict(PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc, OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
|
|
{
|
|
CM_RESOURCE_LIST CmList;
|
|
NTSTATUS Status;
|
|
|
|
CmList.Count = 1;
|
|
CmList.List[0].InterfaceType = InterfaceTypeUndefined;
|
|
CmList.List[0].BusNumber = 0;
|
|
CmList.List[0].PartialResourceList.Version = 1;
|
|
CmList.List[0].PartialResourceList.Revision = 1;
|
|
CmList.List[0].PartialResourceList.Count = 1;
|
|
CmList.List[0].PartialResourceList.PartialDescriptors[0] = *CmDesc;
|
|
|
|
Status = IopDetectResourceConflict(&CmList, TRUE, ConflictingDescriptor);
|
|
if (Status == STATUS_CONFLICTING_ADDRESSES)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
IopFindBusNumberResource(
|
|
IN PIO_RESOURCE_DESCRIPTOR IoDesc,
|
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
|
|
{
|
|
ULONG Start;
|
|
CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
|
|
|
|
ASSERT(IoDesc->Type == CmDesc->Type);
|
|
ASSERT(IoDesc->Type == CmResourceTypeBusNumber);
|
|
|
|
for (Start = IoDesc->u.BusNumber.MinBusNumber;
|
|
Start <= IoDesc->u.BusNumber.MaxBusNumber;
|
|
Start++)
|
|
{
|
|
CmDesc->u.BusNumber.Length = IoDesc->u.BusNumber.Length;
|
|
CmDesc->u.BusNumber.Start = Start;
|
|
|
|
if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
|
|
{
|
|
Start += ConflictingDesc.u.BusNumber.Start + ConflictingDesc.u.BusNumber.Length;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
IopFindMemoryResource(
|
|
IN PIO_RESOURCE_DESCRIPTOR IoDesc,
|
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
|
|
{
|
|
LONGLONG Start;
|
|
CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
|
|
|
|
ASSERT(IoDesc->Type == CmDesc->Type);
|
|
ASSERT(IoDesc->Type == CmResourceTypeMemory);
|
|
|
|
/* HACK */
|
|
if (IoDesc->u.Memory.Alignment == 0) IoDesc->u.Memory.Alignment = 1;
|
|
|
|
for (Start = IoDesc->u.Memory.MinimumAddress.QuadPart;
|
|
Start <= IoDesc->u.Memory.MaximumAddress.QuadPart;
|
|
Start += IoDesc->u.Memory.Alignment)
|
|
{
|
|
CmDesc->u.Memory.Length = IoDesc->u.Memory.Length;
|
|
CmDesc->u.Memory.Start.QuadPart = Start;
|
|
|
|
if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
|
|
{
|
|
Start += ConflictingDesc.u.Memory.Start.QuadPart +
|
|
ConflictingDesc.u.Memory.Length;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
IopFindPortResource(
|
|
IN PIO_RESOURCE_DESCRIPTOR IoDesc,
|
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
|
|
{
|
|
LONGLONG Start;
|
|
CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
|
|
|
|
ASSERT(IoDesc->Type == CmDesc->Type);
|
|
ASSERT(IoDesc->Type == CmResourceTypePort);
|
|
|
|
/* HACK */
|
|
if (IoDesc->u.Port.Alignment == 0) IoDesc->u.Port.Alignment = 1;
|
|
|
|
for (Start = IoDesc->u.Port.MinimumAddress.QuadPart;
|
|
Start <= IoDesc->u.Port.MaximumAddress.QuadPart;
|
|
Start += IoDesc->u.Port.Alignment)
|
|
{
|
|
CmDesc->u.Port.Length = IoDesc->u.Port.Length;
|
|
CmDesc->u.Port.Start.QuadPart = Start;
|
|
|
|
if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
|
|
{
|
|
Start += ConflictingDesc.u.Port.Start.QuadPart + ConflictingDesc.u.Port.Length;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
IopFindDmaResource(
|
|
IN PIO_RESOURCE_DESCRIPTOR IoDesc,
|
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
|
|
{
|
|
ULONG Channel;
|
|
|
|
ASSERT(IoDesc->Type == CmDesc->Type);
|
|
ASSERT(IoDesc->Type == CmResourceTypeDma);
|
|
|
|
for (Channel = IoDesc->u.Dma.MinimumChannel;
|
|
Channel <= IoDesc->u.Dma.MaximumChannel;
|
|
Channel++)
|
|
{
|
|
CmDesc->u.Dma.Channel = Channel;
|
|
CmDesc->u.Dma.Port = 0;
|
|
|
|
if (!IopCheckDescriptorForConflict(CmDesc, NULL))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
IopFindInterruptResource(
|
|
IN PIO_RESOURCE_DESCRIPTOR IoDesc,
|
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
|
|
{
|
|
ULONG Vector;
|
|
|
|
ASSERT(IoDesc->Type == CmDesc->Type);
|
|
ASSERT(IoDesc->Type == CmResourceTypeInterrupt);
|
|
|
|
for (Vector = IoDesc->u.Interrupt.MinimumVector;
|
|
Vector <= IoDesc->u.Interrupt.MaximumVector;
|
|
Vector++)
|
|
{
|
|
CmDesc->u.Interrupt.Vector = Vector;
|
|
CmDesc->u.Interrupt.Level = Vector;
|
|
CmDesc->u.Interrupt.Affinity = (KAFFINITY)-1;
|
|
|
|
if (!IopCheckDescriptorForConflict(CmDesc, NULL))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
IopCreateResourceListFromRequirements(
|
|
IN PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList,
|
|
OUT PCM_RESOURCE_LIST *ResourceList)
|
|
{
|
|
ULONG i, ii, Size;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc;
|
|
|
|
Size = FIELD_OFFSET(CM_RESOURCE_LIST, List);
|
|
for (i = 0; i < RequirementsList->AlternativeLists; i++)
|
|
{
|
|
PIO_RESOURCE_LIST ResList = &RequirementsList->List[i];
|
|
Size += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors)
|
|
+ ResList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
|
}
|
|
|
|
*ResourceList = ExAllocatePool(PagedPool, Size);
|
|
if (!*ResourceList)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
(*ResourceList)->Count = 1;
|
|
(*ResourceList)->List[0].BusNumber = RequirementsList->BusNumber;
|
|
(*ResourceList)->List[0].InterfaceType = RequirementsList->InterfaceType;
|
|
(*ResourceList)->List[0].PartialResourceList.Version = 1;
|
|
(*ResourceList)->List[0].PartialResourceList.Revision = 1;
|
|
(*ResourceList)->List[0].PartialResourceList.Count = 0;
|
|
|
|
ResDesc = &(*ResourceList)->List[0].PartialResourceList.PartialDescriptors[0];
|
|
|
|
for (i = 0; i < RequirementsList->AlternativeLists; i++)
|
|
{
|
|
PIO_RESOURCE_LIST ResList = &RequirementsList->List[i];
|
|
for (ii = 0; ii < ResList->Count; ii++)
|
|
{
|
|
PIO_RESOURCE_DESCRIPTOR ReqDesc = &ResList->Descriptors[ii];
|
|
BOOLEAN FoundResource = TRUE;
|
|
|
|
/* FIXME: Handle alternate ranges */
|
|
if (ReqDesc->Option == IO_RESOURCE_ALTERNATIVE)
|
|
continue;
|
|
|
|
ResDesc->Type = ReqDesc->Type;
|
|
ResDesc->Flags = ReqDesc->Flags;
|
|
ResDesc->ShareDisposition = ReqDesc->ShareDisposition;
|
|
|
|
switch (ReqDesc->Type)
|
|
{
|
|
case CmResourceTypeInterrupt:
|
|
if (!IopFindInterruptResource(ReqDesc, ResDesc))
|
|
{
|
|
DPRINT1("Failed to find an available interrupt resource (0x%x to 0x%x)\n",
|
|
ReqDesc->u.Interrupt.MinimumVector, ReqDesc->u.Interrupt.MaximumVector);
|
|
|
|
if (ReqDesc->Option == 0)
|
|
{
|
|
ExFreePool(*ResourceList);
|
|
*ResourceList = NULL;
|
|
return STATUS_CONFLICTING_ADDRESSES;
|
|
}
|
|
|
|
FoundResource = FALSE;
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypePort:
|
|
if (!IopFindPortResource(ReqDesc, ResDesc))
|
|
{
|
|
DPRINT1("Failed to find an available port resource (0x%I64x to 0x%I64x length: 0x%x)\n",
|
|
ReqDesc->u.Port.MinimumAddress.QuadPart, ReqDesc->u.Port.MaximumAddress.QuadPart,
|
|
ReqDesc->u.Port.Length);
|
|
|
|
if (ReqDesc->Option == 0)
|
|
{
|
|
ExFreePool(*ResourceList);
|
|
*ResourceList = NULL;
|
|
return STATUS_CONFLICTING_ADDRESSES;
|
|
}
|
|
|
|
FoundResource = FALSE;
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypeMemory:
|
|
if (!IopFindMemoryResource(ReqDesc, ResDesc))
|
|
{
|
|
DPRINT1("Failed to find an available memory resource (0x%I64x to 0x%I64x length: 0x%x)\n",
|
|
ReqDesc->u.Memory.MinimumAddress.QuadPart, ReqDesc->u.Memory.MaximumAddress.QuadPart,
|
|
ReqDesc->u.Memory.Length);
|
|
|
|
if (ReqDesc->Option == 0)
|
|
{
|
|
ExFreePool(*ResourceList);
|
|
*ResourceList = NULL;
|
|
return STATUS_CONFLICTING_ADDRESSES;
|
|
}
|
|
|
|
FoundResource = FALSE;
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypeBusNumber:
|
|
if (!IopFindBusNumberResource(ReqDesc, ResDesc))
|
|
{
|
|
DPRINT1("Failed to find an available bus number resource (0x%x to 0x%x length: 0x%x)\n",
|
|
ReqDesc->u.BusNumber.MinBusNumber, ReqDesc->u.BusNumber.MaxBusNumber,
|
|
ReqDesc->u.BusNumber.Length);
|
|
|
|
if (ReqDesc->Option == 0)
|
|
{
|
|
ExFreePool(*ResourceList);
|
|
*ResourceList = NULL;
|
|
return STATUS_CONFLICTING_ADDRESSES;
|
|
}
|
|
|
|
FoundResource = FALSE;
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
if (!IopFindDmaResource(ReqDesc, ResDesc))
|
|
{
|
|
DPRINT1("Failed to find an available dma resource (0x%x to 0x%x)\n",
|
|
ReqDesc->u.Dma.MinimumChannel, ReqDesc->u.Dma.MaximumChannel);
|
|
|
|
if (ReqDesc->Option == 0)
|
|
{
|
|
ExFreePool(*ResourceList);
|
|
*ResourceList = NULL;
|
|
return STATUS_CONFLICTING_ADDRESSES;
|
|
}
|
|
|
|
FoundResource = FALSE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("Unsupported resource type: %x\n", ReqDesc->Type);
|
|
FoundResource = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (FoundResource)
|
|
{
|
|
(*ResourceList)->List[0].PartialResourceList.Count++;
|
|
ResDesc++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
IopCheckResourceDescriptor(
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc,
|
|
IN PCM_RESOURCE_LIST ResourceList,
|
|
IN BOOLEAN Silent,
|
|
OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
|
|
{
|
|
ULONG i, ii;
|
|
BOOLEAN Result = FALSE;
|
|
|
|
for (i = 0; i < ResourceList->Count; i++)
|
|
{
|
|
PCM_PARTIAL_RESOURCE_LIST ResList = &ResourceList->List[i].PartialResourceList;
|
|
for (ii = 0; ii < ResList->Count; ii++)
|
|
{
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc2 = &ResList->PartialDescriptors[ii];
|
|
|
|
/* We don't care about shared resources */
|
|
if (ResDesc->ShareDisposition == CmResourceShareShared &&
|
|
ResDesc2->ShareDisposition == CmResourceShareShared)
|
|
continue;
|
|
|
|
/* Make sure we're comparing the same types */
|
|
if (ResDesc->Type != ResDesc2->Type)
|
|
continue;
|
|
|
|
switch (ResDesc->Type)
|
|
{
|
|
case CmResourceTypeMemory:
|
|
if ((ResDesc->u.Memory.Start.QuadPart < ResDesc2->u.Memory.Start.QuadPart &&
|
|
ResDesc->u.Memory.Start.QuadPart + ResDesc->u.Memory.Length >
|
|
ResDesc2->u.Memory.Start.QuadPart) || (ResDesc2->u.Memory.Start.QuadPart <
|
|
ResDesc->u.Memory.Start.QuadPart && ResDesc2->u.Memory.Start.QuadPart +
|
|
ResDesc2->u.Memory.Length > ResDesc->u.Memory.Start.QuadPart))
|
|
{
|
|
if (!Silent)
|
|
{
|
|
DPRINT1("Resource conflict: Memory (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
|
|
ResDesc->u.Memory.Start.QuadPart, ResDesc->u.Memory.Start.QuadPart +
|
|
ResDesc->u.Memory.Length, ResDesc2->u.Memory.Start.QuadPart,
|
|
ResDesc2->u.Memory.Start.QuadPart + ResDesc2->u.Memory.Length);
|
|
}
|
|
|
|
Result = TRUE;
|
|
|
|
goto ByeBye;
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypePort:
|
|
if ((ResDesc->u.Port.Start.QuadPart < ResDesc2->u.Port.Start.QuadPart &&
|
|
ResDesc->u.Port.Start.QuadPart + ResDesc->u.Port.Length >
|
|
ResDesc2->u.Port.Start.QuadPart) || (ResDesc2->u.Port.Start.QuadPart <
|
|
ResDesc->u.Port.Start.QuadPart && ResDesc2->u.Port.Start.QuadPart +
|
|
ResDesc2->u.Port.Length > ResDesc->u.Port.Start.QuadPart))
|
|
{
|
|
if (!Silent)
|
|
{
|
|
DPRINT1("Resource conflict: Port (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
|
|
ResDesc->u.Port.Start.QuadPart, ResDesc->u.Port.Start.QuadPart +
|
|
ResDesc->u.Port.Length, ResDesc2->u.Port.Start.QuadPart,
|
|
ResDesc2->u.Port.Start.QuadPart + ResDesc2->u.Port.Length);
|
|
}
|
|
|
|
Result = TRUE;
|
|
|
|
goto ByeBye;
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
if (ResDesc->u.Interrupt.Vector == ResDesc2->u.Interrupt.Vector)
|
|
{
|
|
if (!Silent)
|
|
{
|
|
DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n",
|
|
ResDesc->u.Interrupt.Vector, ResDesc->u.Interrupt.Level,
|
|
ResDesc2->u.Interrupt.Vector, ResDesc2->u.Interrupt.Level);
|
|
}
|
|
|
|
Result = TRUE;
|
|
|
|
goto ByeBye;
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypeBusNumber:
|
|
if ((ResDesc->u.BusNumber.Start < ResDesc2->u.BusNumber.Start &&
|
|
ResDesc->u.BusNumber.Start + ResDesc->u.BusNumber.Length >
|
|
ResDesc2->u.BusNumber.Start) || (ResDesc2->u.BusNumber.Start <
|
|
ResDesc->u.BusNumber.Start && ResDesc2->u.BusNumber.Start +
|
|
ResDesc2->u.BusNumber.Length > ResDesc->u.BusNumber.Start))
|
|
{
|
|
if (!Silent)
|
|
{
|
|
DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
|
|
ResDesc->u.BusNumber.Start, ResDesc->u.BusNumber.Start +
|
|
ResDesc->u.BusNumber.Length, ResDesc2->u.BusNumber.Start,
|
|
ResDesc2->u.BusNumber.Start + ResDesc2->u.BusNumber.Length);
|
|
}
|
|
|
|
Result = TRUE;
|
|
|
|
goto ByeBye;
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
if (ResDesc->u.Dma.Channel == ResDesc2->u.Dma.Channel)
|
|
{
|
|
if (!Silent)
|
|
{
|
|
DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n",
|
|
ResDesc->u.Dma.Channel, ResDesc->u.Dma.Port,
|
|
ResDesc2->u.Dma.Channel, ResDesc2->u.Dma.Port);
|
|
}
|
|
|
|
Result = TRUE;
|
|
|
|
goto ByeBye;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ByeBye:
|
|
|
|
if (Result && ConflictingDescriptor)
|
|
{
|
|
RtlCopyMemory(ConflictingDescriptor,
|
|
ResDesc,
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
static
|
|
NTSTATUS
|
|
IopUpdateControlKeyWithResources(IN PDEVICE_NODE DeviceNode)
|
|
{
|
|
UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
|
|
UNICODE_STRING Control = RTL_CONSTANT_STRING(L"Control");
|
|
UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"AllocConfig");
|
|
HANDLE EnumKey, InstanceKey, ControlKey;
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
/* Open the Enum key */
|
|
Status = IopOpenRegistryKeyEx(&EnumKey, NULL, &EnumRoot, KEY_ENUMERATE_SUB_KEYS);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
/* Open the instance key (eg. Root\PNP0A03) */
|
|
Status = IopOpenRegistryKeyEx(&InstanceKey, EnumKey, &DeviceNode->InstancePath, KEY_ENUMERATE_SUB_KEYS);
|
|
ZwClose(EnumKey);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
/* Create/Open the Control key */
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&Control,
|
|
OBJ_CASE_INSENSITIVE,
|
|
InstanceKey,
|
|
NULL);
|
|
Status = ZwCreateKey(&ControlKey,
|
|
KEY_SET_VALUE,
|
|
&ObjectAttributes,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_VOLATILE,
|
|
NULL);
|
|
ZwClose(InstanceKey);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
/* Write the resource list */
|
|
Status = ZwSetValueKey(ControlKey,
|
|
&ValueName,
|
|
0,
|
|
REG_RESOURCE_LIST,
|
|
DeviceNode->ResourceList,
|
|
PnpDetermineResourceListSize(DeviceNode->ResourceList));
|
|
ZwClose(ControlKey);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
NTSTATUS
|
|
IopFilterResourceRequirements(IN PDEVICE_NODE DeviceNode)
|
|
{
|
|
IO_STACK_LOCATION Stack;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n");
|
|
|
|
Stack.Parameters.FilterResourceRequirements.IoResourceRequirementList = DeviceNode->ResourceRequirements;
|
|
Status = IopInitiatePnpIrp(
|
|
DeviceNode->PhysicalDeviceObject,
|
|
&IoStatusBlock,
|
|
IRP_MN_FILTER_RESOURCE_REQUIREMENTS,
|
|
&Stack);
|
|
if (!NT_SUCCESS(Status) && Status != STATUS_NOT_SUPPORTED)
|
|
{
|
|
DPRINT1("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n");
|
|
return Status;
|
|
}
|
|
else if (NT_SUCCESS(Status) && IoStatusBlock.Information)
|
|
{
|
|
DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode, PWCHAR Level1Key, PWCHAR Level2Key)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG Disposition;
|
|
HANDLE PnpMgrLevel1, PnpMgrLevel2, ResourceMapKey;
|
|
UNICODE_STRING KeyName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
RtlInitUnicodeString(&KeyName,
|
|
L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
|
|
0,
|
|
NULL);
|
|
Status = ZwCreateKey(&ResourceMapKey,
|
|
KEY_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_VOLATILE,
|
|
&Disposition);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
RtlInitUnicodeString(&KeyName, Level1Key);
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
|
|
ResourceMapKey,
|
|
NULL);
|
|
Status = ZwCreateKey(&PnpMgrLevel1,
|
|
KEY_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_VOLATILE,
|
|
&Disposition);
|
|
ZwClose(ResourceMapKey);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
RtlInitUnicodeString(&KeyName, Level2Key);
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
|
|
PnpMgrLevel1,
|
|
NULL);
|
|
Status = ZwCreateKey(&PnpMgrLevel2,
|
|
KEY_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_VOLATILE,
|
|
&Disposition);
|
|
ZwClose(PnpMgrLevel1);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
if (DeviceNode->ResourceList)
|
|
{
|
|
UNICODE_STRING NameU;
|
|
UNICODE_STRING RawSuffix, TranslatedSuffix;
|
|
ULONG OldLength = 0;
|
|
|
|
ASSERT(DeviceNode->ResourceListTranslated);
|
|
|
|
RtlInitUnicodeString(&TranslatedSuffix, L".Translated");
|
|
RtlInitUnicodeString(&RawSuffix, L".Raw");
|
|
|
|
Status = IoGetDeviceProperty(DeviceNode->PhysicalDeviceObject,
|
|
DevicePropertyPhysicalDeviceObjectName,
|
|
0,
|
|
NULL,
|
|
&OldLength);
|
|
if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
ASSERT(OldLength);
|
|
|
|
NameU.Buffer = ExAllocatePool(PagedPool, OldLength + TranslatedSuffix.Length);
|
|
if (!NameU.Buffer)
|
|
{
|
|
ZwClose(PnpMgrLevel2);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
NameU.Length = 0;
|
|
NameU.MaximumLength = (USHORT)OldLength + TranslatedSuffix.Length;
|
|
|
|
Status = IoGetDeviceProperty(DeviceNode->PhysicalDeviceObject,
|
|
DevicePropertyPhysicalDeviceObjectName,
|
|
NameU.MaximumLength,
|
|
NameU.Buffer,
|
|
&OldLength);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ZwClose(PnpMgrLevel2);
|
|
ExFreePool(NameU.Buffer);
|
|
return Status;
|
|
}
|
|
}
|
|
else if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Some failure */
|
|
ZwClose(PnpMgrLevel2);
|
|
return Status;
|
|
}
|
|
else
|
|
{
|
|
/* This should never happen */
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
NameU.Length = (USHORT)OldLength;
|
|
|
|
RtlAppendUnicodeStringToString(&NameU, &RawSuffix);
|
|
|
|
Status = ZwSetValueKey(PnpMgrLevel2,
|
|
&NameU,
|
|
0,
|
|
REG_RESOURCE_LIST,
|
|
DeviceNode->ResourceList,
|
|
PnpDetermineResourceListSize(DeviceNode->ResourceList));
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ZwClose(PnpMgrLevel2);
|
|
ExFreePool(NameU.Buffer);
|
|
return Status;
|
|
}
|
|
|
|
/* "Remove" the suffix by setting the length back to what it used to be */
|
|
NameU.Length = (USHORT)OldLength;
|
|
|
|
RtlAppendUnicodeStringToString(&NameU, &TranslatedSuffix);
|
|
|
|
Status = ZwSetValueKey(PnpMgrLevel2,
|
|
&NameU,
|
|
0,
|
|
REG_RESOURCE_LIST,
|
|
DeviceNode->ResourceListTranslated,
|
|
PnpDetermineResourceListSize(DeviceNode->ResourceListTranslated));
|
|
ZwClose(PnpMgrLevel2);
|
|
ExFreePool(NameU.Buffer);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
}
|
|
else
|
|
{
|
|
ZwClose(PnpMgrLevel2);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
IopUpdateResourceMapForPnPDevice(IN PDEVICE_NODE DeviceNode)
|
|
{
|
|
return IopUpdateResourceMap(DeviceNode, L"PnP Manager", L"PnpManager");
|
|
}
|
|
|
|
static
|
|
NTSTATUS
|
|
IopTranslateDeviceResources(
|
|
IN PDEVICE_NODE DeviceNode)
|
|
{
|
|
PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated;
|
|
ULONG i, j, ListSize;
|
|
NTSTATUS Status;
|
|
|
|
if (!DeviceNode->ResourceList)
|
|
{
|
|
DeviceNode->ResourceListTranslated = NULL;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* That's easy to translate a resource list. Just copy the
|
|
* untranslated one and change few fields in the copy
|
|
*/
|
|
ListSize = PnpDetermineResourceListSize(DeviceNode->ResourceList);
|
|
|
|
DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool, ListSize);
|
|
if (!DeviceNode->ResourceListTranslated)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
RtlCopyMemory(DeviceNode->ResourceListTranslated, DeviceNode->ResourceList, ListSize);
|
|
|
|
for (i = 0; i < DeviceNode->ResourceList->Count; i++)
|
|
{
|
|
pPartialResourceList = &DeviceNode->ResourceList->List[i].PartialResourceList;
|
|
for (j = 0; j < pPartialResourceList->Count; j++)
|
|
{
|
|
DescriptorRaw = &pPartialResourceList->PartialDescriptors[j];
|
|
DescriptorTranslated = &DeviceNode->ResourceListTranslated->List[i].PartialResourceList.PartialDescriptors[j];
|
|
switch (DescriptorRaw->Type)
|
|
{
|
|
case CmResourceTypePort:
|
|
{
|
|
ULONG AddressSpace = 1; /* IO space */
|
|
if (!HalTranslateBusAddress(
|
|
DeviceNode->ResourceList->List[i].InterfaceType,
|
|
DeviceNode->ResourceList->List[i].BusNumber,
|
|
DescriptorRaw->u.Port.Start,
|
|
&AddressSpace,
|
|
&DescriptorTranslated->u.Port.Start))
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
DPRINT1("Failed to translate port resource (Start: 0x%I64x)\n", DescriptorRaw->u.Port.Start.QuadPart);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (AddressSpace == 0)
|
|
{
|
|
DPRINT1("Guessed incorrect address space: 1 -> 0\n");
|
|
|
|
/* FIXME: I think all other CM_RESOURCE_PORT_XXX flags are
|
|
* invalid for this state but I'm not 100% sure */
|
|
DescriptorRaw->Flags =
|
|
DescriptorTranslated->Flags = CM_RESOURCE_PORT_MEMORY;
|
|
}
|
|
break;
|
|
}
|
|
case CmResourceTypeInterrupt:
|
|
{
|
|
DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector(
|
|
DeviceNode->ResourceList->List[i].InterfaceType,
|
|
DeviceNode->ResourceList->List[i].BusNumber,
|
|
DescriptorRaw->u.Interrupt.Level,
|
|
DescriptorRaw->u.Interrupt.Vector,
|
|
(PKIRQL)&DescriptorTranslated->u.Interrupt.Level,
|
|
&DescriptorTranslated->u.Interrupt.Affinity);
|
|
|
|
if (!DescriptorTranslated->u.Interrupt.Vector)
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
DPRINT1("Failed to translate interrupt resource (Vector: 0x%x | Level: 0x%x)\n", DescriptorRaw->u.Interrupt.Vector,
|
|
DescriptorRaw->u.Interrupt.Level);
|
|
goto cleanup;
|
|
}
|
|
break;
|
|
}
|
|
case CmResourceTypeMemory:
|
|
{
|
|
ULONG AddressSpace = 0; /* Memory space */
|
|
if (!HalTranslateBusAddress(
|
|
DeviceNode->ResourceList->List[i].InterfaceType,
|
|
DeviceNode->ResourceList->List[i].BusNumber,
|
|
DescriptorRaw->u.Memory.Start,
|
|
&AddressSpace,
|
|
&DescriptorTranslated->u.Memory.Start))
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
DPRINT1("Failed to translate memory resource (Start: 0x%I64x)\n", DescriptorRaw->u.Memory.Start.QuadPart);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (AddressSpace != 0)
|
|
{
|
|
DPRINT1("Guessed incorrect address space: 0 -> 1\n");
|
|
|
|
/* This should never happen for memory space */
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
case CmResourceTypeDma:
|
|
case CmResourceTypeBusNumber:
|
|
case CmResourceTypeDeviceSpecific:
|
|
/* Nothing to do */
|
|
break;
|
|
default:
|
|
DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw->Type);
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
}
|
|
return STATUS_SUCCESS;
|
|
|
|
cleanup:
|
|
/* Yes! Also delete ResourceList because ResourceList and
|
|
* ResourceListTranslated should be a pair! */
|
|
ExFreePool(DeviceNode->ResourceList);
|
|
DeviceNode->ResourceList = NULL;
|
|
if (DeviceNode->ResourceListTranslated)
|
|
{
|
|
ExFreePool(DeviceNode->ResourceListTranslated);
|
|
DeviceNode->ResourceList = NULL;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IopAssignDeviceResources(
|
|
IN PDEVICE_NODE DeviceNode)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG ListSize;
|
|
|
|
IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
|
|
|
|
Status = IopFilterResourceRequirements(DeviceNode);
|
|
if (!NT_SUCCESS(Status))
|
|
goto ByeBye;
|
|
|
|
if (!DeviceNode->BootResources && !DeviceNode->ResourceRequirements)
|
|
{
|
|
DeviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
|
|
DeviceNode->Flags &= ~DNF_ASSIGNING_RESOURCES;
|
|
|
|
/* No resource needed for this device */
|
|
DeviceNode->ResourceList = NULL;
|
|
DeviceNode->ResourceListTranslated = NULL;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Fill DeviceNode->ResourceList
|
|
* FIXME: the PnP arbiter should go there!
|
|
* Actually, use the BootResources if provided, else the resource requirements
|
|
*/
|
|
|
|
if (DeviceNode->BootResources)
|
|
{
|
|
ListSize = PnpDetermineResourceListSize(DeviceNode->BootResources);
|
|
|
|
DeviceNode->ResourceList = ExAllocatePool(PagedPool, ListSize);
|
|
if (!DeviceNode->ResourceList)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto ByeBye;
|
|
}
|
|
RtlCopyMemory(DeviceNode->ResourceList, DeviceNode->BootResources, ListSize);
|
|
|
|
Status = IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL);
|
|
if (NT_SUCCESS(Status) || !DeviceNode->ResourceRequirements)
|
|
{
|
|
if (!NT_SUCCESS(Status) && !DeviceNode->ResourceRequirements)
|
|
{
|
|
DPRINT1("Using conflicting boot resources because no requirements were supplied!\n");
|
|
}
|
|
|
|
goto Finish;
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode->InstancePath);
|
|
ExFreePool(DeviceNode->ResourceList);
|
|
DeviceNode->ResourceList = NULL;
|
|
}
|
|
}
|
|
|
|
Status = IopCreateResourceListFromRequirements(DeviceNode->ResourceRequirements,
|
|
&DeviceNode->ResourceList);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to create a resource list from supplied resources for %wZ\n", &DeviceNode->InstancePath);
|
|
goto ByeBye;
|
|
}
|
|
|
|
/* IopCreateResourceListFromRequirements should NEVER succeed with a conflicting list */
|
|
ASSERT(IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL) != STATUS_CONFLICTING_ADDRESSES);
|
|
|
|
Finish:
|
|
Status = IopTranslateDeviceResources(DeviceNode);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to translate resources for %wZ\n", &DeviceNode->InstancePath);
|
|
goto ByeBye;
|
|
}
|
|
|
|
Status = IopUpdateResourceMapForPnPDevice(DeviceNode);
|
|
if (!NT_SUCCESS(Status))
|
|
goto ByeBye;
|
|
|
|
Status = IopUpdateControlKeyWithResources(DeviceNode);
|
|
if (!NT_SUCCESS(Status))
|
|
goto ByeBye;
|
|
|
|
IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED);
|
|
|
|
IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
ByeBye:
|
|
if (DeviceNode->ResourceList)
|
|
{
|
|
ExFreePool(DeviceNode->ResourceList);
|
|
DeviceNode->ResourceList = NULL;
|
|
}
|
|
|
|
DeviceNode->ResourceListTranslated = NULL;
|
|
|
|
IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
|
|
|
|
return Status;
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
IopCheckForResourceConflict(
|
|
IN PCM_RESOURCE_LIST ResourceList1,
|
|
IN PCM_RESOURCE_LIST ResourceList2,
|
|
IN BOOLEAN Silent,
|
|
OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
|
|
{
|
|
ULONG i, ii;
|
|
BOOLEAN Result = FALSE;
|
|
|
|
for (i = 0; i < ResourceList1->Count; i++)
|
|
{
|
|
PCM_PARTIAL_RESOURCE_LIST ResList = &ResourceList1->List[i].PartialResourceList;
|
|
for (ii = 0; ii < ResList->Count; ii++)
|
|
{
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc = &ResList->PartialDescriptors[ii];
|
|
|
|
Result = IopCheckResourceDescriptor(ResDesc,
|
|
ResourceList2,
|
|
Silent,
|
|
ConflictingDescriptor);
|
|
if (Result) goto ByeBye;
|
|
}
|
|
}
|
|
|
|
ByeBye:
|
|
|
|
return Result;
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
IopDetectResourceConflict(
|
|
IN PCM_RESOURCE_LIST ResourceList,
|
|
IN BOOLEAN Silent,
|
|
OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
|
|
{
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING KeyName;
|
|
HANDLE ResourceMapKey = INVALID_HANDLE_VALUE, ChildKey2 = INVALID_HANDLE_VALUE, ChildKey3 = INVALID_HANDLE_VALUE;
|
|
ULONG KeyInformationLength, RequiredLength, KeyValueInformationLength, KeyNameInformationLength;
|
|
PKEY_BASIC_INFORMATION KeyInformation;
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
|
|
PKEY_VALUE_BASIC_INFORMATION KeyNameInformation;
|
|
ULONG ChildKeyIndex1 = 0, ChildKeyIndex2 = 0, ChildKeyIndex3 = 0;
|
|
NTSTATUS Status;
|
|
|
|
RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
|
|
InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, 0, NULL);
|
|
Status = ZwOpenKey(&ResourceMapKey, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* The key is missing which means we are the first device */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
Status = ZwEnumerateKey(ResourceMapKey,
|
|
ChildKeyIndex1,
|
|
KeyBasicInformation,
|
|
NULL,
|
|
0,
|
|
&RequiredLength);
|
|
if (Status == STATUS_NO_MORE_ENTRIES)
|
|
break;
|
|
else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
KeyInformationLength = RequiredLength;
|
|
KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
|
|
if (!KeyInformation)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto cleanup;
|
|
}
|
|
|
|
Status = ZwEnumerateKey(ResourceMapKey,
|
|
ChildKeyIndex1,
|
|
KeyBasicInformation,
|
|
KeyInformation,
|
|
KeyInformationLength,
|
|
&RequiredLength);
|
|
}
|
|
else
|
|
goto cleanup;
|
|
ChildKeyIndex1++;
|
|
if (!NT_SUCCESS(Status))
|
|
goto cleanup;
|
|
|
|
KeyName.Buffer = KeyInformation->Name;
|
|
KeyName.MaximumLength = KeyName.Length = (USHORT)KeyInformation->NameLength;
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
ResourceMapKey,
|
|
NULL);
|
|
Status = ZwOpenKey(&ChildKey2, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
|
|
ExFreePool(KeyInformation);
|
|
if (!NT_SUCCESS(Status))
|
|
goto cleanup;
|
|
|
|
while (TRUE)
|
|
{
|
|
Status = ZwEnumerateKey(ChildKey2,
|
|
ChildKeyIndex2,
|
|
KeyBasicInformation,
|
|
NULL,
|
|
0,
|
|
&RequiredLength);
|
|
if (Status == STATUS_NO_MORE_ENTRIES)
|
|
break;
|
|
else if (Status == STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
KeyInformationLength = RequiredLength;
|
|
KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
|
|
if (!KeyInformation)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto cleanup;
|
|
}
|
|
|
|
Status = ZwEnumerateKey(ChildKey2,
|
|
ChildKeyIndex2,
|
|
KeyBasicInformation,
|
|
KeyInformation,
|
|
KeyInformationLength,
|
|
&RequiredLength);
|
|
}
|
|
else
|
|
goto cleanup;
|
|
ChildKeyIndex2++;
|
|
if (!NT_SUCCESS(Status))
|
|
goto cleanup;
|
|
|
|
KeyName.Buffer = KeyInformation->Name;
|
|
KeyName.MaximumLength = KeyName.Length = (USHORT)KeyInformation->NameLength;
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
ChildKey2,
|
|
NULL);
|
|
Status = ZwOpenKey(&ChildKey3, KEY_QUERY_VALUE, &ObjectAttributes);
|
|
ExFreePool(KeyInformation);
|
|
if (!NT_SUCCESS(Status))
|
|
goto cleanup;
|
|
|
|
while (TRUE)
|
|
{
|
|
Status = ZwEnumerateValueKey(ChildKey3,
|
|
ChildKeyIndex3,
|
|
KeyValuePartialInformation,
|
|
NULL,
|
|
0,
|
|
&RequiredLength);
|
|
if (Status == STATUS_NO_MORE_ENTRIES)
|
|
break;
|
|
else if (Status == STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
KeyValueInformationLength = RequiredLength;
|
|
KeyValueInformation = ExAllocatePool(PagedPool, KeyValueInformationLength);
|
|
if (!KeyValueInformation)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto cleanup;
|
|
}
|
|
|
|
Status = ZwEnumerateValueKey(ChildKey3,
|
|
ChildKeyIndex3,
|
|
KeyValuePartialInformation,
|
|
KeyValueInformation,
|
|
KeyValueInformationLength,
|
|
&RequiredLength);
|
|
}
|
|
else
|
|
goto cleanup;
|
|
if (!NT_SUCCESS(Status))
|
|
goto cleanup;
|
|
|
|
Status = ZwEnumerateValueKey(ChildKey3,
|
|
ChildKeyIndex3,
|
|
KeyValueBasicInformation,
|
|
NULL,
|
|
0,
|
|
&RequiredLength);
|
|
if (Status == STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
KeyNameInformationLength = RequiredLength;
|
|
KeyNameInformation = ExAllocatePool(PagedPool, KeyNameInformationLength + sizeof(WCHAR));
|
|
if (!KeyNameInformation)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto cleanup;
|
|
}
|
|
|
|
Status = ZwEnumerateValueKey(ChildKey3,
|
|
ChildKeyIndex3,
|
|
KeyValueBasicInformation,
|
|
KeyNameInformation,
|
|
KeyNameInformationLength,
|
|
&RequiredLength);
|
|
}
|
|
else
|
|
goto cleanup;
|
|
|
|
ChildKeyIndex3++;
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
goto cleanup;
|
|
|
|
KeyNameInformation->Name[KeyNameInformation->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
|
|
|
|
/* Skip translated entries */
|
|
if (wcsstr(KeyNameInformation->Name, L".Translated"))
|
|
{
|
|
ExFreePool(KeyNameInformation);
|
|
continue;
|
|
}
|
|
|
|
ExFreePool(KeyNameInformation);
|
|
|
|
if (IopCheckForResourceConflict(ResourceList,
|
|
(PCM_RESOURCE_LIST)KeyValueInformation->Data,
|
|
Silent,
|
|
ConflictingDescriptor))
|
|
{
|
|
ExFreePool(KeyValueInformation);
|
|
Status = STATUS_CONFLICTING_ADDRESSES;
|
|
goto cleanup;
|
|
}
|
|
|
|
ExFreePool(KeyValueInformation);
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
if (ResourceMapKey != INVALID_HANDLE_VALUE)
|
|
ZwClose(ResourceMapKey);
|
|
if (ChildKey2 != INVALID_HANDLE_VALUE)
|
|
ZwClose(ChildKey2);
|
|
if (ChildKey3 != INVALID_HANDLE_VALUE)
|
|
ZwClose(ChildKey3);
|
|
|
|
if (Status == STATUS_NO_MORE_ENTRIES)
|
|
Status = STATUS_SUCCESS;
|
|
|
|
return Status;
|
|
}
|
|
|