Author: sir_richard Date: Mon Jan 11 18:44:09 2010 New Revision: 45045
URL: http://svn.reactos.org/svn/reactos?rev=45045&view=rev Log: Trap Handlers in C Patch 9 of 12: [NTOS]: Fix a logic bug in KiExitTrap: Always only restore segments if we came from user-mode (since they might be bogus on a kernel transition as they're not always saved), even if the caller wants segment restore. [NTOS]: Small perf boot: do a JMP, not a CALL into C handling code. [NTOS]: Make KiGetTickCount/KiCallbackReturn handled in C (as stubs). [NTOS]: Implement KeSynchronizeExecution in C. Move Kei386SpinOnSpinLock to C stub. [NTOS]: Implement overall architecture for handling hardware interrupts in C. Not used yet, since it needs C code in HAL.
Modified: trunk/reactos/ntoskrnl/include/internal/i386/asmmacro.S trunk/reactos/ntoskrnl/include/internal/ke.h trunk/reactos/ntoskrnl/ke/i386/irqobj.c trunk/reactos/ntoskrnl/ke/i386/trap.s trunk/reactos/ntoskrnl/ke/i386/traphdlr.c trunk/reactos/ntoskrnl/ke/spinlock.c
Modified: trunk/reactos/ntoskrnl/include/internal/i386/asmmacro.S URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/i... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/i386/asmmacro.S [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/include/internal/i386/asmmacro.S [iso-8859-1] Mon Jan 11 18:44:09 2010 @@ -238,7 +238,7 @@ pushad sub esp, KTRAP_FRAME_LENGTH - KTRAP_FRAME_PREVIOUS_MODE mov ecx, esp - call @&Name&Handler@4 + jmp @&Name&Handler@4 .endfunc .endm
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/k... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/ke.h [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/include/internal/ke.h [iso-8859-1] Mon Jan 11 18:44:09 2010 @@ -938,6 +938,7 @@ VOID );
+#ifndef HAL_INTERRUPT_SUPPORT_IN_C VOID NTAPI KiInterruptDispatch( @@ -949,6 +950,21 @@ KiChainedDispatch( VOID ); +#else +VOID +FASTCALL +KiInterruptDispatch( + IN PKTRAP_FRAME TrapFrame, + IN PKINTERRUPT Interrupt +); + +VOID +FASTCALL +KiChainedDispatch( + IN PKTRAP_FRAME TrapFrame, + IN PKINTERRUPT Interrupt +); +#endif
VOID NTAPI
Modified: trunk/reactos/ntoskrnl/ke/i386/irqobj.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/irqobj.c?r... ============================================================================== --- trunk/reactos/ntoskrnl/ke/i386/irqobj.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/i386/irqobj.c [iso-8859-1] Mon Jan 11 18:44:09 2010 @@ -48,9 +48,9 @@ KiUnexpectedEntrySize);
/* Setup the handlers */ - Dispatch->InterruptDispatch = KiInterruptDispatch; + Dispatch->InterruptDispatch = (PVOID)KiInterruptDispatch; Dispatch->FloatingDispatch = NULL; // Floating Interrupts are not supported - Dispatch->ChainedDispatch = KiChainedDispatch; + Dispatch->ChainedDispatch = (PVOID)KiChainedDispatch; Dispatch->FlatDispatch = NULL;
/* Get the current handler */ @@ -97,7 +97,9 @@ { 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); @@ -119,6 +121,8 @@ /* Set the handler */ 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 - @@ -126,6 +130,7 @@
/* Apply the patch */ *Patch = (ULONG)((ULONG_PTR)Handler - ((ULONG_PTR)Patch + 4)); +#endif
/* Now set the final handler address */ ASSERT(Dispatch.FlatDispatch == NULL); @@ -195,8 +200,10 @@ }
/* 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 + @@ -390,4 +397,35 @@ return State; }
+/* + * @implemented + */ +BOOLEAN +NTAPI +KeSynchronizeExecution(IN OUT PKINTERRUPT Interrupt, + IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine, + IN PVOID SynchronizeContext OPTIONAL) +{ + NTSTATUS Status; + KIRQL OldIrql; + + /* Raise IRQL */ + OldIrql = KfRaiseIrql(Interrupt->SynchronizeIrql); + + /* Acquire interrupt spinlock */ + KeAcquireSpinLockAtDpcLevel(Interrupt->ActualLock); + + /* Call the routine */ + Status = SynchronizeRoutine(SynchronizeContext); + + /* Release lock */ + KeReleaseSpinLockFromDpcLevel(Interrupt->ActualLock); + + /* Lower IRQL */ + KfLowerIrql(OldIrql); + + /* Return status */ + return Status; +} + /* EOF */
Modified: trunk/reactos/ntoskrnl/ke/i386/trap.s URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/trap.s?rev... ============================================================================== --- trunk/reactos/ntoskrnl/ke/i386/trap.s [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/i386/trap.s [iso-8859-1] Mon Jan 11 18:44:09 2010 @@ -54,7 +54,6 @@ GENERATE_IDT_STUBS /* INT 30-FF: UNEXPECTED INTERRUPTS */
/* Trap handlers referenced from C code */ -.globl _KiTrap2 .globl _KiTrap8 .globl _KiTrap19
@@ -69,7 +68,6 @@ /* And special system-defined software traps: */ .globl _NtRaiseException@12 .globl _NtContinue@8 -.globl _KiCoprocessorError@0 .globl _KiDispatchInterrupt@0
/* Interrupt template entrypoints */ @@ -77,10 +75,12 @@ .globl _KiInterruptTemplateObject .globl _KiInterruptTemplateDispatch
+#ifndef HAL_INTERRUPT_SUPPORT_IN_C /* Chained and Normal generic interrupt handlers for 1st and 2nd level entry*/ .globl _KiChainedDispatch2ndLvl@0 .globl _KiInterruptDispatch@0 .globl _KiChainedDispatch@0 +#endif
/* We implement the following trap exit points: */ .globl _KiServiceExit /* Exit from syscall */ @@ -143,10 +143,6 @@ /* SOFTWARE INTERRUPT SERVICES ***********************************************/ .text
-_KiGetTickCount: -_KiCallbackReturn: - /* FIXME: TODO */ - UNHANDLED_PATH "TickCount/Callback Interrupts\n"
.func KiSystemService TRAP_FIXUPS kss_a, kss_t, DoNotFixupV86, DoNotFixupAbios @@ -473,6 +469,8 @@ /* FIXME: TODO */ UNHANDLED_PATH "ABIOS Exit"
+GENERATE_TRAP_HANDLER KiGetTickCount, 1 +GENERATE_TRAP_HANDLER KiCallbackReturn, 1 GENERATE_TRAP_HANDLER KiRaiseAssertion, 1 GENERATE_TRAP_HANDLER KiDebugService, 1
@@ -768,6 +766,52 @@ ret .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 + * 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 + * EDX, it becomes the second parameter for our FASTCALL function. + * + * Finally, we jump directly to the C interrupt handler, which will choose the + * appropriate dispatcher (chained, single, flat, floating) that was setup. The + * dispatchers themselves are also C FASTCALL functions. This double-indirection + * maintains the NT model should anything depend on it. + * + * Note that since we always jump to the C handler which then jumps to the C + * dispatcher, the first JMP in the template object is NOT patched anymore since + * it's static. Also, keep in mind this code is dynamically copied into nonpaged + * pool! It runs off the KINTERRUPT directly, so you can't just JMP to the code + * since JMPs are relative, and the location of the JMP below is dynamic. So we + * 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 + +_KiInterruptTemplate2ndDispatch: + /* Dummy code, will be replaced by the address of the KINTERRUPT */ + mov edx, 0 + +_KiInterruptTemplateObject: + /* Jump to C code */ + mov edi, offset @KiInterruptHandler@8 + jmp edi + +_KiInterruptTemplateDispatch: + /* Marks the end of the template so that the jump above can be edited */ +.endfunc + +#else + .func KiInterruptTemplate _KiInterruptTemplate:
@@ -982,74 +1026,4 @@ /* Cleanup verification */ VERIFY_INT_END kid, 0 .endfunc - -.globl _KeSynchronizeExecution@12 -.func KeSynchronizeExecution@12 -_KeSynchronizeExecution@12: - - /* Save EBX and put the interrupt object in it */ - push ebx - mov ebx, [esp+8] - - /* Go to DIRQL */ - mov cl, [ebx+KINTERRUPT_SYNCHRONIZE_IRQL] - call @KfRaiseIrql@4 - push eax - -#ifdef CONFIG_SMP - /* Acquire the interrupt spinlock FIXME: Write this in assembly */ - mov ecx, [ebx+KINTERRUPT_ACTUAL_LOCK] - call @KefAcquireSpinLockAtDpcLevel@4 #endif - - /* Call the routine */ - push [esp+20] - call [esp+20] - -#ifdef CONFIG_SMP - /* Release the interrupt spinlock FIXME: Write this in assembly */ - push eax - mov ecx, [ebx+KINTERRUPT_ACTUAL_LOCK] - call @KefReleaseSpinLockFromDpcLevel@4 - pop eax -#endif - - /* Lower IRQL */ - mov ebx, eax - pop ecx - call @KfLowerIrql@4 - - /* Return status */ - mov eax, ebx - pop ebx - ret 12 -.endfunc - -/*++ - * Kii386SpinOnSpinLock - * - * FILLMEIN - * - * Params: - * SpinLock - FILLMEIN - * - * Flags - FILLMEIN - * - * Returns: - * None. - * - * Remarks: - * FILLMEIN - * - *--*/ -.globl _Kii386SpinOnSpinLock@8 -.func Kii386SpinOnSpinLock@8 -_Kii386SpinOnSpinLock@8: - -#ifdef CONFIG_SMP - /* FIXME: TODO */ - int 3 -#endif - - ret 8 -.endfunc
Modified: trunk/reactos/ntoskrnl/ke/i386/traphdlr.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/traphdlr.c... ============================================================================== --- trunk/reactos/ntoskrnl/ke/i386/traphdlr.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/i386/traphdlr.c [iso-8859-1] Mon Jan 11 18:44:09 2010 @@ -89,17 +89,19 @@ while (TRUE); }
- /* Check if segments should be restored */ - if (!SkipBits.SkipSegments) - { - /* Restore segments */ - Ke386SetGs(TrapFrame->SegGs); - Ke386SetEs(TrapFrame->SegEs); - Ke386SetDs(TrapFrame->SegDs); - Ke386SetFs(TrapFrame->SegFs); - } - else if (KiUserTrap(TrapFrame)) - { + /* Check if this is a user trap */ + if (KiUserTrap(TrapFrame)) + { + /* Check if segments should be restored */ + if (!SkipBits.SkipSegments) + { + /* Restore segments */ + Ke386SetGs(TrapFrame->SegGs); + Ke386SetEs(TrapFrame->SegEs); + Ke386SetDs(TrapFrame->SegDs); + Ke386SetFs(TrapFrame->SegFs); + } + /* Always restore FS since it goes from KPCR to TEB */ Ke386SetFs(TrapFrame->SegFs); } @@ -223,6 +225,58 @@ UNIMPLEMENTED; while (TRUE); } +} + +VOID +FASTCALL +KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame) +{ + /* Save registers */ + KiTrapFrameFromPushaStack(TrapFrame); + + /* Set bogus previous mode */ + TrapFrame->PreviousPreviousMode = -1; + + /* Check for V86 mode */ + if (TrapFrame->EFlags & EFLAGS_V86_MASK) + { + UNIMPLEMENTED; + while (TRUE); + } + + /* Check if this wasn't kernel code */ + if (TrapFrame->SegCs != KGDT_R0_CODE) + { + /* Save segments and then switch to correct ones */ + TrapFrame->SegFs = Ke386GetFs(); + TrapFrame->SegGs = Ke386GetGs(); + TrapFrame->SegDs = Ke386GetDs(); + TrapFrame->SegEs = Ke386GetEs(); + Ke386SetFs(KGDT_R0_PCR); + Ke386SetDs(KGDT_R3_DATA | RPL_MASK); + Ke386SetEs(KGDT_R3_DATA | RPL_MASK); + } + + /* Save exception list and terminate it */ + TrapFrame->ExceptionList = KeGetPcr()->Tib.ExceptionList; + KeGetPcr()->Tib.ExceptionList = EXCEPTION_CHAIN_END; + + /* FIXME: This doesn't support 16-bit ABIOS interrupts */ + TrapFrame->ErrCode = 0; + + /* Clear direction flag */ + Ke386ClearDirectionFlag(); + + /* Flush DR7 and check for debugging */ + TrapFrame->Dr7 = 0; + if (KeGetCurrentThread()->DispatcherHeader.DebugActive & 0xFF) + { + UNIMPLEMENTED; + while (TRUE); + } + + /* Set debug header */ + KiFillTrapFrameDebug(TrapFrame); }
VOID @@ -1499,6 +1553,24 @@ KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame); }
+/* SOFTWARE SERVICES **********************************************************/ + +VOID +FASTCALL +KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame) +{ + UNIMPLEMENTED; + while (TRUE); +} + +VOID +FASTCALL +KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame) +{ + UNIMPLEMENTED; + while (TRUE); +} + VOID FASTCALL KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame) @@ -1529,4 +1601,104 @@ KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx); }
+/* 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 */
Modified: trunk/reactos/ntoskrnl/ke/spinlock.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/spinlock.c?rev=... ============================================================================== --- trunk/reactos/ntoskrnl/ke/spinlock.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/spinlock.c [iso-8859-1] Mon Jan 11 18:44:09 2010 @@ -454,3 +454,17 @@ /* Spinlock appears to be free */ return TRUE; } + +#ifdef _M_IX86 +/* + * @unimplemented + */ +VOID +NTAPI +Kii386SpinOnSpinLock(IN PKSPIN_LOCK SpinLock, + IN ULONG Flags) +{ + UNIMPLEMENTED; + while (TRUE); +} +#endif