- New ISR Timeout detection code.
authorAlex Ionescu <aionescu@gmail.com>
Mon, 19 Mar 2007 03:29:29 +0000 (03:29 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Mon, 19 Mar 2007 03:29:29 +0000 (03:29 +0000)
- New Interrupt Storm detection code.
- Use PCR everywhere instead of fs:[ or [fs:. Significant improvements on UP builds because we use ds:[KPCRADDRESSS] for them.
- Ongoing work.

svn path=/trunk/; revision=26137

reactos/include/ndk/asm.h
reactos/include/ndk/ketypes.h
reactos/ntoskrnl/include/internal/i386/asmmacro.S
reactos/ntoskrnl/ke/i386/irqobj.c
reactos/ntoskrnl/ke/i386/trap.s

index 0888ba0..012a232 100644 (file)
@@ -222,10 +222,12 @@ Author:
 //
 #define KINTERRUPT_SERVICE_ROUTINE              0x0C
 #define KINTERRUPT_SERVICE_CONTEXT              0x10
+#define KINTERRUPT_TICK_COUNT                   0x18
 #define KINTERRUPT_ACTUAL_LOCK                  0x1C
 #define KINTERRUPT_IRQL                         0x20
 #define KINTERRUPT_VECTOR                       0x24
 #define KINTERRUPT_SYNCHRONIZE_IRQL             0x29
+#define KINTERRUPT_DISPATCH_COUNT               0x38
 
 //
 // KGDTENTRY Offsets
@@ -546,6 +548,7 @@ Author:
 #define IRQL_GT_ZERO_AT_SYSTEM_SERVICE          0x4A
 #define UNEXPECTED_KERNEL_MODE_TRAP             0x7F
 #define ATTEMPTED_SWITCH_FROM_DPC               0xB8
+#define HARDWARE_INTERRUPT_STORM                0xF2
 
 //
 // IRQL Levels
@@ -607,3 +610,4 @@ Author:
 #define MAXIMUM_IDTVECTOR                       0xFF
 #endif // !_ASM_H
 
+
index 83354dd..2ff4ba7 100644 (file)
@@ -622,14 +622,14 @@ typedef struct _KINTERRUPT
     KSPIN_LOCK SpinLock;
     ULONG TickCount;
     PKSPIN_LOCK ActualLock;
-    PVOID DispatchAddress;
+    PKINTERRUPT_ROUTINE DispatchAddress;
     ULONG Vector;
     KIRQL Irql;
     KIRQL SynchronizeIrql;
     BOOLEAN FloatingSave;
     BOOLEAN Connected;
-    CHAR Number;
-    UCHAR ShareVector;
+    CCHAR Number;
+    BOOLEAN ShareVector;
     KINTERRUPT_MODE Mode;
 #if (NTDDI_VERSION >= NTDDI_LONGHORN)
     KINTERRUPT_POLARITY Polarity;
index 2972df2..7204097 100644 (file)
@@ -353,7 +353,7 @@ _KiUnexpectedInterrupt&Number:
 
     /* Get the current thread */
 1:
-    mov ebx, [fs:KPCR_CURRENT_THREAD]
+    mov ebx, PCR[KPCR_CURRENT_THREAD]
 
     /* Make it non-alerted */
     mov byte ptr [ebx+KTHREAD_ALERTED], 0
@@ -440,7 +440,7 @@ _KiUnexpectedInterrupt&Number:
     mov fs, bx
 
     /* Save exception list and bogus previous mode */
-    push fs:[KPCR_EXCEPTION_LIST]
+    push PCR[KPCR_EXCEPTION_LIST]
     push -1
 
     /* Save volatiles and segment registers */
@@ -476,7 +476,7 @@ _KiUnexpectedInterrupt&Number:
 
 1:
     /* Get current thread */
-    mov ecx, [fs:KPCR_CURRENT_THREAD]
+    mov ecx, PCR[KPCR_CURRENT_THREAD]
     cld
 
     /* Flush DR7 */
@@ -555,10 +555,10 @@ _KiUnexpectedInterrupt&Number:
 
 1: 
     /* Get the previous exception list */
-    mov ebx, [fs:KPCR_EXCEPTION_LIST]
+    mov ebx, PCR[KPCR_EXCEPTION_LIST]
 
     /* Set the exception handler chain terminator */
-    mov dword ptr [fs:KPCR_EXCEPTION_LIST], -1
+    mov dword ptr PCR[KPCR_EXCEPTION_LIST], -1
 
     /* Save the previous exception list */
     mov [esp+KTRAP_FRAME_EXCEPTION_LIST], ebx
@@ -579,7 +579,7 @@ _KiUnexpectedInterrupt&Number:
     and dword ptr [esp+KTRAP_FRAME_ERROR_CODE], 0
 
     /* Get the current thread and clear direction flag */
-    mov ecx, [fs:KPCR_CURRENT_THREAD]
+    mov ecx, PCR[KPCR_CURRENT_THREAD]
     cld
 
     /* Flush DR7 */
@@ -631,13 +631,13 @@ _KiUnexpectedInterrupt&Number:
     mov fs, bx
 
     /* Get a pointer to the current thread */
-    mov esi, [fs:KPCR_CURRENT_THREAD]
+    mov esi, PCR[KPCR_CURRENT_THREAD]
 
     /* Save the previous exception list */
-    push [fs:KPCR_EXCEPTION_LIST]
+    push PCR[KPCR_EXCEPTION_LIST]
 
     /* Set the exception handler chain terminator */
-    mov dword ptr [fs:KPCR_EXCEPTION_LIST], -1
+    mov dword ptr PCR[KPCR_EXCEPTION_LIST], -1
 
     /* Save the old previous mode */
     push [esi+KTHREAD_PREVIOUS_MODE]
@@ -705,7 +705,7 @@ _KiUnexpectedInterrupt&Number:
     mov es, cx
 
     /* Set the current stack to Kernel Stack */
-    mov ecx, [fs:KPCR_TSS]
+    mov ecx, PCR[KPCR_TSS]
     mov esp, [ecx+KTSS_ESP0]
 
     /* Set up a fake INT Stack. */
@@ -728,7 +728,7 @@ _KiUnexpectedInterrupt&Number:
     push KGDT_R3_TEB + RPL_MASK
 
     /* Save pointer to our PCR */
-    mov ebx, [fs:KPCR_SELF]
+    mov ebx, PCR[KPCR_SELF]
 
     /* Get a pointer to the current thread */
     mov esi, [ebx+KPCR_CURRENT_THREAD]
@@ -831,7 +831,7 @@ _KiUnexpectedInterrupt&Number:
     cld
 
     /* Save the exception list */
-    mov eax, [fs:KPCR_EXCEPTION_LIST]
+    mov eax, PCR[KPCR_EXCEPTION_LIST]
     mov [esp+KTRAP_FRAME_EXCEPTION_LIST], eax
 
     /* Check if we need debugging */
@@ -854,7 +854,7 @@ _KiUnexpectedInterrupt&Number:
 
     /* Get the current thread and make it unalerted */
 ExitBegin:
-    mov ebx, [fs:KPCR_CURRENT_THREAD]
+    mov ebx, PCR[KPCR_CURRENT_THREAD]
     mov byte ptr [ebx+KTHREAD_ALERTED], 0
 
     /* Check if it has User-mode APCs pending */
@@ -954,7 +954,7 @@ PendingUserApc:
     jnz 1f
 
     /* Assert exception list */
-    cmp dword ptr fs:[KPCR_EXCEPTION_LIST], 0
+    cmp dword ptr PCR[KPCR_EXCEPTION_LIST], 0
     jnz 2f
 
 1:
@@ -975,7 +975,7 @@ PendingUserApc:
 #endif
 
     /* Restore it */
-    mov [fs:KPCR_EXCEPTION_LIST], edx
+    mov PCR[KPCR_EXCEPTION_LIST], edx
 
 .if \RestorePreviousMode
     /* Get previous mode */
@@ -990,7 +990,7 @@ PendingUserApc:
 #endif
 
     /* Restore the previous mode */
-    mov esi, [fs:KPCR_CURRENT_THREAD]
+    mov esi, PCR[KPCR_CURRENT_THREAD]
     mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], cl
 .else
 
@@ -1211,3 +1211,117 @@ FastExit:
     iret
 .endm
 
+//
+// @name INT_EPILOG
+// 
+// This macro creates an epilogue for leaving any system trap.
+// It is used for exiting system calls, exceptions, interrupts and generic
+// traps.
+//
+// @param Spurious - TRUE if the interrupt was unexpected and spurious.
+//
+// @remark None.
+//
+.macro INT_EPILOG Spurious
+
+.if \Spurious
+    /* Just exit the trap */
+    jmp _Kei386EoiHelper@0
+.else
+    /* Disable interrupts */
+    cli
+
+    /* End the interrupt and do EOI */
+    call _HalEndSystemInterrupt@8
+    jmp _Kei386EoiHelper@0
+.endif
+.endm
+
+#ifdef DBG
+
+.macro VERIFY_INT Label
+    /* Get the current time and mask it to 192 ticks */
+    mov eax, _KeTickCount
+    and eax, 0xC0
+
+    /* Check if we're in the same tick area */
+    cmp eax, dword ptr [edi+KINTERRUPT_TICK_COUNT]
+    jg VfRst_&Label
+    jl VfWrap_&Label
+
+    /* If we got here, then our count is too large */
+    dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT]
+    jz VfOvr_&Label
+Vf_&Label:
+.endm
+
+.macro VERIFY_INT_END Label, Info
+VfOvr_&Label:
+
+    /* Decrement the dispatch count and check if we should bug check */
+    dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2]
+    jz 1f
+
+    /* Update the tick count */
+    add eax, 0x40
+    mov [edi+KINTERRUPT_TICK_COUNT], eax
+    jmp VfRstDef_&Label
+
+.1:
+    /* Check if the debugger is enabled */
+    cmp byte ptr __KdDebuggerEnabled, 0
+    jnz 1f
+
+    /* It isn't, bugcheck */
+    push Info
+    push edi
+    push [edi+KINTERRUPT_SERVICE_CONTEXT]
+    push [edi+KINTERRUPT_SERVICE_ROUTINE]
+    push HARDWARE_INTERRUPT_STORM
+    call _KeBugCheckEx@20
+
+1:
+    /* Debugger enabled, do a debug print + break instead */
+    push [edi+KINTERRUPT_SERVICE_ROUTINE]
+    push offset _IsrOverflowMsg
+    call _DbgPrint
+    add esp, 8
+    int 3
+
+    /* Breakpoint handled, get the new tick count */
+    mov eax, _KeTickCount
+    and eax, 0xC0
+
+VfRst_&Label:
+    /* Reset tick count */
+    mov dword ptr [edi+KINTERRUPT_TICK_COUNT], eax
+    mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2], 64
+
+VfRstDef_&Label:
+    /* Put default overflow count and continue */
+    mov ax, _KiISROverflow
+    mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT], ax
+    jmp Vf_&Label
+
+VfWrap_&Label:
+    /* Check if we wrapped */
+    add eax, 0x40
+    cmp eax, [edi+KINTERRUPT_TICK_COUNT]
+    je Vf_&Label
+
+    /* We did, start over */
+    mov eax, _KeTickCount
+    jmp VfRst_&Label
+.endm
+
+#else
+
+/* We don't verify interrupts on retail builds */
+.macro VERIFY_INT Label
+.endm
+.macro VERIFY_INT_END Label, Info
+.endm
+
+#endif
+
+
index 9b07ea9..deb5a7a 100644 (file)
@@ -9,12 +9,17 @@
  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
  */
 
