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