mirror of
https://github.com/reactos/reactos.git
synced 2024-12-26 17:14:41 +00:00
535 lines
16 KiB
C
535 lines
16 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* COPYRIGHT: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* FILE: ntoskrnl/io/debug.c
|
|
* PURPOSE: Useful functions for debugging IO and PNP managers
|
|
* PROGRAMMERS: Copyright 2020 Vadim Galyant <vgal@rambler.ru>
|
|
*/
|
|
|
|
#include <ntoskrnl.h>
|
|
#include "pnpio.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
extern PDEVICE_NODE IopRootDeviceNode;
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
/* CmResource */
|
|
|
|
/* PipDumpCmResourceDescriptor() displays information about a Cm Descriptor
|
|
|
|
DebugLevel: 0 - always dump
|
|
1 - dump if not defined NDEBUG
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
PipDumpCmResourceDescriptor(
|
|
_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
|
|
_In_ ULONG DebugLevel)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (DebugLevel != 0)
|
|
{
|
|
#ifdef NDEBUG
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
if (Descriptor == NULL)
|
|
{
|
|
DPRINT1("Dump CmDescriptor: Descriptor == NULL\n");
|
|
return;
|
|
}
|
|
|
|
switch (Descriptor->Type)
|
|
{
|
|
case CmResourceTypePort:
|
|
DPRINT1("[%p:%X:%X] IO: Start %X:%X, Len %X\n", Descriptor, Descriptor->ShareDisposition, Descriptor->Flags, Descriptor->u.Port.Start.HighPart, Descriptor->u.Port.Start.LowPart, Descriptor->u.Port.Length);
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
DPRINT1("[%p:%X:%X] INT: Lev %X Vec %X Aff %IX\n", Descriptor, Descriptor->ShareDisposition, Descriptor->Flags, Descriptor->u.Interrupt.Level, Descriptor->u.Interrupt.Vector, Descriptor->u.Interrupt.Affinity);
|
|
break;
|
|
|
|
case CmResourceTypeMemory:
|
|
DPRINT1("[%p:%X:%X] MEM: %X:%X Len %X\n", Descriptor, Descriptor->ShareDisposition, Descriptor->Flags, Descriptor->u.Memory.Start.HighPart, Descriptor->u.Memory.Start.LowPart, Descriptor->u.Memory.Length);
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
DPRINT1("[%p:%X:%X] DMA: Channel %X Port %X\n", Descriptor, Descriptor->ShareDisposition, Descriptor->Flags, Descriptor->u.Dma.Channel, Descriptor->u.Dma.Port);
|
|
break;
|
|
|
|
case CmResourceTypeDeviceSpecific:
|
|
DPRINT1("[%p:%X:%X] DAT: DataSize %X\n", Descriptor, Descriptor->ShareDisposition, Descriptor->Flags, Descriptor->u.DeviceSpecificData.DataSize);
|
|
break;
|
|
|
|
case CmResourceTypeBusNumber:
|
|
DPRINT1("[%p:%X:%X] BUS: Start %X Len %X Reserv %X\n", Descriptor, Descriptor->ShareDisposition, Descriptor->Flags, Descriptor->u.BusNumber.Start, Descriptor->u.BusNumber.Length, Descriptor->u.BusNumber.Reserved);
|
|
break;
|
|
|
|
case CmResourceTypeDevicePrivate:
|
|
DPRINT1("[%p:%X:%X] PVT: D[0] %X D[1] %X D[2] %X\n", Descriptor, Descriptor->ShareDisposition, Descriptor->Flags, Descriptor->u.DevicePrivate.Data[0], Descriptor->u.DevicePrivate.Data[1], Descriptor->u.DevicePrivate.Data[2]);
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("[%p] Unknown type %X\n", Descriptor, Descriptor->Type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* PipGetNextCmPartialDescriptor() return poiner to next a Cm Descriptor */
|
|
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR
|
|
NTAPI
|
|
PipGetNextCmPartialDescriptor(
|
|
_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor)
|
|
{
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR NextDescriptor;
|
|
|
|
/* Assume the descriptors are the fixed size ones */
|
|
NextDescriptor = CmDescriptor + 1;
|
|
|
|
/* But check if this is actually a variable-sized descriptor */
|
|
if (CmDescriptor->Type == CmResourceTypeDeviceSpecific)
|
|
{
|
|
/* Add the size of the variable section as well */
|
|
NextDescriptor = (PVOID)((ULONG_PTR)NextDescriptor +
|
|
CmDescriptor->u.DeviceSpecificData.DataSize);
|
|
}
|
|
|
|
/* Now the correct pointer has been computed, return it */
|
|
return NextDescriptor;
|
|
}
|
|
|
|
/* PipDumpCmResourceList() displays information about a Cm List
|
|
|
|
DebugLevel: 0 - always dump
|
|
1 - dump if not defined NDEBUG
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
PipDumpCmResourceList(
|
|
_In_ PCM_RESOURCE_LIST CmResource,
|
|
_In_ ULONG DebugLevel)
|
|
{
|
|
PCM_FULL_RESOURCE_DESCRIPTOR FullList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
|
|
ULONG ix;
|
|
ULONG jx;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (DebugLevel != 0)
|
|
{
|
|
#ifdef NDEBUG
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
DPRINT1("Dump CmList: CmResource %p\n", CmResource);
|
|
|
|
if (CmResource == NULL)
|
|
{
|
|
DPRINT1("PipDumpCmResourceList: CmResource == NULL\n");
|
|
return;
|
|
}
|
|
|
|
if (CmResource->Count == 0)
|
|
{
|
|
DPRINT1("PipDumpCmResourceList: CmResource->Count == 0\n");
|
|
return;
|
|
}
|
|
|
|
DPRINT1("FullList Count %x\n", CmResource->Count);
|
|
|
|
FullList = &CmResource->List[0];
|
|
|
|
for (ix = 0; ix < CmResource->Count; ix++)
|
|
{
|
|
DPRINT1("List #%X Iface %X Bus #%X Ver.%X Rev.%X Count %X\n",
|
|
ix,
|
|
FullList->InterfaceType,
|
|
FullList->BusNumber,
|
|
FullList->PartialResourceList.Version,
|
|
FullList->PartialResourceList.Revision,
|
|
FullList->PartialResourceList.Count);
|
|
|
|
Descriptor = FullList->PartialResourceList.PartialDescriptors;
|
|
|
|
for (jx = 0; jx < FullList->PartialResourceList.Count; jx++)
|
|
{
|
|
PipDumpCmResourceDescriptor(Descriptor, DebugLevel);
|
|
Descriptor = PipGetNextCmPartialDescriptor(Descriptor);
|
|
}
|
|
|
|
FullList = (PCM_FULL_RESOURCE_DESCRIPTOR)Descriptor;
|
|
}
|
|
}
|
|
|
|
/* IoResource */
|
|
|
|
/* PipDumpIoResourceDescriptor() displays information about a Io Descriptor
|
|
|
|
DebugLevel: 0 - always dump
|
|
1 - dump if not defined NDEBUG
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
PipDumpIoResourceDescriptor(
|
|
_In_ PIO_RESOURCE_DESCRIPTOR Descriptor,
|
|
_In_ ULONG DebugLevel)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (DebugLevel != 0)
|
|
{
|
|
#ifdef NDEBUG
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
if (Descriptor == NULL)
|
|
{
|
|
DPRINT1("DumpResourceDescriptor: Descriptor == 0\n");
|
|
return;
|
|
}
|
|
|
|
switch (Descriptor->Type)
|
|
{
|
|
case CmResourceTypeNull:
|
|
DPRINT1("[%p:%X:%X] O: Len %X Align %X Min %I64X, Max %I64X\n", Descriptor, Descriptor->Option, Descriptor->ShareDisposition, Descriptor->u.Generic.Length, Descriptor->u.Generic.Alignment, Descriptor->u.Generic.MinimumAddress.QuadPart, Descriptor->u.Generic.MaximumAddress.QuadPart);
|
|
break;
|
|
|
|
case CmResourceTypePort:
|
|
DPRINT1("[%p:%X:%X] IO: Min %X:%X, Max %X:%X, Align %X Len %X\n", Descriptor, Descriptor->Option, Descriptor->ShareDisposition, Descriptor->u.Port.MinimumAddress.HighPart, Descriptor->u.Port.MinimumAddress.LowPart, Descriptor->u.Port.MaximumAddress.HighPart, Descriptor->u.Port.MaximumAddress.LowPart, Descriptor->u.Port.Alignment, Descriptor->u.Port.Length);
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
DPRINT1("[%p:%X:%X] INT: Min %X Max %X\n", Descriptor, Descriptor->Option, Descriptor->ShareDisposition, Descriptor->u.Interrupt.MinimumVector, Descriptor->u.Interrupt.MaximumVector);
|
|
break;
|
|
|
|
case CmResourceTypeMemory:
|
|
DPRINT1("[%p:%X:%X] MEM: Min %X:%X, Max %X:%X, Align %X Len %X\n", Descriptor, Descriptor->Option, Descriptor->ShareDisposition, Descriptor->u.Memory.MinimumAddress.HighPart, Descriptor->u.Memory.MinimumAddress.LowPart, Descriptor->u.Memory.MaximumAddress.HighPart, Descriptor->u.Memory.MaximumAddress.LowPart, Descriptor->u.Memory.Alignment, Descriptor->u.Memory.Length);
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
DPRINT1("[%p:%X:%X] DMA: Min %X Max %X\n", Descriptor, Descriptor->Option, Descriptor->ShareDisposition, Descriptor->u.Dma.MinimumChannel, Descriptor->u.Dma.MaximumChannel);
|
|
break;
|
|
|
|
case CmResourceTypeBusNumber:
|
|
DPRINT1("[%p:%X:%X] BUS: Min %X Max %X Len %X\n", Descriptor, Descriptor->Option, Descriptor->ShareDisposition, Descriptor->u.BusNumber.MinBusNumber, Descriptor->u.BusNumber.MaxBusNumber, Descriptor->u.BusNumber.Length);
|
|
break;
|
|
|
|
case CmResourceTypeConfigData:
|
|
DPRINT1("[%p:%X:%X] CFG: Priority %X\n", Descriptor, Descriptor->Option, Descriptor->ShareDisposition, Descriptor->u.ConfigData.Priority);
|
|
break;
|
|
|
|
case CmResourceTypeDevicePrivate:
|
|
DPRINT1("[%p:%X:%X] DAT: %X %X %X\n", Descriptor, Descriptor->Option, Descriptor->ShareDisposition, Descriptor->u.DevicePrivate.Data[0], Descriptor->u.DevicePrivate.Data[1], Descriptor->u.DevicePrivate.Data[2]);
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("[%p:%X:%X]. Unknown type %X\n", Descriptor, Descriptor->Option, Descriptor->ShareDisposition, Descriptor->Type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* PipDumpResourceRequirementsList() displays information about a Io List
|
|
|
|
DebugLevel: 0 - always dump
|
|
1 - dump if not defined NDEBUG
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
PipDumpResourceRequirementsList(
|
|
_In_ PIO_RESOURCE_REQUIREMENTS_LIST IoResource,
|
|
_In_ ULONG DebugLevel)
|
|
{
|
|
PIO_RESOURCE_LIST AltList;
|
|
PIO_RESOURCE_DESCRIPTOR Descriptor;
|
|
ULONG ix;
|
|
ULONG jx;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (DebugLevel != 0)
|
|
{
|
|
#ifdef NDEBUG
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
if (IoResource == NULL)
|
|
{
|
|
DPRINT1("PipDumpResourceRequirementsList: IoResource == 0\n");
|
|
return;
|
|
}
|
|
|
|
DPRINT1("Dump RequirementsList: IoResource %p\n", IoResource);
|
|
DPRINT1("Interface %X Bus %X Slot %X AlternativeLists %X\n",
|
|
IoResource->InterfaceType,
|
|
IoResource->BusNumber,
|
|
IoResource->SlotNumber,
|
|
IoResource->AlternativeLists);
|
|
|
|
AltList = &IoResource->List[0];
|
|
|
|
if (IoResource->AlternativeLists < 1)
|
|
{
|
|
DPRINT1("PipDumpResourceRequirementsList: AlternativeLists < 1\n");
|
|
return;
|
|
}
|
|
|
|
for (ix = 0; ix < IoResource->AlternativeLists; ix++)
|
|
{
|
|
DPRINT1("AltList %p, AltList->Count %X\n", AltList, AltList->Count);
|
|
|
|
for (jx = 0; jx < AltList->Count; jx++)
|
|
{
|
|
Descriptor = &AltList->Descriptors[jx];
|
|
PipDumpIoResourceDescriptor(Descriptor, DebugLevel);
|
|
}
|
|
|
|
AltList = (PIO_RESOURCE_LIST)(AltList->Descriptors + AltList->Count);
|
|
DPRINT1("End Descriptors %p\n", AltList);
|
|
}
|
|
}
|
|
|
|
/* Gets the name of the device node state. */
|
|
|
|
PWSTR
|
|
NTAPI
|
|
PipGetDeviceNodeStateName(
|
|
_In_ PNP_DEVNODE_STATE State)
|
|
{
|
|
switch (State)
|
|
{
|
|
case DeviceNodeUnspecified:
|
|
return L"DeviceNodeUnspecified";
|
|
|
|
case DeviceNodeUninitialized:
|
|
return L"DeviceNodeUninitialized";
|
|
|
|
case DeviceNodeInitialized:
|
|
return L"DeviceNodeInitialized";
|
|
|
|
case DeviceNodeDriversAdded:
|
|
return L"DeviceNodeDriversAdded";
|
|
|
|
case DeviceNodeResourcesAssigned:
|
|
return L"DeviceNodeResourcesAssigned";
|
|
|
|
case DeviceNodeStartPending:
|
|
return L"DeviceNodeStartPending";
|
|
|
|
case DeviceNodeStartCompletion:
|
|
return L"DeviceNodeStartCompletion";
|
|
|
|
case DeviceNodeStartPostWork:
|
|
return L"DeviceNodeStartPostWork";
|
|
|
|
case DeviceNodeStarted:
|
|
return L"DeviceNodeStarted";
|
|
|
|
case DeviceNodeQueryStopped:
|
|
return L"DeviceNodeQueryStopped";
|
|
|
|
case DeviceNodeStopped:
|
|
return L"DeviceNodeStopped";
|
|
|
|
case DeviceNodeRestartCompletion:
|
|
return L"DeviceNodeRestartCompletion";
|
|
|
|
case DeviceNodeEnumeratePending:
|
|
return L"DeviceNodeEnumeratePending";
|
|
|
|
case DeviceNodeEnumerateCompletion:
|
|
return L"DeviceNodeEnumerateCompletion";
|
|
|
|
case DeviceNodeAwaitingQueuedDeletion:
|
|
return L"DeviceNodeAwaitingQueuedDeletion";
|
|
|
|
case DeviceNodeAwaitingQueuedRemoval:
|
|
return L"DeviceNodeAwaitingQueuedRemoval";
|
|
|
|
case DeviceNodeQueryRemoved:
|
|
return L"DeviceNodeQueryRemoved";
|
|
|
|
case DeviceNodeRemovePendingCloses:
|
|
return L"DeviceNodeRemovePendingCloses";
|
|
|
|
case DeviceNodeRemoved:
|
|
return L"DeviceNodeRemoved";
|
|
|
|
case DeviceNodeDeletePendingCloses:
|
|
return L"DeviceNodeDeletePendingCloses";
|
|
|
|
case DeviceNodeDeleted:
|
|
return L"DeviceNodeDeleted";
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (State != MaxDeviceNodeState)
|
|
{
|
|
DPRINT1("PipGetDeviceNodeStateName: Unknown State %X\n", State);
|
|
}
|
|
|
|
return L"";
|
|
}
|
|
|
|
/* Dump list arbiters for the device node */
|
|
|
|
VOID
|
|
NTAPI
|
|
PipDumpArbiters(
|
|
_In_ PDEVICE_NODE DeviceNode,
|
|
_In_ ULONG NodeLevel)
|
|
{
|
|
DPRINT("Level %X DevNode %p for PDO %p\n", NodeLevel, DeviceNode, DeviceNode->PhysicalDeviceObject);
|
|
|
|
/* Definitions needed for arbiter */
|
|
UNIMPLEMENTED;
|
|
}
|
|
|
|
/* PipDumpDeviceNode() displays information about a device node
|
|
|
|
Flags is bitmask parametr:
|
|
1 - traversal of all children nodes
|
|
2 - dump allocated resources and boot configuration resources
|
|
4 - dump resources required
|
|
8 - dump translated resources
|
|
|
|
DebugLevel: 0 - always dump
|
|
1 - dump if not defined NDEBUG
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
PipDumpDeviceNode(
|
|
_In_ PDEVICE_NODE DeviceNode,
|
|
_In_ ULONG NodeLevel,
|
|
_In_ ULONG Flags,
|
|
_In_ ULONG DebugLevel)
|
|
{
|
|
PDEVICE_NODE ChildDeviceNode;
|
|
|
|
if (DebugLevel != 0)
|
|
{
|
|
#ifdef NDEBUG
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
DPRINT1("* Level %X DevNode %p for PDO %p\n", NodeLevel, DeviceNode, DeviceNode->PhysicalDeviceObject);
|
|
DPRINT1("Instance %wZ\n", &DeviceNode->InstancePath);
|
|
if (DeviceNode->ServiceName.Length)
|
|
DPRINT1("Service %wZ\n", &DeviceNode->ServiceName);
|
|
#if 0
|
|
/* It is not used yet */
|
|
DPRINT1("State %X %S\n", DeviceNode->State, PipGetDeviceNodeStateName(DeviceNode->State));
|
|
DPRINT1("Prev State %X %S\n", DeviceNode->PreviousState, PipGetDeviceNodeStateName(DeviceNode->PreviousState));
|
|
#endif
|
|
if (DeviceNode->Problem)
|
|
DPRINT1("Problem %X\n", DeviceNode->Problem);
|
|
#if 0
|
|
/* It is not implemeted yet */
|
|
PipDumpArbiters(DeviceNode, NodeLevel);
|
|
#endif
|
|
|
|
/* Allocated resources and Boot configuration (reported by IRP_MN_QUERY_RESOURCES)*/
|
|
if (Flags & PIP_DUMP_FL_RES_ALLOCATED)
|
|
{
|
|
if (DeviceNode->ResourceList)
|
|
{
|
|
DPRINT1("---------- ResourceList ----------\n");
|
|
PipDumpCmResourceList(DeviceNode->ResourceList, DebugLevel);
|
|
}
|
|
|
|
if (DeviceNode->BootResources)
|
|
{
|
|
DPRINT1("---------- BootResources ----------\n");
|
|
PipDumpCmResourceList(DeviceNode->BootResources, DebugLevel);
|
|
}
|
|
}
|
|
|
|
/* Resources required (reported by IRP_MN_FILTER_RESOURCE_REQUIREMENTS) */
|
|
if (Flags & PIP_DUMP_FL_RES_REQUIREMENTS)
|
|
{
|
|
if (DeviceNode->ResourceRequirements)
|
|
{
|
|
DPRINT1("---------- ResourceRequirements ----------\n");
|
|
PipDumpResourceRequirementsList(DeviceNode->ResourceRequirements, DebugLevel);
|
|
}
|
|
}
|
|
|
|
/* Translated resources (AllocatedResourcesTranslated) */
|
|
if (Flags & PIP_DUMP_FL_RES_TRANSLATED)
|
|
{
|
|
if (DeviceNode->ResourceListTranslated)
|
|
{
|
|
DPRINT1("---------- ResourceListTranslated ----------\n");
|
|
PipDumpCmResourceList(DeviceNode->ResourceListTranslated, DebugLevel);
|
|
}
|
|
}
|
|
|
|
/* Traversal of all children nodes */
|
|
if (Flags & PIP_DUMP_FL_ALL_NODES)
|
|
{
|
|
for (ChildDeviceNode = DeviceNode->Child;
|
|
ChildDeviceNode != NULL;
|
|
ChildDeviceNode = ChildDeviceNode->Sibling)
|
|
{
|
|
/* Recursive call */
|
|
PipDumpDeviceNode(ChildDeviceNode, (NodeLevel + 1), Flags, DebugLevel);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* PipDumpDeviceNodes() displays information about a node(s) in the device tree
|
|
|
|
If DeviceNode is NULL, then the dump starts at the beginning of the device tree.
|
|
|
|
Flags is bitmask parametr:
|
|
1 - traversal of all children nodes
|
|
2 - dump allocated resources and boot configuration resources
|
|
4 - dump resources required
|
|
8 - dump translated resources
|
|
|
|
DebugLevel: 0 - always dump
|
|
1 - dump if not defined NDEBUG
|
|
|
|
See also: Windows DDK -> General Driver Information ->
|
|
Kernel-Mode Driver Architecture -> Design Guide -> Plug and Play ->
|
|
Introduction to Plug and Play -> Hardware Resources
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
PipDumpDeviceNodes(
|
|
_In_ PDEVICE_NODE DeviceNode,
|
|
_In_ ULONG Flags,
|
|
_In_ ULONG DebugLevel)
|
|
{
|
|
if (DebugLevel != 0)
|
|
{
|
|
#ifdef NDEBUG
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
DPRINT1("PipDumpDeviceNodes: DeviceNode %X, Flags %X Level %X\n", DeviceNode, Flags, DebugLevel);
|
|
|
|
if (DeviceNode == NULL)
|
|
{
|
|
DeviceNode = IopRootDeviceNode;
|
|
}
|
|
|
|
PipDumpDeviceNode(DeviceNode, 0, Flags, DebugLevel);
|
|
}
|
|
|
|
/* EOF */
|