The Complete Guide for Debugging a Stop 0x9F

x BlueRobot

Administrator
Staff member
Joined
May 7, 2013
Posts
10,391
Purpose: A collective summary of on the workings of a Stop 0x9F, and how to debug the two most common Stop 0x9F bugcheck types. I originally wrote this article in a Word document which spans 10 pages, so there may be most grammar mistakes or spelling mistakes.

Note: Since we're dealing with Stop 0x9F's, I switch interchangeably Watchdog Timer and Timer when speaking about the Timer types. Thanks to Jared for providing me with the Kernel Mode Dump files.

How it Works?

The Stop 0x9F common refers to the system being in a inconsistent or unsupported power state. This bugcheck is almost always exclusively related to device drivers not handling Power IRPs correctly. It's important to remember that filter and bus drivers are commonly blamed with these bugchecks, because these drivers tend to be the only drivers which will handle the actual Power IRP.

Stop 0x9Fs are largely caused by a device driver which isn't passing the Power IRP through it's driver stack to appropriate drivers which are able to process the Power IRP. Windows monitors this activity with the use of timer dispatcher objects. If we examine the stack of a Stop 0x9F, we can notice a few interesting functions.

knL Stop 0x9F.jpg

The most two most important functions are PopCheckIrpWatchdog and PopCheckForIdleness. The Pop prefix indicates we're dealing with the Power Manager, an important subsystem of the Windows kernel. The PopCheckForIdleness function periodically checks for inactivity, and is built upon a DPC object. If examine the lower stack frames then we can see a timer object has expired, the timer object is associated with the previously stated function, so when the timer object expires, the PopCheckForIdleness is called and calls it's own code. The function will run in intervals of 100 seconds, each time it will call another function called PopCheckIrpWatchdog. The Watchdog will check a linked list where the IRPs with the pending status are stored (PopIrpList), and then increment a counter. Once the counter threshold has been breached, the KeBugCheckEx function will be called and a crash with the Stop 0x9F stop code will be produced. The counter threshold is stored within a variable called PopWatchdogMaxTicks.

Rich (BB code):
0: kd> ? poi(nt!PopWatchdogMaxTicks)
Evaluate expression: 41 = 00000029

You can find the pending power IRPs using the following method:

Rich (BB code):
0: kd> ? poi(nt!PopIrpList)
Evaluate expression: -89566253447376 = ffffae8a`3b478730

Rich (BB code):
0: kd> dl ffffae8a`3b478730
ffffae8a`3b478730  ffffae8a`4407a010 fffff802`137df450
ffffae8a`3b478740  ffffae8a`452e6940 ffffae8a`3fb61060
ffffae8a`4407a010  ffffae8a`42747a30 ffffae8a`3b478730
ffffae8a`4407a020  ffffae8a`43ee77e0 ffffae8a`3fad2060
ffffae8a`42747a30  ffffae8a`3b238da0 ffffae8a`4407a010
ffffae8a`42747a40  ffffae8a`44bc9360 ffffae8a`3fac7060
ffffae8a`3b238da0  ffffae8a`43ab41e0 ffffae8a`42747a30
ffffae8a`3b238db0  ffffae8a`43e666f0 ffffae8a`3fa938f0
ffffae8a`43ab41e0  ffffae8a`419c84a0 ffffae8a`3b238da0
ffffae8a`43ab41f0  ffffae8a`3b296b80 ffffae8a`3ebe3e20
ffffae8a`419c84a0  fffff802`137df450 ffffae8a`43ab41e0
ffffae8a`419c84b0  ffffae8a`427376e0 ffffae8a`3bb0d060
fffff802`137df450  ffffae8a`3b478730 ffffae8a`419c84a0
fffff802`137df460  fffff802`137df460 fffff802`137df460

The highlighted entry is a pointer to one of the pending power IRPs.

We can view all pending timers with either the !timer extension or !ms_timers (requires SwishDbgExt.dll). All timers are created using a structure called _KTIMER or IO_TIMER.

Before Windows 7, the timers were stored inside a doubly linked list which has a different expiration time associated with each list head. There were 512 list heads, and each list head was stored within an array called KiTimerListHead. However, from Windows 7 onwards, the timer lists are now stored within a structure called KTIMER_TABLE.

Rich (BB code):
0: kd> dt nt!_KTIMER_TABLE
   +0x000 TimerExpiry      : [64] Ptr64 _KTIMER
   +0x200 TimerEntries     : [256] _KTIMER_TABLE_ENTRY

The TimerExpiry field corresponds to the list of timers which are set to be wakened at a given time interval. The TimerEntries field indicates the list heads for the given time interval. The KTIMER_TABLE_ENTRY has the following structure:

Rich (BB code):
0: kd> dt nt!_KTIMER_TABLE_ENTRY
   +0x000 Lock             : Uint8B
   +0x008 Entry            : _LIST_ENTRY
   +0x018 Time             : _ULARGE_INTEGER

The Entry field is the position of a timer object within the linked list as discussed above, and the Time entry is the time where the timer object is set to expire.

The _KTIMER data structure has the following entries:

Rich (BB code):
0: kd> dt nt!_KTIMER
   +0x000 Header           : _DISPATCHER_HEADER
   +0x018 DueTime          : _ULARGE_INTEGER
   +0x020 TimerListEntry   : _LIST_ENTRY
   +0x030 Dpc              : Ptr64 _KDPC
   +0x038 Processor        : Uint4B
   +0x03c Period           : Uint4B

The DueTime field is self-explanatory, it's the time which the timer has been set to expire. The Processor field is which processor number the timer object has been associated with, and the Dpc field is which DPC object is being used to schedule when the appropriate driver should be notified of the timer expiration, this for synchronization purposes. However, threads attached to timer objects can be awoken immediately after the timer expiration. The Period field is the same as the DueTime field. It's also important to remember that timer objects can be episodic (repeatedly) or periodic (only once).

There is another timer structure called _IO_TIMER, and is used with a associated device object. These timer objects can be used by driver developers to check specific operations within their device.

Rich (BB code):
0: kd> dt nt!_DEVICE_OBJECT
   +0x000 Type             : Int2B
   +0x002 Size             : Uint2B
   +0x004 ReferenceCount   : Int4B
   +0x008 DriverObject     : Ptr64 _DRIVER_OBJECT
   +0x010 NextDevice       : Ptr64 _DEVICE_OBJECT
   +0x018 AttachedDevice   : Ptr64 _DEVICE_OBJECT
   +0x020 CurrentIrp       : Ptr64 _IRP
   +0x028 Timer            : Ptr64 _IO_TIMER
   +0x030 Flags            : Uint4B
   +0x034 Characteristics  : Uint4B
   +0x038 Vpb              : Ptr64 _VPB
   +0x040 DeviceExtension  : Ptr64 Void
   +0x048 DeviceType       : Uint4B
   +0x04c StackSize        : Char
   +0x050 Queue            : <unnamed-tag>
   +0x098 AlignmentRequirement : Uint4B
   +0x0a0 DeviceQueue      : _KDEVICE_QUEUE
   +0x0c8 Dpc              : _KDPC
   +0x108 ActiveThreadCount : Uint4B
   +0x110 SecurityDescriptor : Ptr64 Void
   +0x118 DeviceLock       : _KEVENT
   +0x130 SectorSize       : Uint2B
   +0x132 Spare1           : Uint2B
   +0x138 DeviceObjectExtension : Ptr64 _DEVOBJ_EXTENSION
   +0x140 Reserved         : Ptr64 Void

The Timer field within the DEVICE_OBJECT structure contains a 64-bit pointer to the _IO_TIMER structure, which is defined as follows:

