- Fix MmCreateKernelStack to actually take into account the GuiStack parameter.

- Implement KeSwitchKernelStack
- Enable code in PsConvertToGuiThread to create a new stack and switch to it. GUI Threads now get the 60KB of kernel stack space they deserve.
- Define exported DDK constants for kernel stack size and undefine our own internal ones.

svn path=/trunk/; revision=20780
This commit is contained in:
Alex Ionescu 2006-01-11 05:55:49 +00:00
parent 7816643eb5
commit d86450eb7b
5 changed files with 419 additions and 47 deletions

View file

@ -254,9 +254,5 @@ DefaultQueryInfoBufferCheck(UINT Class,
#endif
#endif
/*
*
*/
#define MM_STACK_SIZE (3*4096)
#endif /* INCLUDE_INTERNAL_NTOSKRNL_H */

View file

@ -1,53 +1,439 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/i386s/usercall.S
* PROJECT: ReactOS Kernel
* FILE: ntoskrnl/ke/i386/usercall_asm.S
* PURPOSE: User-Mode callbacks and return.
*
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES ******************************************************************/
#include <roscfg.h>
#include <asm.h>
//#include <bugcodes.h>
#define APC_INDEX_MISMATCH 1
#define IRQL_GT_ZERO_AT_SYSTEM_SERVICE 0x4A
#define STATUS_NO_CALLBACK_ACTIVE 0xC0000258
.intel_syntax noprefix
/* GLOBALS ****************************************************************/
.extern PVOID _SystemDllCallbackDispatcher
// This file is a work in progress. Most of the code is currently disabled.
/* GLOBALS ****************************************************************/
.extern PVOID _KeUserCallbackDispatcher
#define CBSTACK_BUFFER_ADDRESS 0x20
#define CBSTACK_BUFFER_LENGTH 0x24
/* FUNCTIONS ****************************************************************/
.globl _KiGetUserModeStackAddress@0
.func 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]
.endfunc
/*++
* KiSwitchToUserMode
* @name KiCallUserMode
*
* The KiSwitchToUserMode routine sets up a Trap Frame and a Callback stack
* for the purpose of switching to user mode. The actual final jump is done
* by KiServiceExit which will treat this as a syscall return.
*
* Params:
* OutputBuffer - Pointer to a caller-allocated buffer where to receive
* the return data from the user-mode function
* @param OutputBuffer
* Pointer to a caller-allocated buffer where to receive the return data
* from the user-mode function
*
* OutputLength - Size of the Output Buffer described above.
* @param OutputLength
* Size of the Output Buffer described above.
*
* Returns:
* Jumps into KiServiceExit.
* @return None. Jumps into KiServiceExit.
*
* Remarks:
* If there is not enough Kernel Stack space, the routine will increase the
* Kernel Stack.
* @remark If there is not enough Kernel Stack space, the routine will increase the
* Kernel Stack.
*
* User mode execution resumes at ntdll!KiUserCallbackDispatcher.
* User mode execution resumes at ntdll!KiUserCallbackDispatcher.
*
* This call MUST be paired by interrupt 0x2B or NtCallbackReturn.
* This call MUST be paired by interrupt 0x2B or NtCallbackReturn.
*
*--*/
.globl _KiSwitchToUserMode@8
.func KiSwitchToUserMode@8
_KiSwitchToUserMode@8:
.globl _KiCallUserMode@8
.func KiCallUserMode@8
_KiCallUserMode@8:
/* Save volatile registers */
push ebp
push ebx
push esi
push edi
/* Get the current thread */
mov ebx, fs:[KPCR_CURRENT_THREAD]
/* Make sure we're at passive */
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
jz InvalidIndex
or edx, edx
jz ApcsEnabled
InvalidIndex:
push 0
push edx
push eax
push 0
push APC_INDEX_MISMATCH
call _KeBugCheckEx@20
ApcsEnabled:
/* Get the lowest stack limit and check if we can handle it */
lea eax, [esp-0x3000]
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, ~16
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+FN_CONTROL_WORD]
mov [esi+FN_CONTROL_WORD], ecx
mov ecx, [esi+FN_STATUS_WORD]
mov [esi+FN_STATUS_WORD], ecx
mov ecx, [esi+FN_TAG_WORD]
mov [esi+FN_TAG_WORD], ecx
mov ecx, [esi+FN_DATA_SELECTOR]
mov [esi+FN_DATA_SELECTOR], ecx
mov ecx, [esi+FN_CR0_NPX_STATE]
mov [esi+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, [esp+KTRAP_FRAME_FS]
rep movsd
/* FIXME: Copy debug registers if needed */
/* Get user-mode dispatcher address and set it as EIP */
mov eax, _KeUserCallbackDispatcher
mov [esp+KTRAP_FRAME_EIP], eax
/* Set the exception list */
mov eax, [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
/* Write the debug data */
mov edi, [ebp+KTRAP_FRAME_EBP]
mov edx, [ebp+KTRAP_FRAME_EIP]
mov [ebp+KTRAP_FRAME_DEBUGPOINTER], edx
mov dword ptr [ebp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
mov [ebp+KTRAP_FRAME_DEBUGEBP], ebx
mov [ebp+KTRAP_FRAME_DEBUGEIP], edi
/* Exit to user-mode */
jmp _KiServiceExit
GrowFailed:
/* Restore registers */
pop edi
pop esi
pop ebx
pop ebp
/* Return */
ret 8
.endfunc
/*++
* @name NtCallbackReturn
*
* The NtCallbackReturn routine returns to kernel mode after a user-mode
* callback was done through KeUserModeCallback. It uses the callback frame
* which was setup in order to return the information, restores the stack,
* and resumes execution where it was left off.
*
* @param Result
* Pointer to a caller-allocated buffer where the return data
* from the user-mode function is located.
*
* @param ResultLength
* Size of the Output Buffer described above.
*
* @param CallbackStatus
* Status code of the callback operation.
*
* @return Status code of the callback operation.
*
* @remark This call MUST be paired with KeUserModeCallback.
*
*--*/
.globl _NtCallbackReturn2@12
.func NtCallbackReturn2@12
_NtCallbackReturn2@12:
/* Get the current thread and make sure we have a callback stack */
mov eax, fs:[KPCR_CURRENT_THREAD]
mov ecx, [eax+KTHREAD_CALLBACK_STACK]
test ecx, ecx
jz NoStack
/* Get the trap frame */
mov ebx, [eax+KTHREAD_TRAP_FRAME]
/* Restore the exception list */
mov edx, [ebx+KTRAP_FRAME_EXCEPTION_LIST]
mov fs:[KPCR_EXCEPTION_LIST], edx
/* Get the result, the result length and the status */
mov edi, [esp+4]
mov esi, [esp+8]
mov ebp, [esp+12]
/* Store the results in the callback stack */
mov ebx, [ecx+CBSTACK_RESULT]
mov [ebx], edi
mov ebx, [ecx+CBSTACK_RESULT_LENGTH]
mov [ebx], esi
/* Get the previous stack */
mov ebx, [ecx]
/* Disable interrupts for NPX save and stack switch */
cli
/* Get the initial stack and restore it */
mov esi, fs:[KPCR_INITIAL_STACK]
mov [eax+KTHREAD_INITIAL_STACK], ebx
/* Set desination and origin NPX Frames */
sub esi, NPX_FRAME_LENGTH
sub ebx, NPX_FRAME_LENGTH
/* Copy NPX Data */
mov edx, [esi+FN_CONTROL_WORD]
mov [ebx+FN_CONTROL_WORD], edx
mov edx, [esi+FN_STATUS_WORD]
mov [ebx+FN_STATUS_WORD], edx
mov edx, [esi+FN_TAG_WORD]
mov [ebx+FN_TAG_WORD], edx
mov edx, [esi+FN_DATA_SELECTOR]
mov [ebx+FN_DATA_SELECTOR], edx
mov edx, [esi+FN_CR0_NPX_STATE]
mov [ebx+FN_CR0_NPX_STATE], edx
/* Get saved trap frame and clear DR7 */
mov edi, [ecx+CBSTACK_TRAP_FRAME]
and dword ptr [edi+KTRAP_FRAME_DR7], 0
/* FIXME: Restore debug regs */
/* Get TSS */
mov edx, fs:[KPCR_TSS]
/* Restore stack pointer */
lea esp, [ecx+CBSTACK_CALLBACK_STACK]
/* Check if we were in V86 mode */
test dword ptr [edi+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
jnz V86Ret
sub ebx, 16
V86Ret:
/* Restore the ESP in TSS */
mov [edx+KTSS_ESP0], ebx
/* Restore the trap frame */
mov [eax+KTHREAD_TRAP_FRAME], edi
/* Bring interrupts back */
sti
/* Restore the callback stack*/
pop [eax+KTHREAD_CALLBACK_STACK]
/* Set status and return */
mov eax, ebp
pop edi
pop esi
pop ebx
pop ebp
pop edx
/* Clean stack and jump back */
add esp, 8
jmp edx
NoStack:
/* Return failure */
mov eax, STATUS_NO_CALLBACK_ACTIVE
ret 12
.endfunc
.globl _KeSwitchKernelStack@8
.func KeSwitchKernelStack@8
_KeSwitchKernelStack@8:
/* Save volatiles */
push esi
push edi
/* Get current thread */
mov edx, fs:[KPCR_CURRENT_THREAD]
/* Get new and current base */
mov edi, [esp+12]
mov ecx, [edx+KTHREAD_STACK_BASE]
/* Fixup the frame pointer */
sub ebp, ecx
add ebp, edi
/* Fixup the trap frame */
mov eax, [edx+KTHREAD_TRAP_FRAME]
sub eax, ecx
add eax, edi
mov [edx+KTHREAD_TRAP_FRAME], eax
/* Calculate stack size */
sub ecx, esp
/* Get desination and origin */
sub edi, ecx
mov esi, esp
/* Save stack pointer */
push edi
/* Copy stack */
rep movsb
/* Restore stack pointer */
pop edi
/* Save old stack base and get new limit/base */
mov eax, [edx+KTHREAD_STACK_BASE]
mov ecx, [esp+12]
mov esi, [esp+16]
/* Disable interrupts for stack switch */
cli
/* Set new base/limit */
mov [edx+KTHREAD_STACK_BASE], ecx
mov [edx+KTHREAD_STACK_LIMIT], esi
/* Set LargeStack */
mov byte ptr [edx+KTHREAD_LARGE_STACK], 1
/* Set new initial stack */
mov [edx+KTHREAD_INITIAL_STACK], ecx
/* Get trap frame */
mov esi, [edx+KTHREAD_TRAP_FRAME]
/* Get TSS */
mov edx, fs:[KPCR_TSS]
/* Check if we came from V86 mode */
test dword ptr [esi+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
/* Bias for NPX Area */
lea ecx, [ecx-NPX_FRAME_LENGTH]
jnz V86Switch
sub ecx, 16
V86Switch:
/* Update ESP in TSS */
mov [edx+KTSS_ESP0], ecx
/* Update stack pointer */
mov esp, edi
/* Bring back interrupts and return */
sti
pop edi
pop esi
ret 8
.endfunc

View file

@ -134,7 +134,8 @@ MmCreateKernelStack(BOOLEAN GuiStack)
PMEMORY_AREA StackArea;
ULONG i;
PHYSICAL_ADDRESS BoundaryAddressMultiple;
PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE];
ULONG StackSize = GuiStack ? KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE;
PFN_TYPE Page[KERNEL_LARGE_STACK_SIZE / PAGE_SIZE];
PVOID KernelStack = NULL;
NTSTATUS Status;
@ -148,7 +149,7 @@ MmCreateKernelStack(BOOLEAN GuiStack)
Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
MEMORY_AREA_KERNEL_STACK,
&KernelStack,
MM_STACK_SIZE,
StackSize,
PAGE_READWRITE,
&StackArea,
FALSE,
@ -166,7 +167,7 @@ MmCreateKernelStack(BOOLEAN GuiStack)
}
/* Mark the Stack in use */
for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++)
for (i = 0; i < (StackSize / PAGE_SIZE); i++)
{
Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]);
}
@ -176,7 +177,7 @@ MmCreateKernelStack(BOOLEAN GuiStack)
KernelStack,
PAGE_READWRITE,
Page,
MM_STACK_SIZE / PAGE_SIZE);
StackSize / PAGE_SIZE);
/* Check for success */
if (!NT_SUCCESS(Status))

