Second part of patch, implements the new RTL functions which will be used (not used by kernel yet). 
    - RtlCreateUserProcess:
        * Created RtlpInitEnvironment to manage Environment Block creation. Rougly based on
          old KlInitPeb code but with some optimizations.
        * Don't ignore Process Security Descriptor if one was specified.
        * Don't ignore ZeroBits, get correct entrypoint, and don't assume PEB address.
        * Don't close handle of section before closing process handle on failure.
        * Support new undocumented flag which pre-allocates 1MB of memory for Native Processes
        * FIXME: Hande duplication should be done, but wasn't and still isn't.
    
    - RtlpCreateUserStack:
        * New function to create a stack for a Thread, similar to BasepCreateStack but
          has some differences related to StackCommit/StackReserve.
        * Also create Guard Page
        
    - RtlpFreeUserStack:
        * Undoes what the function above does, in case of failure in code using it.
        
    - RtlCreateUserThread:
        * Use the new functions instead of rosrtl.
        
    - RtlInitializeContext:
        * New function similar to BasepInitializeContext but;
            > Uses a single entrypoint, not many possible thunks like Kernel32 (no need)
            > The starting EFLAGS is Interrupts Enabled, not IOPL 3.
            > We don't initialize the same Context Flags
            > The initial context registers are different
            
    - RtlFreeUserThreadStack
        * Don't assume the TEB address
          
    - RtlExitUserThread
        * Remove deprecated stack-switching semantics and use new TEB flag to tell the Kernel
          to deallocate the stack for us.
Modified: trunk/reactos/lib/kernel32/process/create.c
Modified: trunk/reactos/lib/ntdll/rtl/process.c
Modified: trunk/reactos/lib/rtl/process.c
Modified: trunk/reactos/lib/rtl/thread.c
Modified: trunk/reactos/ntoskrnl/mm/pe.c

Modified: trunk/reactos/lib/kernel32/process/create.c
--- trunk/reactos/lib/kernel32/process/create.c	2005-07-12 02:45:33 UTC (rev 16541)
+++ trunk/reactos/lib/kernel32/process/create.c	2005-07-12 04:41:41 UTC (rev 16542)
@@ -16,7 +16,7 @@
 /* FIXME */
 #include <rosrtl/thread.h>
 
-//#define NDEBUG
+#define NDEBUG
 #include "../include/debug.h"
 
 /* FUNCTIONS ****************************************************************/
@@ -1378,11 +1378,11 @@
     * Create the thread for the kernel
     */
    DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
-          (PVOID)((ULONG_PTR)ImageBaseAddress + (ULONG_PTR)Sii.TransferAddress));
+          Sii.TransferAddress);
    hThread =  KlCreateFirstThread(hProcess,
 				  lpThreadAttributes,
 				  &Sii,
-				  (PVOID)((ULONG_PTR)ImageBaseAddress + (ULONG_PTR)Sii.TransferAddress),
+				  Sii.TransferAddress,
 				  dwCreationFlags,
 				  &lpProcessInformation->dwThreadId);
    if (hThread == NULL)

Modified: trunk/reactos/lib/ntdll/rtl/process.c
--- trunk/reactos/lib/ntdll/rtl/process.c	2005-07-12 02:45:33 UTC (rev 16541)
+++ trunk/reactos/lib/ntdll/rtl/process.c	2005-07-12 04:41:41 UTC (rev 16542)
@@ -90,4 +90,19 @@
    return STATUS_INVALID_PARAMETER;
 }
 
+/*
+ * @implemented
+ */
+VOID 
+STDCALL 
+RtlExitUserThread(NTSTATUS Status)
+{
+    /* Call the Loader and tell him to notify the DLLs */
+    LdrShutdownThread();
+    
+    /* Shut us down */
+    NtCurrentTeb()->FreeStackOnTermination = TRUE;
+    NtTerminateThread(NtCurrentThread(), Status);
+}
+
 /* EOF */

Modified: trunk/reactos/lib/rtl/process.c
--- trunk/reactos/lib/rtl/process.c	2005-07-12 02:45:33 UTC (rev 16541)
+++ trunk/reactos/lib/rtl/process.c	2005-07-12 04:41:41 UTC (rev 16542)
@@ -16,176 +16,161 @@
 #define NDEBUG
 #include <debug.h>
 
-/* FUNCTIONS ****************************************************************/
+/* INTERNAL FUNCTIONS *******************************************************/
 
