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/trap_x.h?rev=45147&r1=45146&r2=45147&view=diff
==============================================================================
--- 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?rev=45147&r1=45146&r2=45147&view=diff
==============================================================================
--- 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 _ntraiseexcept...@12
-.globl _ntconti...@8
 .globl _kidispatchinterr...@0
 
 /* Interrupt template entrypoints                                           */
@@ -84,7 +82,6 @@
 
 /* We implement the following trap exit points:                             */
 .globl _kei386eoihel...@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.c?rev=45147&r1=45146&r2=45147&view=diff
==============================================================================
--- 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 
********************************************************/
 
 /*


Reply via email to