Rich (BB code):
0: kd> dt nt!_IO_TIMER
   +0x000 Type             : Int2B
   +0x002 TimerFlag        : Int2B
   +0x008 TimerList        : _LIST_ENTRY
   +0x018 TimerRoutine     : Ptr64     void
   +0x020 Context          : Ptr64 Void
   +0x028 DeviceObject     : Ptr64 _DEVICE_OBJECT

The timer object described is used to monitor any important operations, and ensure that these operations are successful, otherwise the operating system is informed to crash and produce a bugcheck. The timer is created with the IoIntializeTimer function, taking parameters which include the address of the specified device object and callback routine which is to be called every second (see TimerRoutine field), once the timer object has been started with the IoStartTimer. If the operation is successful or unsuccessful, then the timer can be stopped with IoStopTimer, and the appropriate code will be executed to handle the exception. The same timer can be restarted (called 'kicking the dog') by calling IoStartTimer again.

To summarise quickly, the timer object is used when the driver notices an operation hasn't been completed for a given timer interval, and this operation is vital for the stability of the device, thereby the Watchdog Timer is called once every second until that Timer has timed out - or the operation completes successfully - leading to an exception and an IRP with status code STATUS_IO_TIMEOUT being used to implement any exception handling for the device object. The IoCompleteRequest function will check the stated status, by looking into the _IO_STATUS_BLOCK structure.

Rich (BB code):
0: kd> dt nt!_IO_STATUS_BLOCK
   +0x000 Status           : Int4B
   +0x000 Pointer          : Ptr64 Void
   +0x008 Information      : Uint8B

We have now discussed how the Stop 0x9F is created and have briefly examined how timer objects work. We'll now discuss a little about Power IRPs and particularly how they handled within a Stop 0x9F. This last section will wrap up about the internals of a Stop 0x9F. In preceding sections, we will investigate the common causes of a Stop 0x9F and how to debug these crashes accordingly.

A Stop 0x9F is generally caused by a Power IRP being blocked somewhere within the device stack. Power IRPs are sent by the Power Manager or the Power Policy Device Manager. This is achieved by PoRequestPowerIrp. Power IRPs are used to achieve several things, but to say within the topic of discussion, we'll let Power IRPs main purpose being handling power transitions, wherever from sleep or to sleep. We can check power transition states with the !poaction.

Power IRPs are filtered through the device stack until they reach a bus driver, which is typically the only type of driver which can handle such IRPs. We can view a device stack for a specified physical device object by using the !devstack.