-
-static NTSTATUS
+NTSTATUS
+STDCALL
 RtlpMapFile(PUNICODE_STRING ImageFileName,
-            PRTL_USER_PROCESS_PARAMETERS Ppb,
-	    ULONG Attributes,
-	    PHANDLE Section)
+            ULONG Attributes,
+            PHANDLE Section)
 {
-   HANDLE hFile;
-   IO_STATUS_BLOCK IoStatusBlock;
-   OBJECT_ATTRIBUTES ObjectAttributes;
-   PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
-   NTSTATUS Status;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    NTSTATUS Status;
+    HANDLE hFile = NULL;
+    IO_STATUS_BLOCK IoStatusBlock;
 
-   hFile = NULL;
+    /* Open the Image File */
+    InitializeObjectAttributes(&ObjectAttributes,
+                               ImageFileName,
+                               Attributes & (OBJ_CASE_INSENSITIVE | OBJ_INHERIT),
+                               NULL,
+                               NULL);
+    Status = ZwOpenFile(&hFile,
+                        SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA,
+                        &ObjectAttributes,
+                        &IoStatusBlock,
+                        FILE_SHARE_DELETE | FILE_SHARE_READ,
+                        FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to read image file from disk\n");
+        return(Status);
+    }
+    
+    /* Now create a section for this image */    
+    Status = ZwCreateSection(Section,
+                             SECTION_ALL_ACCESS,
+                             NULL,
+                             NULL,
+                             PAGE_EXECUTE,
+                             SEC_IMAGE,
+                             hFile);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to create section for image file\n");
+    }
 
-   RtlDeNormalizeProcessParams (Ppb);
+    ZwClose(hFile);
+    return Status;
+}
 
-/*   DbgPrint("ImagePathName 0x%p\n", Ppb->ImagePathName.Buffer); */
+/* FUNCTIONS ****************************************************************/
 
-   InitializeObjectAttributes(&ObjectAttributes,
-			      ImageFileName,
-			      Attributes & (OBJ_CASE_INSENSITIVE | OBJ_INHERIT),
-			      NULL,
-			      SecurityDescriptor);
-
-   RtlNormalizeProcessParams (Ppb);
-
-   /*
-    * Try to open the executable
-    */
-
-   Status = ZwOpenFile(&hFile,
-			SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
-			&ObjectAttributes,
-			&IoStatusBlock,
-			FILE_SHARE_DELETE|FILE_SHARE_READ,
-			FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
-
-   if (!NT_SUCCESS(Status))
-     {
-	return(Status);
-     }
-
-   Status = ZwCreateSection(Section,
-			    SECTION_ALL_ACCESS,
-			    NULL,
-			    NULL,
-			    PAGE_EXECUTE,
-			    SEC_IMAGE,
-			    hFile);
-   ZwClose(hFile);
-
-   if (!NT_SUCCESS(Status))
-     {
-	return(Status);
-     }
-
-   return(STATUS_SUCCESS);
-}
-
-static NTSTATUS KlInitPeb (HANDLE ProcessHandle,
-			   PRTL_USER_PROCESS_PARAMETERS	Ppb,
-			   PVOID* ImageBaseAddress)
+NTSTATUS
+STDCALL
+RtlpInitEnvironment(HANDLE ProcessHandle,
+                    PPEB Peb,
+                    PRTL_USER_PROCESS_PARAMETERS ProcessParameters)
 {
-   NTSTATUS Status;
-   PVOID PpbBase;
-   ULONG PpbSize;
-   ULONG BytesWritten;
-   ULONG Offset;
-   PVOID EnvPtr = NULL;
-   ULONG EnvSize = 0;
+    NTSTATUS Status;
+    PVOID BaseAddress = NULL;
+    ULONG EnviroSize;
+    ULONG Size;
+    PWCHAR Environment = 0;
+    
+    DPRINT("RtlpInitEnvironment (hProcess: %lx, Peb: %p Params: %p)\n",
+            ProcessHandle, Peb, ProcessParameters);
+            
+    /* Give the caller 1MB if he requested it */
+    if (ProcessParameters->Flags & PPF_RESERVE_1MB)
+    {
+        /* Give 1MB starting at 0x4 */
+        BaseAddress = (PVOID)4;
+        EnviroSize = 1024 * 1024;
+        Status = ZwAllocateVirtualMemory(ProcessHandle,
+                                         &BaseAddress,
+                                         0,
+                                         &EnviroSize,
+                                         MEM_RESERVE,
+                                         PAGE_READWRITE);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to reserve 1MB of space \n");
+            return(Status);
+        }
+    }
+    
+    /* Find the end of the Enviroment Block */
+    if ((Environment = (PWCHAR)ProcessParameters->Environment))
+    {
+        while (*Environment++) while (*Environment++);
 
-   /* create the Environment */
-   if (Ppb->Environment != NULL)
-     {
-	MEMORY_BASIC_INFORMATION MemInfo;
+        /* Calculate the size of the block */
+        EnviroSize = (ULONG)((ULONG_PTR)Environment -
+                             (ULONG_PTR)ProcessParameters->Environment);
+        DPRINT("EnvironmentSize %ld\n", EnviroSize);
 
-   Status = ZwQueryVirtualMemory (NtCurrentProcess (),
-	                               Ppb->Environment,
-	                               MemoryBasicInformation,
-	                               &MemInfo,
-	                               sizeof(MEMORY_BASIC_INFORMATION),
-	                               NULL);
-	if (!NT_SUCCESS(Status))
-	  {
-	     return Status;
-	  }
-	EnvSize = MemInfo.RegionSize;
-     }
-   DPRINT("EnvironmentSize %ld\n", EnvSize);
+        /* Allocate and Initialize new Environment Block */
+        Size = EnviroSize;
+        Status = ZwAllocateVirtualMemory(ProcessHandle,
+                                         &BaseAddress,
+                                         0,
+                                         &Size,
+                                         MEM_RESERVE | MEM_COMMIT,
+                                         PAGE_READWRITE);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to allocate Environment Block\n");
+            return(Status);
+        }
+        
+        /* Write the Environment Block */
+        ZwWriteVirtualMemory(ProcessHandle,
+                             BaseAddress,
+                             ProcessParameters->Environment,
+                             EnviroSize,
+                             NULL);
+                             
+        /* Save pointer */
+        ProcessParameters->Environment = BaseAddress;
+    }
+    
+    DPRINT("EnvironmentPointer %p\n", BaseAddress);
+    DPRINT("Ppb->MaximumLength %x\n", ProcessParameters->MaximumLength);
 
