[NTOS:PNP] Halfplement IoInvalidateDeviceState

Implement the correct start-stop sequence for resource rebalancing
without the actual rebalancing. Also move IoInvalidateDeviceState
processing into the enumeration thread as it should be.

CORE-17519
This commit is contained in:
Victor Perevertkin
2022-04-27 02:42:20 +03:00
parent 8f40fc7ede
commit cf0bc1c132
4 changed files with 169 additions and 85 deletions
+12 -1
View File
@@ -527,7 +527,8 @@ typedef enum _DEVICE_ACTION
PiActionEnumRootDevices, PiActionEnumRootDevices,
PiActionResetDevice, PiActionResetDevice,
PiActionAddBootDevices, PiActionAddBootDevices,
PiActionStartDevice PiActionStartDevice,
PiActionQueryState,
} DEVICE_ACTION; } DEVICE_ACTION;
// //
@@ -1403,6 +1404,16 @@ PiIrpQueryDeviceRelations(
_In_ PDEVICE_NODE DeviceNode, _In_ PDEVICE_NODE DeviceNode,
_In_ DEVICE_RELATION_TYPE Type); _In_ DEVICE_RELATION_TYPE Type);
NTSTATUS
PiIrpQueryResources(
_In_ PDEVICE_NODE DeviceNode,
_Out_ PCM_RESOURCE_LIST *Resources);
NTSTATUS
PiIrpQueryResourceRequirements(
_In_ PDEVICE_NODE DeviceNode,
_Out_ PIO_RESOURCE_REQUIREMENTS_LIST *Resources);
NTSTATUS NTSTATUS
PiIrpQueryDeviceText( PiIrpQueryDeviceText(
_In_ PDEVICE_NODE DeviceNode, _In_ PDEVICE_NODE DeviceNode,
+95 -83
View File
@@ -1552,8 +1552,8 @@ PiStartDeviceFinal(
DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status); DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
} }
/* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */ // Query the device state (IRP_MN_QUERY_PNP_DEVICE_STATE)
IoInvalidateDeviceState(DeviceNode->PhysicalDeviceObject); PiQueueDeviceAction(DeviceNode->PhysicalDeviceObject, PiActionQueryState, NULL, NULL);
DPRINT("Sending GUID_DEVICE_ARRIVAL %wZ\n", &DeviceNode->InstancePath); DPRINT("Sending GUID_DEVICE_ARRIVAL %wZ\n", &DeviceNode->InstancePath);
IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, &DeviceNode->InstancePath); IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, &DeviceNode->InstancePath);
@@ -2025,25 +2025,27 @@ IopRemoveDevice(PDEVICE_NODE DeviceNode)
return Status; return Status;
} }
/* /**
* @implemented * @brief Processes the IoInvalidateDeviceState request
*
* Sends IRP_MN_QUERY_PNP_DEVICE_STATE request and sets device node's flags
* according to the result.
* Tree reenumeration should be started upon a successful return of the function.
*
* @todo Do not return STATUS_SUCCESS if nothing is changed.
*/ */
VOID static
NTAPI NTSTATUS
IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject) PiUpdateDeviceState(
_In_ PDEVICE_NODE DeviceNode)
{ {
PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
PNP_DEVICE_STATE PnPFlags; PNP_DEVICE_STATE PnPFlags;
NTSTATUS Status; NTSTATUS Status;
Status = PiIrpQueryPnPDeviceState(DeviceNode, &PnPFlags); Status = PiIrpQueryPnPDeviceState(DeviceNode, &PnPFlags);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
if (Status != STATUS_NOT_SUPPORTED) return Status;
{
DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%lx\n", Status);
}
return;
} }
if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE) if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE)
@@ -2056,83 +2058,37 @@ IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
else else
DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI; DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
if ((PnPFlags & PNP_DEVICE_REMOVED) || if (PnPFlags & PNP_DEVICE_REMOVED || PnPFlags & PNP_DEVICE_DISABLED)
((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)))
{ {
/* Flag it if it's failed */ PiSetDevNodeProblem(DeviceNode,
if (PnPFlags & PNP_DEVICE_FAILED) PnPFlags & PNP_DEVICE_DISABLED
{ ? CM_PROB_HARDWARE_DISABLED
PiSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_POST_START); : CM_PROB_DEVICE_NOT_THERE);
}
DeviceNode->Flags |= DNF_DEVICE_GONE;
PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval); PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval);
} }
// it doesn't work anyway. A real resource rebalancing should be implemented else if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)
#if 0
else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))
{ {
/* Stop for resource rebalance */ // Query resource rebalance
Status = IopStopDevice(DeviceNode);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to stop device for rebalancing\n");
/* Stop failed so don't rebalance */ if (PnPFlags & PNP_DEVICE_FAILED)
PnPFlags &= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED; DeviceNode->Flags &= DNF_NON_STOPPED_REBALANCE;
} else
DeviceNode->Flags |= DNF_NON_STOPPED_REBALANCE;
// Clear DNF_NO_RESOURCE_REQUIRED just in case (will be set back if needed)
DeviceNode->Flags &= ~DNF_NO_RESOURCE_REQUIRED;
// This will be caught up later by enumeration
DeviceNode->Flags |= DNF_RESOURCE_REQUIREMENTS_CHANGED;
}
else if (PnPFlags & PNP_DEVICE_FAILED)
{
PiSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_POST_START);
PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval);
} }
/* Resource rebalance */ return STATUS_SUCCESS;
if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)
{
DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
Status = IopInitiatePnpIrp(PhysicalDeviceObject,
&IoStatusBlock,
IRP_MN_QUERY_RESOURCES,
NULL);
if (NT_SUCCESS(Status) && IoStatusBlock.Information)
{
DeviceNode->BootResources =
(PCM_RESOURCE_LIST)IoStatusBlock.Information;
IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
}
else
{
DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
DeviceNode->BootResources = NULL;
}
DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
Status = IopInitiatePnpIrp(PhysicalDeviceObject,
&IoStatusBlock,
IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
NULL);
if (NT_SUCCESS(Status))
{
DeviceNode->ResourceRequirements =
(PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
}
else
{
DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
DeviceNode->ResourceRequirements = NULL;
}
/* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
if (IopStartDevice(DeviceNode) != STATUS_SUCCESS)
{
DPRINT1("Restart after resource rebalance failed\n");
DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
DeviceNode->Flags |= DNF_START_FAILED;
IopRemoveDevice(DeviceNode);
}
}
#endif
} }
static static
@@ -2327,6 +2283,30 @@ cleanup:
&DeviceNode->InstancePath); &DeviceNode->InstancePath);
} }
static
VOID
PiFakeResourceRebalance(
_In_ PDEVICE_NODE DeviceNode)
{
ASSERT(DeviceNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED);
PCM_RESOURCE_LIST bootConfig = NULL;
PIO_RESOURCE_REQUIREMENTS_LIST resourceRequirements = NULL;
PiIrpQueryResources(DeviceNode, &bootConfig);
PiIrpQueryResourceRequirements(DeviceNode, &resourceRequirements);
DeviceNode->BootResources = bootConfig;
DeviceNode->ResourceRequirements = resourceRequirements;
if (bootConfig)
{
DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
}
DeviceNode->Flags &= ~DNF_RESOURCE_REQUIREMENTS_CHANGED;
}
static static
VOID VOID
PiDevNodeStateMachine( PiDevNodeStateMachine(
@@ -2420,12 +2400,28 @@ PiDevNodeStateMachine(
PiSetDevNodeState(currentNode, DeviceNodeEnumerateCompletion); PiSetDevNodeState(currentNode, DeviceNodeEnumerateCompletion);
doProcessAgain = TRUE; doProcessAgain = TRUE;
} }
else if (currentNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED)
{
if (currentNode->Flags & DNF_NON_STOPPED_REBALANCE)
{
PiFakeResourceRebalance(currentNode);
currentNode->Flags &= ~DNF_NON_STOPPED_REBALANCE;
}
else
{
PiIrpQueryStopDevice(currentNode);
PiSetDevNodeState(currentNode, DeviceNodeQueryStopped);
}
doProcessAgain = TRUE;
}
break; break;
case DeviceNodeQueryStopped: case DeviceNodeQueryStopped:
// we're here after sending IRP_MN_QUERY_STOP_DEVICE // we're here after sending IRP_MN_QUERY_STOP_DEVICE
status = currentNode->CompletionStatus; status = currentNode->CompletionStatus;
if (NT_SUCCESS(status)) if (NT_SUCCESS(status))
{ {
PiIrpStopDevice(currentNode);
PiSetDevNodeState(currentNode, DeviceNodeStopped); PiSetDevNodeState(currentNode, DeviceNodeStopped);
} }
else else
@@ -2433,10 +2429,14 @@ PiDevNodeStateMachine(
PiIrpCancelStopDevice(currentNode); PiIrpCancelStopDevice(currentNode);
PiSetDevNodeState(currentNode, DeviceNodeStarted); PiSetDevNodeState(currentNode, DeviceNodeStarted);
} }
doProcessAgain = TRUE;
break; break;
case DeviceNodeStopped: case DeviceNodeStopped:
// TODO: do resource rebalance (not implemented) // TODO: do resource rebalance (not implemented)
ASSERT(FALSE); PiFakeResourceRebalance(currentNode);
PiSetDevNodeState(currentNode, DeviceNodeDriversAdded);
doProcessAgain = TRUE;
break; break;
case DeviceNodeRestartCompletion: case DeviceNodeRestartCompletion:
break; break;
@@ -2522,6 +2522,8 @@ ActionToStr(
return "PiActionAddBootDevices"; return "PiActionAddBootDevices";
case PiActionStartDevice: case PiActionStartDevice:
return "PiActionStartDevice"; return "PiActionStartDevice";
case PiActionQueryState:
return "PiActionQueryState";
default: default:
return "(request unknown)"; return "(request unknown)";
} }
@@ -2596,6 +2598,16 @@ PipDeviceActionWorker(
} }
break; break;
case PiActionQueryState:
// First, do a IRP_MN_QUERY_PNP_DEVICE_STATE request,
// it will update node's flags and then do enumeration if something changed
status = PiUpdateDeviceState(deviceNode);
if (NT_SUCCESS(status))
{
PiDevNodeStateMachine(deviceNode);
}
break;
default: default:
DPRINT1("Unimplemented device action %u\n", Request->Action); DPRINT1("Unimplemented device action %u\n", Request->Action);
status = STATUS_NOT_IMPLEMENTED; status = STATUS_NOT_IMPLEMENTED;
+54 -1
View File
@@ -196,6 +196,58 @@ PiIrpQueryDeviceRelations(
return status; return status;
} }
// IRP_MN_QUERY_RESOURCES (0x0A)
NTSTATUS
PiIrpQueryResources(
_In_ PDEVICE_NODE DeviceNode,
_Out_ PCM_RESOURCE_LIST *Resources)
{
PAGED_CODE();
ASSERT(DeviceNode);
ULONG_PTR longRes;
IO_STACK_LOCATION stack = {
.MajorFunction = IRP_MJ_PNP,
.MinorFunction = IRP_MN_QUERY_RESOURCES
};
NTSTATUS status;
status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, (PVOID)&longRes);
if (NT_SUCCESS(status))
{
*Resources = (PVOID)longRes;
}
return status;
}
// IRP_MN_QUERY_RESOURCE_REQUIREMENTS (0x0B)
NTSTATUS
PiIrpQueryResourceRequirements(
_In_ PDEVICE_NODE DeviceNode,
_Out_ PIO_RESOURCE_REQUIREMENTS_LIST *Resources)
{
PAGED_CODE();
ASSERT(DeviceNode);
ULONG_PTR longRes;
IO_STACK_LOCATION stack = {
.MajorFunction = IRP_MJ_PNP,
.MinorFunction = IRP_MN_QUERY_RESOURCE_REQUIREMENTS
};
NTSTATUS status;
status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, (PVOID)&longRes);
if (NT_SUCCESS(status))
{
*Resources = (PVOID)longRes;
}
return status;
}
// IRP_MN_QUERY_DEVICE_TEXT (0x0C) // IRP_MN_QUERY_DEVICE_TEXT (0x0C)
NTSTATUS NTSTATUS
PiIrpQueryDeviceText( PiIrpQueryDeviceText(
@@ -236,7 +288,8 @@ PiIrpQueryPnPDeviceState(
PAGED_CODE(); PAGED_CODE();
ASSERT(DeviceNode); ASSERT(DeviceNode);
ASSERT(DeviceNode->State == DeviceNodeStartPostWork || ASSERT(DeviceNode->State == DeviceNodeResourcesAssigned ||
DeviceNode->State == DeviceNodeStartPostWork ||
DeviceNode->State == DeviceNodeStarted); DeviceNode->State == DeviceNodeStarted);
ULONG_PTR longState; ULONG_PTR longState;
+8
View File
@@ -2412,3 +2412,11 @@ IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
AddressSpace, AddressSpace,
TranslatedAddress); TranslatedAddress);
} }
VOID
NTAPI
IoInvalidateDeviceState(
IN PDEVICE_OBJECT DeviceObject)
{
PiQueueDeviceAction(DeviceObject, PiActionQueryState, NULL, NULL);
}