인터럽트 스톰 디버깅

중단된 시스템의 가장 일반적인 예 중 하나는 인터럽트 폭풍입니다. 인터럽트 스톰은 어설션된 상태로 유지되는 수준 트리거 인터럽트 신호입니다.

다음 이벤트는 인터럽트 폭풍을 일으킬 수 있습니다.

  • 하드웨어 디바이스는 디바이스 드라이버가 지시한 후 인터럽트 신호를 해제하지 않습니다.

  • 디바이스 드라이버는 하드웨어에서 인터럽트를 시작했음을 감지하지 않으므로 하드웨어에 인터럽트 신호를 해제하도록 지시하지 않습니다.

  • 디바이스 드라이버는 인터럽트를 하드웨어에서 시작하지 않았더라도 인터럽트를 주장합니다. 이 상황은 여러 디바이스가 동일한 IRQ를 공유하는 경우에만 발생할 수 있습니다.

  • ELCR(에지 수준 컨트롤 레지스터)이 올바르게 설정되지 않았습니다.

  • Edge 및 수준 인터럽트 트리거 디바이스는 IRQ(예: COM 포트 및 PCI SCSI 컨트롤러)를 공유합니다.

이 예제에서는 인터럽트 폭풍을 감지하고 디버깅하는 한 가지 방법을 보여 줍니다.

컴퓨터가 중단되면 커널 디버거를 사용하여 침입합니다. !irpfind 확장 명령을 사용하여 보류 중인 IRP를 찾습니다. 그런 다음 !irp 확장을 사용하여 보류 중인 IRP에 대한 세부 정보를 가져옵니다. 예를 들면 다음과 같습니다.

kd> !irp 81183468
Irp is active with 2 stacks 2 is current (= 0x811834fc)
 No Mdl Thread 00000000:  Irp stack trace.
     cmd  flg cl Device   File     Completion-Context
 [  0, 0]   0  0 8145f470 00000000 00000000-00000000
               \Driver\E100B
                        Args: 00000000 00000000 00000000 00000000
>[ 16, 2]   0 e1 8145f470 00000000 8047f744-814187a8 Success Error Cancel pending
               \Driver\E100B    ntoskrnl!PopCompleteSystemPowerIrp
                        Args: 00000000 00000000 00000002 00000002 

이 예제에서는 \driver\e100b가 ntoskrnl에 대한 IRP를 반환하지 않은 것을 보여 줍니다 . PopCompleteSystemPowerIrp. 중단된 것으로 보이며 인터럽트 폭풍이 발생할 수 있습니다.

조사하려면 kb 명령을 사용하여 스택 추적을 요청합니다. 예를 들어:

kd> kb
ChildEBP RetAddr  Args to Child
f714ee68 8046355a 00000001 80068c10 00000030 ntoskrnl!RtlpBreakWithStatusInstruction
f714ee68 80067a4f 00000001 80068c10 00000030 ntoskrnl!KeUpdateSystemTime+0x13e
f714eeec 8046380b 01001010 0000003b f714ef00 halacpi!HalBeginSystemInterrupt+0x83
f714eeec 80463c50 01001010 0000003b f714ef00 ntoskrnl!KiChainedDispatch+0x1b
f714ef78 80067cc2 00000000 00000240 8000017c ntoskrnl!KiDispatchInterrupt
f714ef78 80501cb5 00000000 00000240 8000017c halacpi!HalpDispatchInterrupt2ndEnt  

시작 halacpi!HalBeginSystemInterrupt 섹션은 인터럽트 디스패치입니다. g 명령을 사용하고 다시 침입하는 경우 다른 스택 추적이 표시될 가능성이 높지만 인터럽트 디스패치가 계속 표시됩니다. 시스템 중단을 담당하는 인터럽트를 확인하려면 HalBeginSystemInterrupt 에 전달된 두 번째 매개 변수를 확인합니다(이 경우 0x3B). 표준 규칙은 표시된 인터럽트 벡터(0x3B)가 IRQ 줄과 0x30 더하기 때문에 인터럽트는 0xB 수입니다. 다른 스택 추적을 실행하면 ISR(인터럽트 서비스 요청)을 실행한 디바이스에 대한 자세한 정보를 제공할 수 있습니다. 이 경우 두 번째 스택 추적의 결과는 다음과 같습니다.