-   /* allocate and initialize new environment block */
-   if (EnvSize != 0)
-     {
-   Status = ZwAllocateVirtualMemory(ProcessHandle,
-					 &EnvPtr,
-					 0,
-					 &EnvSize,
-					 MEM_RESERVE | MEM_COMMIT,
-					 PAGE_READWRITE);
-	if (!NT_SUCCESS(Status))
-	  {
-	     return(Status);
-	  }
+    /* Now allocate space for the Parameter Block */
+    BaseAddress = NULL;
+    Size = ProcessParameters->MaximumLength;    
+    Status = ZwAllocateVirtualMemory(ProcessHandle,
+                                     &BaseAddress,
+                                     0,
+                                     &Size,
+                                     MEM_COMMIT,
+                                     PAGE_READWRITE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to allocate Parameter Block\n");
+        return(Status);
+    }
+    
+    /* Write the Parameter Block */
+    ZwWriteVirtualMemory(ProcessHandle,
+                         BaseAddress,
+                         ProcessParameters,
+                         ProcessParameters->Length,
+                         NULL);
+  
+    /* Write pointer to Parameter Block */
+    ZwWriteVirtualMemory(ProcessHandle,
+                         &Peb->ProcessParameters,
+                         &BaseAddress,
+                         sizeof(BaseAddress),
+                         NULL);
 
-   ZwWriteVirtualMemory(ProcessHandle,
-			     EnvPtr,
-			     Ppb->Environment,
-			     EnvSize,
-			     &BytesWritten);
-     }
-   DPRINT("EnvironmentPointer %p\n", EnvPtr);
-
-   /* create the PPB */
-   PpbBase = NULL;
-   PpbSize = Ppb->MaximumLength;
-
-   Status = ZwAllocateVirtualMemory(ProcessHandle,
-				    &PpbBase,
-				    0,
-				    &PpbSize,
-				    MEM_RESERVE | MEM_COMMIT,
-				    PAGE_READWRITE);
-   if (!NT_SUCCESS(Status))
-     {
-	return(Status);
-     }
-
-   DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
-
-   /* write process parameters block*/
-   RtlDeNormalizeProcessParams (Ppb);
-   ZwWriteVirtualMemory(ProcessHandle,
-			PpbBase,
-			Ppb,
-			Ppb->MaximumLength,
-
-			&BytesWritten);
-   RtlNormalizeProcessParams (Ppb);
-
-   /* write pointer to environment */
-   Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
-   ZwWriteVirtualMemory(ProcessHandle,
-			(PVOID)((ULONG_PTR)PpbBase + Offset),
-			&EnvPtr,
-			sizeof(EnvPtr),
-			&BytesWritten);
-
-   /* write pointer to process parameter block */
-   Offset = FIELD_OFFSET(PEB, ProcessParameters);
-   ZwWriteVirtualMemory(ProcessHandle,
-			(PVOID)(PEB_BASE + Offset),
-			&PpbBase,
-			sizeof(PpbBase),
-			&BytesWritten);
-
-   /* Read image base address. */
-   Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
-   ZwReadVirtualMemory(ProcessHandle,
-		       (PVOID)(PEB_BASE + Offset),
-		       ImageBaseAddress,
-		       sizeof(PVOID),
-		       &BytesWritten);
-
-   return(STATUS_SUCCESS);
+    /* Return */
+    return STATUS_SUCCESS;
 }
 
