[NTOSKRNL]
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Mon, 25 Jul 2011 00:01:29 +0000 (00:01 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Mon, 25 Jul 2011 00:01:29 +0000 (00:01 +0000)
- Convert KiCallUserMode from asm to C (with a small asm wrapper)
- Convert KiGetUserModeStackAddress into a C inline function

svn path=/trunk/; revision=52855

reactos/ntoskrnl/include/internal/i386/ke.h
reactos/ntoskrnl/include/internal/ke.h
reactos/ntoskrnl/include/internal/mm.h
reactos/ntoskrnl/ke/i386/usercall.c
reactos/ntoskrnl/ke/i386/usercall_asm.S

index fa8ea3f..8abc50f 100644 (file)
@@ -846,4 +846,11 @@ Ki386PerfEnd(VOID)
              KeGetContextSwitches(KeGetCurrentPrcb()));
 }
 
+FORCEINLINE
+PULONG
+KiGetUserModeStackAddress(void)
+{
+    return &(KeGetCurrentThread()->TrapFrame->HardwareEsp);
+}
+
 #endif
index 56f3ee0..86ea126 100644 (file)
@@ -164,7 +164,7 @@ extern VOID __cdecl KiInterruptTemplate(VOID);
 #define TIMER_WAIT_BLOCK 0x3L
 
 #ifdef _M_ARM // FIXME: remove this once our headers are cleaned up
-// 
+//
 // A system call ID is formatted as such:
 // .________________________________________________________________.
 // | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
@@ -187,7 +187,7 @@ extern VOID __cdecl KiInterruptTemplate(VOID);
 //
 // NB. From assembly code, the table number must be computed as an offset into
 //     the service descriptor table.
-//     
+//
 //     Each entry into the table is 16 bytes long on 32-bit architectures, and
 //     32 bytes long on 64-bit architectures.
 //
@@ -864,7 +864,7 @@ KeBugCheckWithTf(
     ULONG_PTR BugCheckParameter4,
     PKTRAP_FRAME Tf
 );
-                              
+
 BOOLEAN
 NTAPI
 KiHandleNmi(VOID);
@@ -1020,12 +1020,6 @@ KiCallUserMode(
     IN PULONG OutputLength
 );
 
-PULONG
-NTAPI
-KiGetUserModeStackAddress(
-    VOID
-);
-
 VOID
 NTAPI
 KiInitMachineDependent(VOID);
index a704e2a..803dc81 100644 (file)
@@ -6,6 +6,7 @@
 
 struct _EPROCESS;
 
+extern PMMSUPPORT MmKernelAddressSpace;
 extern PFN_NUMBER MiFreeSwapPages;
 extern PFN_NUMBER MiUsedSwapPages;
 extern SIZE_T MmTotalPagedPoolQuota;
@@ -1134,7 +1135,7 @@ MiGetPfnEntry(IN PFN_NUMBER Pfn)
 
     /* Make sure the PFN number is valid */
     if (Pfn > MmHighestPhysicalPage) return NULL;
-    
+
     /* Make sure this page actually has a PFN entry */
     if ((MiPfnBitMap.Buffer) && !(RtlTestBit(&MiPfnBitMap, (ULONG)Pfn))) return NULL;
 
@@ -1338,7 +1339,7 @@ MmRawDeleteVirtualMapping(PVOID Address);
 VOID
 NTAPI
 MmGetPageFileMapping(
-       struct _EPROCESS *Process, 
+       struct _EPROCESS *Process,
        PVOID Address,
        SWAPENTRY* SwapEntry);
 
@@ -1735,7 +1736,15 @@ MmCallDllInitialize(
     IN PLIST_ENTRY ListHead
 );
 
-extern PMMSUPPORT MmKernelAddressSpace;
+
+/* procsup.c *****************************************************************/
+
+NTSTATUS
+NTAPI
+MmGrowKernelStack(
+    IN PVOID StackPointer
+);
+
 
 FORCEINLINE
 VOID
index 07ce444..78c977c 100644 (file)
@@ -208,4 +208,146 @@ KeUserModeCallback(IN ULONG RoutineIndex,
     return CallbackStatus;
 }
 