kd> kb
ChildEBP RetAddr  Args to Child
f714ee24 8046355a 00000001 00000010 00000030 ntoskrnl!RtlpBreakWithStatusInstruction
f714ee24 bfe854b9 00000001 00000010 00000030 ntoskrnl!KeUpdateSystemTime+0x13e
f714eed8 f7051796 00000000 80463850 8143ec88 atimpab!AtiInterrupt+0x109
f714eee0 80463850 8143ec88 81444038 8046380b VIDEOPRT!pVideoPortInterrupt+0x16
f714eef8 80463818 00000202 0000003b 80450bb8 ntoskrnl!KiChainedDispatch2ndLvl+0x28
f714eef8 80463c50 00000202 0000003b 80450bb8 ntoskrnl!KiChainedDispatch+0x28
f714ef78 80067cc2 00000000 00000240 8000017c ntoskrnl!KiDispatchInterrupt
f714ef78 80501cb5 00000000 00000240 8000017c halacpi!HalpDispatchInterrupt2ndEntry+0x1b
f714f084 8045f744 f714f16c 00020019 f714f148 ntoskrnl!NtCreateKey+0x113
f714f084 8042e487 f714f16c 00020019 f714f148 ntoskrnl!KiSystemService+0xc4
f714f118 804ab556 f714f16c 00020019 f714f148 ntoskrnl!ZwCreateKey+0xb
f714f184 8041f75b f714f1e8 8000017c f714f1d0 ntoskrnl!IopCreateRegistryKeyEx+0x4e
f714f204 804965cd 8145f630 00000000 00000001 ntoskrnl!IopProcessSetInterfaceState+0x93
f714f220 bfee1eb9 8145f630 00000000 8145f5a0 ntoskrnl!IoSetDeviceInterfaceState+0x2b
f714f254 bfedb416 00000004 00000800 0045f570 NDIS!ndisMCommonHaltMiniport+0x1f
f714f268 bfed4ddb bfed0660 811a2708 811a2708 NDIS!ndisPmHaltMiniport+0x9a
f714f288 bfed5146 811a2708 00000004 8145f570 NDIS!ndisSetPower+0x1d1
f714f2a8 8041c60f 81453a30 811a2708 80475b18 NDIS!ndisPowerDispatch+0x84
f714f2bc 8044cc52 80475b18 811a2708 811a279c ntoskrnl!IopfCallDriver+0x35
f714f2d4 8044cb89 811a279c 811a2708 811a27c0 ntoskrnl!PopPresentIrp+0x62 

시스템은 현재 비디오 카드에 대한 ISR을 실행하고 있습니다. 시스템은 IRQ 0xB 공유하는 각 디바이스에 대해 ISR을 실행합니다. 인터럽트 클레임 프로세스가 없으면 운영 체제가 무한히 대기하여 드라이버 ISR이 인터럽트 처리를 요청합니다. 프로세스에서 인터럽트를 처리하고 중지할 수도 있지만 하드웨어가 손상되면 인터럽트를 다시 어설션할 수 있습니다.

!중재자 4 확장을 사용하여 IRQ 0xB 있는 디바이스를 확인합니다. IRQ 0xB 디바이스가 하나만 있는 경우 문제의 원인을 찾았습니다. 인터럽트(사례의 99%)를 공유하는 디바이스가 두 개 이상 있는 경우 LNK 노드를 수동으로 프로그래밍하거나(시스템 상태에 파괴적인) 하드웨어를 제거하거나 사용하지 않도록 설정하여 디바이스를 격리해야 합니다.