View file

@ -71,7 +71,7 @@ NTSTATUS
NTAPI
PsConvertToGuiThread(VOID)
{
//PVOID NewStack, OldStack;
PVOID NewStack, OldStack;
PETHREAD Thread = PsGetCurrentThread();
PEPROCESS Process = PsGetCurrentProcess();
NTSTATUS Status;
@ -99,11 +99,9 @@ PsConvertToGuiThread(VOID)
}
/* Check if we don't already have a kernel-mode stack */
#if 0
if (!Thread->Tcb.LargeStack)
{
/* We don't create one */
DPRINT1("Creating large stack\n");
NewStack = MmCreateKernelStack(TRUE);
if (!NewStack)
{
@ -116,28 +114,15 @@ PsConvertToGuiThread(VOID)
KeEnterCriticalRegion();
/* Switch stacks */
DPRINT1("Switching stacks. NS IT, SL, SB, KS %p %p %p %p %p\n",
NewStack,
Thread->Tcb.InitialStack,
Thread->Tcb.StackLimit,
Thread->Tcb.StackBase,
Thread->Tcb.KernelStack);
OldStack = KeSwitchKernelStack((PVOID)((ULONG_PTR)NewStack + 0x3000),
NewStack);
/* Leave the critical region */
KeLeaveCriticalRegion();
DPRINT1("We made it!\n");
/* Delete the old stack */
//MmDeleteKernelStack(OldStack, FALSE);
DPRINT1("Old stack deleted. IT, SL, SB, KS %p %p %p %p\n",
Thread->Tcb.InitialStack,
Thread->Tcb.StackLimit,
Thread->Tcb.StackBase,
Thread->Tcb.KernelStack);
}
#endif
/* This check is bizare. Check out win32k later */
if (!Process->Win32Process)

View file

@ -204,6 +204,10 @@ typedef struct _ADAPTER_OBJECT *PADAPTER_OBJECT;
#define NtCurrentThread() ( (HANDLE)(LONG_PTR) -2 )
#define ZwCurrentThread() NtCurrentThread()
#define KERNEL_STACK_SIZE 12288
#define KERNEL_LARGE_STACK_SIZE 61440
#define DPFLTR_ERROR_LEVEL 0
#define DPFLTR_WARNING_LEVEL 1
#define DPFLTR_TRACE_LEVEL 2