-
 /*
  * @implemented
  *
@@ -200,114 +185,136 @@
  *
  * -Gunnar
  */
-NTSTATUS STDCALL
-RtlCreateUserProcess(
-   IN PUNICODE_STRING ImageFileName,
-   IN ULONG Attributes,
-   IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
-   IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor  OPTIONAL,
-   IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor  OPTIONAL,
-   IN HANDLE ParentProcess  OPTIONAL,
-   IN BOOLEAN InheritHandles,
-   IN HANDLE DebugPort  OPTIONAL,
-   IN HANDLE ExceptionPort  OPTIONAL,
-   OUT PRTL_USER_PROCESS_INFORMATION ProcessInfo
-   )
+NTSTATUS
+STDCALL
+RtlCreateUserProcess(IN PUNICODE_STRING ImageFileName,
+                     IN ULONG Attributes,
+                     IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
+                     IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL,
+                     IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL,
+                     IN HANDLE ParentProcess OPTIONAL,
+                     IN BOOLEAN InheritHandles,
+                     IN HANDLE DebugPort OPTIONAL,
+                     IN HANDLE ExceptionPort OPTIONAL,
+                     OUT PRTL_USER_PROCESS_INFORMATION ProcessInfo)
 {
-   HANDLE hSection;
-   NTSTATUS Status;
-   PROCESS_BASIC_INFORMATION ProcessBasicInfo;
-   ULONG retlen;
-   SECTION_IMAGE_INFORMATION Sii;
-   ULONG ResultLength;
-   PVOID ImageBaseAddress;
+    NTSTATUS Status;
+    HANDLE hSection;
+    PROCESS_BASIC_INFORMATION ProcessBasicInfo;
+    OBJECT_ATTRIBUTES ObjectAttributes;
 
-   DPRINT("RtlCreateUserProcess\n");
+    DPRINT("RtlCreateUserProcess: %wZ\n", ImageFileName);
 
-   Status = RtlpMapFile(ImageFileName,
-                        ProcessParameters,
-			Attributes,
-			&hSection);
-   if( !NT_SUCCESS( Status ) )
-     return Status;
+    /* Map and Load the File */
+    Status = RtlpMapFile(ImageFileName,
+                         Attributes,
+                         &hSection);
+    if(!NT_SUCCESS(Status))
+    {
+        DPRINT1("Could not map process image\n");
+        return Status;
+    }
+    
+    /* Clean out the CurDir Handle if we won't use it */
+    if (!InheritHandles) ProcessParameters->CurrentDirectory.Handle = NULL;
+    
+    /* Use us as parent if none other specified */
+    if (!ParentProcess) ParentProcess = NtCurrentProcess();
+    
+    /* Initialize the Object Attributes */
+    InitializeObjectAttributes(&ObjectAttributes, 
+                               NULL, 
+                               0, 
+                               NULL,
+                               ProcessSecurityDescriptor);
 
-   /*
-    * Create a new process
-    */
-   if (ParentProcess == NULL)
-     ParentProcess = NtCurrentProcess();
+    /*
+     * If FLG_ENABLE_CSRDEBUG is used, then CSRSS is created under the
+     * watch of WindowsSS
+     */
+    if ((RtlGetNtGlobalFlags() & FLG_ENABLE_CSRDEBUG) &&
+        (wcsstr(ImageFileName->Buffer, L"csrss")))
+    {
+        UNICODE_STRING DebugString = RTL_CONSTANT_STRING(L"\\WindowsSS");
+        InitializeObjectAttributes(&ObjectAttributes, 
+                                   &DebugString, 
+                                   0, 
+                                   NULL,
+                                   ProcessSecurityDescriptor);
+    }
+    
+                               
+    /* Create Kernel Process Object */
+    Status = ZwCreateProcess(&ProcessInfo->ProcessHandle,
+                             PROCESS_ALL_ACCESS,
+                             &ObjectAttributes,
+                             ParentProcess,
+                             InheritHandles,
+                             hSection,
+                             DebugPort,
+                             ExceptionPort);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Could not create Kernel Process Object\n");
+        ZwClose(hSection);
+        return(Status);
+    }
+    
+    /* Get some information on the image */
+    Status = ZwQuerySection(hSection,
+                            SectionImageInformation,
+                            &ProcessInfo->ImageInformation,
+                            sizeof(SECTION_IMAGE_INFORMATION),
+                            NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Could not query Section Info\n");
+        ZwClose(ProcessInfo->ProcessHandle);
+        ZwClose(hSection);
+        return(Status);
+    }
 