Rich (BB code):
0: kd> !devstack fffffa80`05823060
  !DevObj   !DrvObj            !DevExt   ObjectName
  fffffa80058882c0  \Driver\partmgr    fffffa8005888410
  fffffa8005888790  \Driver\Disk       fffffa80058888e0  DR0
  fffffa80057399b0  \Driver\ACPI       fffffa80039c5d50
> fffffa8005823060  \Driver\atapi      fffffa80058231b0  IdeDeviceP2T0L0-2
!DevNode fffffa800573d900 :
  DeviceInst is "IDE\DiskST3250824A______________________________3.AAH___\5&3731d328&0&0.0.0"
  ServiceName is "disk"

The Power IRP is passed down the device stack until it reaches the bus driver, which as stated before, tends to be only driver that is able to process the Power IRP, and therefore tends to be the driver which is blamed for the crash. With some IRPs, several different device stacks may be used to process an IRP, and therefore it can become more difficult in tracking where the IRP has become blocked, or if a preceding driver has caused the IRP to become blocked in some other location.

Stack PNG.png


The above device stack belongs to the device node stated below it. Each device node (represents a physical device) will have a device stack associated with it.

Rich (BB code):
0: kd> !devnode fffffa800573d900
DevNode 0xfffffa800573d900 for PDO 0xfffffa8005823060
  Parent 0xfffffa8005726900   Sibling 0xfffffa800573e900   Child 0000000000
  InstancePath is "IDE\DiskST3250824A______________________________3.AAH___\5&3731d328&0&0.0.0"
  ServiceName is "disk"
  State = DeviceNodeStarted (0x308)
  Previous State = DeviceNodeEnumerateCompletion (0x30d)
  StateHistory[08] = DeviceNodeEnumerateCompletion (0x30d)
  StateHistory[07] = DeviceNodeEnumeratePending (0x30c)
  StateHistory[06] = DeviceNodeStarted (0x308)
  StateHistory[05] = DeviceNodeStartPostWork (0x307)
  StateHistory[04] = DeviceNodeStartCompletion (0x306)
  StateHistory[03] = DeviceNodeResourcesAssigned (0x304)
  StateHistory[02] = DeviceNodeDriversAdded (0x303)
  StateHistory[01] = DeviceNodeInitialized (0x302)
  StateHistory[00] = DeviceNodeUninitialized (0x301)
  StateHistory[19] = Unknown State (0x0)
  StateHistory[18] = Unknown State (0x0)
  StateHistory[17] = Unknown State (0x0)
  StateHistory[16] = Unknown State (0x0)
  StateHistory[15] = Unknown State (0x0)
  StateHistory[14] = Unknown State (0x0)
  StateHistory[13] = Unknown State (0x0)
  StateHistory[12] = Unknown State (0x0)
  StateHistory[11] = Unknown State (0x0)
  StateHistory[10] = Unknown State (0x0)
  StateHistory[09] = Unknown State (0x0)
  Flags (0x2c000130)  DNF_ENUMERATED, DNF_IDS_QUERIED,
                      DNF_NO_RESOURCE_REQUIRED, DNF_NO_LOWER_DEVICE_FILTERS,
                      DNF_NO_LOWER_CLASS_FILTERS, DNF_NO_UPPER_DEVICE_FILTERS
  UserFlags (0x00000008)  DNUF_NOT_DISABLEABLE
  DisableableDepends = 1 (including self)

The drivers used by the device objects to process the IRP form another called the driver stack. Every IRP has a Major Function Code and a Minor Function Code, in the case of a Stop 0x9F, the very common IRP which is seen is the [16,2], where 0x16 is the Major Function Code (IRP_MJ_POWER) and 0x2 is the Minor Function Code (IRP_MN_SET_POWER). The 0x16 Major Function Code shows us that the IRP is in fact a Power IRP, with the 0x2 indicating that the specific purpose of the Power IRP was to notify a driver of a power state change in the system.

0x4 – How it Works?

Let's have a quick look at the internal works of a Stop 0x9F in relation to the PnP Manager. I've explained most of this Stop 0x9F in the debugging example, but this will provide a small generic description of how PnPs work.

There are two types of PnP IRPs: State Changing and Non-State Changing. With this particular type of bugcheck, we're most interested in the State Changing PnP IRPs.

PnP IRP Table.JPG


The main difference between State Changing and Non-State Changing IRPs, is how these IRPs are handled by the I/O Manager. State Changing IRPs must be synchronized against each other, this prevents two state changing IRPs from existing in the same stack. The most obvious problem this helps to prevent, this when an removal request and a start request are being processed at the same time. The State Changing IRPs have to be synchronized with System Power IRPs, a power transition must be processed before a PnP IRP. The State Changing PnP IRPs are only reserved for the use of system drivers.

On the other hand, there is a few Power IRPs which the PnPs aren't synchronized with, and these IRPs are the following:

  • IRP_MN_SET_POWER
  • IRP_MN_WAIT_WAKE
  • IRP_MN_QUERY_POWER
  • IRP_MN_POWER_SEQUENCE
Causes and Debugging

There is a number of causes for a Stop 0x9F, but the main two causes are a device driver blocking a IRP within the device stack, or a timer object has timed out and failed to notify a thread of a power transition state change and synchronize with the PnP Manager.

A complete list of parameters can be found on the MSDN page and in the BSOD Index.

Stop 0x9F – 0x3:

Rich (BB code):
DRIVER_POWER_STATE_FAILURE (9f)
A driver has failed to complete a power IRP within a specific time (usually 10 minutes).
Arguments:
Arg1: 0000000000000003, A device object has been blocking an Irp for too long a time
Arg2: fffffa8005823060, Physical Device Object of the stack
Arg3: fffff80000b9c518, nt!TRIAGE_9F_POWER on Win7, otherwise the Functional Device Object of the stack
Arg4: fffff9801c458dc0, The blocked IRP

The two most important arguments are the second and the fourth argument. The fourth argument contains the address of the blocked IRP, and the second argument contains the address of the PDO (Physical Device Object) of the stack location where the IRP has become blocked.

Using the !irp extension on the fourth parameter, we can view the current stack where the IRP has become stuck.

Rich (BB code):
0: kd> !irp fffff9801c458dc0
Irp is active with 5 stacks 1 is current (= 0xfffff9801c458e90)
 No Mdl: No System Buffer: Thread 00000000:  Irp stack trace.
     cmd  flg cl Device   File     Completion-Context
>[ 16, 2]   0 e1 fffffa8005823060 00000000 fffff88000e0957c-fffff88000e093c4 Success Error Cancel pending
           \Driver\atapi    ACPI!ACPIDeviceIrpDeviceFilterRequest
            Args: 00000000 00000001 00000004 00000000
 [ 16, 2]   0 e1 fffffa80057399b0 00000000 fffff880018f27d0-fffffa8005888cd0 Success Error Cancel pending
           \Driver\ACPI    CLASSPNP!ClasspStartNextPowerIrpCompletion
            Args: 00000000 00000001 00000004 00000000
 [ 16, 2]   0 e1 fffffa8005888790 00000000 fffff88000eaff50-00000000 Success Error Cancel pending
           \Driver\Disk    partmgr!PmPowerCompletion
            Args: 00000000 00000001 00000004 00000000
 [ 16, 2]   0 e1 fffffa80058882c0 00000000 00000000-00000000    pending
           \Driver\partmgr
            Args: 00000000 00000001 00000004 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-fffffa8006c71c50

            Args: 00000000 00000000 00000000 00000000

The output doesn't give us much indication, in most cases, a potential third party driver can be found, however, we'll need to investigate further using the !stacks extension to display all the kernel stacks in the system. I don't regularly use this extension simply because of the sheer volume of output it produces, there is hundreds of threads to check through.

As a side note, the fffff9801c458e90 address seen with the IRP is the current I/O Stack Location, which is stored with the IO_STACK_LOCATION structure:

Rich (BB code):
0: kd> dt nt!_IO_STACK_LOCATION
   +0x000 MajorFunction    : UChar
   +0x001 MinorFunction    : UChar
   +0x002 Flags            : UChar
   +0x003 Control          : UChar
   +0x008 Parameters       : <unnamed-tag>
   +0x028 DeviceObject     : Ptr64 _DEVICE_OBJECT
   +0x030 FileObject       : Ptr64 _FILE_OBJECT
   +0x038 CompletionRoutine : Ptr64     long
   +0x040 Context          : Ptr64 Void

There is one IO_STACK_LOCATION for each driver within the driver stack for the associated IRP.

Rich (BB code):
0: kd> !stacks
Proc.Thread  .Thread  Ticks   ThreadState Blocker
                            [fffff80002c0d180 Idle]
   0.000000  fffff80002c0ccc0 ff1674ec RUNNING    nt!KeBugCheckEx
   0.000000  fffff880009f3fc0 ff187841 RUNNING    amdppm!C1Halt+0x2
   0.000000  fffff88002f6efc0 ff186575 RUNNING    amdppm!C1Halt+0x2
   0.000000  fffff88002fdffc0 ff184b88 RUNNING    nt!KiIdleLoop+0x10d
                            [fffffa8003989b30 System]
*** ERROR: Module load completed but symbols could not be loaded for avgidsfiltera.sys
   4.000018  fffffa80039fbb50 ff1849a6 Blocked    Ntfs!NtfsWaitOnIo+0x28
   4.00001c  fffffa80039fb660 ff1848b8 Blocked    Ntfs!NtfsWaitOnIo+0x28
   4.000020  fffffa80039fb170 ff1845b7 Blocked    Ntfs!NtfsWaitOnIo+0x28
   4.000024  fffffa80039fd040 ff184537 Blocked    Ntfs!NtfsWaitOnIo+0x28
   4.000028  fffffa80039fdb50 ff167729 Blocked    tdtcp!TdiSubmitRequest+0xca
   4.00002c  fffffa80039fd660 ff1681d2 Blocked    +0xfffffa80075dfcda
   4.000038  fffffa80039fe660 ff184b88 Blocked    nt!IopCloseFile+0x260
   4.00003c  fffffa80039ff040 ff184a83 Blocked    nt!CmpDoFileWrite+0x281
   4.000040  fffffa80039ffb50 ff1849b5 STANDBY    nt!KeSetSystemGroupAffinityThread+0x18a
   4.000044  fffffa80039ff660 ff1797f0 Blocked    disk!DiskPerformSmartCommand+0x1f0
   4.000060  fffffa800460eb50 ff167536 Blocked    nt!ViKeTrimWorkerThreadRoutine+0x1e
   4.000064  fffffa800460e660 ff184b89 Blocked    nt!ViPoolDelayFreeTrimThreadRoutine+0x29
   4.000068  fffffa800460f040 ff167ff5 Blocked    nt!ViPoolDelayFreeTrimThreadRoutine+0x29
   4.00006c  fffffa800460fb50 ff168ad9 Blocked    nt!ViPendingWorkerThread+0x20
   4.000070  fffffa800460f660 ff168ad9 Blocked    nt!ViPendingWorkerThread+0x20
   4.000074  fffffa8004610040 ff167ff5 Blocked    nt!ViPendingWorkerThread+0x20
   4.000078  fffffa8004610b50 ff167ff5 Blocked    nt!ViPendingWorkerThread+0x20
   4.00007c  fffffa8004610660 ff167ff5 Blocked    nt!ViPendingWorkerThread+0x20
   4.000080  fffffa8004611040 ff167ff5 Blocked    nt!ViPendingWorkerThread+0x20
   4.000084  fffffa8004611b50 ff167ff5 Blocked    nt!ViPendingWorkerThread+0x20
   4.000088  fffffa8004611660 ff167ff5 Blocked    nt!ViPendingWorkerThread+0x20
   4.000090  fffffa8004612660 ff18486c Blocked    nt!MiModifiedPageWriter+0xcf
   4.000094  fffffa8004613b50 ff183446 Blocked    Ntfs!NtfsWaitOnIo+0x28
   4.0000b0  fffffa8004617610 ff1843b6 Blocked    nt!CcQueueLazyWriteScanThread+0x85
   4.0000bc  fffffa800461e940 ff167ff5 Blocked    nt!AlpcpReceiveMessagePort+0x189
   4.0000c0  fffffa800466f040 ff184bfa Blocked    nt!EtwpLogger+0xf2
   4.0000c4  fffffa800466f790 ff16753a Blocked    nt!EtwpLogger+0xf2
   4.0000c8  fffffa800467c5d0 ff16753a Blocked    nt!EtwpLogger+0xf2
   4.0000cc  fffffa80046bd040 ff16753a Blocked    nt!EtwpLogger+0xf2
   4.0000d4  fffffa80047c9b50 ff1674fa Blocked    nt!EtwpLogger+0xf2
   4.0000d8  fffffa80047ec040 ffffe2ed Blocked    nt!EtwpLogger+0xf2
   4.0000dc  fffffa80047f1b50 ff167d9a Blocked    nt!WdipSemCheckTimeout+0x12c
   4.0000e0  fffffa80039a65c0 fffffb53 Blocked    ACPI!ACPIWorkerThread+0x74
   4.0000e8  fffffa8005636b50 fffff583 Blocked    ndis!ndisThreadPoolTimerHandler+0x10c
   4.0000f0  fffffa8005639740 ff167644 Blocked    ndis!ndisCmWaitThread+0x6e
   4.0000f4  fffffa80057fc110 ffffff8d Blocked    ACPI!PciRootBusBiosMethodDispatcherOnResume+0x51
   4.000104  fffffa8005766b50 ffcd71dd Blocked    volsnap!VspWorkerThread+0x80
   4.000108  fffffa8005769b50 ff197630 Blocked    volsnap!VspWorkerThread+0x80
   4.00010c  fffffa800576ab50 ff1880a0 Blocked    volsnap!VspWorkerThread+0x80
   4.000110  fffffa800576bb50 fffffdf4 Blocked    volsnap!VspWorkerThread+0x80
   4.000114  fffffa800576cb50 fffffea1 Blocked    volsnap!VspWorkerThread+0x80
   4.000118  fffffa800576db50 fffffea1 Blocked    volsnap!VspWorkerThread+0x80
   4.00011c  fffffa800576eb50 fffffea1 Blocked    volsnap!VspWorkerThread+0x80
   4.000120  fffffa800576fb50 fffffea1 Blocked    volsnap!VspWorkerThread+0x80
   4.000124  fffffa8005770b50 fffffea1 Blocked    volsnap!VspWorkerThread+0x80
   4.00012c  fffffa8005c0a930 fffffde0 Blocked    watchdog!SMgrGdiCalloutThread+0x4f
*** ERROR: Module load completed but symbols could not be loaded for avgtdia.sys
   4.000130  fffffa8005c3d040 fffffddc Blocked    nt!VerifierKeWaitForMultipleObjects+0x1dc
   4.000134  fffffa8005c2cb50 ff16759e Blocked    avgtdia+0x31676

[...]

Threads Processed: 939

This is a small subset of the stacks extension, the first column contains the Process ID and the Thread ID, in this case it is a System process. The second column contains the address of the _ETHREAD block which we can pass to the !thread extension. The threads which are of a interest to us are the ones which have the Blocked status.

I haven't been able to find a direct cause, but based on the device stack for the blocked IRP, I'm assuming that AVG may a culprit driver.

Rich (BB code):
0: kd> lmvm avgrkx64

start             end                 module name
fffff880`01911000 fffff880`0191d000   avgrkx64   (deferred)         
    Image path: \SystemRoot\system32\DRIVERS\avgrkx64.sys
    Image name: avgrkx64.sys
    Timestamp:        Tue Jan 31 03:11:41 2012 (4F275BED)
    CheckSum:         0000D438
    ImageSize:        0000C000
    Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4

Stop 0x9F – 0x4:

This bugcheck indicates that we have failed to synchronize our power transition with the PnP Manager. This is common for the removal PnP devices, since after the removal of the device we need to update the device tree to show that the device object has been removed from the system.

Rich (BB code):
DRIVER_POWER_STATE_FAILURE (9f)
A driver has failed to complete a power IRP within a specific time (usually 10 minutes).
Arguments:
Arg1: 0000000000000004, The power transition timed out waiting to synchronize with the Pnp
    subsystem.
Arg2: 0000000000000258, Timeout in seconds.
Arg3: fffffa8007005660, The thread currently holding on to the Pnp lock.
Arg4: fffff800053e83d0, nt!TRIAGE_9F_PNP on Win7

The timeout is specified in the second argument, and the thread which is holding onto the lock required to access the PnP is shown in the third argument. We'll begin by using the !thread extension with the thread address, and then examining the stack.

Rich (BB code):
0: kd> !thread fffffa8007005660
THREAD fffffa8007005660  Cid 0004.0048  Teb: 0000000000000000 Win32Thread: 0000000000000000 WAIT: (Executive) KernelMode Non-Alertable
    fffffa800d035ee8  NotificationEvent
IRP List:
    fffffa8008f5cc10: (0006,03e8) Flags: 00000000  Mdl: 00000000
Not impersonating
DeviceMap                 fffff8a000008c10
Owning Process            fffffa8006f8d890       Image:         System
Attached Process          N/A            Image:         N/A
Wait Start TickCount      396427         Ticks: 38463 (0:00:10:00.026)
Context Switch Count      44059          IdealProcessor: 0  NoStackSwap
UserTime                  00:00:00.000
KernelTime                00:00:00.343
Win32 Start Address nt!ExpWorkerThread (0xfffff80003298150)
Stack Init fffff88003bd2c70 Current fffff88003bd2280
Base fffff88003bd3000 Limit fffff88003bcd000 Call 0
Priority 15 BasePriority 12 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
Child-SP          RetAddr           : Args to Child                                                           : Call Site
fffff880`03bd22c0 fffff800`032845f2 : fffffa80`07005660 fffffa80`07005660 00000000`00000000 00000000`00000000 : nt!KiSwapContext+0x7a
fffff880`03bd2400 fffff800`0329599f : fffffa80`0d0df208 fffff880`0ae9e10b fffffa80`00000000 00000000`00000000 : nt!KiCommitThreadWait+0x1d2
fffff880`03bd2490 fffff880`0ae915dd : fffffa80`0d035000 00000000`00000000 fffffa80`0dd8ca00 00000000`00000000 : nt!KeWaitForSingleObject+0x19f
fffff880`03bd2530 fffff880`0ae92627 : fffffa80`0d035000 00000000`00000000 fffffa80`0c0891a0 fffff880`03bd2670 : ZTEusbnet+0x35dd
fffff880`03bd2580 fffff880`0215d809 : fffffa80`0c0891a0 fffff880`020f0ecd fffff880`03bd2670 fffffa80`091c5550 : ZTEusbnet+0x4627
fffff880`03bd25b0 fffff880`0215d7d0 : fffffa80`091c54a0 fffffa80`0c0891a0 fffff880`03bd2670 fffffa80`08fc2ac0 : ndis!NdisFDevicePnPEventNotify+0x89
fffff880`03bd25e0 fffff880`0215d7d0 : fffffa80`08fc2a10 fffffa80`0c0891a0 fffffa80`091f9010 fffffa80`091f90c0 : ndis!NdisFDevicePnPEventNotify+0x50
fffff880`03bd2610 fffff880`0219070c : fffffa80`0c0891a0 00000000`00000000 00000000`00000000 fffffa80`0c0891a0 : ndis!NdisFDevicePnPEventNotify+0x50
fffff880`03bd2640 fffff880`021a1da2 : 00000000`00000000 fffffa80`08f5cc10 00000000`00000000 fffffa80`0c0891a0 : ndis! ?? ::LNCPHCLB::`string'+0xddf
fffff880`03bd26f0 fffff800`034fb121 : fffffa80`091c7060 fffffa80`0c089050 fffff880`03bd2848 fffffa80`070bfa00 : ndis!ndisPnPDispatch+0x843
fffff880`03bd2790 fffff800`0367b3a1 : fffffa80`070bfa00 00000000`00000000 fffffa80`0dc19990 fffff880`03bd2828 : nt!IopSynchronousCall+0xe1
fffff880`03bd2800 fffff800`03675d78 : fffffa80`09196e00 fffffa80`070bfa00 00000000`0000030a 00000000`00000308 : nt!IopRemoveDevice+0x101
fffff880`03bd28c0 fffff800`0367aee7 : fffffa80`0dc19990 00000000`00000000 00000000`00000003 00000000`00000136 : nt!PnpSurpriseRemoveLockedDeviceNode+0x128
fffff880`03bd2900 fffff800`0367b000 : 00000000`00000000 fffff8a0`11d1c000 fffff8a0`049330d0 fffff880`03bd2a58 : nt!PnpDeleteLockedDeviceNode+0x37
fffff880`03bd2930 fffff800`0370b97f : 00000000`00000002 00000000`00000000 fffffa80`09122010 00000000`00000000 : nt!PnpDeleteLockedDeviceNodes+0xa0
fffff880`03bd29a0 fffff800`0370c53c : fffff880`03bd2b78 fffffa80`114ab700 fffffa80`07005600 fffffa80`00000000 : nt!PnpProcessQueryRemoveAndEject+0x6cf
fffff880`03bd2ae0 fffff800`035f573e : 00000000`00000000 fffffa80`114ab7d0 fffff8a0`123a25b0 00000000`00000000 : nt!PnpProcessTargetDeviceEvent+0x4c
fffff880`03bd2b10 fffff800`03298261 : fffff800`034f9f88 fffff8a0`11d1c010 fffff800`034342d8 fffff800`034342d8 : nt! ?? ::NNGAKEGL::`string'+0x54d9b
fffff880`03bd2b70 fffff800`0352b2ea : 00000000`00000000 fffffa80`07005660 00000000`00000080 fffffa80`06f8d890 : nt!ExpWorkerThread+0x111
fffff880`03bd2c00 fffff800`0327f8e6 : fffff880`03965180 fffffa80`07005660 fffff880`0396ffc0 00000000`00000000 : nt!PspSystemThreadStartup+0x5a
fffff880`03bd2c40 00000000`00000000 : fffff880`03bd3000 fffff880`03bcd000 fffff880`03bd2410 00000000`00000000 : nt!KxStartSystemThread+0x16

As we can see in the call stack for the thread, there is two device removal functions, which in turn supports our argument from earlier on. More importantly, if we check the pending IRP for the current thread, we'll find some more evidence relating to PnP and the third party driver shown in our call stack.

Rich (BB code):
0: kd> !irp fffffa8008f5cc10
Irp is active with 10 stacks 10 is current (= 0xfffffa8008f5cf68)
 No Mdl: No System Buffer: Thread fffffa8007005660:  Irp stack trace.
     cmd  flg cl Device   File     Completion-Context
 [  0, 0]   0  0 00000000 00000000 00000000-00000000

            Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000

            Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000

            Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000

            Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000

            Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000

            Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000

            Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000

            Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000

            Args: 00000000 00000000 00000000 00000000
>[ 1b,17]   0  0 fffffa800c089050 00000000 00000000-00000000
           \Driver\ZTEusbnet
            Args: 00000000 00000000 00000000 00000000

The Major Function code corresponds to IRP_MJ_PNP, and the Minor Function Code corresponds to IRP_MN_SURPRISE_REMOVAL. These IRP function codes can be found within the WinDbg documentation, and an explanation can be found on the appropriate MSDN pages. I will briefly explain these function codes, and how they link in with the nature of the bugcheck. PnP IRPs are handled by DispatchPnP driver dispatch rountine.

The Minor Function Code is used to notify important Kernel components and User Mode applications that the device is being removed from the system, and no other IRPs will be able to be sent to that device. The IRP is exclusively reserved for the system, and thus no other drivers should be sending the IRP. The IRP is processed from the top layer of the device stack down to the bottom layer of the device stack.

By checking the IRP, the call stack makes much more sense to us, at the moment the thread is currently waiting on a lock. We need to investigate what this lock is, and why these locks are required. Using the !locks extension, we can list all the currently acquired locks on executive resources (_ERESOURCE).

Rich (BB code):
0: kd> !locks
**** DUMP OF ALL RESOURCE OBJECTS ****
KD: Scanning for held locks..

Resource @ nt!IopDeviceTreeLock (0xfffff80003492ce0)    Shared 1 owning threads
    Contention Count = 1
     Threads: fffffa8007005660-01<*>
KD: Scanning for held locks.

Resource @ nt!PiEngineLock (0xfffff80003492be0)    Exclusively owned
    Contention Count = 21
    NumberOfExclusiveWaiters = 1
     Threads: fffffa8007005660-01<*>
     Threads Waiting On Exclusive Access:
              fffffa800f308b50   

KD: Scanning for held locks.....

The current thread holding both locks is our PnP thread. The most interesting lock is the IopDeviceTreeLock. The other thread waiting on the PiEngineLock is a kernel related thread which is handling other device removal operations and power transitions.

Instead of going in depth about the various locks and synchronization mechanisms used in Windows, it would be better to explain why the thread is using a lock to begin with. The answer with our PnP device.

The main reason of acquiring the lock is to ensure that the driver will not use DispatchPnP to handle a IRP_MN_REMOVE_DEVICE IRP while another driver is performing an I/O operation at the same time. Furthermore, by using these lock routines, the driver can determine when all I/O operations have been completed for that device, and therefore when it is safe to remove that device.

irp.JPG

The IO_REMOVE_LOCK illustrates a counter which is used to check when all the pending I/O operations have been completed for that device. Once the I/O operations have been completed, then the device can be safely removed from the system. A safe removal of the device is indicated with the IoRemoveLockAndWait. The IO_REMOVE_LOCK is destroyed when the device is removed from the system.

In conclusion, the ZTEusbnet.sys driver seems like the most likely culprit, it is a USB NDIS Miniport driver developed by a company called ZTE.

Rich (BB code):
0: kd> lmvm ZTEusbnet

start             end                 module name
fffff880`0ae8e000 fffff880`0aebc000   ZTEusbnet   (no symbols)       
    Loaded symbol image file: ZTEusbnet.sys
    Image path: \SystemRoot\system32\DRIVERS\ZTEusbnet.sys
    Image name: ZTEusbnet.sys
    Timestamp:        Mon Oct 13 06:50:10 2008 (48F2E192)
    CheckSum:         000329ED
    ImageSize:        0002E000
    Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4

Commands and Extensions

This a quick overview of the extensions and commands which can be used for debugging Stop 0x9F. Some of the extensions are added for informational purposes i.e. you wish to learn a little about the nature of the device etc.

!irp, !irpfind, !devext, !devobj, !drvobj, !popolicy, !timer, !ms_timer, !thread, !stacks, !devnode,
!devstack, !podev, !poaction, !popolicy, !poreqlist, !locks and !pnptriage.

Data Structures

*Discussed in article

_IO_TIMER*, _DEVICE_OBJECT*, _DRIVER_OBJECT, _KTIMER*, _KTIMER_TABLE_ENTRY*, _KTIMER_TABLE*, _SYSTEM_POWER_STATE, _DEVICE_POWER_STATE, _SYSTEM_POWER_POLICY, _IO_STATUS_BLOCK*, _TRIAGE_9F_POWER

References:

Managing PnP State Transistions
Using Remove Locks
Debugging Stop 0x9F - CodeMachine
Which PnP IRPs are State Changing? - Hole In My Head
A Performance Issue in Windows Timer Management?
Ain't Nuthin But A K(Timer) Thing, Baby
Power IRPs for Individual Devices
I/O Stack Locations
 
Last edited:
Rich (BB code):
0: kd> !stack -p
Call Stack : 6 frames
## Stack-Pointer    Return-Address   Call-Site      
00 fffff80662c6c848 fffff8065cf07b56 nt!KeBugCheckEx+0
    Parameter[0] = 000000000000009f
    Parameter[1] = 0000000000000004
    Parameter[2] = 000000000000012c
    Parameter[3] = ffffc501b2e3d040
01 fffff80662c6c850 fffff8065d3ae8e6 nt!PnpBugcheckPowerTimeout+76
    Parameter[0] = (unknown)      
    Parameter[1] = 0000000000000000
    Parameter[2] = 0000000000000000
    Parameter[3] = (unknown)      
02 fffff80662c6c8b0 fffff8065cc44f12 nt!PopBuildDeviceNotifyListWatchdog+16
    Parameter[0] = ffff810ac21d2370
    Parameter[1] = (unknown)      
    Parameter[2] = (unknown)      
    Parameter[3] = (unknown)      
03 fffff80662c6c8e0 fffff8065cc06eed nt!KiProcessExpiredTimerList+172 (perf)
    Parameter[0] = (unknown)      
    Parameter[1] = (unknown)      
    Parameter[2] = (unknown)      
    Parameter[3] = (unknown)      
04 fffff80662c6c9d0 fffff8065cdf97be nt!KiRetireDpcList+5dd
    Parameter[0] = (unknown)      
    Parameter[1] = (unknown)      
    Parameter[2] = (unknown)      
    Parameter[3] = (unknown)      
05 fffff80662c6cc60 0000000000000000 nt!KiIdleLoop+9e
    Parameter[0] = (unknown)      
    Parameter[1] = (unknown)      
    Parameter[2] = (unknown)      
    Parameter[3] = (unknown)

Just thought it would interesting to note, that the PopBuildDeviceNotifyListWatchdog function appears to take a watchdog object?

Rich (BB code):
0: kd> dt _PNP_WATCHDOG ffff810ac21d2370
nt!_PNP_WATCHDOG
   +0x000 WatchdogStart    : 0x113
   +0x008 WatchdogTimer    : (null)
   +0x010 WatchdogContextType : 1 ( PNP_EVENT_WORKER_WATCHDOG )
   +0x018 WatchdogContext  : 0xfffff806`5d3ae8d0 Void
   +0x020 TriggerEventLogged : 0x10 ''

