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
PipDumpCmResourceDescriptor(_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,_In_ ULONG DebugLevel)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
PipGetNextCmPartialDescriptor(_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor)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
PipDumpCmResourceList(_In_ PCM_RESOURCE_LIST CmResource,_In_ ULONG DebugLevel)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
PipDumpIoResourceDescriptor(_In_ PIO_RESOURCE_DESCRIPTOR Descriptor,_In_ ULONG DebugLevel)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
PipDumpResourceRequirementsList(_In_ PIO_RESOURCE_REQUIREMENTS_LIST IoResource,_In_ ULONG DebugLevel)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
PipGetDeviceNodeStateName(_In_ PNP_DEVNODE_STATE State)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
PipDumpArbiters(_In_ PDEVICE_NODE DeviceNode,_In_ ULONG NodeLevel)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
PipDumpDeviceNode(_In_ PDEVICE_NODE DeviceNode,_In_ ULONG NodeLevel,_In_ ULONG Flags,_In_ ULONG DebugLevel)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
PipDumpDeviceNodes(_In_ PDEVICE_NODE DeviceNode,_In_ ULONG Flags,_In_ ULONG DebugLevel)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