From ee1da65d47aaacb727c88cb94d3f9cd57339b5d2 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Mon, 25 Jul 2011 00:01:29 +0000 Subject: [PATCH] [NTOSKRNL] - 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 | 7 + reactos/ntoskrnl/include/internal/ke.h | 12 +- reactos/ntoskrnl/include/internal/mm.h | 15 +- reactos/ntoskrnl/ke/i386/usercall.c | 142 ++++++++++++++++ reactos/ntoskrnl/ke/i386/usercall_asm.S | 170 ++------------------ 5 files changed, 173 insertions(+), 173 deletions(-) diff --git a/reactos/ntoskrnl/include/internal/i386/ke.h b/reactos/ntoskrnl/include/internal/i386/ke.h index fa8ea3f8b84..8abc50f0fd1 100644 --- a/reactos/ntoskrnl/include/internal/i386/ke.h +++ b/reactos/ntoskrnl/include/internal/i386/ke.h @@ -846,4 +846,11 @@ Ki386PerfEnd(VOID) KeGetContextSwitches(KeGetCurrentPrcb())); } +FORCEINLINE +PULONG +KiGetUserModeStackAddress(void) +{ + return &(KeGetCurrentThread()->TrapFrame->HardwareEsp); +} + #endif diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 56f3ee013c2..86ea126aec5 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -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); diff --git a/reactos/ntoskrnl/include/internal/mm.h b/reactos/ntoskrnl/include/internal/mm.h index a704e2ae005..803dc81b5a7 100644 --- a/reactos/ntoskrnl/include/internal/mm.h +++ b/reactos/ntoskrnl/include/internal/mm.h @@ -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 diff --git a/reactos/ntoskrnl/ke/i386/usercall.c b/reactos/ntoskrnl/ke/i386/usercall.c index 07ce4442df4..78c977cb933 100644 --- a/reactos/ntoskrnl/ke/i386/usercall.c +++ b/reactos/ntoskrnl/ke/i386/usercall.c @@ -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 */ diff --git a/reactos/ntoskrnl/ke/i386/usercall_asm.S b/reactos/ntoskrnl/ke/i386/usercall_asm.S index 341cefd9bee..2135b8c2517 100644 --- a/reactos/ntoskrnl/ke/i386/usercall_asm.S +++ b/reactos/ntoskrnl/ke/i386/usercall_asm.S @@ -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] + /* load the address of the callout frame into ecx */ + lea ecx, [esp - 12] - /* Make sure we're at passive */ -#if DBG - call _KeGetCurrentIrql@0 - or al, al - jz AtPassive + /* Allocate space for the inital stack */ + sub esp, 12 + NPX_FRAME_LENGTH + KTRAP_FRAME_LENGTH + 16 - /* We're not, bugcheck! */ - push 0 - push 0 - push eax - push 0 - push IRQL_GT_ZERO_AT_SYSTEM_SERVICE - call _KeBugCheckEx@20 + call @KiUserModeCallout@4 -AtPassive: + add esp, 12 + NPX_FRAME_LENGTH + KTRAP_FRAME_LENGTH + 16 - /* 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 - - /* 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 - -DontBias: - /* Set new stack address in TSS */ - mov [esi+KTSS_ESP0], ecx - - /* 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 - -GrowFailed: /* Restore registers */ pop edi pop esi