Author: sir_richard
Date: Tue Jan 19 10:20:40 2010
New Revision: 45147
URL:
http://svn.reactos.org/svn/reactos?rev=45147&view=rev
Log:
[NTOS]: Convert system call handling to C. Only kernel system calls are done this way for
now, not SYSENTER calls from user-mode. A small ASM trampoline is used inline for the call
itself.
Modified:
trunk/reactos/ntoskrnl/include/internal/trap_x.h
trunk/reactos/ntoskrnl/ke/i386/trap.s
trunk/reactos/ntoskrnl/ke/i386/traphdlr.c
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] Tue Jan 19 10:20:40
2010
@@ -111,15 +111,55 @@
while (TRUE);
}
}
+
+FORCEINLINE
+VOID
+KiExitSystemCallDebugChecks(IN ULONG SystemCall,
+ IN PKTRAP_FRAME TrapFrame)
+{
+ KIRQL OldIrql;
+
+ /* Check if this was a user call */
+ if (KiUserMode(TrapFrame))
+ {
+ /* Make sure we are not returning with elevated IRQL */
+ OldIrql = KeGetCurrentIrql();
+ if (OldIrql != PASSIVE_LEVEL)
+ {
+ /* Forcibly put us in a sane state */
+ KeGetPcr()->CurrentIrql = PASSIVE_LEVEL;
+ _disable();
+
+ /* Fail */
+ KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE,
+ SystemCall,
+ OldIrql,
+ 0,
+ 0);
+ }
+
+ /* Make sure we're not attached and that APCs are not disabled */
+ if ((KeGetCurrentThread()->ApcStateIndex != CurrentApcEnvironment) ||
+ (KeGetCurrentThread()->CombinedApcDisable != 0))
+ {
+ /* Fail */
+ KeBugCheckEx(APC_INDEX_MISMATCH,
+ SystemCall,
+ KeGetCurrentThread()->ApcStateIndex,
+ KeGetCurrentThread()->CombinedApcDisable,
+ 0);
+ }
+ }
+}
#else
#define KiExitTrapDebugChecks(x, y)
#define KiFillTrapFrameDebug(x)
+#define KiExitSystemCallDebugChecks(x, y)
#endif
//
// Helper Code
//
-
BOOLEAN
FORCEINLINE
KiUserTrap(IN PKTRAP_FRAME TrapFrame)
@@ -354,3 +394,45 @@
: "%esp"
);
}
+
+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;
+}
Modified: trunk/reactos/ntoskrnl/ke/i386/trap.s
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/trap.s?re…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/trap.s [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/trap.s [iso-8859-1] Tue Jan 19 10:20:40 2010
@@ -66,8 +66,6 @@
.globl _KiSystemService
/* And special system-defined software traps: */
-.globl _NtRaiseException@12
-.globl _NtContinue@8
.globl _KiDispatchInterrupt@0
/* Interrupt template entrypoints */
@@ -84,7 +82,6 @@
/* We implement the following trap exit points: */
.globl _Kei386EoiHelper@0 /* Exit from interrupt or H/W trap */
-.globl _Kei386EoiHelper2ndEntry /* Exit from unexpected interrupt */
.globl _KiIdtDescriptor
_KiIdtDescriptor:
@@ -115,14 +112,20 @@
.text
.func KiSystemService
-TRAP_FIXUPS kss_a, kss_t, DoNotFixupV86, DoNotFixupAbios
_KiSystemService:
- /* Enter the shared system call prolog */
- SYSCALL_PROLOG kss_a, kss_t
-
- /* Jump to the actual handler */
- jmp SharedCode
+ /* Make space for trap frame on the stack */
+ sub esp, KTRAP_FRAME_EIP
+
+ /* Save EBP, EBX, ESI, EDI only! */
+ mov [esp+KTRAP_FRAME_EBX], ebx
+ mov [esp+KTRAP_FRAME_ESI], esi
+ mov [esp+KTRAP_FRAME_EDI], edi
+ mov [esp+KTRAP_FRAME_EBP], ebp
+
+ /* Call C handler -- note that EDX is the caller stack, EAX is the ID */
+ mov ecx, esp
+ jmp _KiSystemServiceHandler
.endfunc
.func KiFastCallEntry
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] Tue Jan 19 10:20:40 2010
@@ -1691,6 +1691,165 @@
KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
}
+VOID
+FASTCALL
+KiSystemCall(IN ULONG SystemCallNumber,
+ IN PVOID Arguments)
+{
+ PKTHREAD Thread;
+ PKTRAP_FRAME TrapFrame;
+ PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
+ ULONG Id, Offset, StackBytes, Result;
+ PVOID Handler;
+
+ /* Loop because we might need to try this twice in case of a GUI call */
+ while (TRUE)
+ {
+ /* Decode the system call number */
+ Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) &
SERVICE_TABLE_MASK;
+ Id = SystemCallNumber & SERVICE_NUMBER_MASK;
+
+ /* Get current thread, trap frame, and descriptor table */
+ Thread = KeGetCurrentThread();
+ TrapFrame = Thread->TrapFrame;
+ DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset);
+
+ /* Validate the system call number */
+ if (__builtin_expect(Id > DescriptorTable->Limit, 0))
+ {
+ /* Check if this is a GUI call */
+ if (__builtin_expect(!(Offset & SERVICE_TABLE_TEST), 0))
+ {
+ /* Fail the call */
+ Result = STATUS_INVALID_SYSTEM_SERVICE;
+ goto ExitCall;
+ }
+
+ /* GUI calls are not yet supported */
+ UNIMPLEMENTED;
+ while (TRUE);
+
+ /* Try the call again */
+ continue;
+ }
+
+ /* If we made it here, the call is good */
+ break;
+ }
+
+ /* Check if this is a GUI call */
+ if (__builtin_expect(Offset & SERVICE_TABLE_TEST, 0))
+ {
+ /* Get the batch count and flush if necessary */
+ UNIMPLEMENTED;
+ while (TRUE);
+ }
+
+ /* Increase system call count */
+ KeGetCurrentPrcb()->KeSystemCalls++;
+
+ /* FIXME: Increase individual counts on debug systems */
+ //KiIncreaseSystemCallCount(DescriptorTable, Id);
+
+ /* Get stack bytes */
+ StackBytes = DescriptorTable->Number[Id];
+
+ /* Probe caller stack */
+ if (__builtin_expect((Arguments < (PVOID)MmUserProbeAddress) &&
!(KiUserTrap(TrapFrame)), 0))
+ {
+ /* Access violation */
+ UNIMPLEMENTED;
+ while (TRUE);
+ }
+
+ /* Get the handler and make the system call */
+ Handler = (PVOID)DescriptorTable->Base[Id];
+ Result = KiSystemCallTrampoline(Handler, Arguments, StackBytes);
+
+ /* Make sure we're exiting correctly */
+ KiExitSystemCallDebugChecks(Id, TrapFrame);
+
+ /* Restore the old trap frame */
+ExitCall:
+ Thread->TrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
+
+ /* Exit from system call */
+ KiServiceExit(TrapFrame, Result);
+}
+
+VOID
+FORCEINLINE
+KiSystemCallHandler(IN PKTRAP_FRAME TrapFrame,
+ IN ULONG ServiceNumber,
+ IN PVOID Arguments,
+ IN PKTHREAD Thread,
+ IN KPROCESSOR_MODE PreviousMode,
+ IN KPROCESSOR_MODE PreviousPreviousMode,
+ IN USHORT SegFs)
+{
+ /* No error code */
+ TrapFrame->ErrCode = 0;
+
+ /* Save previous mode and FS segment */
+ TrapFrame->PreviousPreviousMode = PreviousPreviousMode;
+ TrapFrame->SegFs = SegFs;
+
+ /* Save the SEH chain and terminate it for now */
+ TrapFrame->ExceptionList = KeGetPcr()->Tib.ExceptionList;
+ KeGetPcr()->Tib.ExceptionList = EXCEPTION_CHAIN_END;
+
+ /* Clear DR7 and check for debugging */
+ TrapFrame->Dr7 = 0;
+ if (__builtin_expect(Thread->DispatcherHeader.DebugActive & 0xFF, 0))
+ {
+ UNIMPLEMENTED;
+ while (TRUE);
+ }
+
+ /* Set thread fields */
+ Thread->TrapFrame = TrapFrame;
+ Thread->PreviousMode = PreviousMode;
+
+ /* Set debug header */
+ KiFillTrapFrameDebug(TrapFrame);
+
+ /* Enable interrupts and make the call */
+ _enable();
+ KiSystemCall(ServiceNumber, Arguments);
+}
+
+VOID
+__attribute__((regparm(3)))
+KiSystemServiceHandler(IN ULONG ServiceNumber,
+ IN PVOID Arguments,
+ IN PKTRAP_FRAME TrapFrame)
+{
+ USHORT SegFs;
+ PKTHREAD Thread;
+
+ /* Save and fixup FS */
+ SegFs = Ke386GetFs();
+ Ke386SetFs(KGDT_R0_PCR);
+
+ /* Get the current thread */
+ Thread = KeGetCurrentThread();
+
+ /* Chain trap frames */
+ TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame;
+
+ /* Clear direction flag */
+ Ke386ClearDirectionFlag();
+
+ /* Call the shared handler (inline) */
+ KiSystemCallHandler(TrapFrame,
+ ServiceNumber,
+ Arguments,
+ Thread,
+ KiUserTrap(TrapFrame),
+ Thread->PreviousMode,
+ SegFs);
+}
+
/* HARDWARE INTERRUPTS ********************************************************/
/*