-   Status = ZwCreateProcess(&(ProcessInfo->ProcessHandle),
-			    PROCESS_ALL_ACCESS,
-			    NULL,
-			    ParentProcess,
-             InheritHandles,
-			    hSection,
-			    DebugPort,
-			    ExceptionPort);
-   if (!NT_SUCCESS(Status))
-     {
-   ZwClose(hSection);
-	return(Status);
-     }
+    /* Get some information about the process */
+    ZwQueryInformationProcess(ProcessInfo->ProcessHandle,
+                              ProcessBasicInformation,
+                              &ProcessBasicInfo,
+                              sizeof(ProcessBasicInfo),
+                              NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Could not query Process Info\n");
+        ZwClose(ProcessInfo->ProcessHandle);
+        ZwClose(hSection);
+        return(Status);
+    }  
 
-   /*
-    * Get some information about the process
-    */
-   ZwQueryInformationProcess(ProcessInfo->ProcessHandle,
-			     ProcessBasicInformation,
-			     &ProcessBasicInfo,
-			     sizeof(ProcessBasicInfo),
-			     &retlen);
-   DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
-	  ProcessBasicInfo.UniqueProcessId);
-   ProcessInfo->ClientId.UniqueProcess = (HANDLE)ProcessBasicInfo.UniqueProcessId;
+    /* Create Process Environment */
+    RtlpInitEnvironment(ProcessInfo->ProcessHandle,
+                        ProcessBasicInfo.PebBaseAddress,
+                        ProcessParameters);
 
-   /*
-    * Create Process Environment Block
-    */
-   DPRINT("Creating peb\n");
-   KlInitPeb(ProcessInfo->ProcessHandle,
-	     ProcessParameters,
-	     &ImageBaseAddress);
-
-   Status = ZwQuerySection(hSection,
-			   SectionImageInformation,
-			   &Sii,
-			   sizeof(Sii),
-			   &ResultLength);
-   if (!NT_SUCCESS(Status) || ResultLength != sizeof(Sii))
-     {
-       DPRINT("Failed to get section image information.\n");
-       ZwClose(hSection);
-       return(Status);
-     }
-
-   DPRINT("Creating thread for process\n");
-   Status = RtlCreateUserThread(
-      ProcessInfo->ProcessHandle,
-      NULL,
-      TRUE, /* CreateSuspended? */
-      0,
-      Sii.MaximumStackSize,
-      Sii.CommittedStackSize,
-      (PVOID)((ULONG_PTR)ImageBaseAddress + (ULONG_PTR)Sii.TransferAddress),
-      (PVOID)PEB_BASE,
-      &ProcessInfo->ThreadHandle,
-      &ProcessInfo->ClientId
-      );
-
-   ZwClose(hSection);
-
-   if (!NT_SUCCESS(Status))
-   {
-	DPRINT("Failed to create thread\n");
-	return(Status);
-   }
-
-   return(STATUS_SUCCESS);
+    /* Create the first Thread */
+    Status = RtlCreateUserThread(ProcessInfo->ProcessHandle,
+                                 ThreadSecurityDescriptor,
+                                 TRUE,
+                                 ProcessInfo->ImageInformation.ZeroBits,
+                                 ProcessInfo->ImageInformation.MaximumStackSize,
+                                 ProcessInfo->ImageInformation.CommittedStackSize,
+                                 ProcessInfo->ImageInformation.TransferAddress,
+                                 ProcessBasicInfo.PebBaseAddress,
+                                 &ProcessInfo->ThreadHandle,
+                                 &ProcessInfo->ClientId);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Could not Create Thread\n");
+        ZwClose(ProcessInfo->ProcessHandle);
+        ZwClose(hSection); /* Don't try to optimize this on top! */
+        return Status;
+    }
+    
+    /* Close the Section Handle and return */
+    ZwClose(hSection);
+    return STATUS_SUCCESS;
 }
 
