Author: sir_richard
Date: Mon Jan 25 00:19:40 2010
New Revision: 45235
URL: http://svn.reactos.org/svn/reactos?rev=45235&view=rev
Log:
[HAL]: Document and implement KiI8259MaskTable in C using actual bit positions. Each mapping is best to the best of my ability.
[HAL]: Implement KfRaiseIrql in C, remove ASM version.
Modified:
trunk/reactos/hal/halx86/generic/irq.S
trunk/reactos/hal/halx86/generic/pic.c
trunk/reactos/hal/halx86/include/halp.h
Modified: trunk/reactos/hal/halx86/generic/irq.S
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/generic/irq.S?r…
==============================================================================
--- trunk/reactos/hal/halx86/generic/irq.S [iso-8859-1] (original)
+++ trunk/reactos/hal/halx86/generic/irq.S [iso-8859-1] Mon Jan 25 00:19:40 2010
@@ -624,67 +624,6 @@
ret
.endfunc
-.globl @KfRaiseIrql@4
-.func @KfRaiseIrql@4
-_@KfRaiseIrql@4:
-@KfRaiseIrql@4:
-
- /* Get the IRQL */
- movzx ecx, cl
- mov eax, PCR[KPCR_IRQL]
-
-#if DBG
- /* Validate it */
- cmp eax, ecx
- ja InvalidKfRaise
-#endif
-
- /* Check if it's in the software level */
- cmp cl, DISPATCH_LEVEL
- jbe SetIrql
-
- /* Save the current IRQL */
- mov edx, eax
-
- /* It's a hardware IRQL, so disable interrupts */
- pushf
- cli
-
- /* Set the new IRQL */
- mov PCR[KPCR_IRQL], ecx
-
- /* Mask the interrupts in the PIC */
- mov eax, KiI8259MaskTable[ecx*4]
- or eax, PCR[KPCR_IDR]
- out 0x21, al
- shr eax, 8
- out 0xA1, al
-
- /* Restore interrupts and return old IRQL */
- popf
- mov eax, edx
- ret
-
-SetIrql:
- /* Set the IRQL and return */
- mov PCR[KPCR_IRQL], ecx
- ret
-
-#if DBG
-InvalidKfRaise:
- /* Set to passive */
- mov dword ptr PCR[KPCR_IRQL], PASSIVE_LEVEL
-
- /* Bugcheck the system */
- push 9
- push 0
- push ecx
- push eax
- push IRQL_NOT_GREATER_OR_EQUAL
- call _KeBugCheckEx@20
-#endif
-.endfunc
-
.globl _HalpApcInterrupt
.func HalpApcInterrupt
TRAP_FIXUPS hapc_a, hapc_t, DoFixupV86, DoFixupAbios
Modified: trunk/reactos/hal/halx86/generic/pic.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/generic/pic.c?r…
==============================================================================
--- trunk/reactos/hal/halx86/generic/pic.c [iso-8859-1] (original)
+++ trunk/reactos/hal/halx86/generic/pic.c [iso-8859-1] Mon Jan 25 00:19:40 2010
@@ -13,6 +13,87 @@
#include <debug.h>
/* GLOBALS ********************************************************************/
+
+/* This table contains the static x86 PIC mapping between IRQLs and IRQs */
+ULONG KiI8259MaskTable[32] =
+{
+ /*
+ * It Device IRQLs only start at 4 or higher, so these are just software
+ * IRQLs that don't really change anything on the hardware
+ */
+ 0b00000000000000000000000000000000, /* IRQL 0 */
+ 0b00000000000000000000000000000000, /* IRQL 1 */
+ 0b00000000000000000000000000000000, /* IRQL 2 */
+ 0b00000000000000000000000000000000, /* IRQL 3 */
+
+ /*
+ * These next IRQLs are actually useless from the PIC perspective, because
+ * with only 2 PICs, the mask you can send them is only 8 bits each, for 16
+ * bits total, so these IRQLs are masking off a phantom PIC.
+ */
+ 0b11111111100000000000000000000000, /* IRQL 4 */
+ 0b11111111110000000000000000000000, /* IRQL 5 */
+ 0b11111111111000000000000000000000, /* IRQL 6 */
+ 0b11111111111100000000000000000000, /* IRQL 7 */
+ 0b11111111111110000000000000000000, /* IRQL 8 */
+ 0b11111111111111000000000000000000, /* IRQL 9 */
+ 0b11111111111111100000000000000000, /* IRQL 10 */
+ 0b11111111111111110000000000000000, /* IRQL 11 */
+
+ /*
+ * Okay, now we're finally starting to mask off IRQs on the slave PIC, from
+ * IRQ15 to IRQ8. This means the higher-level IRQs get less priority in the
+ * IRQL sense.
+ */
+ 0b11111111111111111000000000000000, /* IRQL 12 */
+ 0b11111111111111111100000000000000, /* IRQL 13 */
+ 0b11111111111111111110000000000000, /* IRQL 14 */
+ 0b11111111111111111111000000000000, /* IRQL 15 */
+ 0b11111111111111111111100000000000, /* IRQL 16 */
+ 0b11111111111111111111110000000000, /* IRQL 17 */
+ 0b11111111111111111111111000000000, /* IRQL 18 */
+ 0b11111111111111111111111000000000, /* IRQL 19 */
+
+ /*
+ * Now we mask off the IRQs on the master. Notice the 0 "droplet"? You might
+ * have also seen that IRQL 18 and 19 are essentially equal as far as the
+ * PIC is concerned. That bit is actually IRQ8, which happens to be the RTC.
+ * The RTC will keep firing as long as we don't reach PROFILE_LEVEL which
+ * actually kills it. The RTC clock (unlike the system clock) is used by the
+ * profiling APIs in the HAL, so that explains the logic.
+ */
+ 0b11111111111111111111111010000000, /* IRQL 20 */
+ 0b11111111111111111111111011000000, /* IRQL 21 */
+ 0b11111111111111111111111011100000, /* IRQL 22 */
+ 0b11111111111111111111111011110000, /* IRQL 23 */
+ 0b11111111111111111111111011111000, /* IRQL 24 */
+ 0b11111111111111111111111011111000, /* IRQL 25 */
+ 0b11111111111111111111111011111010, /* IRQL 26 */
+ 0b11111111111111111111111111111010, /* IRQL 27 */
+
+ /*
+ * IRQL 24 and 25 are actually identical, so IRQL 28 is actually the last
+ * IRQL to modify a bit on the master PIC. It happens to modify the very
+ * last of the IRQs, IRQ0, which corresponds to the system clock interval
+ * timer that keeps track of time (the Windows heartbeat). We only want to
+ * turn this off at a high-enough IRQL, which is why IRQLs 24 and 25 are the
+ * same to give this guy a chance to come up higher. Note that IRQL 28 is
+ * called CLOCK2_LEVEL, which explains the usage we just explained.
+ */
+ 0b11111111111111111111111111111011, /* IRQL 28 */
+
+ /*
+ * We have finished off with the PIC so there's nothing left to mask at the
+ * level of these IRQLs, making them only logical IRQLs on x86 machines.
+ * Note that we have another 0 "droplet" you might've caught since IRQL 26.
+ * In this case, it's the 2nd bit that never gets turned off, which is IRQ2,
+ * the cascade IRQ that we use to bridge the slave PIC with the master PIC.
+ * We never want to turn it off, so no matter the IRQL, it will be set to 0.
+ */
+ 0b11111111111111111111111111111011, /* IRQL 29 */
+ 0b11111111111111111111111111111011, /* IRQL 30 */
+ 0b11111111111111111111111111111011 /* IRQL 31 */
+};
USHORT HalpEisaELCR;
@@ -191,6 +272,62 @@
return CurrentIrql;
}
+/*
+ * @implemented
+ */
+KIRQL
+FASTCALL
+KfRaiseIrql(IN KIRQL NewIrql)
+{
+ PKPCR Pcr = KeGetPcr();
+ ULONG EFlags;
+ KIRQL CurrentIrql;
+ PIC_MASK Mask;
+
+ /* Read current IRQL */
+ CurrentIrql = Pcr->Irql;
+
+#ifdef IRQL_DEBUG
+ /* Validate correct raise */
+ if (CurrentIrql > NewIrql)
+ {
+ /* Crash system */
+ Pcr->Irql = PASSIVE_LEVEL;
+ KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
+ CurrentIrql,
+ NewIrql,
+ 0,
+ 9);
+ }
+#endif
+
+ /* Check if new IRQL affects hardware state */
+ if (NewIrql > DISPATCH_LEVEL)
+ {
+ /* Save current interrupt state and disable interrupts */
+ EFlags = __readeflags();
+ _disable();
+
+ /* Update the IRQL */
+ Pcr->Irql = NewIrql;
+
+ /* Set new PIC mask */
+ Mask.Both = KiI8259MaskTable[NewIrql] | Pcr->IDR;
+ __outbyte(PIC1_DATA_PORT, Mask.Master);
+ __outbyte(PIC2_DATA_PORT, Mask.Slave);
+
+ /* Restore interrupt state */
+ __writeeflags(EFlags);
+ }
+ else
+ {
+ /* Set new IRQL */
+ Pcr->Irql = NewIrql;
+ }
+
+ /* Return old IRQL */
+ return CurrentIrql;
+}
/* SOFTWARE INTERRUPTS ********************************************************/
Modified: trunk/reactos/hal/halx86/include/halp.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/include/halp.h?…
==============================================================================
--- trunk/reactos/hal/halx86/include/halp.h [iso-8859-1] (original)
+++ trunk/reactos/hal/halx86/include/halp.h [iso-8859-1] Mon Jan 25 00:19:40 2010
@@ -282,6 +282,19 @@
USHORT Bits;
} EISA_ELCR, *PEISA_ELCR;
+typedef struct _PIC_MASK
+{
+ union
+ {
+ struct
+ {
+ UCHAR Master;
+ UCHAR Slave;
+ };
+ USHORT Both;
+ };
+} PIC_MASK, *PPIC_MASK;
+
//
// Mm PTE/PDE to Hal PTE/PDE
//
Author: sir_richard
Date: Sun Jan 24 06:40:04 2010
New Revision: 45231
URL: http://svn.reactos.org/svn/reactos?rev=45231&view=rev
Log:
[PERF]: Make the trap entry/exit macros inlined, just as they used to be before in their pure-assembly forms. This should boost performance quite a bit by avoiding 2-3 extra calls during traps and system calls.
[NTOS]: Cleanup the traphdlr.c vs. trap_x.h mess into something much more structured. trap_x.h is now all inlined C functions which pretty much replace the asmmacros.S file. It is meant to be used outside the kernel as well (such as by the HAL, which requires trap entry/exit too).
[PERF]: Give UNREACHABLE another try, this time with GCC 4.5+, 4.4+, 4.4- and MSVC support.
[PERF]: Remove ABIOS checks since ReactOS does not support this, and since it doesn't look like the target kernel actually does either, we can remove this vestigal/unsupported code, saving some extra branches and checks.
Modified:
trunk/reactos/ntoskrnl/include/internal/i386/ke.h
trunk/reactos/ntoskrnl/include/internal/ke.h
trunk/reactos/ntoskrnl/include/internal/trap_x.h
trunk/reactos/ntoskrnl/ke/i386/exp.c
trunk/reactos/ntoskrnl/ke/i386/traphdlr.c
Modified: trunk/reactos/ntoskrnl/include/internal/i386/ke.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/i386/ke.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/i386/ke.h [iso-8859-1] Sun Jan 24 06:40:04 2010
@@ -410,6 +410,18 @@
ULONG_PTR
FASTCALL
KiExitV86Mode(
+ IN PKTRAP_FRAME TrapFrame
+);
+
+VOID
+NTAPI
+KiDispatchExceptionFromTrapFrame(
+ IN NTSTATUS Code,
+ IN ULONG_PTR Address,
+ IN ULONG ParameterCount,
+ IN ULONG_PTR Parameter1,
+ IN ULONG_PTR Parameter2,
+ IN ULONG_PTR Parameter3,
IN PKTRAP_FRAME TrapFrame
);
@@ -443,6 +455,14 @@
extern VOID __cdecl ReadBatch(VOID);
extern VOID __cdecl FrRestore(VOID);
+//
+// Trap Macros
+//
+#include "../trap_x.h"
+
+//
+// Returns a thread's FPU save area
+//
PFX_SAVE_AREA
FORCEINLINE
KiGetThreadNpxArea(IN PKTHREAD Thread)
@@ -523,20 +543,196 @@
(DrAddress <= MM_HIGHEST_USER_ADDRESS) ? DrAddress : 0);
}
-FORCEINLINE
-VOID
-KiV86TrapReturn(IN ULONG_PTR Stack)
-{
- /* Restore volatiles and stack */
+//
+// Exception with no arguments
+//
+VOID
+FORCEINLINE
+//DECLSPEC_NORETURN
+KiDispatchException0Args(IN NTSTATUS Code,
+ IN ULONG_PTR Address,
+ IN PKTRAP_FRAME TrapFrame)
+{
+ /* Helper for exceptions with no arguments */
+ KiDispatchExceptionFromTrapFrame(Code, Address, 0, 0, 0, 0, TrapFrame);
+}
+
+//
+// Exception with one argument
+//
+VOID
+FORCEINLINE
+//DECLSPEC_NORETURN
+KiDispatchException1Args(IN NTSTATUS Code,
+ IN ULONG_PTR Address,
+ IN ULONG P1,
+ IN PKTRAP_FRAME TrapFrame)
+{
+ /* Helper for exceptions with no arguments */
+ KiDispatchExceptionFromTrapFrame(Code, Address, 1, P1, 0, 0, TrapFrame);
+}
+
+//
+// Exception with two arguments
+//
+VOID
+FORCEINLINE
+//DECLSPEC_NORETURN
+KiDispatchException2Args(IN NTSTATUS Code,
+ IN ULONG_PTR Address,
+ IN ULONG P1,
+ IN ULONG P2,
+ IN PKTRAP_FRAME TrapFrame)
+{
+ /* Helper for exceptions with no arguments */
+ KiDispatchExceptionFromTrapFrame(Code, Address, 2, P1, P2, 0, TrapFrame);
+}
+
+//
+// Performs a system call
+//
+NTSTATUS
+FORCEINLINE
+KiSystemCallTrampoline(IN PVOID Handler,
+ IN PVOID Arguments,
+ IN ULONG StackBytes)
+{
+ NTSTATUS Result;
+
+ /*
+ * This sequence does a RtlCopyMemory(Stack - StackBytes, Arguments, StackBytes)
+ * and then calls the function associated with the system call.
+ *
+ * It's done in assembly for two reasons: we need to muck with the stack,
+ * and the call itself restores the stack back for us. The only way to do
+ * this in C is to do manual C handlers for every possible number of args on
+ * the stack, and then have the handler issue a call by pointer. This is
+ * wasteful since it'll basically push the values twice and require another
+ * level of call indirection.
+ *
+ * The ARM kernel currently does this, but it should probably be changed
+ * later to function like this as well.
+ *
+ */
+ __asm__ __volatile__
+ (
+ "subl %1, %%esp\n"
+ "movl %%esp, %%edi\n"
+ "movl %2, %%esi\n"
+ "shrl $2, %1\n"
+ "rep movsd\n"
+ "call *%3\n"
+ "movl %%eax, %0\n"
+ : "=r"(Result)
+ : "c"(StackBytes),
+ "d"(Arguments),
+ "r"(Handler)
+ : "%esp", "%esi", "%edi"
+ );
+
+ return Result;
+}
+
+//
+// Checks for pending APCs
+//
+VOID
+FORCEINLINE
+KiCheckForApcDelivery(IN PKTRAP_FRAME TrapFrame)
+{
+ PKTHREAD Thread;
+ KIRQL OldIrql;
+
+ /* Check for V8086 or user-mode trap */
+ if ((TrapFrame->EFlags & EFLAGS_V86_MASK) || (KiUserTrap(TrapFrame)))
+ {
+ /* 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();
+ }
+ }
+}
+
+//
+// Converts a base thread to a GUI thread
+//
+NTSTATUS
+FORCEINLINE
+KiConvertToGuiThread(VOID)
+{
+ NTSTATUS Result;
+ PVOID StackFrame;
+
+ /*
+ * Converting to a GUI thread safely updates ESP in-place as well as the
+ * current Thread->TrapFrame and EBP when KeSwitchKernelStack is called.
+ *
+ * However, PsConvertToGuiThread "helpfully" restores EBP to the original
+ * caller's value, since it is considered a nonvolatile register. As such,
+ * as soon as we're back after the conversion and we try to store the result
+ * which will probably be in some stack variable (EBP-based), we'll crash as
+ * we are touching the de-allocated non-expanded stack.
+ *
+ * Thus we need a way to update our EBP before EBP is touched, and the only
+ * way to guarantee this is to do the call itself in assembly, use the EAX
+ * register to store the result, fixup EBP, and then let the C code continue
+ * on its merry way.
+ *
+ */
+ __asm__ __volatile__
+ (
+ "movl %%ebp, %1\n"
+ "subl %%esp, %1\n"
+ "call _PsConvertToGuiThread@0\n"
+ "addl %%esp, %1\n"
+ "movl %1, %%ebp\n"
+ "movl %%eax, %0\n"
+ : "=r"(Result), "=r"(StackFrame)
+ :
+ : "%esp", "%ecx", "%edx"
+ );
+
+ return Result;
+}
+
+//
+// Switches from boot loader to initial kernel stack
+//
+VOID
+FORCEINLINE
+KiSwitchToBootStack(IN ULONG_PTR InitialStack)
+{
+ /* We have to switch to a new stack before continuing kernel initialization */
__asm__ __volatile__
(
"movl %0, %%esp\n"
- "popa\n"
- "ret\n"
- :
- : "r"(Stack)
+ "subl %1, %%esp\n"
+ "pushl %2\n"
+ "jmp _KiSystemStartupBootStack@0\n"
+ :
+ : "c"(InitialStack),
+ "i"(NPX_FRAME_LENGTH + KTRAP_FRAME_ALIGN + KTRAP_FRAME_LENGTH),
+ "i"(CR0_EM | CR0_TS | CR0_MP)
: "%esp"
);
}
+
#endif
#endif /* __NTOSKRNL_INCLUDE_INTERNAL_I386_KE_H */
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/ke.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/ke.h [iso-8859-1] Sun Jan 24 06:40:04 2010
@@ -863,19 +863,7 @@
ULONG_PTR BugCheckParameter4,
PKTRAP_FRAME Tf
);
-
-VOID
-NTAPI
-KiDispatchExceptionFromTrapFrame(
- IN NTSTATUS Code,
- IN ULONG_PTR Address,
- IN ULONG ParameterCount,
- IN ULONG_PTR Parameter1,
- IN ULONG_PTR Parameter2,
- IN ULONG_PTR Parameter3,
- IN PKTRAP_FRAME TrapFrame
-);
-
+
BOOLEAN
NTAPI
KiHandleNmi(VOID);
@@ -1124,6 +1112,14 @@
VOID
);
+VOID
+FASTCALL
+//DECLSPEC_NORETURN
+KiSystemFatalException(
+ IN ULONG ExceptionCode,
+ IN PKTRAP_FRAME TrapFrame
+);
+
#include "ke_x.h"
#endif /* __NTOSKRNL_INCLUDE_INTERNAL_KE_H */
Modified: trunk/reactos/ntoskrnl/include/internal/trap_x.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/trap_x.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/trap_x.h [iso-8859-1] Sun Jan 24 06:40:04 2010
@@ -5,26 +5,21 @@
* PURPOSE: Internal Inlined Functions for the Trap Handling Code
* PROGRAMMERS: ReactOS Portable Systems Group
*/
-
-#if 0
-
-#ifdef __GNUC__
+#ifndef _TRAP_X_
+#define _TRAP_X_
+
+//
+// Unreachable code hint for GCC 4.5.x, 4.4.x, and MSVC
+//
#if __GNUC__ * 100 + __GNUC_MINOR__ >= 405
#define UNREACHABLE __builtin_unreachable()
+#elif __GNUC__ * 100 + __GNUC_MINOR__ >= 404
+#define UNREACHABLE __builtin_trap()
+#elif _MSC_VER
+#define UNREACHABLE __assume(0)
#else
-DECLSPEC_NORETURN void exit(int s) {exit(s);}
-#define UNREACHABLE exit(0)
+#define UNREACHABLE
#endif
-#else /* not __GNUC__ */
-DECLSPEC_NORETURN void exit(int s) {exit(s);}
-#define UNREACHABLE exit(0)
-#endif
-
-#else
-
-#define UNREACHABLE
-
-#endif
//
// Debug Macros
@@ -34,46 +29,46 @@
KiDumpTrapFrame(IN PKTRAP_FRAME TrapFrame)
{
/* Dump the whole thing */
- DPRINT1("DbgEbp: %x\n", TrapFrame->DbgEbp);
- DPRINT1("DbgEip: %x\n", TrapFrame->DbgEip);
- DPRINT1("DbgArgMark: %x\n", TrapFrame->DbgArgMark);
- DPRINT1("DbgArgPointer: %x\n", TrapFrame->DbgArgPointer);
- DPRINT1("TempSegCs: %x\n", TrapFrame->TempSegCs);
- DPRINT1("TempEsp: %x\n", TrapFrame->TempEsp);
- DPRINT1("Dr0: %x\n", TrapFrame->Dr0);
- DPRINT1("Dr1: %x\n", TrapFrame->Dr1);
- DPRINT1("Dr2: %x\n", TrapFrame->Dr2);
- DPRINT1("Dr3: %x\n", TrapFrame->Dr3);
- DPRINT1("Dr6: %x\n", TrapFrame->Dr6);
- DPRINT1("Dr7: %x\n", TrapFrame->Dr7);
- DPRINT1("SegGs: %x\n", TrapFrame->SegGs);
- DPRINT1("SegEs: %x\n", TrapFrame->SegEs);
- DPRINT1("SegDs: %x\n", TrapFrame->SegDs);
- DPRINT1("Edx: %x\n", TrapFrame->Edx);
- DPRINT1("Ecx: %x\n", TrapFrame->Ecx);
- DPRINT1("Eax: %x\n", TrapFrame->Eax);
- DPRINT1("PreviousPreviousMode: %x\n", TrapFrame->PreviousPreviousMode);
- DPRINT1("ExceptionList: %x\n", TrapFrame->ExceptionList);
- DPRINT1("SegFs: %x\n", TrapFrame->SegFs);
- DPRINT1("Edi: %x\n", TrapFrame->Edi);
- DPRINT1("Esi: %x\n", TrapFrame->Esi);
- DPRINT1("Ebx: %x\n", TrapFrame->Ebx);
- DPRINT1("Ebp: %x\n", TrapFrame->Ebp);
- DPRINT1("ErrCode: %x\n", TrapFrame->ErrCode);
- DPRINT1("Eip: %x\n", TrapFrame->Eip);
- DPRINT1("SegCs: %x\n", TrapFrame->SegCs);
- DPRINT1("EFlags: %x\n", TrapFrame->EFlags);
- DPRINT1("HardwareEsp: %x\n", TrapFrame->HardwareEsp);
- DPRINT1("HardwareSegSs: %x\n", TrapFrame->HardwareSegSs);
- DPRINT1("V86Es: %x\n", TrapFrame->V86Es);
- DPRINT1("V86Ds: %x\n", TrapFrame->V86Ds);
- DPRINT1("V86Fs: %x\n", TrapFrame->V86Fs);
- DPRINT1("V86Gs: %x\n", TrapFrame->V86Gs);
-}
-
-#if YDEBUG
-FORCEINLINE
-VOID
+ DbgPrint("DbgEbp: %x\n", TrapFrame->DbgEbp);
+ DbgPrint("DbgEip: %x\n", TrapFrame->DbgEip);
+ DbgPrint("DbgArgMark: %x\n", TrapFrame->DbgArgMark);
+ DbgPrint("DbgArgPointer: %x\n", TrapFrame->DbgArgPointer);
+ DbgPrint("TempSegCs: %x\n", TrapFrame->TempSegCs);
+ DbgPrint("TempEsp: %x\n", TrapFrame->TempEsp);
+ DbgPrint("Dr0: %x\n", TrapFrame->Dr0);
+ DbgPrint("Dr1: %x\n", TrapFrame->Dr1);
+ DbgPrint("Dr2: %x\n", TrapFrame->Dr2);
+ DbgPrint("Dr3: %x\n", TrapFrame->Dr3);
+ DbgPrint("Dr6: %x\n", TrapFrame->Dr6);
+ DbgPrint("Dr7: %x\n", TrapFrame->Dr7);
+ DbgPrint("SegGs: %x\n", TrapFrame->SegGs);
+ DbgPrint("SegEs: %x\n", TrapFrame->SegEs);
+ DbgPrint("SegDs: %x\n", TrapFrame->SegDs);
+ DbgPrint("Edx: %x\n", TrapFrame->Edx);
+ DbgPrint("Ecx: %x\n", TrapFrame->Ecx);
+ DbgPrint("Eax: %x\n", TrapFrame->Eax);
+ DbgPrint("PreviousPreviousMode: %x\n", TrapFrame->PreviousPreviousMode);
+ DbgPrint("ExceptionList: %x\n", TrapFrame->ExceptionList);
+ DbgPrint("SegFs: %x\n", TrapFrame->SegFs);
+ DbgPrint("Edi: %x\n", TrapFrame->Edi);
+ DbgPrint("Esi: %x\n", TrapFrame->Esi);
+ DbgPrint("Ebx: %x\n", TrapFrame->Ebx);
+ DbgPrint("Ebp: %x\n", TrapFrame->Ebp);
+ DbgPrint("ErrCode: %x\n", TrapFrame->ErrCode);
+ DbgPrint("Eip: %x\n", TrapFrame->Eip);
+ DbgPrint("SegCs: %x\n", TrapFrame->SegCs);
+ DbgPrint("EFlags: %x\n", TrapFrame->EFlags);
+ DbgPrint("HardwareEsp: %x\n", TrapFrame->HardwareEsp);
+ DbgPrint("HardwareSegSs: %x\n", TrapFrame->HardwareSegSs);
+ DbgPrint("V86Es: %x\n", TrapFrame->V86Es);
+ DbgPrint("V86Ds: %x\n", TrapFrame->V86Ds);
+ DbgPrint("V86Fs: %x\n", TrapFrame->V86Fs);
+ DbgPrint("V86Gs: %x\n", TrapFrame->V86Gs);
+}
+
+#ifdef TRAP_DEBUG
+VOID
+FORCEINLINE
KiFillTrapFrameDebug(IN PKTRAP_FRAME TrapFrame)
{
/* Set the debug information */
@@ -83,22 +78,22 @@
TrapFrame->DbgEbp = TrapFrame->Ebp;
}
-FORCEINLINE
-VOID
+VOID
+FORCEINLINE
KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame,
IN KTRAP_STATE_BITS SkipBits)
{
/* Make sure interrupts are disabled */
if (__readeflags() & EFLAGS_INTERRUPT_MASK)
{
- DPRINT1("Exiting with interrupts enabled: %lx\n", __readeflags());
+ DbgPrint("Exiting with interrupts enabled: %lx\n", __readeflags());
while (TRUE);
}
/* Make sure this is a real trap frame */
if (TrapFrame->DbgArgMark != 0xBADB0D00)
{
- DPRINT1("Exiting with an invalid trap frame? (No MAGIC in trap frame)\n");
+ DbgPrint("Exiting with an invalid trap frame? (No MAGIC in trap frame)\n");
KiDumpTrapFrame(TrapFrame);
while (TRUE);
}
@@ -106,34 +101,34 @@
/* Make sure we're not in user-mode or something */
if (Ke386GetFs() != KGDT_R0_PCR)
{
- DPRINT1("Exiting with an invalid FS: %lx\n", Ke386GetFs());
+ DbgPrint("Exiting with an invalid FS: %lx\n", Ke386GetFs());
while (TRUE);
}
/* Make sure we have a valid SEH chain */
if (KeGetPcr()->Tib.ExceptionList == 0)
{
- DPRINT1("Exiting with NULL exception chain: %p\n", KeGetPcr()->Tib.ExceptionList);
+ DbgPrint("Exiting with NULL exception chain: %p\n", KeGetPcr()->Tib.ExceptionList);
while (TRUE);
}
/* Make sure we're restoring a valid SEH chain */
if (TrapFrame->ExceptionList == 0)
{
- DPRINT1("Entered a trap with a NULL exception chain: %p\n", TrapFrame->ExceptionList);
+ DbgPrint("Entered a trap with a NULL exception chain: %p\n", TrapFrame->ExceptionList);
while (TRUE);
}
/* If we're ignoring previous mode, make sure caller doesn't actually want it */
if ((SkipBits.SkipPreviousMode) && (TrapFrame->PreviousPreviousMode != -1))
{
- DPRINT1("Exiting a trap witout restoring previous mode, yet previous mode seems valid: %lx", TrapFrame->PreviousPreviousMode);
- while (TRUE);
- }
-}
-
-FORCEINLINE
-VOID
+ DbgPrint("Exiting a trap witout restoring previous mode, yet previous mode seems valid: %lx", TrapFrame->PreviousPreviousMode);
+ while (TRUE);
+ }
+}
+
+VOID
+FORCEINLINE
KiExitSystemCallDebugChecks(IN ULONG SystemCall,
IN PKTRAP_FRAME TrapFrame)
{
@@ -188,88 +183,11 @@
return (TrapFrame->SegCs & MODE_MASK);
}
-BOOLEAN
-FORCEINLINE
-KiVdmTrap(IN PKTRAP_FRAME TrapFrame)
-{
- /* Either the V8086 flag is on, or this is user-mode with a VDM */
- return ((TrapFrame->EFlags & EFLAGS_V86_MASK) ||
- ((KiUserTrap(TrapFrame)) && (PsGetCurrentProcess()->VdmObjects)));
-}
-
-VOID
-FORCEINLINE
-KiCheckForApcDelivery(IN PKTRAP_FRAME TrapFrame)
-{
- PKTHREAD Thread;
- KIRQL OldIrql;
-
- /* Check for V8086 or user-mode trap */
- if ((TrapFrame->EFlags & EFLAGS_V86_MASK) ||
- (KiUserTrap(TrapFrame)))
- {
- /* 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();
- }
- }
-}
-
-VOID
-FORCEINLINE
-//DECLSPEC_NORETURN
-KiDispatchException0Args(IN NTSTATUS Code,
- IN ULONG_PTR Address,
- IN PKTRAP_FRAME TrapFrame)
-{
- /* Helper for exceptions with no arguments */
- KiDispatchExceptionFromTrapFrame(Code, Address, 0, 0, 0, 0, TrapFrame);
-}
-
-VOID
-FORCEINLINE
-//DECLSPEC_NORETURN
-KiDispatchException1Args(IN NTSTATUS Code,
- IN ULONG_PTR Address,
- IN ULONG P1,
- IN PKTRAP_FRAME TrapFrame)
-{
- /* Helper for exceptions with no arguments */
- KiDispatchExceptionFromTrapFrame(Code, Address, 1, P1, 0, 0, TrapFrame);
-}
-
-VOID
-FORCEINLINE
-//DECLSPEC_NORETURN
-KiDispatchException2Args(IN NTSTATUS Code,
- IN ULONG_PTR Address,
- IN ULONG P1,
- IN ULONG P2,
- IN PKTRAP_FRAME TrapFrame)
-{
- /* Helper for exceptions with no arguments */
- KiDispatchExceptionFromTrapFrame(Code, Address, 2, P1, P2, 0, TrapFrame);
-}
-
-FORCEINLINE
-VOID
+//
+// Assembly exit stubs
+//
+VOID
+FORCEINLINE
//DECLSPEC_NORETURN
KiSystemCallReturn(IN PKTRAP_FRAME TrapFrame)
{
@@ -299,8 +217,8 @@
UNREACHABLE;
}
-FORCEINLINE
-VOID
+VOID
+FORCEINLINE
//DECLSPEC_NORETURN
KiSystemCallTrapReturn(IN PKTRAP_FRAME TrapFrame)
{
@@ -328,8 +246,8 @@
UNREACHABLE;
}
-FORCEINLINE
-VOID
+VOID
+FORCEINLINE
//DECLSPEC_NORETURN
KiSystemCallSysExitReturn(IN PKTRAP_FRAME TrapFrame)
{
@@ -361,8 +279,8 @@
UNREACHABLE;
}
-FORCEINLINE
-VOID
+VOID
+FORCEINLINE
//DECLSPEC_NORETURN
KiTrapReturn(IN PKTRAP_FRAME TrapFrame)
{
@@ -394,8 +312,8 @@
UNREACHABLE;
}
-FORCEINLINE
-VOID
+VOID
+FORCEINLINE
//DECLSPEC_NORETURN
KiEditedTrapReturn(IN PKTRAP_FRAME TrapFrame)
{
@@ -428,102 +346,326 @@
UNREACHABLE;
}
-NTSTATUS
-FORCEINLINE
-KiSystemCallTrampoline(IN PVOID Handler,
- IN PVOID Arguments,
- IN ULONG StackBytes)
-{
- NTSTATUS Result;
+//
+// Generic Exit Routine
+//
+VOID
+FORCEINLINE
+//DECLSPEC_NORETURN
+KiExitTrap(IN PKTRAP_FRAME TrapFrame,
+ IN UCHAR Skip)
+{
+ KTRAP_EXIT_SKIP_BITS SkipBits = { .Bits = Skip };
+ PULONG ReturnStack;
+
+ /* Debugging checks */
+ KiExitTrapDebugChecks(TrapFrame, SkipBits);
+
+ /* Restore the SEH handler chain */
+ KeGetPcr()->Tib.ExceptionList = TrapFrame->ExceptionList;
+
+ /* Check if the previous mode must be restored */
+ if (__builtin_expect(!SkipBits.SkipPreviousMode, 0)) /* More INTS than SYSCALLs */
+ {
+ /* Restore it */
+ KeGetCurrentThread()->PreviousMode = TrapFrame->PreviousPreviousMode;
+ }
+
+ /* Check if there are active debug registers */
+ if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
+ {
+ /* Not handled yet */
+ DbgPrint("Need Hardware Breakpoint Support!\n");
+ DbgBreakPoint();
+ while (TRUE);
+ }
+
+ /* Check if this was a V8086 trap */
+ if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 0)) KiTrapReturn(TrapFrame);
+
+ /* Check if the trap frame was edited */
+ if (__builtin_expect(!(TrapFrame->SegCs & FRAME_EDITED), 0))
+ {
+ /*
+ * An edited trap frame happens when we need to modify CS and/or ESP but
+ * don't actually have a ring transition. This happens when a kernelmode
+ * caller wants to perform an NtContinue to another kernel address, such
+ * as in the case of SEH (basically, a longjmp), or to a user address.
+ *
+ * Therefore, the CPU never saved CS/ESP on the stack because we did not
+ * get a trap frame due to a ring transition (there was no interrupt).
+ * Even if we didn't want to restore CS to a new value, a problem occurs
+ * due to the fact a normal RET would not work if we restored ESP since
+ * RET would then try to read the result off the stack.
+ *
+ * The NT kernel solves this by adding 12 bytes of stack to the exiting
+ * trap frame, in which EFLAGS, CS, and EIP are stored, and then saving
+ * the ESP that's being requested into the ErrorCode field. It will then
+ * exit with an IRET. This fixes both issues, because it gives the stack
+ * some space where to hold the return address and then end up with the
+ * wanted stack, and it uses IRET which allows a new CS to be inputted.
+ *
+ */
+
+ /* Set CS that is requested */
+ TrapFrame->SegCs = TrapFrame->TempSegCs;
+
+ /* First make space on requested stack */
+ ReturnStack = (PULONG)(TrapFrame->TempEsp - 12);
+ TrapFrame->ErrCode = (ULONG_PTR)ReturnStack;
+
+ /* Now copy IRET frame */
+ ReturnStack[0] = TrapFrame->Eip;
+ ReturnStack[1] = TrapFrame->SegCs;
+ ReturnStack[2] = TrapFrame->EFlags;
+
+ /* Do special edited return */
+ KiEditedTrapReturn(TrapFrame);
+ }
+
+ /* Check if this is a user trap */
+ if (__builtin_expect(KiUserTrap(TrapFrame), 1)) /* Ring 3 is where we spend time */
+ {
+ /* 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);
+ }
+
+ /* Check for system call -- a system call skips volatiles! */
+ if (__builtin_expect(SkipBits.SkipVolatiles, 0)) /* More INTs than SYSCALLs */
+ {
+ /* Kernel call or user call? */
+ if (__builtin_expect(KiUserTrap(TrapFrame), 1)) /* More Ring 3 than 0 */
+ {
+ /* Is SYSENTER supported and/or enabled, or are we stepping code? */
+ if (__builtin_expect((KiFastSystemCallDisable) ||
+ (TrapFrame->EFlags & EFLAGS_TF), 0))
+ {
+ /* Exit normally */
+ KiSystemCallTrapReturn(TrapFrame);
+ }
+ else
+ {
+ /* Restore user FS */
+ Ke386SetFs(KGDT_R3_TEB | RPL_MASK);
+
+ /* Remove interrupt flag */
+ TrapFrame->EFlags &= ~EFLAGS_INTERRUPT_MASK;
+ __writeeflags(TrapFrame->EFlags);
+
+ /* Exit through SYSEXIT */
+ KiSystemCallSysExitReturn(TrapFrame);
+ }
+ }
+ else
+ {
+ /* Restore EFLags */
+ __writeeflags(TrapFrame->EFlags);
+
+ /* Call is kernel, so do a jump back since this wasn't a real INT */
+ KiSystemCallReturn(TrapFrame);
+ }
+ }
+ else
+ {
+ /* Return from interrupt */
+ KiTrapReturn(TrapFrame);
+ }
+}
+
+//
+// Virtual 8086 Mode Optimized Trap Exit
+//
+VOID
+FORCEINLINE
+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 (__builtin_expect(!Thread->ApcState.UserApcPending, 1)) 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 (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 0)) return;
+ }
+
+ /* If we got here, we're still in a valid V8086 context, so quit it */
+ if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
+ {
+ /* Not handled yet */
+ DbgPrint("Need Hardware Breakpoint Support!\n");
+ while (TRUE);
+ }
+
+ /* Return from interrupt */
+ KiTrapReturn(TrapFrame);
+}
+
+//
+// Virtual 8086 Mode Optimized Trap Entry
+//
+VOID
+FORCEINLINE
+KiEnterV86Trap(IN PKTRAP_FRAME 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 (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
+ {
+ DbgPrint("Need Hardware Breakpoint Support!\n");
+ while (TRUE);
+ }
+}
+
+//
+// Interrupt Trap Entry
+//
+VOID
+FORCEINLINE
+KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame)
+{
+ /* Set bogus previous mode */
+ TrapFrame->PreviousPreviousMode = -1;
+
+ /* Check for V86 mode */
+ if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 0))
+ {
+ DbgPrint("Need V8086 Interrupt Support!\n");
+ while (TRUE);
+ }
+
+ /* Check if this wasn't kernel code */
+ if (__builtin_expect(TrapFrame->SegCs != KGDT_R0_CODE, 1)) /* Ring 3 is more common */
+ {
+ /* 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;
+
+ /* No error code */
+ TrapFrame->ErrCode = 0;
+
+ /* Clear direction flag */
+ Ke386ClearDirectionFlag();
+
+ /* Flush DR7 and check for debugging */
+ TrapFrame->Dr7 = 0;
+ if (__builtin_expect(KeGetCurrentThread()->DispatcherHeader.DebugActive & 0xFF, 0))
+ {
+ DbgPrint("Need Hardware Breakpoint Support!\n");
+ while (TRUE);
+ }
+
+ /* Set debug header */
+ KiFillTrapFrameDebug(TrapFrame);
+}
+
+//
+// Generic Trap Entry
+//
+VOID
+FORCEINLINE
+KiEnterTrap(IN PKTRAP_FRAME TrapFrame)
+{
+ ULONG Ds, Es;
/*
- * This sequence does a RtlCopyMemory(Stack - StackBytes, Arguments, StackBytes)
- * and then calls the function associated with the system call.
+ * We really have to get a good DS/ES first before touching any data.
*
- * It's done in assembly for two reasons: we need to muck with the stack,
- * and the call itself restores the stack back for us. The only way to do
- * this in C is to do manual C handlers for every possible number of args on
- * the stack, and then have the handler issue a call by pointer. This is
- * wasteful since it'll basically push the values twice and require another
- * level of call indirection.
+ * These two reads will either go in a register (with optimizations ON) or
+ * a stack variable (which is on SS:ESP, guaranteed to be good/valid).
*
- * The ARM kernel currently does this, but it should probably be changed
- * later to function like this as well.
+ * Because the assembly is marked volatile, the order of instructions is
+ * as-is, otherwise the optimizer could simply get rid of our DS/ES.
*
*/
- __asm__ __volatile__
- (
- "subl %1, %%esp\n"
- "movl %%esp, %%edi\n"
- "movl %2, %%esi\n"
- "shrl $2, %1\n"
- "rep movsd\n"
- "call *%3\n"
- "movl %%eax, %0\n"
- : "=r"(Result)
- : "c"(StackBytes),
- "d"(Arguments),
- "r"(Handler)
- : "%esp", "%esi", "%edi"
- );
-
- return Result;
-}
-
-NTSTATUS
-FORCEINLINE
-KiConvertToGuiThread(VOID)
-{
- NTSTATUS Result;
- PVOID StackFrame;
-
- /*
- * Converting to a GUI thread safely updates ESP in-place as well as the
- * current Thread->TrapFrame and EBP when KeSwitchKernelStack is called.
- *
- * However, PsConvertToGuiThread "helpfully" restores EBP to the original
- * caller's value, since it is considered a nonvolatile register. As such,
- * as soon as we're back after the conversion and we try to store the result
- * which will probably be in some stack variable (EBP-based), we'll crash as
- * we are touching the de-allocated non-expanded stack.
- *
- * Thus we need a way to update our EBP before EBP is touched, and the only
- * way to guarantee this is to do the call itself in assembly, use the EAX
- * register to store the result, fixup EBP, and then let the C code continue
- * on its merry way.
- *
- */
- __asm__ __volatile__
- (
- "movl %%ebp, %1\n"
- "subl %%esp, %1\n"
- "call _PsConvertToGuiThread@0\n"
- "addl %%esp, %1\n"
- "movl %1, %%ebp\n"
- "movl %%eax, %0\n"
- : "=r"(Result), "=r"(StackFrame)
- :
- : "%esp", "%ecx", "%edx"
- );
+ Ds = Ke386GetDs();
+ Es = Ke386GetEs();
+ Ke386SetDs(KGDT_R3_DATA | RPL_MASK);
+ Ke386SetEs(KGDT_R3_DATA | RPL_MASK);
+ TrapFrame->SegDs = Ds;
+ TrapFrame->SegEs = Es;
- return Result;
-}
-
-VOID
-FORCEINLINE
-KiSwitchToBootStack(IN ULONG_PTR InitialStack)
-{
- /* We have to switch to a new stack before continuing kernel initialization */
- __asm__ __volatile__
- (
- "movl %0, %%esp\n"
- "subl %1, %%esp\n"
- "pushl %2\n"
- "jmp _KiSystemStartupBootStack@0\n"
- :
- : "c"(InitialStack),
- "i"(NPX_FRAME_LENGTH + KTRAP_FRAME_ALIGN + KTRAP_FRAME_LENGTH),
- "i"(CR0_EM | CR0_TS | CR0_MP)
- : "%esp"
- );
-}
+ /* Now we can save the other segments and then switch to the correct FS */
+ TrapFrame->SegFs = Ke386GetFs();
+ TrapFrame->SegGs = Ke386GetGs();
+ Ke386SetFs(KGDT_R0_PCR);
+
+ /* Save exception list and bogus previous mode */
+ TrapFrame->PreviousPreviousMode = -1;
+ TrapFrame->ExceptionList = KeGetPcr()->Tib.ExceptionList;
+
+ /* Check for V86 mode */
+ if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 0))
+ {
+ /* Restore V8086 segments into Protected Mode segments */
+ TrapFrame->SegFs = TrapFrame->V86Fs;
+ TrapFrame->SegGs = TrapFrame->V86Gs;
+ TrapFrame->SegDs = TrapFrame->V86Ds;
+ TrapFrame->SegEs = TrapFrame->V86Es;
+ }
+
+ /* Clear direction flag */
+ Ke386ClearDirectionFlag();
+
+ /* Flush DR7 and check for debugging */
+ TrapFrame->Dr7 = 0;
+ if (__builtin_expect(KeGetCurrentThread()->DispatcherHeader.DebugActive & 0xFF, 0))
+ {
+ DbgPrint("Need Hardware Breakpoint Support!\n");
+ while (TRUE);
+ }
+
+ /* Set debug header */
+ KiFillTrapFrameDebug(TrapFrame);
+}
+#endif
Modified: trunk/reactos/ntoskrnl/ke/i386/exp.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/exp.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/exp.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/exp.c [iso-8859-1] Sun Jan 24 06:40:04 2010
@@ -1105,6 +1105,62 @@
return;
}
+VOID
+NTAPI
+//DECLSPEC_NORETURN
+KiDispatchExceptionFromTrapFrame(IN NTSTATUS Code,
+ IN ULONG_PTR Address,
+ IN ULONG ParameterCount,
+ IN ULONG_PTR Parameter1,
+ IN ULONG_PTR Parameter2,
+ IN ULONG_PTR Parameter3,
+ IN PKTRAP_FRAME TrapFrame)
+{
+ EXCEPTION_RECORD ExceptionRecord;
+
+ /* Build the exception record */
+ ExceptionRecord.ExceptionCode = Code;
+ ExceptionRecord.ExceptionFlags = 0;
+ ExceptionRecord.ExceptionRecord = NULL;
+ ExceptionRecord.ExceptionAddress = (PVOID)Address;
+ ExceptionRecord.NumberParameters = ParameterCount;
+ if (ParameterCount)
+ {
+ /* Copy extra parameters */
+ ExceptionRecord.ExceptionInformation[0] = Parameter1;
+ ExceptionRecord.ExceptionInformation[1] = Parameter2;
+ ExceptionRecord.ExceptionInformation[2] = Parameter3;
+ }
+
+ /* Now go dispatch the exception */
+ KiDispatchException(&ExceptionRecord,
+ NULL,
+ TrapFrame,
+ TrapFrame->EFlags & EFLAGS_V86_MASK ?
+ -1 : KiUserTrap(TrapFrame),
+ TRUE);
+
+ /* Return from this trap */
+ KiEoiHelper(TrapFrame);
+}
+
+VOID
+FASTCALL
+//DECLSPEC_NORETURN
+KiSystemFatalException(IN ULONG ExceptionCode,
+ IN PKTRAP_FRAME TrapFrame)
+{
+ /* Bugcheck the system */
+ KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP,
+ ExceptionCode,
+ 0,
+ 0,
+ 0,
+ TrapFrame);
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
/*
* @implemented
*/
Modified: trunk/reactos/ntoskrnl/ke/i386/traphdlr.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/traphdlr.…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/traphdlr.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/traphdlr.c [iso-8859-1] Sun Jan 24 06:40:04 2010
@@ -11,7 +11,6 @@
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
-#include "internal/trap_x.h"
/* GLOBALS ********************************************************************/
@@ -45,198 +44,21 @@
0x6E, /* OUTS */
0x6F, /* OUTS */
};
+
+BOOLEAN
+FORCEINLINE
+KiVdmTrap(IN PKTRAP_FRAME TrapFrame)
+{
+ /* Either the V8086 flag is on, or this is user-mode with a VDM */
+ return ((TrapFrame->EFlags & EFLAGS_V86_MASK) ||
+ ((KiUserTrap(TrapFrame)) && (PsGetCurrentProcess()->VdmObjects)));
+}
/* TRAP EXIT CODE *************************************************************/
VOID
FASTCALL
//DECLSPEC_NORETURN
-KiExitTrap(IN PKTRAP_FRAME TrapFrame,
- IN UCHAR Skip)
-{
- KTRAP_EXIT_SKIP_BITS SkipBits = { .Bits = Skip };
- PULONG ReturnStack;
-
- /* Debugging checks */
- KiExitTrapDebugChecks(TrapFrame, SkipBits);
-
- /* Restore the SEH handler chain */
- KeGetPcr()->Tib.ExceptionList = TrapFrame->ExceptionList;
-
- /* Check if the previous mode must be restored */
- if (__builtin_expect(!SkipBits.SkipPreviousMode, 0)) /* More INTS than SYSCALLs */
- {
- /* Restore it */
- KeGetCurrentThread()->PreviousMode = TrapFrame->PreviousPreviousMode;
- }
-
- /* Check if there are active debug registers */
- if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
- {
- /* Not handled yet */
- UNIMPLEMENTED;
- DbgBreakPoint();
- KiDumpTrapFrame(TrapFrame);
- while (TRUE);
- }
-
- /* Check if this was a V8086 trap */
- if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 0)) KiTrapReturn(TrapFrame);
-
- /* Check if the trap frame was edited */
- if (__builtin_expect(!(TrapFrame->SegCs & FRAME_EDITED), 0))
- {
- /*
- * An edited trap frame happens when we need to modify CS and/or ESP but
- * don't actually have a ring transition. This happens when a kernelmode
- * caller wants to perform an NtContinue to another kernel address, such
- * as in the case of SEH (basically, a longjmp), or to a user address.
- *
- * Therefore, the CPU never saved CS/ESP on the stack because we did not
- * get a trap frame due to a ring transition (there was no interrupt).
- * Even if we didn't want to restore CS to a new value, a problem occurs
- * due to the fact a normal RET would not work if we restored ESP since
- * RET would then try to read the result off the stack.
- *
- * The NT kernel solves this by adding 12 bytes of stack to the exiting
- * trap frame, in which EFLAGS, CS, and EIP are stored, and then saving
- * the ESP that's being requested into the ErrorCode field. It will then
- * exit with an IRET. This fixes both issues, because it gives the stack
- * some space where to hold the return address and then end up with the
- * wanted stack, and it uses IRET which allows a new CS to be inputted.
- *
- */
-
- /* Set CS that is requested */
- TrapFrame->SegCs = TrapFrame->TempSegCs;
-
- /* First make space on requested stack */
- ReturnStack = (PULONG)(TrapFrame->TempEsp - 12);
- TrapFrame->ErrCode = (ULONG_PTR)ReturnStack;
-
- /* Now copy IRET frame */
- ReturnStack[0] = TrapFrame->Eip;
- ReturnStack[1] = TrapFrame->SegCs;
- ReturnStack[2] = TrapFrame->EFlags;
-
- /* Do special edited return */
- KiEditedTrapReturn(TrapFrame);
- }
-
- /* Check if this is a user trap */
- if (__builtin_expect(KiUserTrap(TrapFrame), 1)) /* Ring 3 is where we spend time */
- {
- /* 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);
- }
-
- /* Check for ABIOS code segment */
- if (__builtin_expect(TrapFrame->SegCs == 0x80, 0))
- {
- /* Not handled yet */
- UNIMPLEMENTED;
- while (TRUE);
- }
-
- /* Check for system call -- a system call skips volatiles! */
- if (__builtin_expect(SkipBits.SkipVolatiles, 0)) /* More INTs than SYSCALLs */
- {
- /* Kernel call or user call? */
- if (__builtin_expect(KiUserTrap(TrapFrame), 1)) /* More Ring 3 than 0 */
- {
- /* Is SYSENTER supported and/or enabled, or are we stepping code? */
- if (__builtin_expect((KiFastSystemCallDisable) ||
- (TrapFrame->EFlags & EFLAGS_TF), 0))
- {
- /* Exit normally */
- KiSystemCallTrapReturn(TrapFrame);
- }
- else
- {
- /* Restore user FS */
- Ke386SetFs(KGDT_R3_TEB | RPL_MASK);
-
- /* Remove interrupt flag */
- TrapFrame->EFlags &= ~EFLAGS_INTERRUPT_MASK;
- __writeeflags(TrapFrame->EFlags);
-
- /* Exit through SYSEXIT */
- KiSystemCallSysExitReturn(TrapFrame);
- }
- }
- else
- {
- /* Restore EFLags */
- __writeeflags(TrapFrame->EFlags);
-
- /* Call is kernel, so do a jump back since this wasn't a real INT */
- KiSystemCallReturn(TrapFrame);
- }
- }
- else
- {
- /* Return from interrupt */
- KiTrapReturn(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 (__builtin_expect(!Thread->ApcState.UserApcPending, 1)) 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 (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 0)) return;
- }
-
- /* If we got here, we're still in a valid V8086 context, so quit it */
- if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
- {
- /* Not handled yet */
- UNIMPLEMENTED;
- while (TRUE);
- }
-
- /* Return from interrupt */
- KiTrapReturn(TrapFrame);
-}
-
-VOID
-FASTCALL
-//DECLSPEC_NORETURN
KiEoiHelper(IN PKTRAP_FRAME TrapFrame)
{
/* Disable interrupts until we return */
@@ -281,202 +103,6 @@
/* Now exit the trap for real */
KiExitTrap(TrapFrame, 0);
-}
-
-/* TRAP ENTRY CODE ************************************************************/
-
-VOID
-FASTCALL
-KiEnterV86Trap(IN PKTRAP_FRAME 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 (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
- {
- UNIMPLEMENTED;
- while (TRUE);
- }
-}
-
-VOID
-FASTCALL
-KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame)
-{
- /* Set bogus previous mode */
- TrapFrame->PreviousPreviousMode = -1;
-
- /* Check for V86 mode */
- if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 0))
- {
- UNIMPLEMENTED;
- while (TRUE);
- }
-
- /* Check if this wasn't kernel code */
- if (__builtin_expect(TrapFrame->SegCs != KGDT_R0_CODE, 1)) /* Ring 3 is more common */
- {
- /* 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 (__builtin_expect(KeGetCurrentThread()->DispatcherHeader.DebugActive & 0xFF, 0))
- {
- UNIMPLEMENTED;
- while (TRUE);
- }
-
- /* Set debug header */
- KiFillTrapFrameDebug(TrapFrame);
-}
-
-VOID
-FASTCALL
-KiEnterTrap(IN PKTRAP_FRAME TrapFrame)
-{
- ULONG Ds, Es;
-
- /*
- * We really have to get a good DS/ES first before touching any data.
- *
- * These two reads will either go in a register (with optimizations ON) or
- * a stack variable (which is on SS:ESP, guaranteed to be good/valid).
- *
- * Because the assembly is marked volatile, the order of instructions is
- * as-is, otherwise the optimizer could simply get rid of our DS/ES.
- *
- */
- Ds = Ke386GetDs();
- Es = Ke386GetEs();
- Ke386SetDs(KGDT_R3_DATA | RPL_MASK);
- Ke386SetEs(KGDT_R3_DATA | RPL_MASK);
- TrapFrame->SegDs = Ds;
- TrapFrame->SegEs = Es;
-
- /* Now we can save the other segments and then switch to the correct FS */
- TrapFrame->SegFs = Ke386GetFs();
- TrapFrame->SegGs = Ke386GetGs();
- Ke386SetFs(KGDT_R0_PCR);
-
- /* Save exception list and bogus previous mode */
- TrapFrame->PreviousPreviousMode = -1;
- TrapFrame->ExceptionList = KeGetPcr()->Tib.ExceptionList;
-
- /* Check for 16-bit stack */
- if (__builtin_expect((ULONG_PTR)TrapFrame < 0x10000, 0))
- {
- UNIMPLEMENTED;
- while (TRUE);
- }
-
- /* Check for V86 mode */
- if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 0))
- {
- /* Restore V8086 segments into Protected Mode segments */
- TrapFrame->SegFs = TrapFrame->V86Fs;
- TrapFrame->SegGs = TrapFrame->V86Gs;
- TrapFrame->SegDs = TrapFrame->V86Ds;
- TrapFrame->SegEs = TrapFrame->V86Es;
- }
-
- /* Clear direction flag */
- Ke386ClearDirectionFlag();
-
- /* Flush DR7 and check for debugging */
- TrapFrame->Dr7 = 0;
- if (__builtin_expect(KeGetCurrentThread()->DispatcherHeader.DebugActive & 0xFF, 0))
- {
- UNIMPLEMENTED;
- while (TRUE);
- }
-
- /* Set debug header */
- KiFillTrapFrameDebug(TrapFrame);
-}
-
-/* EXCEPTION CODE *************************************************************/
-
-VOID
-FASTCALL
-//DECLSPEC_NORETURN
-KiSystemFatalException(IN ULONG ExceptionCode,
- IN PKTRAP_FRAME TrapFrame)
-{
- /* Bugcheck the system */
- KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP,
- ExceptionCode,
- 0,
- 0,
- 0,
- TrapFrame);
-}
-
-VOID
-NTAPI
-//DECLSPEC_NORETURN
-KiDispatchExceptionFromTrapFrame(IN NTSTATUS Code,
- IN ULONG_PTR Address,
- IN ULONG ParameterCount,
- IN ULONG_PTR Parameter1,
- IN ULONG_PTR Parameter2,
- IN ULONG_PTR Parameter3,
- IN PKTRAP_FRAME TrapFrame)
-{
- EXCEPTION_RECORD ExceptionRecord;
-
- /* Build the exception record */
- ExceptionRecord.ExceptionCode = Code;
- ExceptionRecord.ExceptionFlags = 0;
- ExceptionRecord.ExceptionRecord = NULL;
- ExceptionRecord.ExceptionAddress = (PVOID)Address;
- ExceptionRecord.NumberParameters = ParameterCount;
- if (ParameterCount)
- {
- /* Copy extra parameters */
- ExceptionRecord.ExceptionInformation[0] = Parameter1;
- ExceptionRecord.ExceptionInformation[1] = Parameter2;
- ExceptionRecord.ExceptionInformation[2] = Parameter3;
- }
-
- /* Now go dispatch the exception */
- KiDispatchException(&ExceptionRecord,
- NULL,
- TrapFrame,
- TrapFrame->EFlags & EFLAGS_V86_MASK ?
- -1 : KiUserTrap(TrapFrame),
- TRUE);
-
- /* Return from this trap */
- KiEoiHelper(TrapFrame);
}
/* TRAP HANDLERS **************************************************************/