xref: /reactos/ntoskrnl/io/debug.c (revision 1734f297)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * COPYRIGHT:       GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * FILE:            ntoskrnl/io/debug.c
5  * PURPOSE:         Useful functions for debugging IO and PNP managers
6  * PROGRAMMERS:     Copyright 2020 Vadim Galyant <vgal@rambler.ru>
7  */
8 
9 #include <ntoskrnl.h>
10 #include "pnpio.h"
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* GLOBALS ********************************************************************/
16 
17 extern PDEVICE_NODE IopRootDeviceNode;
18 
19 /* FUNCTIONS ******************************************************************/
20 
21 /* CmResource */
22 
23 /* PipDumpCmResourceDescriptor() displays information about a Cm Descriptor
24 
25    DebugLevel: 0 - always dump
26                1 - dump if not defined NDEBUG
27 */
28 VOID
29 NTAPI
30 PipDumpCmResourceDescriptor(
31     _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
32     _In_ ULONG DebugLevel)
33 {
34     PAGED_CODE();
35 
36     if (DebugLevel != 0)
37     {
38 #ifdef NDEBUG
39         return;
40 #endif
41     }
42 
43     if (Descriptor == NULL)
44     {
45         DPRINT1("Dump CmDescriptor: Descriptor == NULL\n");
46         return;
47     }
48 
49     switch (Descriptor->Type)
50     {
51         case CmResourceTypePort:
52             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);
53             break;
54 
55         case CmResourceTypeInterrupt:
56             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);
57             break;
58 
59         case CmResourceTypeMemory:
60             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);
61             break;
62 
63         case CmResourceTypeDma:
64             DPRINT1("[%p:%X:%X] DMA: Channel %X Port %X\n", Descriptor, Descriptor->ShareDisposition, Descriptor->Flags, Descriptor->u.Dma.Channel, Descriptor->u.Dma.Port);
65             break;
66 
67         case CmResourceTypeDeviceSpecific:
68             DPRINT1("[%p:%X:%X] DAT: DataSize %X\n", Descriptor, Descriptor->ShareDisposition, Descriptor->Flags, Descriptor->u.DeviceSpecificData.DataSize);
69             break;
70 
71         case CmResourceTypeBusNumber:
72             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);
73             break;
74 
75         case CmResourceTypeDevicePrivate:
76             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]);
77             break;
78 
79         default:
80             DPRINT1("[%p] Unknown type %X\n", Descriptor, Descriptor->Type);
81             break;
82     }
83 }
84 
85 /* PipGetNextCmPartialDescriptor() return poiner to next a Cm Descriptor */
86 
87 PCM_PARTIAL_RESOURCE_DESCRIPTOR
88 NTAPI
89 PipGetNextCmPartialDescriptor(
90     _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor)
91 {
92     PCM_PARTIAL_RESOURCE_DESCRIPTOR NextDescriptor;
93 
94     /* Assume the descriptors are the fixed size ones */
95     NextDescriptor = CmDescriptor + 1;
96 
97     /* But check if this is actually a variable-sized descriptor */
98     if (CmDescriptor->Type == CmResourceTypeDeviceSpecific)
99     {
100         /* Add the size of the variable section as well */
101         NextDescriptor = (PVOID)((ULONG_PTR)NextDescriptor +
102                                  CmDescriptor->u.DeviceSpecificData.DataSize);
103     }
104 
105     /* Now the correct pointer has been computed, return it */
106     return NextDescriptor;
107 }
108 
109 /* PipDumpCmResourceList() displays information about a Cm List
110 
111    DebugLevel: 0 - always dump
112                1 - dump if not defined NDEBUG
113 */
114 VOID
115 NTAPI
116 PipDumpCmResourceList(
117     _In_ PCM_RESOURCE_LIST CmResource,
118     _In_ ULONG DebugLevel)
119 {
120     PCM_FULL_RESOURCE_DESCRIPTOR FullList;
121     PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
122     ULONG ix;
123     ULONG jx;
124 
125     PAGED_CODE();
126 
127     if (DebugLevel != 0)
128     {
129 #ifdef NDEBUG
130         return;
131 #endif
132     }
133 
134     DPRINT1("Dump CmList: CmResource %p\n", CmResource);
135 
136     if (CmResource == NULL)
137     {
138         DPRINT1("PipDumpCmResourceList: CmResource == NULL\n");
139         return;
140     }
141 
142     if (CmResource->Count == 0)
143     {
144         DPRINT1("PipDumpCmResourceList: CmResource->Count == 0\n");
145         return;
146     }
147 
148     DPRINT1("FullList Count %x\n", CmResource->Count);
149 
150     FullList = &CmResource->List[0];
151 
152     for (ix = 0; ix < CmResource->Count; ix++)
153     {
154         DPRINT1("List #%X Iface %X Bus #%X Ver.%X Rev.%X Count %X\n",
155                 ix,
156                 FullList->InterfaceType,
157                 FullList->BusNumber,
158                 FullList->PartialResourceList.Version,
159                 FullList->PartialResourceList.Revision,
160                 FullList->PartialResourceList.Count);
161 
162         Descriptor = FullList->PartialResourceList.PartialDescriptors;
163 
164         for (jx = 0; jx < FullList->PartialResourceList.Count; jx++)
165         {
166             PipDumpCmResourceDescriptor(Descriptor, DebugLevel);
167             Descriptor = PipGetNextCmPartialDescriptor(Descriptor);
168         }
169 
170         FullList = (PCM_FULL_RESOURCE_DESCRIPTOR)Descriptor;
171     }
172 }
173 
174 /* IoResource */
175 
176 /* PipDumpIoResourceDescriptor() displays information about a Io Descriptor
177 
178    DebugLevel: 0 - always dump
179                1 - dump if not defined NDEBUG
180 */
181 VOID
182 NTAPI
183 PipDumpIoResourceDescriptor(
184     _In_ PIO_RESOURCE_DESCRIPTOR Descriptor,
185     _In_ ULONG DebugLevel)
186 {
187     PAGED_CODE();
188 
189     if (DebugLevel != 0)
190     {
191 #ifdef NDEBUG
192         return;
193 #endif
194     }
195 
196     if (Descriptor == NULL)
197     {
198         DPRINT1("DumpResourceDescriptor: Descriptor == 0\n");
199         return;
200     }
201 
202     switch (Descriptor->Type)
203     {
204         case CmResourceTypeNull:
205             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);
206             break;
207 
208         case CmResourceTypePort:
209             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);
210             break;
211 
212         case CmResourceTypeInterrupt:
213             DPRINT1("[%p:%X:%X] INT: Min %X Max %X\n", Descriptor, Descriptor->Option, Descriptor->ShareDisposition, Descriptor->u.Interrupt.MinimumVector, Descriptor->u.Interrupt.MaximumVector);
214             break;
215 
216         case CmResourceTypeMemory:
217             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);
218             break;
219 
220         case CmResourceTypeDma:
221             DPRINT1("[%p:%X:%X] DMA: Min %X Max %X\n", Descriptor, Descriptor->Option, Descriptor->ShareDisposition, Descriptor->u.Dma.MinimumChannel, Descriptor->u.Dma.MaximumChannel);
222             break;
223 
224         case CmResourceTypeBusNumber:
225             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);
226             break;
227 
228         case CmResourceTypeConfigData:
229             DPRINT1("[%p:%X:%X] CFG: Priority %X\n", Descriptor, Descriptor->Option, Descriptor->ShareDisposition, Descriptor->u.ConfigData.Priority);
230             break;
231 
232         case CmResourceTypeDevicePrivate:
233             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]);
234             break;
235 
236         default:
237             DPRINT1("[%p:%X:%X]. Unknown type %X\n", Descriptor, Descriptor->Option, Descriptor->ShareDisposition, Descriptor->Type);
238             break;
239     }
240 }
241 
242 /* PipDumpResourceRequirementsList() displays information about a Io List
243 
244    DebugLevel: 0 - always dump
245                1 - dump if not defined NDEBUG
246 */
247 VOID
248 NTAPI
249 PipDumpResourceRequirementsList(
250     _In_ PIO_RESOURCE_REQUIREMENTS_LIST IoResource,
251     _In_ ULONG DebugLevel)
252 {
253     PIO_RESOURCE_LIST AltList;
254     PIO_RESOURCE_DESCRIPTOR Descriptor;
255     ULONG ix;
256     ULONG jx;
257 
258     PAGED_CODE();
259 
260     if (DebugLevel != 0)
261     {
262 #ifdef NDEBUG
263         return;
264 #endif
265     }
266 
267     if (IoResource == NULL)
268     {
269         DPRINT1("PipDumpResourceRequirementsList: IoResource == 0\n");
270         return;
271     }
272 
273     DPRINT1("Dump RequirementsList: IoResource %p\n", IoResource);
274     DPRINT1("Interface %X Bus %X Slot %X AlternativeLists %X\n",
275             IoResource->InterfaceType,
276             IoResource->BusNumber,
277             IoResource->SlotNumber,
278             IoResource->AlternativeLists);
279 
280     AltList = &IoResource->List[0];
281 
282     if (IoResource->AlternativeLists < 1)
283     {
284         DPRINT1("PipDumpResourceRequirementsList: AlternativeLists < 1\n");
285         return;
286     }
287 
288     for (ix = 0; ix < IoResource->AlternativeLists; ix++)
289     {
290         DPRINT1("AltList %p, AltList->Count %X\n", AltList, AltList->Count);
291 
292         for (jx = 0; jx < AltList->Count; jx++)
293         {
294             Descriptor = &AltList->Descriptors[jx];
295             PipDumpIoResourceDescriptor(Descriptor, DebugLevel);
296         }
297 
298         AltList = (PIO_RESOURCE_LIST)(AltList->Descriptors + AltList->Count);
299         DPRINT1("End Descriptors %p\n", AltList);
300     }
301 }
302 
303 /* Gets the name of the device node state. */
304 
305 PWSTR
306 NTAPI
307 PipGetDeviceNodeStateName(
308     _In_ PNP_DEVNODE_STATE State)
309 {
310     switch (State)
311     {
312         case DeviceNodeUnspecified:
313             return L"DeviceNodeUnspecified";
314 
315         case DeviceNodeUninitialized:
316             return L"DeviceNodeUninitialized";
317 
318         case DeviceNodeInitialized:
319             return L"DeviceNodeInitialized";
320 
321         case DeviceNodeDriversAdded:
322             return L"DeviceNodeDriversAdded";
323 
324         case DeviceNodeResourcesAssigned:
325             return L"DeviceNodeResourcesAssigned";
326 
327         case DeviceNodeStartPending:
328             return L"DeviceNodeStartPending";
329 
330         case DeviceNodeStartCompletion:
331             return L"DeviceNodeStartCompletion";
332 
333         case DeviceNodeStartPostWork:
334             return L"DeviceNodeStartPostWork";
335 
336         case DeviceNodeStarted:
337             return L"DeviceNodeStarted";
338 
339         case DeviceNodeQueryStopped:
340             return L"DeviceNodeQueryStopped";
341 
342         case DeviceNodeStopped:
343             return L"DeviceNodeStopped";
344 
345         case DeviceNodeRestartCompletion:
346             return L"DeviceNodeRestartCompletion";
347 
348         case DeviceNodeEnumeratePending:
349             return L"DeviceNodeEnumeratePending";
350 
351         case DeviceNodeEnumerateCompletion:
352             return L"DeviceNodeEnumerateCompletion";
353 
354         case DeviceNodeAwaitingQueuedDeletion:
355             return L"DeviceNodeAwaitingQueuedDeletion";
356 
357         case DeviceNodeAwaitingQueuedRemoval:
358             return L"DeviceNodeAwaitingQueuedRemoval";
359 
360         case DeviceNodeQueryRemoved:
361             return L"DeviceNodeQueryRemoved";
362 
363         case DeviceNodeRemovePendingCloses:
364             return L"DeviceNodeRemovePendingCloses";
365 
366         case DeviceNodeRemoved:
367             return L"DeviceNodeRemoved";
368 
369         case DeviceNodeDeletePendingCloses:
370             return L"DeviceNodeDeletePendingCloses";
371 
372         case DeviceNodeDeleted:
373             return L"DeviceNodeDeleted";
374 
375         default:
376             break;
377     }
378 
379     if (State != MaxDeviceNodeState)
380     {
381         DPRINT1("PipGetDeviceNodeStateName: Unknown State %X\n", State);
382     }
383 
384     return L"";
385 }
386 
387 /* Dump list arbiters for the device node */
388 
389 VOID
390 NTAPI
391 PipDumpArbiters(
392     _In_ PDEVICE_NODE DeviceNode,
393     _In_ ULONG NodeLevel)
394 {
395     DPRINT("Level %X DevNode %p for PDO %p\n", NodeLevel, DeviceNode, DeviceNode->PhysicalDeviceObject);
396 
397     /* Definitions needed for arbiter */
398     UNIMPLEMENTED;
399 }
400 
401 /* PipDumpDeviceNode() displays information about a device node
402 
403     Flags is bitmask parametr:
404         1 - traversal of all children nodes
405         2 - dump allocated resources and boot configuration resources
406         4 - dump resources required
407         8 - dump translated resources
408 
409     DebugLevel: 0 - always dump
410                 1 - dump if not defined NDEBUG
411 */
412 VOID
413 NTAPI
414 PipDumpDeviceNode(
415     _In_ PDEVICE_NODE DeviceNode,
416     _In_ ULONG NodeLevel,
417     _In_ ULONG Flags,
418     _In_ ULONG DebugLevel)
419 {
420     PDEVICE_NODE ChildDeviceNode;
421 
422     if (DebugLevel != 0)
423     {
424 #ifdef NDEBUG
425         return;
426 #endif
427     }
428 
429     DPRINT1("* Level %X DevNode %p for PDO %p\n", NodeLevel, DeviceNode, DeviceNode->PhysicalDeviceObject);
430     DPRINT1("Instance    %wZ\n", &DeviceNode->InstancePath);
431 if (DeviceNode->ServiceName.Length)
432     DPRINT1("Service     %wZ\n", &DeviceNode->ServiceName);
433 #if 0
434     /* It is not used yet */
435     DPRINT1("State       %X %S\n", DeviceNode->State, PipGetDeviceNodeStateName(DeviceNode->State));
436     DPRINT1("Prev State  %X %S\n", DeviceNode->PreviousState, PipGetDeviceNodeStateName(DeviceNode->PreviousState));
437 #endif
438 if (DeviceNode->Problem)
439     DPRINT1("Problem     %X\n", DeviceNode->Problem);
440 #if 0
441     /* It is not implemeted yet */
442     PipDumpArbiters(DeviceNode, NodeLevel);
443 #endif
444 
445     /* Allocated resources and  Boot configuration (reported by IRP_MN_QUERY_RESOURCES)*/
446     if (Flags & PIP_DUMP_FL_RES_ALLOCATED)
447     {
448         if (DeviceNode->ResourceList)
449         {
450             DPRINT1("---------- ResourceList ----------\n");
451             PipDumpCmResourceList(DeviceNode->ResourceList, DebugLevel);
452         }
453 
454         if (DeviceNode->BootResources)
455         {
456             DPRINT1("---------- BootResources ----------\n");
457             PipDumpCmResourceList(DeviceNode->BootResources, DebugLevel);
458         }
459     }
460 
461     /* Resources required (reported by IRP_MN_FILTER_RESOURCE_REQUIREMENTS) */
462     if (Flags & PIP_DUMP_FL_RES_REQUIREMENTS)
463     {
464         if (DeviceNode->ResourceRequirements)
465         {
466             DPRINT1("---------- ResourceRequirements ----------\n");
467             PipDumpResourceRequirementsList(DeviceNode->ResourceRequirements, DebugLevel);
468         }
469     }
470 
471     /* Translated resources (AllocatedResourcesTranslated)  */
472     if (Flags & PIP_DUMP_FL_RES_TRANSLATED)
473     {
474         if (DeviceNode->ResourceListTranslated)
475         {
476             DPRINT1("---------- ResourceListTranslated ----------\n");
477             PipDumpCmResourceList(DeviceNode->ResourceListTranslated, DebugLevel);
478         }
479     }
480 
481     /* Traversal of all children nodes */
482     if (Flags & PIP_DUMP_FL_ALL_NODES)
483     {
484         for (ChildDeviceNode = DeviceNode->Child;
485              ChildDeviceNode != NULL;
486              ChildDeviceNode = ChildDeviceNode->Sibling)
487         {
488             /* Recursive call */
489             PipDumpDeviceNode(ChildDeviceNode, (NodeLevel + 1), Flags, DebugLevel);
490         }
491     }
492 }
493 
494 /* PipDumpDeviceNodes() displays information about a node(s) in the device tree
495 
496     If DeviceNode is NULL, then the dump starts at the beginning of the device tree.
497 
498     Flags is bitmask parametr:
499         1 - traversal of all children nodes
500         2 - dump allocated resources and boot configuration resources
501         4 - dump resources required
502         8 - dump translated resources
503 
504     DebugLevel: 0 - always dump
505                 1 - dump if not defined NDEBUG
506 
507     See also: Windows DDK -> General Driver Information ->
508         Kernel-Mode Driver Architecture -> Design Guide -> Plug and Play ->
509         Introduction to Plug and Play -> Hardware Resources
510 */
511 VOID
512 NTAPI
513 PipDumpDeviceNodes(
514     _In_ PDEVICE_NODE DeviceNode,
515     _In_ ULONG Flags,
516     _In_ ULONG DebugLevel)
517 {
518     if (DebugLevel != 0)
519     {
520 #ifdef NDEBUG
521         return;
522 #endif
523     }
524 
525     DPRINT1("PipDumpDeviceNodes: DeviceNode %X, Flags %X Level %X\n", DeviceNode, Flags, DebugLevel);
526 
527     if (DeviceNode == NULL)
528     {
529         DeviceNode = IopRootDeviceNode;
530     }
531 
532     PipDumpDeviceNode(DeviceNode, 0, Flags, DebugLevel);
533 }
534 
535 /* EOF */
536