-
-
 /* EOF */

Modified: trunk/reactos/lib/rtl/thread.c
--- trunk/reactos/lib/rtl/thread.c	2005-07-12 02:45:33 UTC (rev 16541)
+++ trunk/reactos/lib/rtl/thread.c	2005-07-12 04:41:41 UTC (rev 16542)
@@ -3,113 +3,349 @@
  * PROJECT:           ReactOS kernel
  * PURPOSE:           Rtl user thread functions
  * FILE:              lib/ntdll/rtl/thread.c
- * PROGRAMER:         Eric Kohl
- * REVISION HISTORY:
- *                    09/07/99: Created
- *                    09/10/99: Cleanup and full stack support.
- *                    25/04/03: Near rewrite. Made code more readable, replaced
- *                              INITIAL_TEB with USER_STACK, added support for
- *                              fixed-size stacks
- *                    28/04/03: Moved all code to a new statically linked
- *                              library (ROSRTL) so it can be shared with
- *                              kernel32.dll without exporting non-standard
- *                              functions from ntdll.dll
+ * PROGRAMERS:        
+ *                    Alex Ionescu (alex@relsoft.net)
+ *                    Eric Kohl
+ *                    KJK::Hyperion
  */
 
 /* INCLUDES *****************************************************************/
 
 #include "rtl.h"
-#include <rosrtl/thread.h>
 
 #define NDEBUG
 #include <debug.h>
 
-/* FUNCTIONS ***************************************************************/
+/* PRIVATE FUNCTIONS *******************************************************/
 
-/*
- @implemented
-*/
-NTSTATUS STDCALL RtlCreateUserThread
-(
- HANDLE ProcessHandle,
- PSECURITY_DESCRIPTOR SecurityDescriptor,
- BOOLEAN CreateSuspended,
- LONG StackZeroBits,
- ULONG StackReserve,
- ULONG StackCommit,
- PTHREAD_START_ROUTINE StartAddress,
- PVOID Parameter,
- PHANDLE ThreadHandle,
- PCLIENT_ID ClientId
-)
+NTSTATUS
+STDCALL
+RtlpCreateUserStack(HANDLE hProcess,
+                    ULONG StackReserve,
+                    ULONG StackCommit,
+                    ULONG StackZeroBits,
+                    PINITIAL_TEB InitialTeb)
 {
- OBJECT_ATTRIBUTES oaThreadAttribs;
+    NTSTATUS Status;
+    SYSTEM_BASIC_INFORMATION SystemBasicInfo;
+    PIMAGE_NT_HEADERS Headers;
+    ULONG_PTR Stack = 0;
+    BOOLEAN UseGuard = FALSE;
+    
+    DPRINT("RtlpCreateUserStack\n");
+    
+    /* Get some memory information */
+    Status = NtQuerySystemInformation(SystemBasicInformation,
+                                      &SystemBasicInfo,
+                                      sizeof(SYSTEM_BASIC_INFORMATION),
+                                      NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failure to query system info\n");
+        return Status;
+    }
+    
+    /* Use the Image Settings if we are dealing with the current Process */
+    if (hProcess == NtCurrentProcess())
+    {
+        /* Get the Image Headers */
+        Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
+        DPRINT("Headers: %p\n", Headers);
+        
+        /* If we didn't get the parameters, find them ourselves */
+        StackReserve = (StackReserve) ? 
+                        StackReserve : Headers->OptionalHeader.SizeOfStackReserve;
+        StackCommit = (StackCommit) ? 
+                       StackCommit : Headers->OptionalHeader.SizeOfStackCommit;
+    }
+    else
+    {
+        /* Use the System Settings if needed */
+        StackReserve = (StackReserve) ? StackReserve :
+                                        SystemBasicInfo.AllocationGranularity;
+        StackCommit = (StackCommit) ? StackCommit : SystemBasicInfo.PageSize;
+    }
+    
+    /* Align everything to Page Size */
+    StackReserve = ROUND_UP(StackReserve, SystemBasicInfo.AllocationGranularity);
+    StackCommit = ROUND_UP(StackCommit, SystemBasicInfo.PageSize);
+    #if 1 // FIXME: Remove once Guard Page support is here
+    StackCommit = StackReserve;
+    #endif
+    DPRINT("StackReserve: %lx, StackCommit: %lx\n", StackReserve, StackCommit);
+    
+    /* Reserve memory for the stack */
+    Status = ZwAllocateVirtualMemory(hProcess,
+                                     (PVOID*)&Stack,
+                                     StackZeroBits,
+                                     &StackReserve,
+                                     MEM_RESERVE,
+                                     PAGE_READWRITE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failure to reserve stack\n");
+        return Status;
+    }
+    
+    /* Now set up some basic Initial TEB Parameters */
+    InitialTeb->AllocatedStackBase = (PVOID)Stack;
+    InitialTeb->StackBase = (PVOID)(Stack + StackReserve);
+    
+    /* Update the Stack Position */
+    Stack += StackReserve - StackCommit;
+    
+    /* Check if we will need a guard page */
+    if (StackReserve > StackCommit)
+    {
+        Stack -= SystemBasicInfo.PageSize;
+        StackCommit += SystemBasicInfo.PageSize;
+        UseGuard = TRUE;
+    }
+    
+    DPRINT("AllocatedBase: %p, StackBase: %p, Stack: %p, StackCommit: %lx\n",
+            InitialTeb->AllocatedStackBase, InitialTeb->StackBase, Stack,
+            StackCommit);
+    
+    /* Allocate memory for the stack */
+    Status = ZwAllocateVirtualMemory(hProcess,
+                                     (PVOID*)&Stack,
+                                     0,
+                                     &StackCommit,
+                                     MEM_COMMIT,
+                                     PAGE_READWRITE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failure to allocate stack\n");
+        return Status;
+    }
+    
+    /* Now set the current Stack Limit */
+    InitialTeb->StackLimit = (PVOID)Stack;
+    DPRINT("StackLimit: %p\n", Stack);
+    
+    /* Create a guard page */
+    if (UseGuard)
+    {
+        ULONG GuardPageSize = SystemBasicInfo.PageSize;
+        ULONG Dummy;
+        
+        /* Attempt maximum space possible */        
+        Status = ZwProtectVirtualMemory(hProcess,
+                                        (PVOID*)&Stack,
+                                        &GuardPageSize,
+                                        PAGE_GUARD | PAGE_READWRITE,
+                                        &Dummy);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failure to create guard page\n");
+            return Status;
+        }
+        
+        /* Update the Stack Limit keeping in mind the Guard Page */
+        InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit -
+                                         GuardPageSize);
+        DPRINT1("StackLimit: %p\n", Stack);   
+    }
+    
+    /* We are done! */
+    return Status;
+}
 