-/* INCLUDES ****************************************************************/
+/* INCLUDES *****************************************************************/
 
 #include <ntoskrnl.h>
 #define NDEBUG
 #include <debug.h>
 
+/* GLOBALS *******************************************************************/
+
+ULONG KiISRTimeout = 55;
+USHORT KiISROverflow = 30000;
+
 /* PRIVATE FUNCTIONS *********************************************************/
 
 VOID
@@ -172,6 +177,8 @@ KeInitializeInterrupt(IN PKINTERRUPT Interrupt,
     Interrupt->ShareVector = ShareVector;
     Interrupt->Number = ProcessorNumber;
     Interrupt->FloatingSave = FloatingSave;
+    Interrupt->TickCount = (ULONG)-1;
+    Interrupt->DispatchCount = (ULONG)-1;
 
     /* Loop the template in memory */
     for (i = 0; i < KINTERRUPT_DISPATCH_CODES; i++)
@@ -180,6 +187,14 @@ KeInitializeInterrupt(IN PKINTERRUPT Interrupt,
         *DispatchCode++ = KiInterruptTemplate[i];
     }
 
+    /* Sanity check */
+    DPRINT1("Template Size: %lx. Code Size: %lx\n",
+            (ULONG_PTR)&KiInterruptTemplateDispatch -
+            (ULONG_PTR)KiInterruptTemplate,
+            KINTERRUPT_DISPATCH_CODES * 4);
+    ASSERT((ULONG_PTR)&KiInterruptTemplateDispatch -
+           (ULONG_PTR)KiInterruptTemplate <= (KINTERRUPT_DISPATCH_CODES * 4));
+
     /* Jump to the last 4 bytes */
     Patch = (PULONG)((ULONG_PTR)Patch +
                      ((ULONG_PTR)&KiInterruptTemplateObject -
@@ -216,7 +231,6 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
         (Interrupt->SynchronizeIrql < Irql) ||
         (Interrupt->FloatingSave))
     {
-        DPRINT1("Invalid interrupt object\n");
         return FALSE;
     }
 
@@ -254,7 +268,7 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
                 (Dispatch.Interrupt->Mode == Interrupt->Mode))
         {
             /* The vector is shared and the interrupts are compatible */
-            ASSERT(FALSE); // FIXME: NOT YET SUPPORTED/TESTED
+            while (TRUE); // FIXME: NOT YET SUPPORTED/TESTED
             Interrupt->Connected = Connected = TRUE;
             ASSERT(Irql <= SYNCH_LEVEL);
 
@@ -275,6 +289,14 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
     KiReleaseDispatcherLock(OldIrql);
     KeRevertToUserAffinityThread();
 
+    /* Check if we failed while trying to connect */
+    if ((Connected) && (Error))
+    {
+        DPRINT1("HalEnableSystemInterrupt failed\n");
+        KeDisconnectInterrupt(Interrupt);
+        Connected = FALSE;
+    }
+
     /* Return to caller */
     return Connected;
 }
index cba533b..8aabaf6 100644 (file)
@@ -93,6 +93,12 @@ _UnexpectedMsg:
 _UnhandledMsg:
     .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx!!!\n"
 
+_IsrTimeoutMsg:
+    .asciz "\n*** ISR at %lx took over .5 second\n"
+
+_IsrOverflowMsg:
+    .asciz "\n*** ISR at %lx appears to have an interrupt storm\n"
+
 _KiTrapPrefixTable:
     .byte 0xF2                      /* REP                                  */
     .byte 0xF3                      /* REP INS/OUTS                         */
@@ -174,7 +180,7 @@ SharedCode:
     jnz NotWin32K
 
     /* Get the TEB */
-    mov ecx, [fs:KPCR_TEB]
+    mov ecx, PCR[KPCR_TEB]
 
     /* Check if we should flush the User Batch */
     xor ebx, ebx
@@ -191,7 +197,7 @@ ReadBatch:
 
 NotWin32K:
     /* Increase total syscall count */
-    inc dword ptr fs:[KPCR_SYSTEM_CALLS]
+    inc dword ptr PCR[KPCR_SYSTEM_CALLS]
 
 #ifdef DBG
     /* Increase per-syscall count */
@@ -243,7 +249,7 @@ AfterSysCall:
     mov eax, esi                /* Restore it */
 
     /* Get our temporary current thread pointer for sanity check */
-    mov ecx, fs:[KPCR_CURRENT_THREAD]
+    mov ecx, PCR[KPCR_CURRENT_THREAD]
 
     /* Make sure that we are not attached and that APCs are not disabled */
     mov dl, [ecx+KTHREAD_APC_STATE_INDEX]
@@ -262,7 +268,7 @@ SkipCheck:
 KeReturnFromSystemCall:
 
     /* Get the Current Thread */
-    mov ecx, [fs:KPCR_CURRENT_THREAD]
+    mov ecx, PCR[KPCR_CURRENT_THREAD]
 
     /* Restore the old trap frame pointer */
     mov edx, [ebp+KTRAP_FRAME_EDX]
@@ -353,7 +359,7 @@ AccessViolation:
 BadStack:
 
     /* Restore ESP0 stack */
-    mov ecx, [fs:KPCR_TSS]
+    mov ecx, PCR[KPCR_TSS]
     mov esp, ss:[ecx+KTSS_ESP0]
 
     /* Generate V86M Stack for Trap 6 */
@@ -373,10 +379,10 @@ BadStack:
 #ifdef DBG
 InvalidIrql:
     /* Save current IRQL */
-    push fs:[KPCR_IRQL]
+    push PCR[KPCR_IRQL]
 
     /* Set us at passive */
-    mov dword ptr fs:[KPCR_IRQL], 0
+    mov dword ptr PCR[KPCR_IRQL], 0
     cli
 
     /* Bugcheck */
@@ -485,7 +491,7 @@ _NtRaiseException@12:
     push ebp
 
     /* Get the current thread and restore its trap frame */
-    mov ebx, [fs:KPCR_CURRENT_THREAD]
+    mov ebx, PCR[KPCR_CURRENT_THREAD]
     mov edx, [ebp+KTRAP_FRAME_EDX]
     mov [ebx+KTHREAD_TRAP_FRAME], edx
 
@@ -497,7 +503,7 @@ _NtRaiseException@12:
 
     /* Get the exception list and restore */
     mov eax, [ebx+KTRAP_FRAME_EXCEPTION_LIST]
-    mov [fs:KPCR_EXCEPTION_LIST], eax
+    mov PCR[KPCR_EXCEPTION_LIST], eax
 
     /* Get the parameters */
     mov edx, [ebp+16] /* Search frames */
@@ -532,7 +538,7 @@ _NtContinue@8:
     push ebp
 
     /* Get the current thread and restore its trap frame */
-    mov ebx, [fs:KPCR_CURRENT_THREAD]
+    mov ebx, PCR[KPCR_CURRENT_THREAD]
     mov edx, [ebp+KTRAP_FRAME_EDX]
     mov [ebx+KTHREAD_TRAP_FRAME], edx
 
@@ -696,7 +702,7 @@ SendException:
 
 VdmCheck:
     /* Check if this is a VDM process */
-    mov ebx, [fs:KPCR_CURRENT_THREAD]
+    mov ebx, PCR[KPCR_CURRENT_THREAD]
     mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
     cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
     jz SendException
@@ -742,7 +748,7 @@ PrepInt1:
 
 V86Int1:
     /* Check if this is a VDM process */
-    mov ebx, [fs:KPCR_CURRENT_THREAD]
+    mov ebx, PCR[KPCR_CURRENT_THREAD]
     mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
     cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
     jz EnableInterrupts
@@ -806,7 +812,7 @@ PrepInt3:
 
 V86Int3:
     /* Check if this is a VDM process */
-    mov ebx, [fs:KPCR_CURRENT_THREAD]
+    mov ebx, PCR[KPCR_CURRENT_THREAD]
     mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
     cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
     jz EnableInterrupts3
@@ -847,7 +853,7 @@ SendException4:
 
 VdmCheck4:
     /* Check if this is a VDM process */
-    mov ebx, [fs:KPCR_CURRENT_THREAD]
+    mov ebx, PCR[KPCR_CURRENT_THREAD]
     mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
     cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
     jz SendException4
@@ -893,7 +899,7 @@ SendException5:
 
 VdmCheck5:
     /* Check if this is a VDM process */
-    mov ebx, [fs:KPCR_CURRENT_THREAD]
+    mov ebx, PCR[KPCR_CURRENT_THREAD]
     mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
     cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
     jz SendException5
@@ -934,7 +940,7 @@ NotV86UD:
     jz UmodeOpcode
 
     /* Check if the process is vDM */
-    mov ebx, fs:[KPCR_CURRENT_THREAD]
+    mov ebx, PCR[KPCR_CURRENT_THREAD]
     mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
     cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
     jnz IsVdmOpcode
@@ -950,8 +956,8 @@ UmodeOpcode:
     /* Setup a SEH frame */
     push ebp
     push OpcodeSEH
-    push fs:[KPCR_EXCEPTION_LIST]
-    mov fs:[KPCR_EXCEPTION_LIST], esp
+    push PCR[KPCR_EXCEPTION_LIST]
+    mov PCR[KPCR_EXCEPTION_LIST], esp
 
 OpcodeLoop:
     /* Get the instruction and check if it's LOCK */
@@ -964,7 +970,7 @@ OpcodeLoop:
     loop OpcodeLoop
 
     /* Undo SEH frame */
-    pop fs:[KPCR_EXCEPTION_LIST]
+    pop PCR[KPCR_EXCEPTION_LIST]
     add esp, 8
 
 KmodeOpcode:
@@ -980,7 +986,7 @@ KmodeOpcode:
 LockCrash:
 
     /* Undo SEH Frame */
-    pop fs:[KPCR_EXCEPTION_LIST]
+    pop PCR[KPCR_EXCEPTION_LIST]
     add esp, 8
 
     /* Setup invalid lock exception and dispatch it */
@@ -1000,7 +1006,7 @@ OpcodeSEH:
 
     /* Get SEH frame */
     mov esp, [esp+8]
-    pop fs:[KPCR_EXCEPTION_LIST]
+    pop PCR[KPCR_EXCEPTION_LIST]
     add esp, 4
     pop ebp
 
@@ -1030,7 +1036,7 @@ _KiTrap7:
 
     /* Get the current thread and stack */
 StartTrapHandle:
-    mov eax, [fs:KPCR_CURRENT_THREAD]
+    mov eax, PCR[KPCR_CURRENT_THREAD]
     mov ecx, [eax+KTHREAD_INITIAL_STACK]
     sub ecx, NPX_FRAME_LENGTH
 
@@ -1049,7 +1055,7 @@ CheckState:
     mov cr0, ebx
 
     /* Check the NPX thread */
-    mov edx, [fs:KPCR_NPX_THREAD]
+    mov edx, PCR[KPCR_NPX_THREAD]
     or edx, edx
     jz NoNpxThread
 
@@ -1083,7 +1089,7 @@ FrRestore:
 AfterRestore:
     /* Set state loaded */
     mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
-    mov [fs:KPCR_NPX_THREAD], eax
+    mov PCR[KPCR_NPX_THREAD], eax
 
     /* Enable interrupts to happen now */
     sti
@@ -1144,7 +1150,7 @@ HandleNpxFault:
 
 UserNpx:
     /* Get the current thread */
-    mov eax, fs:[KPCR_CURRENT_THREAD]
+    mov eax, PCR[KPCR_CURRENT_THREAD]
 
     /* Check NPX state */
     cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
@@ -1180,7 +1186,7 @@ MakeCr0Dirty:
 
     /* Update NPX state */
     mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
-    mov dword ptr fs:[KPCR_NPX_THREAD], 0
+    mov dword ptr PCR[KPCR_NPX_THREAD], 0
 
 NoSaveRestore:
     /* Clear the TS bit and re-enable interrupts */
@@ -1293,7 +1299,7 @@ UnexpectedNpx:
 
 V86Npx:
     /* Check if this is a VDM */
-    mov eax, fs:[KPCR_CURRENT_THREAD]
+    mov eax, PCR[KPCR_CURRENT_THREAD]
     mov ebx, [eax+KTHREAD_APCSTATE_PROCESS]
     cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
     jz HandleUserNpx
@@ -1414,7 +1420,7 @@ _KiTrapExceptHandler:
 
     /* Setup SEH handler frame */
     mov esp, [esp+8]
-    pop fs:[KPCR_EXCEPTION_LIST]
+    pop PCR[KPCR_EXCEPTION_LIST]
     add esp, 4
     pop ebp
 
@@ -1445,7 +1451,7 @@ _KiTrap13:
     V86_TRAP_PROLOG kitd
 
     /* Make sure that this is a V86 process */
-    mov ecx, [fs:KPCR_CURRENT_THREAD]
+    mov ecx, PCR[KPCR_CURRENT_THREAD]
     mov ecx, [ecx+KTHREAD_APCSTATE_PROCESS]
     cmp dword ptr [ecx+EPROCESS_VDM_OBJECTS], 0
     jnz RaiseIrql
@@ -1505,7 +1511,7 @@ NotV86:
     jnz UserModeGpf
 
     /* Check if we have a VDM alert */
-    cmp dword ptr fs:[KPCR_VDM_ALERT], 0
+    cmp dword ptr PCR[KPCR_VDM_ALERT], 0
     jnz VdmAlertGpf
 
     /* Check for GPF during GPF */
@@ -1565,7 +1571,7 @@ KmodeGpf:
 
 NotBiosGpf:
     /* Check if the thread was in kernel mode */
-    mov ebx, [fs:KPCR_CURRENT_THREAD]
+    mov ebx, PCR[KPCR_CURRENT_THREAD]
     test byte ptr [ebx+KTHREAD_PREVIOUS_MODE], 0xFF
     jz UserModeGpf
 
@@ -1656,7 +1662,7 @@ UserModeGpf:
     jz _KiSystemFatalException
 
     /* Get the process and check which CS this came from */
-    mov ebx, fs:[KPCR_CURRENT_THREAD]
+    mov ebx, PCR[KPCR_CURRENT_THREAD]
     mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
     cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
     jz CheckVdmGpf
@@ -1719,8 +1725,8 @@ CheckPrivilegedInstruction:
     /* Setup a SEH handler */
     push ebp
     push offset _KiTrapExceptHandler
-    push fs:[KPCR_EXCEPTION_LIST]
-    mov fs:[KPCR_EXCEPTION_LIST], esp
+    push PCR[KPCR_EXCEPTION_LIST]
+    mov PCR[KPCR_EXCEPTION_LIST], esp
 
     /* Get EIP */
     mov esi, [ebp+KTRAP_FRAME_EIP]
@@ -1790,7 +1796,7 @@ CheckPrivilegedInstruction2:
 
 IsPrivInstruction:
     /* Cleanup the SEH frame */
-    pop fs:[KPCR_EXCEPTION_LIST]
+    pop PCR[KPCR_EXCEPTION_LIST]
     add esp, 8
 
     /* Setup the exception */
@@ -1800,7 +1806,7 @@ IsPrivInstruction:
 
 NotIoViolation:
     /* Cleanup the SEH frame */
-    pop fs:[KPCR_EXCEPTION_LIST]
+    pop PCR[KPCR_EXCEPTION_LIST]
     add esp, 8
 
 SetException:
@@ -1824,11 +1830,11 @@ _KiTrap14:
     TRAP_PROLOG kit14
 
     /* Check if we have a VDM alert */
-    cmp dword ptr fs:[KPCR_VDM_ALERT], 0
+    cmp dword ptr PCR[KPCR_VDM_ALERT], 0
     jnz VdmAlertGpf
 
     /* Get the current thread */
-    mov edi, fs:[KPCR_CURRENT_THREAD]
+    mov edi, PCR[KPCR_CURRENT_THREAD]
 
     /* Get the stack address of the frame */
     lea eax, [esp+KTRAP_FRAME_LENGTH+NPX_FRAME_LENGTH]
@@ -1840,7 +1846,7 @@ _KiTrap14:
     jb NoFixUp
 
     /* Check if we have a TEB */
-    mov eax, fs:[KPCR_TEB]
+    mov eax, PCR[KPCR_TEB]
     or eax, eax
     jle NoFixUp
 
@@ -1913,7 +1919,7 @@ CheckVdmPf:
     jnz VdmPF
 
     /* Check if the fault occured in a VDM */
-    mov esi, fs:[KPCR_CURRENT_THREAD]
+    mov esi, PCR[KPCR_CURRENT_THREAD]
     mov esi, [esi+KTHREAD_APCSTATE_PROCESS]
     cmp dword ptr [esi+EPROCESS_VDM_OBJECTS], 0
     jz CheckStatus
@@ -2006,8 +2012,8 @@ _KiTrap16:
     TRAP_PROLOG kit16
 
     /* Check if this is the NPX Thread */
-    mov eax, fs:[KPCR_CURRENT_THREAD]
-    cmp eax, fs:[KPCR_NPX_THREAD]
+    mov eax, PCR[KPCR_CURRENT_THREAD]
+    cmp eax, PCR[KPCR_NPX_THREAD]
 
     /* Get the initial stack and NPX frame */
     mov ecx, [eax+KTHREAD_INITIAL_STACK]
@@ -2059,7 +2065,7 @@ _KiSystemFatalException:
 _KiCoprocessorError@0:
 
     /* Get the NPX Thread's Initial stack */
-    mov eax, [fs:KPCR_NPX_THREAD]
+    mov eax, PCR[KPCR_NPX_THREAD]
     mov eax, [eax+KTHREAD_INITIAL_STACK]
 
     /* Make space for the FPU Save area */
@@ -2085,7 +2091,7 @@ _Ki16BitStackException:
     push esp
 
     /* Go to kernel mode thread stack */
-    mov eax, fs:[KPCR_CURRENT_THREAD]
+    mov eax, PCR[KPCR_CURRENT_THREAD]
     add esp, [eax+KTHREAD_INITIAL_STACK]
 
     /* Switch to good stack segment */
@@ -2112,7 +2118,7 @@ _KiUnexpectedInterruptTail:
     INT_PROLOG kui, DoNotPushFakeErrorCode
 
     /* Increase interrupt count */
-    inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
+    inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
 
     /* Put vector in EBX and make space for KIRQL */
     mov ebx, [esp]
@@ -2161,7 +2167,7 @@ _KiUnexpectedInterrupt:
 _KiDispatchInterrupt@0:
 
     /* Get the PCR  and disable interrupts */
-    mov ebx, [fs:KPCR_SELF]
+    mov ebx, PCR[KPCR_SELF]
     cli
 
     /* Check if we have to deliver DPCs, timers, or deferred threads */
@@ -2281,7 +2287,7 @@ _KiChainedDispatch2ndLvl@0:
 _KiChainedDispatch@0:
 
     /* Increase interrupt count */
-    inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
+    inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
 
     /* Save trap frame */
     mov ebp, esp
@@ -2308,17 +2314,14 @@ _KiChainedDispatch@0:
     call _KiChainedDispatch2ndLvl@0
 
     /* Exit the interrupt */
-    mov esi, $
-    cli
-    call _HalEndSystemInterrupt@8
-    jmp _Kei386EoiHelper@0
+    INT_EPILOG 0
 .endfunc
 
 .func KiInterruptDispatch@0
 _KiInterruptDispatch@0:
 
     /* Increase interrupt count */
-    inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
+    inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
 
     /* Save trap frame */
     mov ebp, esp
@@ -2346,27 +2349,51 @@ GetIntLock:
     mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
     ACQUIRE_SPINLOCK(esi, IntSpin)
 
+    /* Make sure that this interrupt isn't storming */
+    VERIFY_INT kid
+
+    /* Save the tick count */
+    mov ebx, _KeTickCount
+
     /* Call the ISR */
     mov eax, [edi+KINTERRUPT_SERVICE_CONTEXT]
     push eax
     push edi
     call [edi+KINTERRUPT_SERVICE_ROUTINE]
 
+    /* Check if the ISR timed out */
+    add ebx, _KiISRTimeout
+    cmp _KeTickCount, ebx
+    jnc IsrTimeout
+
+ReleaseLock:
     /* Release the lock */
     RELEASE_SPINLOCK(esi)
 
     /* Exit the interrupt */
-    cli
-    call _HalEndSystemInterrupt@8
-    jmp _Kei386EoiHelper@0
+    INT_EPILOG 0
 
 SpuriousInt:
     /* Exit the interrupt */
     add esp, 8
-    jmp _Kei386EoiHelper@0
+    INT_EPILOG 1
 
 #ifdef CONFIG_SMP
 IntSpin:
     SPIN_ON_LOCK esi, GetIntLock
 #endif
+
+IsrTimeout:
+    /* Print warning message */
+    push [edi+KINTERRUPT_SERVICE_ROUTINE]
+    push offset _IsrTimeoutMsg
+    call _DbgPrint
+    add esp,8
+
+    /* Break into debugger, then continue */
+    int 3
+    jmp ReleaseLock
+
+    /* Cleanup verification */
+    VERIFY_INT_END kid, 0
 .endfunc