Rich (BB code):
0: kd> dt _PNP_WATCHDOG_TYPE
nt!_PNP_WATCHDOG_TYPE
   PNP_EVENT_WORKER_WATCHDOG = 0n1
   PNP_DEVICE_COMPLETION_QUEUE_WATCHDOG = 0n2
   PNP_DELAYED_REMOVE_WORKER_WATCHDOG = 0n3
   PNP_ADD_DEVICE_WATCHDOG = 0n4
   PNP_DRIVER_ENTRY_WATCHDOG = 0n5
 
I thought I would provide an updated version for the 0x4 scenario, this is from a Windows 10 machine and the culprit driver is easy to find if you know where to look.

Rich (BB code):
DRIVER_POWER_STATE_FAILURE (9f)
A driver has failed to complete a power IRP within a specific time.
Arguments:
Arg1: 0000000000000004, The power transition timed out waiting to synchronize with the Pnp
    subsystem.
Arg2: 000000000000012c, Timeout in seconds.
Arg3: ffffa70f2c092040, The thread currently holding on to the Pnp lock.
Arg4: ffffc985b60bf780, nt!TRIAGE_9F_PNP on Win7 and higher

As mentioned previously, the third and fourth parameter are the most important, in particular the third parameter which contains a pointer to the thread which is deadlocking the system. Unfortunately, this time, the call stack of the thread did not contain any reference to a third party driver. Fortunately, with a little investigation work, we can find the culprit driver very easily.