+/* Stack layout:
+ *
+ * ----------------------------------
+ * KCALLOUT_FRAME.ResultLength    <= 2nd Parameter to KiCallUserMode
+ * KCALLOUT_FRAME.Result          <= 1st Parameter to KiCallUserMode
+ * KCALLOUT_FRAME.ReturnAddress   <= Return address of KiCallUserMode
+ * KCALLOUT_FRAME.Ebp             \
+ * KCALLOUT_FRAME.Ebx              | = volatile registers, pushed
+ * KCALLOUT_FRAME.Esi              |   by KiCallUserMode
+ * KCALLOUT_FRAME.Edi             /
+ * KCALLOUT_FRAME.CallbackStack
+ * KCALLOUT_FRAME.TrapFrame
+ * KCALLOUT_FRAME.InitialStack    <= CalloutFrame points here
+ * ----------------------------------
+ * ~~ optional alignment ~~
+ * ----------------------------------
+ * FX_SAVE_AREA
+ * ----------------------------------
+ * KTRAP_FRAME
+ * ----------------------------------
+ * ~~ begin of stack frame for KiUserModeCallout ~~
+ *
+ */
+
+NTSTATUS
+FASTCALL
+KiUserModeCallout(PKCALLOUT_FRAME CalloutFrame)
+{
+    PKTHREAD CurrentThread;
+    PKTRAP_FRAME TrapFrame, CallbackTrapFrame;
+    PFX_SAVE_AREA FxSaveArea, OldFxSaveArea;
+    PKPCR Pcr;
+    PKTSS Tss;
+    ULONG_PTR InitialStack;
+    NTSTATUS Status;
+
+    /* Get the current thread */
+    CurrentThread = KeGetCurrentThread();
+
+#if DBG
+    /* Check if we are at pasive level */
+    if (KeGetCurrentIrql() != PASSIVE_LEVEL)
+    {
+        /* We're not, bugcheck */
+        KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE,
+                     0,
+                     KeGetCurrentIrql(),
+                     0,
+                     0);
+    }
+
+    /* Check if we are attached or APCs are disabled */
+    if ((CurrentThread->ApcStateIndex != OriginalApcEnvironment) ||
+        (CurrentThread->CombinedApcDisable > 0))
+    {
+        KeBugCheckEx(APC_INDEX_MISMATCH,
+                     0,
+                     CurrentThread->ApcStateIndex,
+                     CurrentThread->CombinedApcDisable,
+                     0);
+    }
+#endif
+
+    /* Align stack on 16-byte boundary */
+    InitialStack = (ULONG_PTR)CalloutFrame & ~15;
+
+    /* Check if we have enough space on the stack */
+    if ((InitialStack - KERNEL_STACK_SIZE) < CurrentThread->StackLimit)
+    {
+        /* We don't, we'll have to grow our stack */
+        Status = MmGrowKernelStack((PVOID)InitialStack);
+
+        /* Quit if we failed */
+        if (!NT_SUCCESS(Status)) return Status;
+    }
+
+    /* Save the current callback stack and initial stack */
+    CalloutFrame->CallbackStack = (ULONG_PTR)CurrentThread->CallbackStack;
+    CalloutFrame->InitialStack = (ULONG_PTR)CurrentThread->InitialStack;
+
+    /* Get and save the trap frame */
+    TrapFrame = CurrentThread->TrapFrame;
+    CalloutFrame->TrapFrame = (ULONG_PTR)TrapFrame;
+
+    /* Set the new callback stack */
+    CurrentThread->CallbackStack = CalloutFrame;
+
+    /* Set destination and origin NPX Areas */
+    OldFxSaveArea = (PVOID)(CalloutFrame->InitialStack - sizeof(FX_SAVE_AREA));
+    FxSaveArea = (PVOID)(InitialStack - sizeof(FX_SAVE_AREA));
+
+    /* Disable interrupts so we can fill the NPX State */
+    _disable();
+
+    /* Now copy the NPX State */
+    FxSaveArea->U.FnArea.ControlWord = OldFxSaveArea->U.FnArea.ControlWord;
+    FxSaveArea->U.FnArea.StatusWord = OldFxSaveArea->U.FnArea.StatusWord;
+    FxSaveArea->U.FnArea.TagWord = OldFxSaveArea->U.FnArea.TagWord;
+    FxSaveArea->U.FnArea.DataSelector = OldFxSaveArea->U.FnArea.DataSelector;
+    FxSaveArea->Cr0NpxState = OldFxSaveArea->Cr0NpxState;
+
+    /* Set the stack address */
+    CurrentThread->InitialStack = (PVOID)InitialStack;
+
+    /* Locate the trap frame on the callback stack */
+    CallbackTrapFrame = (PVOID)((ULONG_PTR)FxSaveArea - sizeof(KTRAP_FRAME));
+
+    /* Copy the trap frame to the new location */
+    *CallbackTrapFrame = *TrapFrame;
+
+    /* Get PCR */
+    Pcr = KeGetPcr();
+
+    /* Update the exception list */
+    CallbackTrapFrame->ExceptionList = Pcr->Used_ExceptionList;
+
+    /* Get TSS */
+    Tss = Pcr->TSS;
+
+    /* Bias the stack for V86 mode */
+    if (CallbackTrapFrame->EFlags & EFLAGS_V86_MASK)
+    {
+        /* Set new stack address in TSS */
+        Tss->Esp0 = (ULONG_PTR)(CallbackTrapFrame + 1);
+    }
+    else
+    {
+        /* Set new stack address in TSS */
+        Tss->Esp0 = (ULONG_PTR)&CallbackTrapFrame->V86Es;
+    }
+
+    /* Set user-mode dispatcher address as EIP */
+    CallbackTrapFrame->Eip = (ULONG_PTR)KeUserCallbackDispatcher;
+
+    /* Bring interrupts back */
+    _enable();
+
+    /* Exit to user-mode */
+    KiServiceExit(CallbackTrapFrame, 0);
+}
+
+
 /* EOF */