- InitializeObjectAttributes
- (
-  &oaThreadAttribs,
-  NULL,
-  0,
-  NULL,
-  SecurityDescriptor
- );
-
- return RtlRosCreateUserThread
- (
-  ProcessHandle,
-  &oaThreadAttribs,
-  CreateSuspended,
-  StackZeroBits,
-  &StackReserve,
-  &StackCommit,
-  StartAddress,
-  ThreadHandle,
-  ClientId,
-  1,
-  (ULONG_PTR *)&Parameter
- );
+NTSTATUS
+STDCALL
+RtlpFreeUserStack(HANDLE hProcess,
+                  PINITIAL_TEB InitialTeb)
+{
+    ULONG Dummy = 0;
+    
+    /* Free the Stack */
+    return ZwFreeVirtualMemory(hProcess,
+                               &InitialTeb->AllocatedStackBase,
+                               &Dummy,
+                               MEM_RELEASE);
 }
+    
+/* FUNCTIONS ***************************************************************/
 
 /*
  @implemented
 */
-VOID STDCALL
-RtlInitializeContext(
-  IN HANDLE ProcessHandle,
-  OUT PCONTEXT ThreadContext,
-  IN PVOID ThreadStartParam  OPTIONAL,
-  IN PTHREAD_START_ROUTINE ThreadStartAddress,
-  IN PINITIAL_TEB InitialTeb)
+NTSTATUS 
+STDCALL 
+RtlCreateUserThread(HANDLE ProcessHandle,
+                    PSECURITY_DESCRIPTOR SecurityDescriptor,
+                    BOOLEAN CreateSuspended,
+                    LONG StackZeroBits,
+                    ULONG StackReserve,
+                    ULONG StackCommit,
+                    PTHREAD_START_ROUTINE StartAddress,
+                    PVOID Parameter,
+                    PHANDLE ThreadHandle,
+                    PCLIENT_ID ClientId)
 {
- RtlRosInitializeContext
- (
-  ProcessHandle,
-  ThreadContext,
-  ThreadStartAddress,
-  InitialTeb,
-  1,
-  (ULONG_PTR *)&ThreadStartParam
- );
+    NTSTATUS Status;
+    HANDLE Handle;
+    CLIENT_ID ThreadCid;
+    INITIAL_TEB InitialTeb;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    CONTEXT Context;
+    
+    DPRINT("RtlCreateUserThread: (hProcess: %lx, Suspended: %lx,"
+            "ZeroBits: %lx, StackReserve: %lx, StackCommit: %lx,"
+            "StartAddress: %p, Parameter: %lx)\n", ProcessHandle,
+            CreateSuspended, StackZeroBits, StackReserve, StackCommit,
+            StartAddress, Parameter);
+    
+    /* First, we'll create the Stack */
+    Status = RtlpCreateUserStack(ProcessHandle,
+                                 StackReserve,
+                                 StackCommit,
+                                 StackZeroBits,
+                                 &InitialTeb);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failure to create User Stack\n");
+        return Status;
+    }
+    
+    /* Next, we'll set up the Initial Context */
+    RtlInitializeContext(ProcessHandle,
+                         &Context,
+                         Parameter,
+                         StartAddress,
+                         InitialTeb.StackBase);
+                         
+    /* We are now ready to create the Kernel Thread Object */
+    InitializeObjectAttributes(&ObjectAttributes, 
+                               NULL, 
+                               0, 
+                               NULL, 
+                               SecurityDescriptor);
+    Status = ZwCreateThread(&Handle,
+                            THREAD_ALL_ACCESS,
+                            &ObjectAttributes,
+                            ProcessHandle,
+                            &ThreadCid,
+                            &Context,
+                            &InitialTeb,
+                            CreateSuspended);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failure to create Thread\n");
+        
+        /* Free the stack */
+        RtlpFreeUserStack(ProcessHandle, &InitialTeb);
+    }
+    else
+    {
+        DPRINT("Thread created: %lx\n", Handle);
+        if (ThreadHandle) *ThreadHandle = Handle;
+        if (ClientId) *ClientId = ThreadCid;
+    }
+    
+    /* Return success or the previous failure */
+    return Status;
 }
 
 /*
+ * FIXME: Should go in /i386
  @implemented
 */