Let's begin by setting the thread context to that of the hung thread:

Rich (BB code):
10: kd> .thread ffffa70f2c092040
Implicit thread is now ffffa70f`2c092040

Now, let's dump the call stack using !stack -p since we'll need to know what parameters are being passed in. You could of course dump each stack frame individually, but !stack -p makes this progress much more efficient.

Rich (BB code):
10: kd> !stack -p
Call Stack : 14 frames
## Stack-Pointer    Return-Address   Call-Site       
00 ffffc985b70e7420 fffff8010d40c800 nt!KiSwapContext+76 
    Parameter[0] = ffffa70f2c092040
    Parameter[1] = ffff8580df6ac340
    Parameter[2] = 0000000000000004
    Parameter[3] = (unknown)       
01 ffffc985b70e7560 fffff8010d40bd2f nt!KiSwapThread+500 (perf)
    Parameter[0] = (unknown)       
    Parameter[1] = (unknown)       
    Parameter[2] = (unknown)       
    Parameter[3] = (unknown)       
02 ffffc985b70e7610 fffff8010d40b5d3 nt!KiCommitThreadWait+14f (perf)
    Parameter[0] = ffffa70f2c092040
    Parameter[1] = 0000000000000000
    Parameter[2] = ffffa70f2c092040
    Parameter[3] = 0000000000000000
03 ffffc985b70e76b0 fffff8010d56b789 nt!KeWaitForSingleObject+233 
    Parameter[0] = (unknown)       
    Parameter[1] = (unknown)       
    Parameter[2] = (unknown)       
    Parameter[3] = (unknown)       
04 ffffc985b70e77a0 fffff8010d56b632 nt!PopFxActivateDevice+149 
    Parameter[0] = (unknown)       
    Parameter[1] = 0000000000000000
    Parameter[2] = 0000000000000000
    Parameter[3] = (unknown)       
05 ffffc985b70e77f0 fffff8010d932194 nt!PoFxActivateDevice+e 
    Parameter[0] = (unknown)       
    Parameter[1] = (unknown)       
    Parameter[2] = (unknown)       
    Parameter[3] = (unknown)       
06 ffffc985b70e7820 fffff8010d931ea3 nt!PnpDeleteLockedDeviceNode+74 
    Parameter[0] = ffffa70f2650b420
    Parameter[1] = 0000000000000003
    Parameter[2] = 0000000000000000
    Parameter[3] = 0000000000000000
07 ffffc985b70e7860 fffff8010d9305ee nt!PnpDeleteLockedDeviceNodes+f7 
    Parameter[0] = (unknown)       
    Parameter[1] = (unknown)       
    Parameter[2] = (unknown)       
    Parameter[3] = (unknown)       
08 ffffc985b70e78e0 fffff8010d92b3ab nt!PnpProcessQueryRemoveAndEject+1da 
    Parameter[0] = ffffc985b70e7a20
    Parameter[1] = (unknown)       
    Parameter[2] = (unknown)       
    Parameter[3] = (unknown)       
09 ffffc985b70e79c0 fffff8010d848efe nt!PnpProcessTargetDeviceEvent+eb 
    Parameter[0] = (unknown)       
    Parameter[1] = (unknown)       
    Parameter[2] = (unknown)       
    Parameter[3] = (unknown)       
0a ffffc985b70e79f0 fffff8010d4b8515 nt!PnpDeviceEventWorker+2ce 
    Parameter[0] = ffffa70f2e1f4860
    Parameter[1] = (unknown)       
    Parameter[2] = (unknown)       
    Parameter[3] = (unknown)       
0b ffffc985b70e7a70 fffff8010d555855 nt!ExpWorkerThread+105 (perf)
    Parameter[0] = (unknown)       
    Parameter[1] = (unknown)       
    Parameter[2] = (unknown)       
    Parameter[3] = (unknown)       
0c ffffc985b70e7b10 fffff8010d5fe8f8 nt!PspSystemThreadStartup+55 
    Parameter[0] = ffffa70f2c092040
    Parameter[1] = ffffa70f20096970
    Parameter[2] = (unknown)       
    Parameter[3] = (unknown)       
0d ffffc985b70e7b60 0000000000000000 nt!KiStartSystemThread+28 
    Parameter[0] = (unknown)       
    Parameter[1] = (unknown)       
    Parameter[2] = (unknown)       
    Parameter[3] = (unknown)

The nt!PnpDeleteLockedDeviceNode function takes a pointer to a device node. This is the device node which was being removed at the time of the crash. Let's dump the corresponding device node using the !devnode command.

Rich (BB code):
10: kd> !devnode ffffa70f2650b420
DevNode 0xffffa70f2650b420 for PDO 0xffffa70f265b75b0
  Parent 0xffffa70f26c10620   Sibling 0000000000   Child 0xffffa70f26ca3c70   
  InstancePath is "USB\VID_045E&PID_02A0&IG_00\7&2c2af897&0&00"
  ServiceName is "HidUsb"
  State = DeviceNodeAwaitingQueuedDeletion (0x30e)
  Previous State = DeviceNodeStarted (0x308)
  StateHistory[13] = DeviceNodeStarted (0x308)
  StateHistory[12] = DeviceNodeEnumerateCompletion (0x30d)
  StateHistory[11] = DeviceNodeEnumeratePending (0x30c)
  StateHistory[10] = DeviceNodeStarted (0x308)
  StateHistory[09] = DeviceNodeEnumerateCompletion (0x30d)
  StateHistory[08] = DeviceNodeEnumeratePending (0x30c)
  StateHistory[07] = DeviceNodeStarted (0x308)
  StateHistory[06] = DeviceNodeStartPostWork (0x307)
  StateHistory[05] = DeviceNodeStartCompletion (0x306)
  StateHistory[04] = DeviceNodeStartPending (0x305)
  StateHistory[03] = DeviceNodeResourcesAssigned (0x304)
  StateHistory[02] = DeviceNodeDriversAdded (0x303)
  StateHistory[01] = DeviceNodeInitialized (0x302)
  StateHistory[00] = DeviceNodeUninitialized (0x301)
  StateHistory[19] = Unknown State (0x0)
  StateHistory[18] = Unknown State (0x0)
  StateHistory[17] = Unknown State (0x0)
  StateHistory[16] = Unknown State (0x0)
  StateHistory[15] = Unknown State (0x0)
  StateHistory[14] = Unknown State (0x0)
  Flags (0x6c000138)  DNF_REENUMERATE, DNF_ENUMERATED, 
                      DNF_IDS_QUERIED, DNF_NO_RESOURCE_REQUIRED, 
                      DNF_NO_LOWER_DEVICE_FILTERS, DNF_NO_LOWER_CLASS_FILTERS, 
                      DNF_NO_UPPER_DEVICE_FILTERS, DNF_NO_UPPER_CLASS_FILTERS
  CapabilityFlags (0x00000200)  SurpriseRemovalOK

As we can see, we now know that the device is USB-based and this significantly helps to narrow down the device. We can look up the vendor Id and device Id in an online PCI database. It appears the device being removed was related to Xbox 360 and from the information the user provided, the device in question was an Xbox 360 controller.

We can dump the associated device object to the driver which is responsible for the device itself.

Rich (BB code):
10: kd> !devobj ffffa70f265b75b0
Device object (ffffa70f265b75b0) is for:
 00000060 \Driver\xusb22 DriverObject ffffa70f26c62e30
Current Irp 00000000 RefCount 0 Type 00000022 Flags 00003044
SecurityDescriptor ffff960ef003a820 DevExt ffffa70f26cacfb0 DevObjExt ffffa70f265b7728 DevNode ffffa70f2650b420 
ExtensionFlags (0000000000)  
Characteristics (0x00000080)  FILE_AUTOGENERATED_DEVICE_NAME
AttachedDevice (Upper) ffffa70f26caf060 \Driver\HidUsb

The driver - xusb22.sys - in question appears to be for an Xbox 360 controller, therefore it is recommended that the user find an suitable update if possible. Unfortunately, however, in our case there wasn't any additional updates and the issue appeared to be due to one specific controller. The other controllers reportedly worked with no problems.

We can find further confirmation that the device in question was the Xbox 360 controller by checking the PnP event queue using the !pnpevent command. Alternatively, you can obtain the same information by using the !pnptriage command.

Rich (BB code):
10: kd> !pnpevent

********************************************************************************
Dumping PnP DeviceEvent Queue @ 0xffffa70f200d4880
********************************************************************************

List = 0xffff960f05516bb0, 0xffff960f05d15930

Dumping DeviceEventEntry @ 0xffff960f05516bb0
  ListEntry = 0xffff960f03de21e0, 0xffffa70f200d48f8, Argument = 0x00000000
  CallerEvent = 0xffffc985bb5bf8f8, Callback = 0x00000000, Context = 0x00000000
  VetoType = 0x00000000, VetoName = 0x00000000

  Waiting threads:
      0xffffa70f2d6db040

  Dumping PlugPlayEventBlock @ 0x05516C20
    EventGuid = GUID_DEVICE_NOOP
    Category = TargetDeviceChangeEvent
    Result = 0xffffc985bb5bf8e0, Flags = 0x00000000, TotalSize = 80
    DeviceObject = 0x00000000
      DeviceId = 

Dumping DeviceEventEntry @ 0xffff960f03de21e0
  ListEntry = 0xffff960efa2a9150, 0xffff960f05516bb0, Argument = 0x00000000
  CallerEvent = 0x00000000, Callback = 0x00000000, Context = 0x00000000
  VetoType = 0x00000000, VetoName = 0x00000000

  Dumping PlugPlayEventBlock @ 0x03DE2250
    EventGuid = GUID_DEVICE_INTERFACE_REMOVAL
    Category = DeviceClassChangeEvent
    Result = 0x00000000, Flags = 0x00000000, TotalSize = 254
    DeviceObject = 0x00000000
      ClassGuid = 4D1E55B2-F16F-11CF-88CB-001111000030
      SymbolicLinkName = \??\HID#VID_045E&PID_02A0&IG_00#8&634beb5&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}

[...]

In most circumstances, we can use the !object command with the symbolic link name to obtain the directory of the device object, and then use that to get the device object as well. Unfortunately, it appears that either that specific device object had already been released or it was paged out.
 
Here is another variation of the Stop 0x9F bugcheck which only occurs on Windows 8 and later operating systems, due to the introduction of the new power management framework for drivers.

Rich (BB code):
DRIVER_POWER_STATE_FAILURE (9f)
A driver has failed to complete a power IRP within a specific time.
Arguments:
Arg1: 0000000000000005, The device failed to complete a directed power transition within the required
    amount of time.
Arg2: ffff800579662060, Physical Device Object of the stack
Arg3: ffff80059215d8a0, The POP_FX_DEVICE object
Arg4: 0000000000000000

As we can see from the first parameter, the driver has hasn't completed a power IRP within the allotted amount of time. Let's examine the call stack of the thread.

Rich (BB code):
0: kd> knL
 # Child-SP          RetAddr           Call Site
00 fffff807`1e414118 fffff807`21dc7867 nt!KeBugCheckEx
01 fffff807`1e414120 fffff807`21acc2d4 nt!PopFxDirectedWorkOrderWatchdog+0x27
02 fffff807`1e414160 fffff807`21aca8c4 nt!KiProcessExpiredTimerList+0x204
03 fffff807`1e414290 fffff807`21c194de nt!KiRetireDpcList+0x714
04 fffff807`1e414540 00000000`00000000 nt!KiIdleLoop+0x9e

There doesn't appear to be anything particularly interesting occurring apart from the watchdog object which is responsible for triggering the bugcheck. If we dump the device object from the second parameter:

Rich (BB code):
0: kd> !devobj ffff800579662060
Device object (ffff800579662060) is for:
 Cannot read info offset from nt!ObpInfoMaskToOffset
 \Driver\pci DriverObject ffff8005776f52c0
Current Irp 00000000 RefCount 0 Type 0000001d Flags 00001040
SecurityDescriptor ffffa98b6229d620 DevExt ffff8005796621b0 DevObjExt ffff800579662968 DevNode ffff8005794f3c40 
ExtensionFlags (0000000000)  
Characteristics (0x00000100)  FILE_DEVICE_SECURE_OPEN
AttachedDevice (Upper) ffff8005776f1940 Name paged out
Device queue is not busy.

It seems that the device object is for the PCI bus and from what we'll learnt previously, this is unlikely to be the root cause and there will be another device in the device stack causing an issue. We can investigate further by dumping the _PO_FX_DEVICE structure shown in the third parameter.

To keep this post succinct, I'm only to dump the fields which are of the most interest to us:

Rich (BB code):
0: kd> dt _POP_FX_DEVICE -y DeviceObject ffff80059215d8a0
nt!_POP_FX_DEVICE
   +0x060 DeviceObject : 0xffff8005`79662060 _DEVICE_OBJECT

