Monthly Archive for 9월, 2009

PNP_DETECTED_FATAL_ERROR (CA_4)

BugCheck CA 가 발생했을 경우 가장 중요한 부분은 Pnp Manager의 PDO에 대한 Device Node를 찾는 경우 입니다. BugCheck CA의 90%이상이 PDO와 Device Node 사이의 상관 관계에서 발생하기 때문입니다. 간단한 예를 보도록 하죠.

1: kd> !analyze -v
… 생략

PNP_DETECTED_FATAL_ERROR (ca)
PnP encountered a severe error, either as a result of a problem in a driver or
a problem in PnP itself.  The first argument describes the nature of the
problem, the second argument is the address of the PDO.  The other arguments
vary depending on argument 1.
Arguments:
Arg1: 00000004, Invalid enumeration of deleted PDO
 An enumerator has returned a PDO which it has previously deleted
 using IoDeleteDevice.
Arg2: 888a18f0, PDO with DOE_DELETE_PENDING set.
Arg3: 00000000
Arg4: 00000000

Debugging Details:
——————

*** No owner thread found for resource 805624e0
*** No owner thread found for resource 805624e0
*** No owner thread found for resource 805624e0
*** No owner thread found for resource 805624e0

BUGCHECK_STR:  0xCA_4

DEVICE_OBJECT: 888a18f0

DRIVER_OBJECT: 8a6d74b0

IMAGE_NAME:  PnpManager

DEBUG_FLR_IMAGE_TIMESTAMP:  0

MODULE_NAME: PnpManager

FAULTING_MODULE: 00000000

DEFAULT_BUCKET_ID:  DRIVER_FAULT

PROCESS_NAME:  System

LOCK_ADDRESS:  80562560 — (!locks 80562560)

Resource @ nt!IopDeviceTreeLock (0×80562560)    Shared 1 owning threads
    Contention Count = 2
     Threads: 8a6ec640-01<*>
1 total locks, 1 locks currently held

PNP_TRIAGE:
 Lock address  : 0×80562560
 Thread Count  : 1
 Thread address: 0×8a6ec640
 Thread wait   : 0×1c3248

LAST_CONTROL_TRANSFER:  from 80522fa2 to 805393aa

STACK_TEXT: 
f78deaa0 80522fa2 000000ca 00000004 888a18f0 nt!KeBugCheckEx+0×1b
f78deacc 805a14b3 00000005 88156928 8a6d6ee8 nt!PipEnumerateCompleted+0×28c
f78ded20 805a15ef 8a6d6ee8 00000001 00000000 nt!PipProcessDevNodeTree+0×2a9
f78ded54 8050eeae 00000003 805625c0 8056b4fc nt!PiProcessReenumeration+0×60
f78ded7c 804e43b5 00000000 00000000 8a6ec640 nt!PipDeviceActionWorker+0×170
f78dedac 80576120 00000000 00000000 00000000 nt!ExpWorkerThread+0xef
f78deddc 804ee781 804e42f1 00000001 00000000 nt!PspSystemThreadStartup+0×34
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0×16
STACK_COMMAND:  kb

FOLLOWUP_NAME:  MachineOwner

FAILURE_BUCKET_ID:  0xCA_4_IMAGE_PnpManager

BUCKET_ID:  0xCA_4_IMAGE_PnpManager

Followup: MachineOwner
———

PDO의 Status( Extension Flag )에 DOE_DELETE_PENDING 이 Mark 되어 있어서 발생한 상황임을 알 수 있습니다. 즉 PDO와 Link된 Driver가 정상적으로 Unload 되지 않아 Pending 상태가 발생했다고 볼 수 있습니다.

1: kd> !devobj ffffffff888a18f0 f
Device object (888a18f0) is for:
  \Driver\PnpManager DriverObject 8a6d74b0
Current Irp 00000000 RefCount 0 Type 00000004 Flags 00001040
Dacl e177b774 DevExt 888a19a8 DevObjExt 888a19b0 DevNode 889d9ee8
ExtensionFlags (0×00000012)  DOE_DELETE_PENDING, DOE_START_PENDING
Device queue is not busy.

PDO의 Device Object 정보를 보면 해당 DeviceNode를 볼 수 있수 있습니다. Device Node의 정보를 통해서 어떤 드라이버가 정상적으로 Unload 되지 않았는지 확인하면 되겠군요.

1: kd> !devobj ffffffff888a18f0 f
Device object (888a18f0) is for:
  \Driver\PnpManager DriverObject 8a6d74b0