index 341cefd..2135b8c 100644 (file)
@@ -17,20 +17,11 @@ EXTERN _KeUserCallbackDispatcher:DWORD
 EXTERN @KiServiceExit@8:PROC
 EXTERN _KeGetCurrentIrql@0:PROC
 EXTERN _KeBugCheckEx@20:PROC
+EXTERN @KiUserModeCallout@4:PROC
 
 /* FUNCTIONS ****************************************************************/
 .code
 
-PUBLIC _KiGetUserModeStackAddress@0
-_KiGetUserModeStackAddress@0:
-
-    /* Get the current thread's trapframe and return the esp */
-    mov eax, fs:[KPCR_CURRENT_THREAD]
-    mov eax, [eax+KTHREAD_TRAP_FRAME]
-    lea eax, [eax+KTRAP_FRAME_ESP]
-    ret
-
-
 /*++
  * @name KiCallUserMode
  *
@@ -58,166 +49,23 @@ _KiGetUserModeStackAddress@0:
 PUBLIC _KiCallUserMode@8
 _KiCallUserMode@8:
 
-    /* Save volatile registers */
+    /* Push volatile registers on the stack.
+       This is part of the KCALLOUT_FRAME */
     push ebp
     push ebx
     push esi
     push edi
 
-    /* Get the current thread */
-    mov ebx, fs:[KPCR_CURRENT_THREAD]
-
-    /* Make sure we're at passive */
-#if DBG
-    call _KeGetCurrentIrql@0
-    or al, al
-    jz AtPassive
-
-    /* We're not, bugcheck! */
-    push 0
-    push 0
-    push eax
-    push 0
-    push IRQL_GT_ZERO_AT_SYSTEM_SERVICE
-    call _KeBugCheckEx@20
-
-AtPassive:
-
-    /* Make sure that we are not attached and that APCs are not disabled */
-    movzx eax, byte ptr [ebx+KTHREAD_APC_STATE_INDEX]
-    mov edx, [ebx+KTHREAD_COMBINED_APC_DISABLE]
-    or eax, eax
-    jnz InvalidIndex
-    or edx, edx
-    jz ApcsEnabled
-
-InvalidIndex:
-
-    push 0
-    push edx
-    push eax
-    push 0
-    push APC_INDEX_MISMATCH
-    call _KeBugCheckEx@20
-ApcsEnabled:
-#endif
-
-    /* Get the lowest stack limit and check if we can handle it */
-    lea eax, [esp-HEX(3000)]
-    cmp eax, [ebx+KTHREAD_STACK_LIMIT]
-    jnb StackOk
-
-    /* We can't, we'll have to grow our stack */
-    push esp
-    call _MmGrowKernelStack@4
-
-    /* Quit if we failed */
-    or eax, eax
-    jnz GrowFailed
-
-    /* Save the current callback stack */
-StackOk:
-    push [ebx+KTHREAD_CALLBACK_STACK]
-
-    /* Get and save the trap frame */
-    mov edx, [ebx+KTHREAD_TRAP_FRAME]
-    push edx
-
-    /* Get and save the initial stack */
-    mov esi, [ebx+KTHREAD_INITIAL_STACK]
-    push esi
-
-    /* Set the new callback stack */
-    mov [ebx+KTHREAD_CALLBACK_STACK], esp
-
-    /* Align stack on 16-byte boundary */
-    and esp, NOT 15
-    mov edi, esp
-
-    /* Set destination and origin NPX Areas */
-    sub esp, NPX_FRAME_LENGTH
-    sub esi, NPX_FRAME_LENGTH
-
-    /* Disable interrupts so we can fill the NPX State */
-    cli
-
-    /* Now copy the NPX State */
-    mov ecx, [esi+FP_CONTROL_WORD]
-    mov [esp+FP_CONTROL_WORD], ecx
-    mov ecx, [esi+FP_STATUS_WORD]
-    mov [esp+FP_STATUS_WORD], ecx
-    mov ecx, [esi+FP_TAG_WORD]
-    mov [esp+FP_TAG_WORD], ecx
-    mov ecx, [esi+FP_DATA_SELECTOR]
-    mov [esp+FP_DATA_SELECTOR], ecx
-    mov ecx, [esi+FN_CR0_NPX_STATE]
-    mov [esp+FN_CR0_NPX_STATE], ecx
-
-    /* Get TSS */
-    mov esi, fs:[KPCR_TSS]
-
-    /* Set the stack address */
-    mov [ebx+KTHREAD_INITIAL_STACK], edi
+    /* load the address of the callout frame into ecx */
+    lea ecx, [esp - 12]
 
