[NTOS]: The last big step. Now that the HAL is in C, we can handle interrupts in C. Do so using the proposed model that was #if'ed out, but with some improvements.

[NTOS]: Implement KiUnexpectedInterruptTail and KiUnexpectedInterrupt in C as well.
This is [PERF] too since the C interrupt handling code is a lot more efficient than the ASM one. Numbers look good here.

svn path=/trunk/; revision=45304
This commit is contained in:
Sir Richard 2010-01-28 23:18:53 +00:00
parent ac9c20ac0f
commit 5b14ade9f8
5 changed files with 128 additions and 410 deletions

View file

@ -197,7 +197,7 @@ idt _KiUnexpectedInterrupt&Number, INT_32_DPL0
.macro GENERATE_INT_HANDLER Number
.func KiUnexpectedInterrupt&Number
_KiUnexpectedInterrupt&Number:
push PRIMARY_VECTOR_BASE + Number
mov eax, PRIMARY_VECTOR_BASE + Number
jmp _KiEndUnexpectedRange@0
.endfunc
.endm

View file

@ -954,19 +954,6 @@ KiServiceExit2(
IN PKTRAP_FRAME TrapFrame
);
#ifndef HAL_INTERRUPT_SUPPORT_IN_C
VOID
NTAPI
KiInterruptDispatch(
VOID
);
VOID
NTAPI
KiChainedDispatch(
VOID
);
#else
VOID
FASTCALL
KiInterruptDispatch(
@ -980,7 +967,6 @@ KiChainedDispatch(
IN PKTRAP_FRAME TrapFrame,
IN PKINTERRUPT Interrupt
);
#endif
VOID
NTAPI

View file

@ -97,9 +97,6 @@ KiConnectVectorToInterrupt(IN PKINTERRUPT Interrupt,
{
DISPATCH_INFO Dispatch;
PKINTERRUPT_ROUTINE Handler;
#ifndef HAL_INTERRUPT_SUPPORT_IN_C
PULONG Patch = &Interrupt->DispatchCode[0];
#endif
/* Get vector data */
KiGetVectorDispatch(Interrupt->Vector, &Dispatch);
@ -122,15 +119,6 @@ KiConnectVectorToInterrupt(IN PKINTERRUPT Interrupt,
Interrupt->DispatchAddress = Handler;
/* Read note in trap.s -- patching not needed since JMP is static */
#ifndef HAL_INTERRUPT_SUPPORT_IN_C
/* Jump to the last 4 bytes */
Patch = (PULONG)((ULONG_PTR)Patch +
((ULONG_PTR)&KiInterruptTemplateDispatch -
(ULONG_PTR)KiInterruptTemplate) - 4);
/* Apply the patch */
*Patch = (ULONG)((ULONG_PTR)Handler - ((ULONG_PTR)Patch + 4));
#endif
/* Now set the final handler address */
ASSERT(Dispatch.FlatDispatch == NULL);
@ -141,6 +129,130 @@ KiConnectVectorToInterrupt(IN PKINTERRUPT Interrupt,
KeRegisterInterruptHandler(Interrupt->Vector, Handler);
}
VOID
FORCEINLINE
DECLSPEC_NORETURN
KiExitInterrupt(IN PKTRAP_FRAME TrapFrame,
IN KIRQL OldIrql,
IN BOOLEAN Spurious)
{
/* Check if this was a real interrupt */
if (!Spurious)
{
/* Set nested trap frame */
KeGetPcr()->VdmAlert = (ULONG_PTR)TrapFrame;
/* It was, disable interrupts and restore the IRQL */
_disable();
HalEndSystemInterrupt(OldIrql, 0);
}
/* Now exit the trap */
KiEoiHelper(TrapFrame);
}
VOID
KiUnexpectedInterrupt(VOID)
{
/* Crash the machine */
KeBugCheck(TRAP_CAUSE_UNKNOWN);
}
VOID
FASTCALL
KiUnexpectedInterruptTailHandler(IN PKTRAP_FRAME TrapFrame)
{
KIRQL OldIrql;
/* Enter trap */
KiEnterInterruptTrap(TrapFrame);
/* Increase interrupt count */
KeGetCurrentPrcb()->InterruptCount++;
/* Start the interrupt */
if (HalBeginSystemInterrupt(HIGH_LEVEL, TrapFrame->Eax, &OldIrql))
{
/* Warn user */
DPRINT1("\n\x7\x7!!! Unexpected Interrupt %02lx !!!\n");
/* Now call the epilogue code */
KiExitInterrupt(TrapFrame, OldIrql, FALSE);
}
else
{
/* Now call the epilogue code */
KiExitInterrupt(TrapFrame, OldIrql, TRUE);
}
}
typedef
FASTCALL
VOID
(PKI_INTERRUPT_DISPATCH)(
IN PKTRAP_FRAME TrapFrame,
IN PKINTERRUPT Interrupt
);
VOID
FASTCALL
KiInterruptDispatch(IN PKTRAP_FRAME TrapFrame,
IN PKINTERRUPT Interrupt)
{
KIRQL OldIrql;
/* Increase interrupt count */
KeGetCurrentPrcb()->InterruptCount++;
/* Begin the interrupt, making sure it's not spurious */
if (HalBeginSystemInterrupt(Interrupt->SynchronizeIrql,
Interrupt->Vector,
&OldIrql))
{
/* Acquire interrupt lock */
KxAcquireSpinLock(Interrupt->ActualLock);
/* Call the ISR */
Interrupt->ServiceRoutine(Interrupt, Interrupt->ServiceContext);
/* Release interrupt lock */
KxReleaseSpinLock(Interrupt->ActualLock);
/* Now call the epilogue code */
KiExitInterrupt(TrapFrame, OldIrql, FALSE);
}
else
{
/* Now call the epilogue code */
KiExitInterrupt(TrapFrame, OldIrql, TRUE);
}
}
VOID
FASTCALL
KiChainedDispatch(IN PKTRAP_FRAME TrapFrame,
IN PKINTERRUPT Interrupt)
{
/* Increase interrupt count */
KeGetCurrentPrcb()->InterruptCount++;
UNIMPLEMENTED;
while (TRUE);
}
VOID
FASTCALL
KiInterruptHandler(IN PKTRAP_FRAME TrapFrame,
IN PKINTERRUPT Interrupt)
{
/* Enter interrupt frame */
KiEnterInterruptTrap(TrapFrame);
/* Call the correct dispatcher */
((PKI_INTERRUPT_DISPATCH*)Interrupt->DispatchAddress)(TrapFrame, Interrupt);
}
KiTrap(KiUnexpectedInterruptTail, KI_PUSH_FAKE_ERROR_CODE);
/* PUBLIC FUNCTIONS **********************************************************/
/*
@ -199,12 +311,6 @@ KeInitializeInterrupt(IN PKINTERRUPT Interrupt,
*DispatchCode++ = KiInterruptTemplate[i];
}
/* Sanity check */
#ifndef HAL_INTERRUPT_SUPPORT_IN_C
ASSERT((ULONG_PTR)&KiChainedDispatch2ndLvl -
(ULONG_PTR)KiInterruptTemplate <= (KINTERRUPT_DISPATCH_CODES * 4));
#endif
/* Jump to the last 4 bytes */
Patch = (PULONG)((ULONG_PTR)Patch +
((ULONG_PTR)&KiInterruptTemplateObject -

View file

@ -152,58 +152,8 @@ GENERATE_INT_HANDLERS
_KiEndUnexpectedRange@0:
jmp _KiUnexpectedInterruptTail
.func KiUnexpectedInterruptTail
TRAP_FIXUPS kui_a, kui_t, DoFixupV86, DoFixupAbios
_KiUnexpectedInterruptTail:
/* Enter interrupt trap */
INT_PROLOG kui_a, kui_t, DoNotPushFakeErrorCode
/* Increase interrupt count */
inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
/* Put vector in EBX and make space for KIRQL */
mov ebx, [esp]
sub esp, 4
/* Begin interrupt */
push esp
push ebx
push HIGH_LEVEL
call _HalBeginSystemInterrupt@12
/* Check if it was spurious or not */
or al, al
jnz Handled
/* Spurious, ignore it */
add esp, 8
jmp _Kei386EoiHelper@0
Handled:
/* Unexpected interrupt, print a message on debug builds */
#if DBG
push [esp+4]
push offset _UnexpectedMsg
call _DbgPrint
add esp, 8
#endif
/* Exit the interrupt */
mov esi, $
cli
call _HalEndSystemInterrupt@8
jmp _Kei386EoiHelper@0
.endfunc
.globl _KiUnexpectedInterrupt
_KiUnexpectedInterrupt:
/* Bugcheck with invalid interrupt code */
push TRAP_CAUSE_UNKNOWN
call _KeBugCheck@4
/* INTERRUPT HANDLERS ********************************************************/
/* DPC INTERRUPT HANDLER ******************************************************/
.func KiDispatchInterrupt@0
_KiDispatchInterrupt@0:
@ -321,10 +271,8 @@ QuantumEnd:
.endfunc
/*
* This is how the new-style interrupt template will look like.
*
* We setup the stack for a trap frame in the KINTERRUPT DispatchCode itself and
* then mov the stack address in ECX, since the handlers are FASTCALL. We also
* then move the stack address in ECX, since the handlers are FASTCALL. We also
* need to know the address of the KINTERRUPT. To do this, we maintain the old
* dynamic patching technique (EDX instead of EDI, however) and let the C API
* up in KeInitializeInterrupt replace the 0 with the address. Since this is in
@ -343,13 +291,9 @@ QuantumEnd:
* use EDI to store the absolute offset, and jump to that instead.
*
*/
#ifdef HAL_INTERRUPT_SUPPORT_IN_C
.func KiInterruptTemplate
_KiInterruptTemplate:
push 0
pushad
sub esp, KTRAP_FRAME_LENGTH - KTRAP_FRAME_PREVIOUS_MODE
mov ecx, esp
TRAP_HANDLER_PROLOG 1, 0
_KiInterruptTemplate2ndDispatch:
/* Dummy code, will be replaced by the address of the KINTERRUPT */
@ -363,221 +307,3 @@ _KiInterruptTemplateObject:
_KiInterruptTemplateDispatch:
/* Marks the end of the template so that the jump above can be edited */
.endfunc
#else
.func KiInterruptTemplate
_KiInterruptTemplate:
/* Enter interrupt trap */
INT_PROLOG kit_a, kit_t, DoPushFakeErrorCode
_KiInterruptTemplate2ndDispatch:
/* Dummy code, will be replaced by the address of the KINTERRUPT */
mov edi, 0
_KiInterruptTemplateObject:
/* Dummy jump, will be replaced by the actual jump */
jmp _KeSynchronizeExecution@12
_KiInterruptTemplateDispatch:
/* Marks the end of the template so that the jump above can be edited */
TRAP_FIXUPS kit_a, kit_t, DoFixupV86, DoFixupAbios
.endfunc
.func KiChainedDispatch2ndLvl@0
_KiChainedDispatch2ndLvl@0:
NextSharedInt:
/* Raise IRQL if necessary */
mov cl, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
cmp cl, [edi+KINTERRUPT_IRQL]
je 1f
call @KfRaiseIrql@4
1:
/* Acquire the lock */
mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
GetIntLock2:
ACQUIRE_SPINLOCK(esi, IntSpin2)
/* Make sure that this interrupt isn't storming */
VERIFY_INT kid2
/* Save the tick count */
mov esi, _KeTickCount
/* Call the ISR */
mov eax, [edi+KINTERRUPT_SERVICE_CONTEXT]
push eax
push edi
call [edi+KINTERRUPT_SERVICE_ROUTINE]
/* Save the ISR result */
mov bl, al
/* Check if the ISR timed out */
add esi, _KiISRTimeout
cmp _KeTickCount, esi
jnc ChainedIsrTimeout
ReleaseLock2:
/* Release the lock */
mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
RELEASE_SPINLOCK(esi)
/* Lower IRQL if necessary */
mov cl, [edi+KINTERRUPT_IRQL]
cmp cl, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
je 1f
call @KfLowerIrql@4
1:
/* Check if the interrupt is handled */
or bl, bl
jnz 1f
/* Try the next shared interrupt handler */
mov eax, [edi+KINTERRUPT_INTERRUPT_LIST_HEAD]
lea edi, [eax-KINTERRUPT_INTERRUPT_LIST_HEAD]
jmp NextSharedInt
1:
ret
#ifdef CONFIG_SMP
IntSpin2:
SPIN_ON_LOCK(esi, GetIntLock2)
#endif
ChainedIsrTimeout:
/* Print warning message */
push [edi+KINTERRUPT_SERVICE_ROUTINE]
push offset _IsrTimeoutMsg
call _DbgPrint
add esp,8
/* Break into debugger, then continue */
int 3
jmp ReleaseLock2
/* Cleanup verification */
VERIFY_INT_END kid2, 0
.endfunc
.func KiChainedDispatch@0
_KiChainedDispatch@0:
/* Increase interrupt count */
inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
/* Save trap frame */
mov ebp, esp
/* Save vector and IRQL */
mov eax, [edi+KINTERRUPT_VECTOR]
mov ecx, [edi+KINTERRUPT_IRQL]
/* Save old irql */
push eax
sub esp, 4
/* Begin interrupt */
push esp
push eax
push ecx
call _HalBeginSystemInterrupt@12
/* Check if it was handled */
or al, al
jz SpuriousInt
/* Call the 2nd-level handler */
call _KiChainedDispatch2ndLvl@0
/* Exit the interrupt */
INT_EPILOG 0
.endfunc
.func KiInterruptDispatch@0
_KiInterruptDispatch@0:
/* Increase interrupt count */
inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
/* Save trap frame */
mov ebp, esp
/* Save vector and IRQL */
mov eax, [edi+KINTERRUPT_VECTOR]
mov ecx, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
/* Save old irql */
push eax
sub esp, 4
/* Begin interrupt */
push esp
push eax
push ecx
call _HalBeginSystemInterrupt@12
/* Check if it was handled */
or al, al
jz SpuriousInt
/* Acquire the lock */
mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
GetIntLock:
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 */
INT_EPILOG 0
SpuriousInt:
/* Exit the interrupt */
add esp, 8
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
#endif

View file

@ -1601,104 +1601,4 @@ KiTrap(KiDebugService, KI_PUSH_FAKE_ERROR_CODE);
KiTrap(KiSystemService, KI_PUSH_FAKE_ERROR_CODE | KI_NONVOLATILES_ONLY);
KiTrap(KiFastCallEntry, KI_FAST_SYSTEM_CALL);
/* HARDWARE INTERRUPTS ********************************************************/
/*
* This code can only be used once the HAL handles system interrupt code in C.
*
* This is because the HAL, when ending a system interrupt, might see pending
* DPC or APC interrupts, and attempt to piggyback on the interrupt context in
* order to deliver them. Once they have been devlivered, it will then "end" the
* interrupt context by doing a call to the ASM EOI Handler which naturally will
* throw up on our C-style KTRAP_FRAME.
*
* Once it works, expect a noticeable speed boost during hardware interrupts.
*/
#ifdef HAL_INTERRUPT_SUPPORT_IN_C
typedef
FASTCALL
VOID
(PKI_INTERRUPT_DISPATCH)(
IN PKTRAP_FRAME TrapFrame,
IN PKINTERRUPT Interrupt
);
VOID
FORCEINLINE
KiExitInterrupt(IN PKTRAP_FRAME TrapFrame,
IN KIRQL OldIrql,
IN BOOLEAN Spurious)
{
if (Spurious) KiEoiHelper(TrapFrame);
_disable();
DPRINT1("Calling HAL to restore IRQL to: %d\n", OldIrql);
HalEndSystemInterrupt(OldIrql, 0);
DPRINT1("Exiting trap\n");
KiEoiHelper(TrapFrame);
}
VOID
FASTCALL
KiInterruptDispatch(IN PKTRAP_FRAME TrapFrame,
IN PKINTERRUPT Interrupt)
{
KIRQL OldIrql;
KeGetCurrentPrcb()->InterruptCount++;
DPRINT1("Calling HAL with %lx %lx\n", Interrupt->SynchronizeIrql, Interrupt->Vector);
if (HalBeginSystemInterrupt(Interrupt->SynchronizeIrql,
Interrupt->Vector,
&OldIrql))
{
/* Acquire interrupt lock */
KxAcquireSpinLock(Interrupt->ActualLock);
/* Call the ISR */
DPRINT1("Calling ISR: %p with context: %p\n", Interrupt->ServiceRoutine, Interrupt->ServiceContext);
Interrupt->ServiceRoutine(Interrupt, Interrupt->ServiceContext);
/* Release interrupt lock */
KxReleaseSpinLock(Interrupt->ActualLock);
/* Now call the epilogue code */
DPRINT1("Exiting interrupt\n");
KiExitInterrupt(TrapFrame, OldIrql, FALSE);
}
else
{
/* Now call the epilogue code */
DPRINT1("Exiting Spurious interrupt\n");
KiExitInterrupt(TrapFrame, OldIrql, TRUE);
}
}
VOID
FASTCALL
KiChainedDispatch(IN PKTRAP_FRAME TrapFrame,
IN PKINTERRUPT Interrupt)
{
KeGetCurrentPrcb()->InterruptCount++;
UNIMPLEMENTED;
while (TRUE);
}
VOID
FASTCALL
KiInterruptHandler(IN PKTRAP_FRAME TrapFrame,
IN PKINTERRUPT Interrupt)
{
/* Enter interrupt frame */
KiEnterInterruptTrap(TrapFrame);
/* Call the correct dispatcher */
((PKI_INTERRUPT_DISPATCH*)Interrupt->DispatchAddress)(TrapFrame, Interrupt);
}
#endif
/* EOF */