From ff8920ffc171deee26af8daa4d6a4f80edf23bcd Mon Sep 17 00:00:00 2001 From: Sir Richard Date: Sun, 10 Jan 2010 15:00:44 +0000 Subject: [PATCH] [NTOS]: Simplify trap exit code. [NTOS]: Move some stuff in appropriate headers. [NTOS]: Write V86 fast entry/exit traps, needed for later. svn path=/trunk/; revision=45028 --- reactos/ntoskrnl/include/internal/i386/ke.h | 44 ++++++- reactos/ntoskrnl/include/internal/ke.h | 14 -- reactos/ntoskrnl/include/internal/trap_x.h | 4 +- reactos/ntoskrnl/ke/i386/traphdlr.c | 134 +++++++++++++++----- 4 files changed, 146 insertions(+), 50 deletions(-) diff --git a/reactos/ntoskrnl/include/internal/i386/ke.h b/reactos/ntoskrnl/include/internal/i386/ke.h index ba47d5d3f59..d2cb14256d4 100644 --- a/reactos/ntoskrnl/include/internal/i386/ke.h +++ b/reactos/ntoskrnl/include/internal/i386/ke.h @@ -65,7 +65,26 @@ extern ULONG Ke386CacheAlignment; // #define KeGetTrapFrameInterruptState(TrapFrame) \ BooleanFlagOn((TrapFrame)->EFlags, EFLAGS_INTERRUPT_MASK) - + +// +// Flags for exiting a trap +// +#define KTE_SKIP_PM_BIT (((KTRAP_EXIT_SKIP_BITS) { { .SkipPreviousMode = TRUE } }).Bits) +#define KTE_SKIP_SEG_BIT (((KTRAP_EXIT_SKIP_BITS) { { .SkipSegments = TRUE } }).Bits) +#define KTE_SKIP_VOL_BIT (((KTRAP_EXIT_SKIP_BITS) { { .SkipVolatiles = TRUE } }).Bits) + +typedef union _KTRAP_EXIT_SKIP_BITS +{ + struct + { + UCHAR SkipPreviousMode:1; + UCHAR SkipSegments:1; + UCHAR SkipVolatiles:1; + UCHAR Reserved:5; + }; + UCHAR Bits; +} KTRAP_EXIT_SKIP_BITS, *PKTRAP_EXIT_SKIP_BITS; + // // Registers an interrupt handler with an IDT vector // @@ -289,6 +308,25 @@ Ki386EnableXMMIExceptions( IN ULONG_PTR Context ); +BOOLEAN +NTAPI +VdmDispatchBop( + IN PKTRAP_FRAME TrapFrame +); + +BOOLEAN +FASTCALL +KiVdmOpcodePrefix( + IN PKTRAP_FRAME TrapFrame, + IN ULONG Flags +); + +BOOLEAN +FASTCALL +Ki386HandleOpcodeV86( + IN PKTRAP_FRAME TrapFrame +); + // // Global x86 only Kernel data // @@ -312,6 +350,10 @@ extern VOID __cdecl KiTrap2(VOID); extern VOID __cdecl KiTrap8(VOID); extern VOID __cdecl KiTrap19(VOID); extern VOID __cdecl KiFastCallEntry(VOID); +extern VOID NTAPI ExpInterlockedPopEntrySListFault(VOID); +extern VOID __cdecl CopyParams(VOID); +extern VOID __cdecl ReadBatch(VOID); +extern VOID __cdecl FrRestore(VOID); // // Sanitizes a selector diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 659b05938dd..a8c94d21fa7 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -72,20 +72,6 @@ typedef struct _KNMI_HANDLER_CALLBACK PVOID Handle; } KNMI_HANDLER_CALLBACK, *PKNMI_HANDLER_CALLBACK; -typedef union _KTRAP_STATE_BITS -{ - struct - { - UCHAR SystemCall:1; - UCHAR PreviousMode:1; - UCHAR Segments:1; - UCHAR Volatiles:1; - UCHAR Full:1; - UCHAR Reserved:3; - }; - UCHAR Bits; -} KTRAP_STATE_BITS, *PKTRAP_STATE_BITS; - typedef PCHAR (NTAPI *PKE_BUGCHECK_UNICODE_TO_ANSI)( IN PUNICODE_STRING Unicode, diff --git a/reactos/ntoskrnl/include/internal/trap_x.h b/reactos/ntoskrnl/include/internal/trap_x.h index 1d4f3c5c2d7..898bba033c1 100644 --- a/reactos/ntoskrnl/include/internal/trap_x.h +++ b/reactos/ntoskrnl/include/internal/trap_x.h @@ -66,7 +66,7 @@ KiFillTrapFrameDebug(IN PKTRAP_FRAME TrapFrame) FORCEINLINE VOID KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame, - IN KTRAP_STATE_BITS StateBits) + IN KTRAP_STATE_BITS SkipBits) { /* Make sure interrupts are disabled */ if (__readeflags() & EFLAGS_INTERRUPT_MASK) @@ -105,7 +105,7 @@ KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame, } /* If we're ignoring previous mode, make sure caller doesn't actually want it */ - if (!(StateBits.PreviousMode) && (TrapFrame->PreviousPreviousMode != -1)) + if ((SkipBits.SkipPreviousMode) && (TrapFrame->PreviousPreviousMode != -1)) { DPRINT1("Exiting a trap witout restoring previous mode, yet previous mode seems valid: %lx", TrapFrame->PreviousPreviousMode); while (TRUE); diff --git a/reactos/ntoskrnl/ke/i386/traphdlr.c b/reactos/ntoskrnl/ke/i386/traphdlr.c index 7802955d1e1..9bd99c656aa 100644 --- a/reactos/ntoskrnl/ke/i386/traphdlr.c +++ b/reactos/ntoskrnl/ke/i386/traphdlr.c @@ -18,16 +18,19 @@ VOID FASTCALL KiExitTrap(IN PKTRAP_FRAME TrapFrame, - IN UCHAR State) + IN UCHAR Skip) { - KTRAP_STATE_BITS StateBits = { .Bits = State }; - KiExitTrapDebugChecks(TrapFrame, StateBits); + KTRAP_EXIT_SKIP_BITS SkipBits = { .Bits = Skip }; + KiExitTrapDebugChecks(TrapFrame, SkipBits); + + /* If you skip volatile reload, you must skip segment reload */ + ASSERT((SkipBits.SkipVolatiles == FALSE) || (SkipBits.SkipSegments == TRUE)); /* Restore the SEH handler chain */ KeGetPcr()->Tib.ExceptionList = TrapFrame->ExceptionList; /* Check if the previous mode must be restored */ - if (StateBits.PreviousMode) + if (!SkipBits.SkipPreviousMode) { /* Not handled yet */ UNIMPLEMENTED; @@ -53,34 +56,31 @@ KiExitTrap(IN PKTRAP_FRAME TrapFrame, while (TRUE); } - /* Check if all registers must be restored */ - if (StateBits.Full) + /* Check if segments should be restored */ + if (!SkipBits.SkipSegments) { - /* Only do the restore if we made a transition from user-mode */ - if (KiUserTrap(TrapFrame)) - { - /* Restore segments */ - Ke386SetGs(TrapFrame->SegGs); - Ke386SetEs(TrapFrame->SegEs); - Ke386SetDs(TrapFrame->SegDs); - } + /* Restore segments */ + Ke386SetGs(TrapFrame->SegGs); + Ke386SetEs(TrapFrame->SegEs); + Ke386SetDs(TrapFrame->SegDs); + Ke386SetFs(TrapFrame->SegFs); } - - /* Check if we came from user-mode */ - if (KiUserTrap(TrapFrame)) + else if (KiUserTrap(TrapFrame)) { - /* Check if the caller wants segments restored */ - if (StateBits.Segments) - { - /* Restore them */ - Ke386SetGs(TrapFrame->SegGs); - Ke386SetEs(TrapFrame->SegEs); - Ke386SetDs(TrapFrame->SegDs); - } - /* Always restore FS since it goes from KPCR to TEB */ Ke386SetFs(TrapFrame->SegFs); } + + /* Check if the caller wants to skip volatiles */ + if (SkipBits.SkipVolatiles) + { + /* + * When we do the system call handler through this path, we need + * to have some sort to restore the kernel EAX instead of pushing + * back the user EAX. We'll figure it out... + */ + DPRINT1("Warning: caller doesn't want volatiles restored\n"); + } /* Check for ABIOS code segment */ if (TrapFrame->SegCs == 0x80) @@ -90,8 +90,8 @@ KiExitTrap(IN PKTRAP_FRAME TrapFrame, while (TRUE); } - /* Check for system call */ - if (StateBits.SystemCall) + /* Check for system call -- a system call skips volatiles! */ + if (SkipBits.SkipVolatiles) { /* Not handled yet */ UNIMPLEMENTED; @@ -104,6 +104,50 @@ KiExitTrap(IN PKTRAP_FRAME TrapFrame, } } +VOID +FASTCALL +KiExitV86Trap(IN PKTRAP_FRAME TrapFrame) +{ + PKTHREAD Thread; + KIRQL OldIrql; + + /* Get the thread */ + Thread = KeGetCurrentThread(); + while (TRUE) + { + /* Turn off the alerted state for kernel mode */ + Thread->Alerted[KernelMode] = FALSE; + + /* Are there pending user APCs? */ + if (!Thread->ApcState.UserApcPending) break; + + /* Raise to APC level and enable interrupts */ + OldIrql = KfRaiseIrql(APC_LEVEL); + _enable(); + + /* Deliver APCs */ + KiDeliverApc(UserMode, NULL, TrapFrame); + + /* Restore IRQL and disable interrupts once again */ + KfLowerIrql(OldIrql); + _disable(); + + /* Return if this isn't V86 mode anymore */ + if (TrapFrame->EFlags & EFLAGS_V86_MASK) return; + } + + /* If we got here, we're still in a valid V8086 context, so quit it */ + if (TrapFrame->Dr7 & ~DR7_RESERVED_MASK) + { + /* Not handled yet */ + UNIMPLEMENTED; + while (TRUE); + } + + /* Return from interrupt */ + KiTrapReturn(TrapFrame); +} + VOID FASTCALL KiEoiHelper(IN PKTRAP_FRAME TrapFrame) @@ -115,11 +159,39 @@ KiEoiHelper(IN PKTRAP_FRAME TrapFrame) KiCheckForApcDelivery(TrapFrame); /* Now exit the trap for real */ - KiExitTrap(TrapFrame, KTS_SEG_BIT | KTS_VOL_BIT); + KiExitTrap(TrapFrame, KTE_SKIP_PM_BIT); } /* TRAP ENTRY CODE ************************************************************/ +VOID +FASTCALL +KiEnterV86Trap(IN PKTRAP_FRAME TrapFrame) +{ + /* Save registers */ + KiTrapFrameFromPushaStack(TrapFrame); + + /* Load correct registers */ + Ke386SetFs(KGDT_R0_PCR); + Ke386SetDs(KGDT_R3_DATA | RPL_MASK); + Ke386SetEs(KGDT_R3_DATA | RPL_MASK); + + /* Save exception list and bogus previous mode */ + TrapFrame->PreviousPreviousMode = -1; + TrapFrame->ExceptionList = KeGetPcr()->Tib.ExceptionList; + + /* Clear direction flag */ + Ke386ClearDirectionFlag(); + + /* Save DR7 and check for debugging */ + TrapFrame->Dr7 = __readdr(7); + if (TrapFrame->Dr7 & ~DR7_RESERVED_MASK) + { + UNIMPLEMENTED; + while (TRUE); + } +} + VOID FASTCALL KiEnterTrap(IN PKTRAP_FRAME TrapFrame) @@ -258,7 +330,6 @@ KiNpxHandler(IN PKTRAP_FRAME TrapFrame, IN PFX_SAVE_AREA SaveArea) { ULONG Cr0, Mask, Error, ErrorOffset, DataOffset; - extern VOID FrRestore(VOID); /* Check for VDM trap */ ASSERT((KiVdmTrap(TrapFrame)) == FALSE); @@ -718,9 +789,6 @@ KiTrap14Handler(IN PKTRAP_FRAME TrapFrame) PKTHREAD Thread; ULONG_PTR Cr2; NTSTATUS Status; - extern VOID NTAPI ExpInterlockedPopEntrySListFault(VOID); - extern VOID CopyParams(VOID); - extern VOID ReadBatch(VOID); /* Save trap frame */ KiEnterTrap(TrapFrame);