The DeviceObject field is the physical device object for the device stack and the same device object shown in the second parameter. Remember, a device stack can consist of many different device objects and there is usually only one physical device object per a device stack; this is usually the physical bus itself.

Rich (BB code):
0: kd> dt _POP_FX_DEVICE -y TargetDevice ffff80059215d8a0
nt!_POP_FX_DEVICE
   +0x068 TargetDevice : 0xffff8005`91adf740 _DEVICE_OBJECT

The TargetDevice is the device object which the power transition request was directed towards and the one currently responsible for processing the IRP. This is the most important field to investigate along with the IRP itself.

Rich (BB code):
0: kd> dt _POP_FX_DEVICE -y FriendlyName ffff80059215d8a0
nt!_POP_FX_DEVICE
   +0x4a8 FriendlyName : _UNICODE_STRING "Intel(R) Smart Sound Technology (Intel(R) SST) Audio Controller (\_SB.PC00.HDAS)"

The FriendlyName is similar to the device instance name of the device node, it is unicode string which describes what the device node is for. In our case, we can clearly see that the device in question, is for the Intel Smart sound technology controller. As you may have guessed by now, this is the driver which we should be considering, to check for either updates or removal.

Rich (BB code):
0: kd> dt _POP_FX_DEVICE -y Irp ffff80059215d8a0
nt!_POP_FX_DEVICE
   +0x010 Irp : 0xffff8005`921ce340 _IRP
   +0x018 IrpData : 0xffff8005`97a73260 _POP_IRP_DATA
   +0x238 IrpCompleteEvent : _KEVENT

Unfortunately, the IRP can't be fully parsed since we're dealing with a Minidump, however, if we attempt to dump it regardless, we can see that it is indeed pending and stuck at a particular stack location.

Rich (BB code):
0: kd> !irp ffff8005`921ce340
Irp is active with 7 stacks 7 is current (= 0xffff8005921ce5c0)
 No Mdl: No System Buffer: Thread 00000000:  Irp stack trace.  Pending has been returned
     cmd  flg cl Device   File     Completion-Context
 [N/A(0), N/A(0)]
            0  0 00000000 00000000 00000000-00000000    

            Args: 00000000 00000000 00000000 00000000
 [N/A(0), N/A(0)]
            0  0 00000000 00000000 00000000-00000000    

            Args: 00000000 00000000 00000000 00000000