kd> !arbiter 4
DEVNODE 8149a008 (HTREE\ROOT\0)
  Interrupt Arbiter "RootIRQ" at 80472a20
    Allocated ranges:
      0000000000000000 - 0000000000000000   B   8149acd0
      0000000000000001 - 0000000000000001   B   8149acd0
      0000000000000002 - 0000000000000002   B   8149acd0
      0000000000000003 - 0000000000000003   B   8149acd0
      0000000000000004 - 0000000000000004   B   8149acd0
      0000000000000005 - 0000000000000005   B   8149acd0
      0000000000000006 - 0000000000000006   B   8149acd0
      0000000000000007 - 0000000000000007   B   8149acd0
      0000000000000008 - 0000000000000008   B   8149acd0
      0000000000000009 - 0000000000000009   B   8149acd0
      000000000000000a - 000000000000000a   B   8149acd0
      000000000000000b - 000000000000000b   B   8149acd0
      000000000000000c - 000000000000000c   B   8149acd0
 000000000000000d - 000000000000000d   B   8149acd0
      000000000000000e - 000000000000000e   B   8149acd0
 000000000000000f - 000000000000000f   B   8149acd0
      0000000000000010 - 0000000000000010   B   8149acd0
      0000000000000011 - 0000000000000011   B   8149acd0
      0000000000000012 - 0000000000000012   B   8149acd0
      0000000000000013 - 0000000000000013   B   8149acd0
      0000000000000014 - 0000000000000014   B   8149acd0
      0000000000000015 - 0000000000000015   B   8149acd0
      0000000000000016 - 0000000000000016   B   8149acd0
      0000000000000017 - 0000000000000017   B   8149acd0
      0000000000000018 - 0000000000000018   B   8149acd0
      0000000000000019 - 0000000000000019   B   8149acd0
      000000000000001a - 000000000000001a   B   8149acd0
      000000000000001b - 000000000000001b   B   8149acd0
      000000000000001c - 000000000000001c   B   8149acd0
      000000000000001d - 000000000000001d   B   8149acd0
 000000000000001e - 000000000000001e   B   8149acd0
      000000000000001f - 000000000000001f   B   8149acd0
 0000000000000020 - 0000000000000020   B   8149acd0
      0000000000000021 - 0000000000000021   B   8149acd0
      0000000000000022 - 0000000000000022   B   8149acd0
      0000000000000023 - 0000000000000023   B   8149acd0
      0000000000000024 - 0000000000000024   B   8149acd0
      0000000000000025 - 0000000000000025   B   8149acd0
      0000000000000026 - 0000000000000026   B   8149acd0
      0000000000000027 - 0000000000000027   B   8149acd0
      0000000000000028 - 0000000000000028   B   8149acd0
      0000000000000029 - 0000000000000029   B   8149acd0
      000000000000002a - 000000000000002a   B   8149acd0
      000000000000002b - 000000000000002b   B   8149acd0
      000000000000002c - 000000000000002c   B   8149acd0
 000000000000002d - 000000000000002d   B   8149acd0
      000000000000002e - 000000000000002e   B   8149acd0
 000000000000002f - 000000000000002f   B   8149acd0
      0000000000000032 - 0000000000000032   B   8149acd0
      0000000000000039 - 0000000000000039 S     814776d0  (ACPI)
    Possible allocation:
      < none >

    DEVNODE 81476f28 (ACPI_HAL\PNP0C08\0)
      Interrupt Arbiter "ACPI_IRQ" at bfff10e0
        Allocated ranges:
          0000000000000000 - 0000000000000000   B   81495bb0
          0000000000000001 - 0000000000000001       814952b0  (i8042prt)
          0000000000000003 - 0000000000000003 S     81495610  (Serial)
          0000000000000004 - 0000000000000004   B   8149acd0
          0000000000000006 - 0000000000000006       81495730  (fdc)
          0000000000000008 - 0000000000000008       81495a90
          0000000000000009 - 0000000000000009 S     814776d0  (ACPI)
          000000000000000b - 000000000000000b S
            000000000000000b - 000000000000000b S     81453c30  (ds1)
            000000000000000b - 000000000000000b S     81453a30  (E100B)
            000000000000000b - 000000000000000b S     81493c30  (uhcd)
            000000000000000b - 000000000000000b S     8145c390  (atirage3)
          000000000000000c - 000000000000000c       814953d0  (i8042prt)
 000000000000000d - 000000000000000d   B   81495850
          000000000000000e - 000000000000000e       8145bb50  (atapi)
 000000000000000f - 000000000000000f       8145b970  (atapi)
        Possible allocation:
          < none >