-NTSTATUS STDCALL RtlFreeUserThreadStack
-(
- HANDLE ProcessHandle,
- HANDLE ThreadHandle
-)
+VOID
+STDCALL
+RtlInitializeContext(IN HANDLE ProcessHandle,
+                     OUT PCONTEXT ThreadContext,
+                     IN PVOID ThreadStartParam  OPTIONAL,
+                     IN PTHREAD_START_ROUTINE ThreadStartAddress,
+                     IN PINITIAL_TEB InitialTeb)
 {
- return RtlRosFreeUserThreadStack(ProcessHandle, ThreadHandle);
+    DPRINT("RtlInitializeContext: (hProcess: %lx, ThreadContext: %p, Teb: %p\n",
+            ProcessHandle, ThreadContext, InitialTeb);
+
+    /* 
+     * Set the Initial Registers
+     * This is based on NT's default values -- crazy apps might expect this...
+     */
+    ThreadContext->Ebp = 0;
+    ThreadContext->Eax = 0;
+    ThreadContext->Ebx = 1;
+    ThreadContext->Ecx = 2;
+    ThreadContext->Edx = 3;
+    ThreadContext->Esi = 4;
+    ThreadContext->Edi = 5;
+    
+    /* Set the Selectors */
+    ThreadContext->SegGs = 0;
+    ThreadContext->SegFs = TEB_SELECTOR;
+    ThreadContext->SegEs = USER_DS;
+    ThreadContext->SegDs = USER_DS;
+    ThreadContext->SegCs = USER_CS;
+    ThreadContext->SegSs = USER_DS;
+    
+    /* Enable Interrupts */
+    ThreadContext->EFlags = 0x200; /*X86_EFLAGS_IF */
+    
+    /* Settings passed */
+    ThreadContext->Eip = (ULONG)ThreadStartAddress;
+    ThreadContext->Esp = (ULONG)InitialTeb;
+    
+    /* Only the basic Context is initialized */
+    ThreadContext->ContextFlags = CONTEXT_CONTROL | 
+                                  CONTEXT_INTEGER | 
+                                  CONTEXT_SEGMENTS;
+                                  
+    /* Set up ESP to the right value */
+    ThreadContext->Esp -= sizeof(PVOID);
+    ZwWriteVirtualMemory(ProcessHandle,
+                         (PVOID)ThreadContext->Esp,
+                         (PVOID)&ThreadStartParam,
+                         sizeof(PVOID),
+                         NULL);
+                         
+    /* Push it down one more notch for RETEIP */
+    ThreadContext->Esp -= sizeof(PVOID);
 }
 
 /*
  @implemented
 */
[truncated at 1000 lines; 58 more skipped]