--- trunk/reactos/ntoskrnl/ke/i386/usercall_asm.S 2006-01-11 05:42:32 UTC (rev 20779)
+++ trunk/reactos/ntoskrnl/ke/i386/usercall_asm.S 2006-01-11 05:55:49 UTC (rev 20780)
@@ -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
+// This file is a work in progress. Most of the code is currently disabled.
+
/* GLOBALS ****************************************************************/
-.extern PVOID _SystemDllCallbackDispatcher
+.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
--- trunk/reactos/ntoskrnl/mm/process.c 2006-01-11 05:42:32 UTC (rev 20779)
+++ trunk/reactos/ntoskrnl/mm/process.c 2006-01-11 05:55:49 UTC (rev 20780)
@@ -134,7 +134,8 @@
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 @@
Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
MEMORY_AREA_KERNEL_STACK,
&KernelStack,
- MM_STACK_SIZE,
+ StackSize,
PAGE_READWRITE,
&StackArea,
FALSE,
@@ -166,7 +167,7 @@
}
/* 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 @@
KernelStack,
PAGE_READWRITE,
Page,
- MM_STACK_SIZE / PAGE_SIZE);
+ StackSize / PAGE_SIZE);
/* Check for success */
if (!NT_SUCCESS(Status))
--- trunk/reactos/ntoskrnl/ps/win32.c 2006-01-11 05:42:32 UTC (rev 20779)
+++ trunk/reactos/ntoskrnl/ps/win32.c 2006-01-11 05:55:49 UTC (rev 20780)
@@ -71,7 +71,7 @@
NTAPI
PsConvertToGuiThread(VOID)
{
- //PVOID NewStack, OldStack;
+ PVOID NewStack, OldStack;
PETHREAD Thread = PsGetCurrentThread();
PEPROCESS Process = PsGetCurrentProcess();
NTSTATUS Status;
@@ -99,11 +99,9 @@
}
/* 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 @@
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)