이 경우 오디오, USB(유니버설 직렬 버스), NIC(네트워크 인터페이스 카드) 및 비디오는 모두 동일한 IRQ를 사용합니다.

인터럽트 소유권을 클레임하는 ISR을 확인하려면 ISR의 반환 값을 검사합니다. !중재자 디스플레이에 지정된 주소가 있는 U 명령을 사용하여 ISR을 디스어셈블하고 ISR의 마지막 명령('ret' 명령)에 중단점을 설정하기만 하면 됩니다. 명령 g <주소를 사용하는 것은 해당 주소>에 중단점을 설정하는 것과 같습니다.

kd> g bfe33e7b
ds1wdm!AdapterIsr+ad:
bfe33e7b c20800           ret     0x8 

r 명령을 사용하여 레지스터를 검사합니다. 특히 EAX 레지스터를 확인합니다. 다음 코드 예제에 표시된 EAX 레지스터 콘텐츠가 0이면 이 ISR에서 인터럽트 클레임을 수행했습니다. 그렇지 않으면 인터럽트는 클레임되지 않으며 운영 체제는 다음 ISR을 호출합니다. 이 예제에서는 비디오 카드가 인터럽트 클레임을 수행하지 않는 것을 보여 주는 예제입니다.

kd> r
eax=00000000 ebx=813f4ff0 ecx=00000010 edx=ffdff848 esi=8145d168 edi=813f4fc8
eip=bfe33e7b esp=f714eec4 ebp=f714eee0 iopl=0         nv up ei pl zr na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000246
ds1wdm!AdapterIsr+ad:
bfe33e7b c20800           ret     0x8 

실제로 이 경우 IRQ 0xb 디바이스에서 인터럽트가 클레임되지 않습니다. 이 문제가 발생하면 인터럽트와 연결된 각 하드웨어가 실제로 사용하도록 설정되어 있는지도 확인해야 합니다. PCI의 경우 ! pci 확장 출력에 표시되는 CMD 레지스터를 살펴보는 것이 쉽습니다.

kd> !pci 0 0
PCI Bus 0
00:0  8086:7190.03  Cmd[0006:.mb...]  Sts[2210:c....]  Device  Host bridge
01:0  8086:7191.03  Cmd[0107:imb..s]  Sts[0220:.6...]  PciBridge 0->1-1  PCI-PCI bridge
03:0  1073:000c.03  Cmd[0000:......]  Sts[0210:c....]  Device  SubID:1073:000c Audio device
04:0  8086:1229.05  Cmd[0007:imb...]  Sts[0290:c....]  Device  SubID:8086:0008 Ethernet
07:0  8086:7110.02  Cmd[000f:imb...]  Sts[0280:.....]  Device  ISA bridge
07:1  8086:7111.01  Cmd[0005:i.b...]  Sts[0280:.....]  Device  IDE controller
07:2  8086:7112.01  Cmd[0005:i.b...]  Sts[0280:.....]  Device  USB host controller
07:3  8086:7113.02  Cmd[0003:im....]  Sts[0280:.....]  Device  Class:6:80:0

오디오 칩("오디오 디바이스"라는 레이블이 지정됨) CMD 레지스터는 0입니다. 즉, 오디오 칩이 현재 효과적으로 비활성화되어 있습니다. 이는 또한 오디오 칩이 드라이버의 액세스에 응답할 수 없음을 의미합니다.

이 경우 오디오 칩을 수동으로 다시 사용하도록 설정해야 합니다.