Current Irp 00000000 RefCount 0 Type 00000004 Flags 00001040
Dacl e177b774 DevExt 888a19a8 DevObjExt 888a19b0 DevNode 889d9ee8
ExtensionFlags (0×00000012)  DOE_DELETE_PENDING, DOE_START_PENDING
Device queue is not busy.
1: kd> !devnode 889d9ee8
DevNode 0×889d9ee8 for PDO 0×888a18f0
  Parent 0×8a6d6ee8   Sibling 0×88a44a08   Child 0000000000
  InstancePath is “Root\LEGACY_MyDrv\0000″
  ServiceName is “MyDrv”
  State = DeviceNodeRemoved (0×312)
  Previous State = DeviceNodeStarted (0×308)
  StateHistory[02] = DeviceNodeStarted (0×308)
  StateHistory[01] = DeviceNodeInitialized (0×302)
  StateHistory[00] = DeviceNodeUninitialized (0×301)
  StateHistory[19] = Unknown State (0×0)
  StateHistory[18] = Unknown State (0×0)
  StateHistory[17] = Unknown State (0×0)
  StateHistory[16] = Unknown State (0×0)
  StateHistory[15] = Unknown State (0×0)
  StateHistory[14] = Unknown State (0×0)
  StateHistory[13] = Unknown State (0×0)
  StateHistory[12] = Unknown State (0×0)
  StateHistory[11] = Unknown State (0×0)
  StateHistory[10] = Unknown State (0×0)
  StateHistory[09] = Unknown State (0×0)
  StateHistory[08] = Unknown State (0×0)
  StateHistory[07] = Unknown State (0×0)
  StateHistory[06] = Unknown State (0×0)
  StateHistory[05] = Unknown State (0×0)
  StateHistory[04] = Unknown State (0×0)
  StateHistory[03] = Unknown State (0×0)
  Flags (0×00003101)  DNF_MADEUP, DNF_NO_RESOURCE_REQUIRED,
                      DNF_LEGACY_DRIVER, DNF_HAS_PROBLEM
  UserFlags (0×00000001)  DNUF_WILL_BE_REMOVED
  Problem = CM_PROB_DEVICE_NOT_THERE

 MyDrv라는 녀석이 정상적으로 Unload 되지 않았을 것이라 추정할 수 있습니다. 하지만 현재 DeviceNode의 State는 DeviceNodeRemoved로 표시 되어 있는 것을 확인 할 수 있습니다. 이러한 이유에서 ReEnumeration이 발생했을때 DeviceNode가 Removed 되어진 것으로 알고 PDO를 재사용하려다 DOE_DELETE_PENDING 상태이기 때문에 BugCheck 발생하게 된거죠.

해당 Driver의 Device Object를 확인해 보면 좀더 명확히 Unload Pending 여부를 확인 할 수 있습니다.

1: kd> !devobj \device\MyDrv
Device object (88a57030) is for:
 \Driver\MyDrv DriverObject 88d92d60
Current Irp 00000000 RefCount 0 Type 00000022 Flags 00000844
Dacl e177b774 DevExt 88a570e8 DevObjExt 88a570f0
ExtensionFlags (0×00000001)  DOE_UNLOAD_PENDING
Device queue is not busy.
 

이제 드라이버 Unload 로직을 체크해보면 좀더 정확한 답을 얻을 수 있을 것 같군요 .

Enjoy Debugging

Windows 7 & CR4

예전에 CR4에 관한 글을 하나 남긴적이 있습니다.( VMXE 관련 ) CR4 Register라는 놈이 굉장히 예민하기 때문에 Flag 하나 만으로도 바로 BSOD로 이어지는 경우가 많죠. ( 인터넷 뱅킹도중 많이 경험하셨을꺼라 생각합니다. ) Windows 7 부터는 한가지 부분에 대해서 더 유념해야 하는것이 생겼습니다.  바로 OSXSAVE Bit( 18 째 비트 ) 입니다.

기존 Windows에서는 XRSTOR 명령을 사용하지 않기때문에 18bit가 Reserved 되어 있었지만 Windows 7 부터는 XRSTOR 명령을 지원하는 CPU ( Intel CPU )의 경우 이 명령어를 사용하도록 되어 있습니다.
XRSTOR 명령은 기본적으로 CR4 레지스터의 18bit를 기본적으로 OSXSAVE인식 하는것이 BSOD가 발생할 수 있는 함정으로 작용할 수 있습니다.

Intel® 64 and IA-32 ArchitecturesSoftware Developer’s Manual 2.5 CONTROL REGISTERS
- http://www.intel.com/Assets/PDF/manual/253668.pdf
- OSXSAVE
 XSAVE and Processor Extended States-Enable Bit (bit 18 of CR4) — When set, this flag: (1) indicates (via CPUID.01H:ECX.OSXSAVE[bit 27]) that the operating system supports the use of the XGETBV, XSAVE and XRSTOR instructions by general software; (2) enables the XSAVE and XRSTOR instructions to save and restore the x87 FPU state (including MMX registers), the SSE state (XMM registers and MXCSR), along with other processor extended states enabled in the XFEATURE_ENABLED_MASK register (XCR0); (3) enables the processor to execute XGETBV and XSETBV instructions in order to read and write XCR0. See Section 2.6 and Chapter 13, “System Programming for Instruction Set Extensions and Processor Extended States”.

기존의 Windows에서는 대부분 15~31 bit를 Reserved로 사용하고 있었지만 최근의 Intel Manual를 참고하시면 15~31 bit 에 대해서 Reserved 되지 않은 영역이 있는것을 보실수 있습니다. 기존에 코드가 만약 상위 Bit를 Reserved로 생각하고 작성되어 있다면 이제는 바꿀 시기가 온거죠 !!

혹시나 관련 문제가 생긴다면 참고하시길 …

Enjoy Debugging