ffff8005921ce4a0: Could not read IrpStack

If we refer back to our target device object, it will hopefully tell us the exact driver which requires updating or removing.

Rich (BB code):
0: kd> !devobj ffff8005`91adf740
Device object (ffff800591adf740) is for:
 InfoMask field not found for _OBJECT_HEADER at ffff800591adf710
Unable to load image \SystemRoot\System32\DriverStore\FileRepository\intcaudiobus.inf_amd64_8c64c6214ca63c3c\IntcAudioBus.sys, Win32 error 0n2
*** WARNING: Unable to verify timestamp for IntcAudioBus.sys
 Name paged out DriverObject ffff800591befe10
Current Irp 00000000 RefCount 0 Type 0000002a Flags 0000200c
SecurityDescriptor ffffa98b6229d620 DevExt ffff800591ad7860 DevObjExt ffff800591adf8b8 
ExtensionFlags (0000000000)  
Characteristics (0x00000100)  FILE_DEVICE_SECURE_OPEN
Device queue is not busy.

The driver is the Intel Smart Sound technology driver and therefore it is recommend that the user check for a suitable update.

Rich (BB code):
0: kd> lmvm IntcAudioBus
Browse full module list
start             end                 module name
fffff807`3d3b0000 fffff807`3d3f9000   IntcAudioBus T (no symbols)           
    Loaded symbol image file: IntcAudioBus.sys
    Image path: \SystemRoot\System32\DriverStore\FileRepository\intcaudiobus.inf_amd64_8c64c6214ca63c3c\IntcAudioBus.sys
    Image name: IntcAudioBus.sys
    Browse all global symbols  functions  data
    Timestamp:        Fri Nov 27 17:14:37 2020 (5FC133FD)
    CheckSum:         0004EA29
    ImageSize:        00049000
    Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4
    Information from resource tables:
 
Just noticed that the device node has a pointer to a structure called PO_IRP_MANAGER which contains two pointers corresponding to device specific power IRPs and system power IRPs.

Rich (BB code):
0: kd> dt _DEVICE_NODE -y PoIrpManager ffff8b8b0e942c70
nt!_DEVICE_NODE
   +0x108 PoIrpManager : _PO_IRP_MANAGER

Rich (BB code):
0: kd> dt _PO_IRP_MANAGER ffff8b8b0e942c70+0x108
nt!_PO_IRP_MANAGER
   +0x000 DeviceIrpQueue   : _PO_IRP_QUEUE
   +0x010 SystemIrpQueue   : _PO_IRP_QUEUE

Both of the queue structures are the same but one is for this particular device and the other for IRPs generated by the power manager.

Rich (BB code):
0: kd> dt _PO_IRP_QUEUE ffff8b8b0e942c70+0x108
nt!_PO_IRP_QUEUE
   +0x000 CurrentIrp       : 0xffff8b8b`329c8a60 _IRP
   +0x008 PendingIrpList   : (null)

This is the same power IRP which is shown in the fourth parameter of the Stop 0x9F bugcheck.

Rich (BB code):
DRIVER_POWER_STATE_FAILURE (9f)
A driver has failed to complete a power IRP within a specific time.
Arguments:
Arg1: 0000000000000003, A device object has been blocking an Irp for too long a time
Arg2: ffff8b8b0e940630, Physical Device Object of the stack
Arg3: fffff8035a26f750, nt!TRIAGE_9F_POWER on Win7 and higher, otherwise the Functional Device Object of the stack
Arg4: ffff8b8b329c8a60, The blocked IRP

Further Reading:

Power IRPs for the System - Windows drivers
Power IRPs for Individual Devices - Windows drivers
 
Back
Top