From 633c67bdbfddb4a0e50aac21af30932fa36f38f2 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Thu, 1 Apr 2010 22:10:38 +0000 Subject: [PATCH] [NTOSKRNL] - Add 2 parameters to IopUpdateResourceMap to allows for updating different keys - Implement IopDetectResourceConflict and IopCheckForResourceConflict but don't report the conflicts until we get a resource arbiter - Halfplement IoReportResourceForDetection svn path=/trunk/; revision=46654 --- reactos/ntoskrnl/io/pnpmgr/pnpmgr.c | 366 ++++++++++++++++++++++++- reactos/ntoskrnl/io/pnpmgr/pnpreport.c | 42 ++- 2 files changed, 390 insertions(+), 18 deletions(-) diff --git a/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c b/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c index d8b6c675ab0..9d490e2b482 100644 --- a/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c +++ b/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c @@ -57,7 +57,7 @@ IopTranslateDeviceResources( IN ULONG RequiredSize); NTSTATUS -IopUpdateResourceMap( +IopUpdateResourceMapForPnPDevice( IN PDEVICE_NODE DeviceNode); PDEVICE_NODE @@ -163,7 +163,7 @@ IopStartDevice( Status = IopTranslateDeviceResources(DeviceNode, RequiredLength); if (NT_SUCCESS(Status)) { - Status = IopUpdateResourceMap(DeviceNode); + Status = IopUpdateResourceMapForPnPDevice(DeviceNode); if (!NT_SUCCESS(Status)) { DPRINT("IopUpdateResourceMap() failed (Status 0x%08lx)\n", Status); @@ -735,7 +735,7 @@ IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath, } NTSTATUS -IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode) +IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode, PWCHAR Level1Key, PWCHAR Level2Key) { NTSTATUS Status; ULONG Disposition; @@ -760,7 +760,7 @@ IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode) if (!NT_SUCCESS(Status)) return Status; - RtlInitUnicodeString(&KeyName, L"PnP Manager"); + RtlInitUnicodeString(&KeyName, Level1Key); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, @@ -777,7 +777,7 @@ IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode) if (!NT_SUCCESS(Status)) return Status; - RtlInitUnicodeString(&KeyName, L"PnpManager"); + RtlInitUnicodeString(&KeyName, Level2Key); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, @@ -857,6 +857,12 @@ IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode) return STATUS_SUCCESS; } +NTSTATUS +IopUpdateResourceMapForPnPDevice(IN PDEVICE_NODE DeviceNode) +{ + return IopUpdateResourceMap(DeviceNode, L"PnP Manager", L"PnpManager"); +} + NTSTATUS IopSetDeviceInstanceData(HANDLE InstanceKey, PDEVICE_NODE DeviceNode) @@ -945,7 +951,349 @@ IopSetDeviceInstanceData(HANDLE InstanceKey, return STATUS_SUCCESS; } +BOOLEAN +IopCheckForResourceConflict( + IN PCM_RESOURCE_LIST ResourceList1, + IN PCM_RESOURCE_LIST ResourceList2) +{ + ULONG i1, i2, ii1, ii2; + BOOLEAN Result = FALSE; + for (i1 = 0; i1 < ResourceList1->Count; i1++) + { + PCM_PARTIAL_RESOURCE_LIST ResList1 = &ResourceList1->List[i1].PartialResourceList; + for (i2 = 0; i2 < ResourceList2->Count; i2++) + { + PCM_PARTIAL_RESOURCE_LIST ResList2 = &ResourceList2->List[i2].PartialResourceList; + for (ii1 = 0; ii1 < ResList1->Count; ii1++) + { + PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc1 = &ResList1->PartialDescriptors[ii1]; + + if (ResDesc1->ShareDisposition == CmResourceShareShared) + continue; + + for (ii2 = 0; ii2 < ResList2->Count; ii2++) + { + PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc2 = &ResList2->PartialDescriptors[ii2]; + + /* We don't care about shared resources */ + if (ResDesc2->ShareDisposition == CmResourceShareShared) + continue; + + /* Make sure we're comparing the same types */ + if (ResDesc1->Type != ResDesc2->Type) + continue; + + switch (ResDesc1->Type) + { + case CmResourceTypeMemory: + if ((ResDesc1->u.Memory.Start.QuadPart < ResDesc2->u.Memory.Start.QuadPart && + ResDesc1->u.Memory.Start.QuadPart + ResDesc1->u.Memory.Length > + ResDesc2->u.Memory.Start.QuadPart) || (ResDesc2->u.Memory.Start.QuadPart < + ResDesc1->u.Memory.Start.QuadPart && ResDesc2->u.Memory.Start.QuadPart + + ResDesc2->u.Memory.Length > ResDesc1->u.Memory.Start.QuadPart)) + { + DPRINT1("Resource conflict: Memory (0x%x to 0x%x vs. 0x%x to 0x%x)\n", + ResDesc1->u.Memory.Start.QuadPart, ResDesc1->u.Memory.Start.QuadPart + + ResDesc1->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 ((ResDesc1->u.Port.Start.QuadPart < ResDesc2->u.Port.Start.QuadPart && + ResDesc1->u.Port.Start.QuadPart + ResDesc1->u.Port.Length > + ResDesc2->u.Port.Start.QuadPart) || (ResDesc2->u.Port.Start.QuadPart < + ResDesc1->u.Port.Start.QuadPart && ResDesc2->u.Port.Start.QuadPart + + ResDesc2->u.Port.Length > ResDesc1->u.Port.Start.QuadPart)) + { + DPRINT1("Resource conflict: Port (0x%x to 0x%x vs. 0x%x to 0x%x)\n", + ResDesc1->u.Port.Start.QuadPart, ResDesc1->u.Port.Start.QuadPart + + ResDesc1->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 (ResDesc1->u.Interrupt.Vector == ResDesc2->u.Interrupt.Vector) + { + DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n", + ResDesc1->u.Interrupt.Vector, ResDesc1->u.Interrupt.Level, + ResDesc2->u.Interrupt.Vector, ResDesc2->u.Interrupt.Level); + + Result = TRUE; + + goto ByeBye; + } + break; + + case CmResourceTypeBusNumber: + if ((ResDesc1->u.BusNumber.Start < ResDesc2->u.BusNumber.Start && + ResDesc1->u.BusNumber.Start + ResDesc1->u.BusNumber.Length > + ResDesc2->u.BusNumber.Start) || (ResDesc2->u.BusNumber.Start < + ResDesc1->u.BusNumber.Start && ResDesc2->u.BusNumber.Start + + ResDesc2->u.BusNumber.Length > ResDesc1->u.BusNumber.Start)) + { + DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n", + ResDesc1->u.BusNumber.Start, ResDesc1->u.BusNumber.Start + + ResDesc1->u.BusNumber.Length, ResDesc2->u.BusNumber.Start, + ResDesc2->u.BusNumber.Start + ResDesc2->u.BusNumber.Length); + + Result = TRUE; + + goto ByeBye; + } + break; + + case CmResourceTypeDma: + if (ResDesc1->u.Dma.Channel == ResDesc2->u.Dma.Channel) + { + DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n", + ResDesc1->u.Dma.Channel, ResDesc1->u.Dma.Port, + ResDesc2->u.Dma.Channel, ResDesc2->u.Dma.Port); + + Result = TRUE; + + goto ByeBye; + } + break; + } + } + } + } + } + +ByeBye: + +#ifdef ENABLE_RESOURCE_CONFLICT_DETECTION + return Result; +#else + return FALSE; +#endif +} + +NTSTATUS +IopDetectResourceConflict( + IN PCM_RESOURCE_LIST ResourceList) +{ + 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 = 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 = 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)) + { + 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; +} + NTSTATUS IopAssignDeviceResources( IN PDEVICE_NODE DeviceNode, @@ -997,6 +1345,10 @@ IopAssignDeviceResources( } RtlCopyMemory(DeviceNode->ResourceList, DeviceNode->BootResources, Size); + Status = IopDetectResourceConflict(DeviceNode->ResourceList); + if (!NT_SUCCESS(Status)) + goto ByeBye; + *pRequiredSize = Size; return STATUS_SUCCESS; } @@ -1147,6 +1499,10 @@ IopAssignDeviceResources( DeviceNode->ResourceList->List[0].PartialResourceList.Count = NumberOfResources; + Status = IopDetectResourceConflict(DeviceNode->ResourceList); + if (!NT_SUCCESS(Status)) + goto ByeBye; + *pRequiredSize = Size; return STATUS_SUCCESS; diff --git a/reactos/ntoskrnl/io/pnpmgr/pnpreport.c b/reactos/ntoskrnl/io/pnpmgr/pnpreport.c index 69ccd6be43c..13e74148a83 100644 --- a/reactos/ntoskrnl/io/pnpmgr/pnpreport.c +++ b/reactos/ntoskrnl/io/pnpmgr/pnpreport.c @@ -36,9 +36,13 @@ IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode, PVOID Context); NTSTATUS -IopUpdateResourceMap( +IopUpdateResourceMapForPnPDevice( IN PDEVICE_NODE DeviceNode); +NTSTATUS +IopDetectResourceConflict( + IN PCM_RESOURCE_LIST ResourceList); + /* PRIVATE FUNCTIONS *********************************************************/ PWCHAR @@ -272,7 +276,7 @@ IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject, { Status = IopTranslateDeviceResources(DeviceNode, RequiredLength); if (NT_SUCCESS(Status)) - Status = IopUpdateResourceMap(DeviceNode); + Status = IopUpdateResourceMapForPnPDevice(DeviceNode); } IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES); @@ -301,7 +305,7 @@ IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject, } /* - * @unimplemented + * @halfplemented */ NTSTATUS NTAPI @@ -313,23 +317,35 @@ IoReportResourceForDetection(IN PDRIVER_OBJECT DriverObject, IN ULONG DeviceListSize OPTIONAL, OUT PBOOLEAN ConflictDetected) { - static int warned = 0; - if (!warned) - { - DPRINT1("IoReportResourceForDetection partly implemented\n"); - warned = 1; - } + PCM_RESOURCE_LIST ResourceList; + NTSTATUS Status; *ConflictDetected = FALSE; - if (PopSystemPowerDeviceNode && DriverListSize > 0) + if (!DriverList && !DeviceList) + return STATUS_INVALID_PARAMETER; + + /* Find the real list */ + if (!DriverList) + ResourceList = DeviceList; + else + ResourceList = DriverList; + + /* Look for a resource conflict */ + Status = IopDetectResourceConflict(ResourceList); + if (Status == STATUS_CONFLICTING_ADDRESSES) { - /* We hope legacy devices will be enumerated by ACPI */ + /* Oh noes */ *ConflictDetected = TRUE; - return STATUS_CONFLICTING_ADDRESSES; + } + else if (NT_SUCCESS(Status)) + { + /* Looks like we're good to go */ + + /* TODO: Claim the resources in the ResourceMap */ } - return STATUS_SUCCESS; + return Status; } VOID