-/* $Id: usercall.c,v 1.13 2000/06/29 23:35:38 dwelch Exp $
- *
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: ntoskrnl/hal/x86/usercall.c
- * PURPOSE: 2E interrupt handler
- * PROGRAMMER: David Welch (david.welch@seh.ox.ac.uk)
- * UPDATE HISTORY:
- * ???
+/*
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: ntoskrnl/ke/i386/usercall.c
+ * PURPOSE: User-mode Callout Mechanisms (APC and Win32K Callbacks)
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
-#include <ddk/ntddk.h>
-#include <internal/ntoskrnl.h>
-#include <internal/ke.h>
-#include <internal/i386/segment.h>
-#include <internal/mmhal.h>
+/* INCLUDES ******************************************************************/
+#include <ntoskrnl.h>
#define NDEBUG
-#include <internal/debug.h>
-#include <ddk/service.h>
-
-#include <ddk/defines.h>
-
+#include <debug.h>
+extern PGDI_BATCHFLUSH_ROUTINE KeGdiFlushUserBatch;
-#define _STR(x) #x
-#define STR(x) _STR(x)
+/* PRIVATE FUNCTIONS *********************************************************/
-void PsBeginThreadWithContextInternal(void);
- __asm__(
- "\n\t.global _PsBeginThreadWithContextInternal\n\t"
- "_PsBeginThreadWithContextInternal:\n\t"
-// "pushl $1\n\t"
-// "call _KeLowerIrql\n\t"
- "call _PiBeforeBeginThread\n\t"
-// "popl %eax\n\t"
- "popl %eax\n\t"
- "popl %eax\n\t"
- "popl %eax\n\t"
- "popl %eax\n\t"
- "popl %eax\n\t"
- "popl %eax\n\t"
- "popl %eax\n\t"
- "addl $112,%esp\n\t"
- "popl %gs\n\t"
- "popl %fs\n\t"
- "popl %es\n\t"
- "popl %ds\n\t"
- "popl %edi\n\t"
- "popl %esi\n\t"
- "popl %ebx\n\t"
- "popl %edx\n\t"
- "popl %ecx\n\t"
- "popl %eax\n\t"
- "popl %ebp\n\t"
- "iret\n\t");
-
-VOID KiSystemCallHook(ULONG Nr, ...)
+/*++
+ * @name KiInitializeUserApc
+ *
+ * Prepares the Context for a User-Mode APC called through NTDLL.DLL
+ *
+ * @param Reserved
+ * Pointer to the Exception Frame on non-i386 builds.
+ *
+ * @param TrapFrame
+ * Pointer to the Trap Frame.
+ *
+ * @param NormalRoutine
+ * Pointer to the NormalRoutine to call.
+ *
+ * @param NormalContext
+ * Pointer to the context to send to the Normal Routine.
+ *
+ * @param SystemArgument[1-2]
+ * Pointer to a set of two parameters that contain untyped data.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+KiInitializeUserApc(IN PKEXCEPTION_FRAME ExceptionFrame,
+ IN PKTRAP_FRAME TrapFrame,
+ IN PKNORMAL_ROUTINE NormalRoutine,
+ IN PVOID NormalContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2)
{
-#if 0
- va_list ap;
- ULONG i;
+ CONTEXT Context;
+ ULONG_PTR Stack, AlignedEsp;
+ ULONG ContextLength;
+ EXCEPTION_RECORD SehExceptRecord;
- va_start(ap, Nr);
+ /* Don't deliver APCs in V86 mode */
+ if (TrapFrame->EFlags & EFLAGS_V86_MASK) return;
- DbgPrint("%x/%d ", KeServiceDescriptorTable[0].SSDT[Nr].SysCallPtr, Nr);
- DbgPrint("%x (", KeServiceDescriptorTable[0].SSPT[Nr].ParamBytes);
- for (i = 0; i < KeServiceDescriptorTable[0].SSPT[Nr].ParamBytes / 4; i++)
- {
- DbgPrint("%x, ", va_arg(ap, ULONG));
- }
- DbgPrint(")\n");
- assert_irql(PASSIVE_LEVEL);
- va_end(ap);
-#endif
-}
+ /* Save the full context */
+ Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
+ KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
-ULONG KiAfterSystemCallHook(ULONG NtStatus, PCONTEXT Context)
-{
- if (NtStatus != STATUS_USER_APC)
- {
- return(NtStatus);
- }
- KiTestAlert(KeGetCurrentThread(), Context);
- return(NtStatus);
+ /* Protect with SEH */
+ _SEH2_TRY
+ {
+ /* Sanity check */
+ ASSERT((TrapFrame->SegCs & MODE_MASK) != KernelMode);
+
+ /* Get the aligned size */
+ AlignedEsp = Context.Esp & ~3;
+ ContextLength = CONTEXT_ALIGNED_SIZE + (4 * sizeof(ULONG_PTR));
+ Stack = ((AlignedEsp - 8) & ~3) - ContextLength;
+
+ /* Probe the stack */
+ ProbeForWrite((PVOID)Stack, AlignedEsp - Stack, 1);
+ ASSERT(!(Stack & 3));
+
+ /* Copy data into it */
+ RtlCopyMemory((PVOID)(Stack + (4 * sizeof(ULONG_PTR))),
+ &Context,
+ sizeof(CONTEXT));
+
+ /* Run at APC dispatcher */
+ TrapFrame->Eip = (ULONG)KeUserApcDispatcher;
+ TrapFrame->HardwareEsp = Stack;
+
+ /* Setup Ring 3 state */
+ TrapFrame->SegCs = Ke386SanitizeSeg(KGDT_R3_CODE, UserMode);
+ TrapFrame->HardwareSegSs = Ke386SanitizeSeg(KGDT_R3_DATA, UserMode);
+ TrapFrame->SegDs = Ke386SanitizeSeg(KGDT_R3_DATA, UserMode);
+ TrapFrame->SegEs = Ke386SanitizeSeg(KGDT_R3_DATA, UserMode);
+ TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB, UserMode);
+ TrapFrame->SegGs = 0;
+ TrapFrame->ErrCode = 0;
+
+ /* Sanitize EFLAGS */
+ TrapFrame->EFlags = Ke386SanitizeFlags(Context.EFlags, UserMode);
+
+ /* Check if thread has IOPL and force it enabled if so */
+ if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL;
+
+ /* Setup the stack */
+ *(PULONG_PTR)(Stack + 0 * sizeof(ULONG_PTR)) = (ULONG_PTR)NormalRoutine;
+ *(PULONG_PTR)(Stack + 1 * sizeof(ULONG_PTR)) = (ULONG_PTR)NormalContext;
+ *(PULONG_PTR)(Stack + 2 * sizeof(ULONG_PTR)) = (ULONG_PTR)SystemArgument1;
+ *(PULONG_PTR)(Stack + 3 * sizeof(ULONG_PTR)) = (ULONG_PTR)SystemArgument2;
+ }
+ _SEH2_EXCEPT((RtlCopyMemory(&SehExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER))
+ {
+ /* Dispatch the exception */
+ SehExceptRecord.ExceptionAddress = (PVOID)TrapFrame->Eip;
+ KiDispatchException(&SehExceptRecord,
+ ExceptionFrame,
+ TrapFrame,
+ UserMode,
+ TRUE);
+ }
+ _SEH2_END;
}
-// This function should be used by win32k.sys to add its own user32/gdi32 services
-// TableIndex is 0 based
-// ServiceCountTable its not used at the moment
-BOOLEAN
-STDCALL
-KeAddSystemServiceTable (
- PSSDT SSDT,
- PULONG ServiceCounterTable,
- ULONG NumberOfServices,
- PSSPT SSPT,
- ULONG TableIndex
- )
-{
- if (TableIndex > SSDT_MAX_ENTRIES - 1)
- return FALSE;
+/* PUBLIC FUNCTIONS **********************************************************/
- /* check if descriptor table entry is free */
- if ((KeServiceDescriptorTable[TableIndex].SSDT != NULL) ||
- (KeServiceDescriptorTableShadow[TableIndex].SSDT != NULL))
- return FALSE;
-
- /* initialize the shadow service descriptor table */
- KeServiceDescriptorTableShadow[TableIndex].SSDT = SSDT;
- KeServiceDescriptorTableShadow[TableIndex].SSPT = SSPT;
- KeServiceDescriptorTableShadow[TableIndex].NumberOfServices = NumberOfServices;
- KeServiceDescriptorTableShadow[TableIndex].ServiceCounterTable = ServiceCounterTable;
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+KeUserModeCallback(IN ULONG RoutineIndex,
+ IN PVOID Argument,
+ IN ULONG ArgumentLength,
+ OUT PVOID *Result,
+ OUT PULONG ResultLength)
+{
+ ULONG_PTR NewStack, OldStack;
+ PULONG UserEsp;
+ NTSTATUS CallbackStatus;
+ PEXCEPTION_REGISTRATION_RECORD ExceptionList;
+ PTEB Teb;
+ ULONG GdiBatchCount = 0;
+ ASSERT(KeGetCurrentThread()->ApcState.KernelApcInProgress == FALSE);
+ ASSERT(KeGetPreviousMode() == UserMode);
+
+ /* Get the current user-mode stack */
+ UserEsp = KiGetUserModeStackAddress();
+ OldStack = *UserEsp;
+
+ /* Enter a SEH Block */
+ _SEH2_TRY
+ {
+ /* Calculate and align the stack size */
+ NewStack = (OldStack - ArgumentLength) & ~3;
+
+ /* Make sure it's writable */
+ ProbeForWrite((PVOID)(NewStack - 6 * sizeof(ULONG_PTR)),
+ ArgumentLength + 6 * sizeof(ULONG_PTR),
+ sizeof(CHAR));
+
+ /* Copy the buffer into the stack */
+ RtlCopyMemory((PVOID)NewStack, Argument, ArgumentLength);
+
+ /* Write the arguments */
+ NewStack -= 24;
+ *(PULONG)NewStack = 0;
+ *(PULONG)(NewStack + 4) = RoutineIndex;
+ *(PULONG)(NewStack + 8) = (NewStack + 24);
+ *(PULONG)(NewStack + 12) = ArgumentLength;
+
+ /* Save the exception list */
+ Teb = KeGetCurrentThread()->Teb;
+ ExceptionList = Teb->Tib.ExceptionList;
+
+ /* Jump to user mode */
+ *UserEsp = NewStack;
+ CallbackStatus = KiCallUserMode(Result, ResultLength);
+ if (CallbackStatus != STATUS_CALLBACK_POP_STACK)
+ {
+ /* Only restore the exception list if we didn't crash in ring 3 */
+ Teb->Tib.ExceptionList = ExceptionList;
+ CallbackStatus = STATUS_SUCCESS;
+ }
+ else
+ {
+ /* Otherwise, pop the stack */
+ OldStack = *UserEsp;
+ }
+
+ /* Read the GDI Batch count */
+ GdiBatchCount = Teb->GdiBatchCount;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Get the SEH exception */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
- /* initialize the service descriptor table (not for win32k services) */
- if (TableIndex != 1)
+ /* Check if we have GDI Batch operations */
+ if (GdiBatchCount)
{
- KeServiceDescriptorTable[TableIndex].SSDT = SSDT;
- KeServiceDescriptorTable[TableIndex].SSPT = SSPT;
- KeServiceDescriptorTable[TableIndex].NumberOfServices = NumberOfServices;
- KeServiceDescriptorTable[TableIndex].ServiceCounterTable = ServiceCounterTable;
+ *UserEsp -= 256;
+ KeGdiFlushUserBatch();
}
- return TRUE;
+ /* Restore stack and return */
+ *UserEsp = OldStack;
+ return CallbackStatus;
}
-
-void interrupt_handler2e(void);
- __asm__("\n\t.global _interrupt_handler2e\n\t"
- "_interrupt_handler2e:\n\t"
-
- /* Save the user context */
- "pushl %ebp\n\t" /* Ebp */
-
- "pushl %eax\n\t" /* Eax */
- "pushl %ecx\n\t" /* Ecx */
- "pushl %edx\n\t" /* Edx */
- "pushl %ebx\n\t" /* Ebx */
- "pushl %esi\n\t" /* Esi */
- "pushl %edi\n\t" /* Edi */
-
- "pushl %ds\n\t" /* SegDs */
- "pushl %es\n\t" /* SegEs */
- "pushl %fs\n\t" /* SegFs */
- "pushl %gs\n\t" /* SegGs */
-
- "subl $112,%esp\n\t" /* FloatSave */
-
- "pushl $0\n\t" /* Dr7 */
- "pushl $0\n\t" /* Dr6 */
- "pushl $0\n\t" /* Dr3 */
- "pushl $0\n\t" /* Dr2 */
- "pushl $0\n\t" /* Dr1 */
- "pushl $0\n\t" /* Dr0 */
-
- "pushl $0\n\t" /* ContextFlags */
-
- /* Set ES to kernel segment */
- "movw $"STR(KERNEL_DS)",%bx\n\t"
- "movw %bx,%es\n\t"
-
- /* Save pointer to user context as argument to system call */
- "pushl %esp\n\t"
-
- /* Allocate new Kernel stack frame */
- "movl %esp,%ebp\n\t"
-
- /* Users's current stack frame pointer is source */
- "movl %edx,%esi\n\t"
-
- /* Determine system service table to use */
- "cmpl $0x0fff, %eax\n\t"
- "ja useShadowTable\n\t"
-
- /* Check to see if EAX is valid/inrange */
- "cmpl %es:_KeServiceDescriptorTable + 8, %eax\n\t"
- "jbe serviceInRange\n\t"
- "movl $"STR(STATUS_INVALID_SYSTEM_SERVICE)", %eax\n\t"
- "jmp done\n\t"
-
- "serviceInRange:\n\t"
-
- /* Allocate room for argument list from kernel stack */
- "movl %es:_KeServiceDescriptorTable + 12, %ecx\n\t"
- "movl %es:(%ecx, %eax, 4), %ecx\n\t"
- "subl %ecx, %esp\n\t"
-
- /* Copy the arguments from the user stack to the kernel stack */
- "movl %esp,%edi\n\t"
- "rep\n\tmovsb\n\t"
-
- /* DS is now also kernel segment */
- "movw %bx, %ds\n\t"
-
- /* Call system call hook */
- "pushl %eax\n\t"
- "call _KiSystemCallHook\n\t"
- "popl %eax\n\t"
-
- /* Make the system service call */
- "movl %es:_KeServiceDescriptorTable, %ecx\n\t"
- "movl %es:(%ecx, %eax, 4), %eax\n\t"
- "call *%eax\n\t"
-
-#if CHECKED
- /* Bump Service Counter */
-#endif
-
- /* Deallocate the kernel stack frame */
- "movl %ebp,%esp\n\t"
-
- /* Call the post system call hook and deliver any pending APCs */
- "pushl %eax\n\t"
- "call _KiAfterSystemCallHook\n\t"
- "addl $8,%esp\n\t"
-
- "jmp done\n\t"
-
- "useShadowTable:\n\t"
-
- "subl $0x1000, %eax\n\t"
-
- /* Check to see if EAX is valid/inrange */
- "cmpl %es:_KeServiceDescriptorTableShadow + 24, %eax\n\t"
- "jbe shadowServiceInRange\n\t"
- "movl $"STR(STATUS_INVALID_SYSTEM_SERVICE)", %eax\n\t"
- "jmp done\n\t"
-
- "shadowServiceInRange:\n\t"
-
- /* Allocate room for argument list from kernel stack */
- "movl %es:_KeServiceDescriptorTableShadow + 28, %ecx\n\t"
- "movl %es:(%ecx, %eax, 4), %ecx\n\t"
- "subl %ecx, %esp\n\t"
-
- /* Copy the arguments from the user stack to the kernel stack */
- "movl %esp,%edi\n\t"
- "rep\n\tmovsb\n\t"
-
- /* DS is now also kernel segment */
- "movw %bx,%ds\n\t"
-
- /* Call system call hook */
- "pushl %eax\n\t"
- "call _KiSystemCallHook\n\t"
- "popl %eax\n\t"
-
- /* Make the system service call */
- "movl %es:_KeServiceDescriptorTableShadow + 16, %ecx\n\t"
- "movl %es:(%ecx, %eax, 4), %eax\n\t"
- "call *%eax\n\t"
-
-#if CHECKED
- /* Bump Service Counter */
-#endif
-
- /* Deallocate the kernel stack frame */
- "movl %ebp,%esp\n\t"
-
- /* Call the post system call hook and deliver any pending APCs */
- "pushl %eax\n\t"
- "call _KiAfterSystemCallHook\n\t"
- "addl $8,%esp\n\t"
-
- "done:\n\t"
-
- /* Restore the user context */
- "addl $4,%esp\n\t" /* UserContext */
- "addl $24,%esp\n\t" /* Dr[0-3,6-7] */
- "addl $112,%esp\n\t" /* FloatingSave */
- "popl %gs\n\t" /* SegGs */
- "popl %fs\n\t" /* SegFs */
- "popl %es\n\t" /* SegEs */
- "popl %ds\n\t" /* SegDs */
-
- "popl %edi\n\t" /* Edi */
- "popl %esi\n\t" /* Esi */
- "popl %ebx\n\t" /* Ebx */
- "popl %edx\n\t" /* Edx */
- "popl %ecx\n\t" /* Ecx */
- "addl $4,%esp\n\t" /* Eax (Not restored) */
-
- "popl %ebp\n\t" /* Ebp */
-
- "iret\n\t");
-
/* EOF */