Author: sir_richard Date: Mon Jan 11 07:08:11 2010 New Revision: 45040
URL: http://svn.reactos.org/svn/reactos?rev=45040&view=rev Log: Trap Handlers in C Patch 8 of X: [NTOS]: Implement KiCoprocessorError in C. [NTOS]: Make NMI handler fully C, now that the other parts are C too. [NTOS]: Delete more ASM macros and code that are now unused.
Modified: trunk/reactos/ntoskrnl/include/internal/i386/asmmacro.S trunk/reactos/ntoskrnl/include/internal/ke.h trunk/reactos/ntoskrnl/ke/i386/cpu.c trunk/reactos/ntoskrnl/ke/i386/trap.s trunk/reactos/ntoskrnl/ke/i386/traphdlr.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 07:08:11 2010 @@ -114,28 +114,6 @@ .endm
// -// @name UNHANDLED_V86_PATH -// -// This macro prints out that the current code path is for unhandled VDM support -// -// @param None -// -// @remark None. -// -.macro UNHANDLED_V86_PATH - /* Get EIP */ - call $+5 - - /* Print debug message */ - push offset _V86UnhandledMsg - call _DbgPrint - add esp, 8 - - /* Loop indefinitely */ - jmp $ -.endm - -// // @name IDT // // This macro creates an IDT entry for the given handler @@ -277,58 +255,6 @@ .endm
// -// @name INVALID_V86_OPCODE -// -// This macro creates one or more entries for unhandled V86 Opcodes -// in the V86 Opcode Table. -// -// @param count. -// Number of entries to generate. -// -// @remark None. -// -.macro INVALID_V86_OPCODE count - .rept \count - .byte 0 - .endr -.endm - -// -// @name GENERATE_PREFIX_HANDLER -// -// This macro creates a prefix opcode handler. -// -// @param None. -// -// @remark None. -// -.macro GENERATE_PREFIX_HANDLER Name -.func Opcode&Name&PrefixV86 -_Opcode&Name&PrefixV86: - or ebx, PREFIX_FLAG_&Name - jmp _OpcodeGenericPrefixV86 -.endfunc -.endm - -// -// @name INVALID_V86_OPCODE -// -// This macro prints out visible message and hangs the computer. -// -// @param None. -// -// @remark Temporary debugging use. -// -.macro UNHANDLED_V86_OPCODE - /* Print debug message, breakpoint and freeze */ - push ecx - push offset V86DebugMsg - call _DbgPrint - add esp, 8 - jmp $ -.endm - -// // @name TRAP_FIXUPS // // This macro contains out-of-line code for various Trap Frame Fixups, such as: @@ -522,96 +448,6 @@ cli jmp 1b 2: -.endm - -// -// @name TRAP_PROLOG -// -// This macro creates a standard trap entry prologue. -// It should be used for entry into any kernel trap (KiTrapXx), but not for -// system calls, which require special handling. -// -// @param Label -// Identifying name of the caller function; will be used to append -// to the name V86 and DR helper functions, which must already exist. -// -// @remark Use as follows: -// _KiTrap00: -// /* Push fake error code */ -// push 0 -// -// /* Enter common prologue */ -// TRAP_PROLOG(0) -// -// /* Handle trap */ -// <Your Trap Code Here> -// -.macro TRAP_PROLOG Label EndLabel - /* Just to be safe, clear out the HIWORD, since it's reserved */ - mov word ptr [esp+2], 0 - - /* Save the non-volatiles */ - push ebp - push ebx - push esi - push edi - - /* Save FS and set it to PCR */ - push fs - mov ebx, KGDT_R0_PCR - .byte 0x66 - mov fs, bx - - /* Save exception list and bogus previous mode */ - push fs:[KPCR_EXCEPTION_LIST] - push -1 - - /* Save volatiles and segment registers */ - push eax - push ecx - push edx - push ds - push es - push gs - - /* Set the R3 data segment */ - mov ax, KGDT_R3_DATA + RPL_MASK - - /* Skip debug registers and debug stuff */ - sub esp, 0x30 - - /* Load the segment registers */ - .byte 0x66 - mov ds, ax - .byte 0x66 - mov es, ax - - /* Check if this interrupt happened in 16-bit mode */ - cmp esp, 0x10000 - jb _Ki16BitStackException - - /* Set up frame */ - mov ebp, esp - - /* Check if this was from V86 Mode */ - test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK - jnz V86_&Label - -V86_&EndLabel: - /* Get current thread */ - mov ecx, fs:[KPCR_CURRENT_THREAD] - cld - - /* Flush DR7 */ - and dword ptr [ebp+KTRAP_FRAME_DR7], 0 - - /* Check if the thread was being debugged */ - test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF - jnz Dr_&Label - - /* Set the Trap Frame Debug Header */ -Dr_&EndLabel: - SET_TF_DEBUG_HEADER .endm
// @@ -899,164 +735,6 @@ .endm
// -// @name V86_TRAP_PROLOG -// -// This macro creates a V86 Trap entry prologue. -// It should be used for entry into any fast-system call (KiGetTickCount, -// KiCallbackReturn, KiRaiseAssertion) and the generic system call handler -// (KiSystemService) -// -// @param Label -// Unique label identifying the name of the caller function; will be -// used to append to the name of the DR helper function, which must -// already exist. -// -// @remark None. -// -.macro V86_TRAP_PROLOG Label EndLabel - - /* Skip everything to the error code */ - sub esp, KTRAP_FRAME_ERROR_CODE - - /* Clear the error code */ - mov word ptr [esp+KTRAP_FRAME_ERROR_CODE+2], 0 - - /* Save the registers we'll trample */ - mov [esp+KTRAP_FRAME_EBX], ebx - mov [esp+KTRAP_FRAME_EAX], eax - mov [esp+KTRAP_FRAME_EBP], ebp - mov [esp+KTRAP_FRAME_ESI], esi - mov [esp+KTRAP_FRAME_EDI], edi - - /* Save PCR and Ring 3 segments */ - mov ebx, KGDT_R0_PCR - mov eax, KGDT_R3_DATA + RPL_MASK - - /* Save ECX and EDX too */ - mov [esp+KTRAP_FRAME_ECX], ecx - mov [esp+KTRAP_FRAME_EDX], edx - - /* Set debugging markers */ - mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1 - mov dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00 - - /* Now set segments (use OVERRIDE, 0x66) */ - .byte 0x66 - mov fs, bx - .byte 0x66 - mov ds, ax - .byte 0x66 - mov es, ax - - /* Set the trap frame in the stack and clear the direction flag */ - mov ebp, esp - cld - - /* Save the exception list */ - mov eax, fs:[KPCR_EXCEPTION_LIST] - mov [esp+KTRAP_FRAME_EXCEPTION_LIST], eax - - /* Check if we need debugging */ - mov eax, dr7 - test eax, ~DR7_RESERVED_MASK - mov [esp+KTRAP_FRAME_DR7], eax - jnz Dr_&Label - -Dr_&EndLabel: -.endm - -// -// @name V86_TRAP_EPILOG -// -// This macro creates an epilogue for leaving V86 traps -// -// @param None. -// -// @remark None. -// -.macro V86_TRAP_EPILOG - - /* Get the current thread and make it unalerted */ -ExitBegin: - mov ebx, PCR[KPCR_CURRENT_THREAD] - mov byte ptr [ebx+KTHREAD_ALERTED], 0 - - /* Check if it has User-mode APCs pending */ - cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0 - jne PendingUserApc - - /* It doesn't, pop the frame */ - add esp, KTRAP_FRAME_EDX - pop edx - pop ecx - pop eax - - /* Check if DR registers should be restored */ - test dword ptr [ebp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK - jnz V86DebugRestore - - /* Finish popping the rest of the frame, and return to P-mode */ -V86DebugContinue: - add esp, 12 - pop edi - pop esi - pop ebx - pop ebp - add esp, 4 - iretd - -V86DebugRestore: - - /* Get DR0, 1 */ - xor ebx, ebx - mov esi, [ebp+KTRAP_FRAME_DR0] - mov edi, [ebp+KTRAP_FRAME_DR1] - - /* Clear DR 7 */ - mov dr7, ebx - - /* Get DR2 and load DR0-2 */ - mov ebx, [ebp+KTRAP_FRAME_DR2] - mov dr0, esi - mov dr1, edi - mov dr2, ebx - - /* Get DR3-7 */ - mov esi, [ebp+KTRAP_FRAME_DR0] - mov edi, [ebp+KTRAP_FRAME_DR1] - mov ebx, [ebp+KTRAP_FRAME_DR7] - - /* Load them */ - mov dr3, esi - mov dr6, edi - mov dr7, ebx - jmp V86DebugContinue - -PendingUserApc: - - /* Raise to APC level */ - mov ecx, APC_LEVEL - call @KfRaiseIrql@4 - - /* Save KIRQL and deliver APCs */ - push eax - sti - push ebp - push 0 - push UserMode - call _KiDeliverApc@12 - - /* Restore IRQL */ - pop ecx - call @KfLowerIrql@4 - cli - - /* Check if we're not in V86 anymore */ - test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK - jnz ExitBegin -.endm - -// // @name TRAP_EPILOG // // This macro creates an epilogue for leaving any system trap.
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 07:08:11 2010 @@ -1051,6 +1051,13 @@ );
VOID +NTAPI +KiSaveProcessorState( + IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame +); + +VOID FASTCALL KiRetireDpcList( IN PKPRCB Prcb
Modified: trunk/reactos/ntoskrnl/ke/i386/cpu.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/cpu.c?rev=... ============================================================================== --- trunk/reactos/ntoskrnl/ke/i386/cpu.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/i386/cpu.c [iso-8859-1] Mon Jan 11 07:08:11 2010 @@ -944,155 +944,24 @@ KiSaveProcessorControlState(&Prcb->ProcessorState); }
-/* C TRAP HANDLERS ************************************************************/ - -BOOLEAN -NTAPI -KiNmiFault(IN PVOID InterruptStack) -{ - PKTSS Tss, NmiTss; - PKTHREAD Thread; - PKPROCESS Process; - PKGDTENTRY TssGdt; - KTRAP_FRAME TrapFrame; - KIRQL OldIrql; +/* PUBLIC FUNCTIONS **********************************************************/ + +/* + * @implemented + */ +VOID +NTAPI +KiCoprocessorError(VOID) +{ + PFX_SAVE_AREA NpxArea;
- // - // In some sort of strange recursion case, we might end up here with the IF - // flag incorrectly on the interrupt frame -- during a normal NMI this would - // normally already be set. - // - // For sanity's sake, make sure interrupts are disabled for sure. - // NMIs will already be since the CPU does it for us. - // - _disable(); - - // - // Get the current TSS, thread, and process - // - Tss = PCR->TSS; - Thread = ((PKIPCR)PCR)->PrcbData.CurrentThread; - Process = Thread->ApcState.Process; + /* Get the FPU area */ + NpxArea = KiGetThreadNpxArea(KeGetCurrentThread());
- // - // Save data usually not in the TSS - // - Tss->CR3 = Process->DirectoryTableBase[0]; - Tss->IoMapBase = Process->IopmOffset; - Tss->LDT = Process->LdtDescriptor.LimitLow ? KGDT_LDT : 0; - - // - // Now get the base address of the NMI TSS - // - TssGdt = &((PKIPCR)KeGetPcr())->GDT[KGDT_NMI_TSS / sizeof(KGDTENTRY)]; - NmiTss = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow | - TssGdt->HighWord.Bytes.BaseMid << 16 | - TssGdt->HighWord.Bytes.BaseHi << 24); - - // - // Switch to it and activate it, masking off the nested flag - // - // Note that in reality, we are already on the NMI tss -- we just need to - // update the PCR to reflect this - // - PCR->TSS = NmiTss; - __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK); - TssGdt->HighWord.Bits.Dpl = 0; - TssGdt->HighWord.Bits.Pres = 1; - TssGdt->HighWord.Bits.Type = I386_TSS; - - // - // Now build the trap frame based on the original TSS - // - // The CPU does a hardware "Context switch" / task switch of sorts and so it - // takes care of saving our context in the normal TSS. - // - // We just have to go get the values... - // - RtlZeroMemory(&TrapFrame, sizeof(KTRAP_FRAME)); - TrapFrame.HardwareSegSs = Tss->Ss0; - TrapFrame.HardwareEsp = Tss->Esp0; - TrapFrame.EFlags = Tss->EFlags; - TrapFrame.SegCs = Tss->Cs; - TrapFrame.Eip = Tss->Eip; - TrapFrame.Ebp = Tss->Ebp; - TrapFrame.Ebx = Tss->Ebx; - TrapFrame.Esi = Tss->Esi; - TrapFrame.Edi = Tss->Edi; - TrapFrame.SegFs = Tss->Fs; - TrapFrame.ExceptionList = PCR->Tib.ExceptionList; - TrapFrame.PreviousPreviousMode = -1; - TrapFrame.Eax = Tss->Eax; - TrapFrame.Ecx = Tss->Ecx; - TrapFrame.Edx = Tss->Edx; - TrapFrame.SegDs = Tss->Ds; - TrapFrame.SegEs = Tss->Es; - TrapFrame.SegGs = Tss->Gs; - TrapFrame.DbgEip = Tss->Eip; - TrapFrame.DbgEbp = Tss->Ebp; - - // - // Store the trap frame in the KPRCB - // - KiSaveProcessorState(&TrapFrame, NULL); - - // - // Call any registered NMI handlers and see if they handled it or not - // - if (!KiHandleNmi()) - { - // - // They did not, so call the platform HAL routine to bugcheck the system - // - // Make sure the HAL believes it's running at HIGH IRQL... we can't use - // the normal APIs here as playing with the IRQL could change the system - // state - // - OldIrql = PCR->Irql; - PCR->Irql = HIGH_LEVEL; - HalHandleNMI(NULL); - PCR->Irql = OldIrql; - } - - // - // Although the CPU disabled NMIs, we just did a BIOS Call, which could've - // totally changed things. - // - // We have to make sure we're still in our original NMI -- a nested NMI - // will point back to the NMI TSS, and in that case we're hosed. - // - if (PCR->TSS->Backlink != KGDT_NMI_TSS) - { - // - // Restore original TSS - // - PCR->TSS = Tss; - - // - // Set it back to busy - // - TssGdt->HighWord.Bits.Dpl = 0; - TssGdt->HighWord.Bits.Pres = 1; - TssGdt->HighWord.Bits.Type = I386_ACTIVE_TSS; - - // - // Restore nested flag - // - __writeeflags(__readeflags() | EFLAGS_NESTED_TASK); - - // - // Handled, return from interrupt - // - return TRUE; - } - - // - // Unhandled: crash the system - // - return FALSE; -} - -/* PUBLIC FUNCTIONS **********************************************************/ + /* Set CR0_TS */ + NpxArea->Cr0NpxState = CR0_TS; + __writecr0(__readcr0() | CR0_TS); +}
/* * @implemented
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 07:08:11 2010 @@ -577,29 +577,6 @@
GENERATE_TRAP_HANDLER KiTrap0, 1 GENERATE_TRAP_HANDLER KiTrap1, 1 - -.func KiTrap2 -_KiTrap2: - // - // Call the C handler - // - stdCall _KiNmiFault, esp // Handle it in C - or al, al // Check if it got handled - jne 1f // Resume from NMI - - // - // Return from NMI - // - iretd // Interrupt return - jmp _KiTrap2 // Handle recursion -1: - // - // Crash the system - // - mov eax, EXCEPTION_NMI // STOP fault code - jmp _KiSystemFatalException // Bugcheck helper -.endfunc - GENERATE_TRAP_HANDLER KiTrap3, 1 GENERATE_TRAP_HANDLER KiTrap4, 1 GENERATE_TRAP_HANDLER KiTrap5, 1 @@ -616,61 +593,6 @@ GENERATE_TRAP_HANDLER KiTrap16, 1 GENERATE_TRAP_HANDLER KiTrap17, 1 GENERATE_TRAP_HANDLER KiTrap19, 1 - -.func KiSystemFatalException -_KiSystemFatalException: - - /* Push the trap frame */ - push ebp - - /* Push empty parameters */ - push 0 - push 0 - push 0 - - /* Push trap number and bugcheck code */ - push eax - push UNEXPECTED_KERNEL_MODE_TRAP - call _KeBugCheckWithTf@24 - ret -.endfunc - -.func KiCoprocessorError@0 -_KiCoprocessorError@0: - - /* Get the NPX Thread's Initial stack */ - mov eax, PCR[KPCR_NPX_THREAD] - mov eax, [eax+KTHREAD_INITIAL_STACK] - - /* Make space for the FPU Save area */ - sub eax, SIZEOF_FX_SAVE_AREA - - /* Set the CR0 State */ - mov dword ptr [eax+FN_CR0_NPX_STATE], 8 - - /* Update it */ - mov eax, cr0 - or eax, 8 - mov cr0, eax - - /* Return to caller */ - ret -.endfunc - -.func Ki16BitStackException -_Ki16BitStackException: - - /* Save stack */ - push ss - push esp - - /* Go to kernel mode thread stack */ - mov eax, PCR[KPCR_CURRENT_THREAD] - add esp, [eax+KTHREAD_INITIAL_STACK] - - /* Switch to good stack segment */ - UNHANDLED_PATH "16-Bit Stack" -.endfunc
/* UNEXPECTED INTERRUPT HANDLERS **********************************************/
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 07:08:11 2010 @@ -549,6 +549,151 @@ KiDispatchException0Args(STATUS_SINGLE_STEP, TrapFrame->Eip, TrapFrame); +} + +VOID +KiTrap2(VOID) +{ + PKTSS Tss, NmiTss; + PKTHREAD Thread; + PKPROCESS Process; + PKGDTENTRY TssGdt; + KTRAP_FRAME TrapFrame; + KIRQL OldIrql; + + // + // In some sort of strange recursion case, we might end up here with the IF + // flag incorrectly on the interrupt frame -- during a normal NMI this would + // normally already be set. + // + // For sanity's sake, make sure interrupts are disabled for sure. + // NMIs will already be since the CPU does it for us. + // + _disable(); + + // + // Get the current TSS, thread, and process + // + Tss = PCR->TSS; + Thread = ((PKIPCR)PCR)->PrcbData.CurrentThread; + Process = Thread->ApcState.Process; + + // + // Save data usually not in the TSS + // + Tss->CR3 = Process->DirectoryTableBase[0]; + Tss->IoMapBase = Process->IopmOffset; + Tss->LDT = Process->LdtDescriptor.LimitLow ? KGDT_LDT : 0; + + // + // Now get the base address of the NMI TSS + // + TssGdt = &((PKIPCR)KeGetPcr())->GDT[KGDT_NMI_TSS / sizeof(KGDTENTRY)]; + NmiTss = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow | + TssGdt->HighWord.Bytes.BaseMid << 16 | + TssGdt->HighWord.Bytes.BaseHi << 24); + + // + // Switch to it and activate it, masking off the nested flag + // + // Note that in reality, we are already on the NMI tss -- we just need to + // update the PCR to reflect this + // + PCR->TSS = NmiTss; + __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK); + TssGdt->HighWord.Bits.Dpl = 0; + TssGdt->HighWord.Bits.Pres = 1; + TssGdt->HighWord.Bits.Type = I386_TSS; + + // + // Now build the trap frame based on the original TSS + // + // The CPU does a hardware "Context switch" / task switch of sorts and so it + // takes care of saving our context in the normal TSS. + // + // We just have to go get the values... + // + RtlZeroMemory(&TrapFrame, sizeof(KTRAP_FRAME)); + TrapFrame.HardwareSegSs = Tss->Ss0; + TrapFrame.HardwareEsp = Tss->Esp0; + TrapFrame.EFlags = Tss->EFlags; + TrapFrame.SegCs = Tss->Cs; + TrapFrame.Eip = Tss->Eip; + TrapFrame.Ebp = Tss->Ebp; + TrapFrame.Ebx = Tss->Ebx; + TrapFrame.Esi = Tss->Esi; + TrapFrame.Edi = Tss->Edi; + TrapFrame.SegFs = Tss->Fs; + TrapFrame.ExceptionList = PCR->Tib.ExceptionList; + TrapFrame.PreviousPreviousMode = -1; + TrapFrame.Eax = Tss->Eax; + TrapFrame.Ecx = Tss->Ecx; + TrapFrame.Edx = Tss->Edx; + TrapFrame.SegDs = Tss->Ds; + TrapFrame.SegEs = Tss->Es; + TrapFrame.SegGs = Tss->Gs; + TrapFrame.DbgEip = Tss->Eip; + TrapFrame.DbgEbp = Tss->Ebp; + + // + // Store the trap frame in the KPRCB + // + KiSaveProcessorState(&TrapFrame, NULL); + + // + // Call any registered NMI handlers and see if they handled it or not + // + if (!KiHandleNmi()) + { + // + // They did not, so call the platform HAL routine to bugcheck the system + // + // Make sure the HAL believes it's running at HIGH IRQL... we can't use + // the normal APIs here as playing with the IRQL could change the system + // state + // + OldIrql = PCR->Irql; + PCR->Irql = HIGH_LEVEL; + HalHandleNMI(NULL); + PCR->Irql = OldIrql; + } + + // + // Although the CPU disabled NMIs, we just did a BIOS Call, which could've + // totally changed things. + // + // We have to make sure we're still in our original NMI -- a nested NMI + // will point back to the NMI TSS, and in that case we're hosed. + // + if (PCR->TSS->Backlink != KGDT_NMI_TSS) + { + // + // Restore original TSS + // + PCR->TSS = Tss; + + // + // Set it back to busy + // + TssGdt->HighWord.Bits.Dpl = 0; + TssGdt->HighWord.Bits.Pres = 1; + TssGdt->HighWord.Bits.Type = I386_ACTIVE_TSS; + + // + // Restore nested flag + // + __writeeflags(__readeflags() | EFLAGS_NESTED_TASK); + + // + // Handled, return from interrupt + // + __asm__ __volatile__ ("iret\n"); + } + + // + // Unhandled: crash the system + // + KiSystemFatalException(EXCEPTION_NMI, NULL); }
VOID