-    /* Bias the stack for V86 mode */
-    mov ecx, esp
-    sub esp, 16
-    test dword ptr [edx+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
-    jnz DontBias
-    mov ecx, esp
+    /* Allocate space for the inital stack */
+    sub esp, 12 + NPX_FRAME_LENGTH + KTRAP_FRAME_LENGTH + 16
 
-DontBias:
-    /* Set new stack address in TSS */
-    mov [esi+KTSS_ESP0], ecx
+    call @KiUserModeCallout@4
 
-    /* Allocate the trap frame and set it */
-    sub esp, KTRAP_FRAME_V86_ES
-    mov ebp, esp
-
-    /* Set copy iterator and dest/origin parameters and do the copy */
-    mov ecx, (KTRAP_FRAME_V86_ES - KTRAP_FRAME_FS) / 4
-    lea edi, [esp+KTRAP_FRAME_FS]
-    lea esi, [edx+KTRAP_FRAME_FS]
-    rep movsd
-
-    /* Copy DR7 */
-    mov edi, [edx+KTRAP_FRAME_DR7]
-    test edi, NOT DR7_RESERVED_MASK
-    mov [esp+KTRAP_FRAME_DR7], edi
-
-    /* Check if we need to save debug registers */
-    jnz SaveDebug
-
-    /* Get user-mode dispatcher address and set it as EIP */
-SetEip:
-    mov eax, dword ptr [_KeUserCallbackDispatcher]
-    mov [esp+KTRAP_FRAME_EIP], eax
-
-    /* Set the exception list */
-    mov eax, fs:[KPCR_EXCEPTION_LIST]
-    mov [esp+KTRAP_FRAME_EXCEPTION_LIST], eax
-
-    /* Set the previous mode */
-    mov eax, [edx+KTRAP_FRAME_PREVIOUS_MODE]
-    mov [esp+KTRAP_FRAME_PREVIOUS_MODE], eax
-
-    /* Bring interrupts back */
-    sti
-
-    /* Exit to user-mode */
-    mov ecx, esp
-    jmp @KiServiceExit@8
-
-SaveDebug:
-
-    /* Copy all 5 DRs */
-    mov ecx, 5
-    lea edi, [esp+KTRAP_FRAME_DR0]
-    lea esi, [edx+KTRAP_FRAME_DR0]
-    rep movsd
-    jmp SetEip
+    add esp, 12 + NPX_FRAME_LENGTH + KTRAP_FRAME_LENGTH + 16
 
-GrowFailed:
     /* Restore registers */
     pop edi
     pop esi