- NDK 0.98, now with versionned headers. Too many changes to list, see the TinyKRNL...
[reactos.git] / reactos / ntoskrnl / mm / process.c
index b74f4f1..e533c66 100644 (file)
-/*\r
- * COPYRIGHT:       See COPYING in the top level directory\r
- * PROJECT:         ReactOS kernel\r
- * FILE:            ntoskrnl/mm/process.c\r
- * PURPOSE:         Memory functions related to Processes\r
- *\r
- * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)\r
- */\r
-\r
-/* INCLUDES *****************************************************************/\r
-\r
-#include <ntoskrnl.h>\r
-#define NDEBUG\r
-#include <internal/debug.h>\r
-\r
-extern ULONG NtMajorVersion;\r
-extern ULONG NtMinorVersion;\r
-extern ULONG NtOSCSDVersion;\r
-\r
-/* FUNCTIONS *****************************************************************/\r
-\r
-PVOID\r
-STDCALL\r
-MiCreatePebOrTeb(PEPROCESS Process,\r
-                 PVOID BaseAddress)\r
-{\r
-    NTSTATUS Status;\r
-    PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;\r
-    PMEMORY_AREA MemoryArea;\r
-    PHYSICAL_ADDRESS BoundaryAddressMultiple;\r
-    PVOID AllocatedBase = BaseAddress;\r
-    BoundaryAddressMultiple.QuadPart = 0;\r
-\r
-    /* Acquire the Lock */\r
-    MmLockAddressSpace(ProcessAddressSpace);\r
-\r
-    /*\r
-     * Create a Peb or Teb.\r
-     * Loop until it works, decreasing by PAGE_SIZE each time. The logic here\r
-     * is that a PEB allocation should never fail since the address is free,\r
-     * while TEB allocation can fail, and we should simply try the address\r
-     * below. Is there a nicer way of doing this automagically? (ie: findning)\r
-     * a gap region? -- Alex\r
-     */\r
-    do {\r
-        DPRINT("Trying to allocate: %x\n", AllocatedBase);\r
-        Status = MmCreateMemoryArea(Process,\r
-                                    ProcessAddressSpace,\r
-                                    MEMORY_AREA_PEB_OR_TEB,\r
-                                    &AllocatedBase,\r
-                                    PAGE_SIZE,\r
-                                    PAGE_READWRITE,\r
-                                    &MemoryArea,\r
-                                    TRUE,\r
-                                    FALSE,\r
-                                    BoundaryAddressMultiple);\r
-        AllocatedBase = RVA(AllocatedBase, -PAGE_SIZE);\r
-    } while (Status != STATUS_SUCCESS);\r
-\r
-    /* Initialize the Region */\r
-    MmInitialiseRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,\r
-                       PAGE_SIZE,\r
-                       MEM_COMMIT,\r
-                       PAGE_READWRITE);\r
-\r
-    /* Reserve the pages */\r
-    MmReserveSwapPages(PAGE_SIZE);\r
-\r
-    /* Unlock Address Space */\r
-    DPRINT("Returning\n");\r
-    MmUnlockAddressSpace(ProcessAddressSpace);\r
-    return RVA(AllocatedBase, PAGE_SIZE);\r
-}\r
-\r
-VOID\r
-MiFreeStackPage(PVOID Context,\r
-                MEMORY_AREA* MemoryArea,\r
-                PVOID Address,\r
-                PFN_TYPE Page,\r
-                SWAPENTRY SwapEntry,\r
-                BOOLEAN Dirty)\r
-{\r
-    ASSERT(SwapEntry == 0);\r
-    if (Page) MmReleasePageMemoryConsumer(MC_NPPOOL, Page);\r
-}\r
-\r
-VOID\r
-STDCALL\r
-MmDeleteKernelStack(PVOID Stack,\r
-                    BOOLEAN GuiStack)\r
-{\r
-    /* Lock the Address Space */\r
-    MmLockAddressSpace(MmGetKernelAddressSpace());\r
-\r
-    /* Delete the Stack */\r
-    MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),\r
-                          Stack,\r
-                          MiFreeStackPage,\r
-                          NULL);\r
-\r
-    /* Unlock the Address Space */\r
-    MmUnlockAddressSpace(MmGetKernelAddressSpace());\r
-}\r
-\r
-VOID\r
-MiFreePebPage(PVOID Context,\r
-              MEMORY_AREA* MemoryArea,\r
-              PVOID Address,\r
-              PFN_TYPE Page,\r
-              SWAPENTRY SwapEntry,\r
-              BOOLEAN Dirty)\r
-{\r
-    PEPROCESS Process = (PEPROCESS)Context;\r
-\r
-    if (Page != 0)\r
-    {\r
-        SWAPENTRY SavedSwapEntry;\r
-        SavedSwapEntry = MmGetSavedSwapEntryPage(Page);\r
-        if (SavedSwapEntry != 0)\r
-        {\r
-            MmFreeSwapPage(SavedSwapEntry);\r
-            MmSetSavedSwapEntryPage(Page, 0);\r
-        }\r
-        MmDeleteRmap(Page, Process, Address);\r
-        MmReleasePageMemoryConsumer(MC_USER, Page);\r
-    }\r
-    else if (SwapEntry != 0)\r
-    {\r
-        MmFreeSwapPage(SwapEntry);\r
-    }\r
-}\r
-\r
-VOID\r
-STDCALL\r
-MmDeleteTeb(PEPROCESS Process,\r
-            PTEB Teb)\r
-{\r
-    PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;\r
-\r
-    /* Lock the Address Space */\r
-    MmLockAddressSpace(ProcessAddressSpace);\r
-\r
-    /* Delete the Stack */\r
-    MmFreeMemoryAreaByPtr(ProcessAddressSpace,\r
-                          Teb,\r
-                          MiFreePebPage,\r
-                          Process);\r
-\r
-    /* Unlock the Address Space */\r
-    MmUnlockAddressSpace(ProcessAddressSpace);\r
-}\r
-\r
-PVOID\r
-STDCALL\r
-MmCreateKernelStack(BOOLEAN GuiStack)\r
-{\r
-    PMEMORY_AREA StackArea;\r
-    ULONG i;\r
-    PHYSICAL_ADDRESS BoundaryAddressMultiple;\r
-    PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE];\r
-    PVOID KernelStack = NULL;\r
-    NTSTATUS Status;\r
-\r
-    /* Initialize the Boundary Address */\r
-    BoundaryAddressMultiple.QuadPart = 0;\r
-\r
-    /* Lock the Kernel Address Space */\r
-    MmLockAddressSpace(MmGetKernelAddressSpace());\r
-\r
-    /* Create a MAREA for the Kernel Stack */\r
-    Status = MmCreateMemoryArea(NULL,\r
-                                MmGetKernelAddressSpace(),\r
-                                MEMORY_AREA_KERNEL_STACK,\r
-                                &KernelStack,\r
-                                MM_STACK_SIZE,\r
-                                0,\r
-                                &StackArea,\r
-                                FALSE,\r
-                                FALSE,\r
-                                BoundaryAddressMultiple);\r
-\r
-    /* Unlock the Address Space */\r
-    MmUnlockAddressSpace(MmGetKernelAddressSpace());\r
-\r
-    /* Check for Success */\r
-    if (!NT_SUCCESS(Status))\r
-    {\r
-        DPRINT1("Failed to create thread stack\n");\r
-        KEBUGCHECK(0);\r
-    }\r
-\r
-    /* Mark the Stack in use */\r
-    for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++)\r
-    {\r
-        Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]);\r
-    }\r
-\r
-    /* Create a Virtual Mapping for it */\r
-    Status = MmCreateVirtualMapping(NULL,\r
-                                    KernelStack,\r
-                                    PAGE_READWRITE,\r
-                                    Page,\r
-                                    MM_STACK_SIZE / PAGE_SIZE);\r
-\r
-    /* Check for success */\r
-    if (!NT_SUCCESS(Status))\r
-    {\r
-        DPRINT1("Could not create Virtual Mapping for Kernel Stack\n");\r
-        KEBUGCHECK(0);\r
-    }\r
-\r
-    return KernelStack;\r
-}\r
-\r
-NTSTATUS\r
-STDCALL\r
-MmCreatePeb(PEPROCESS Process)\r
-{\r
-    PPEB Peb = NULL;\r
-    LARGE_INTEGER SectionOffset;\r
-    ULONG ViewSize = 0;\r
-    PVOID TableBase = NULL;\r
-    NTSTATUS Status;\r
-    SectionOffset.QuadPart = (ULONGLONG)0;\r
-\r
-    DPRINT("MmCreatePeb\n");\r
-\r
-    /* Map NLS Tables */\r
-    DPRINT("Mapping NLS\n");\r
-    Status = MmMapViewOfSection(NlsSectionObject,\r
-                                Process,\r
-                                &TableBase,\r
-                                0,\r
-                                0,\r
-                                &SectionOffset,\r
-                                &ViewSize,\r
-                                ViewShare,\r
-                                MEM_TOP_DOWN,\r
-                                PAGE_READONLY);\r
-    if (!NT_SUCCESS(Status))\r
-    {\r
-        DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);\r
-        return(Status);\r
-    }\r
-    DPRINT("TableBase %p  ViewSize %lx\n", TableBase, ViewSize);\r
-\r
-    /* Attach to Process */\r
-    KeAttachProcess(&Process->Pcb);\r
-\r
-    /* Allocate the PEB */\r
-    Peb = MiCreatePebOrTeb(Process, (PVOID)PEB_BASE);\r
-\r
-    /* Initialize the PEB */\r
-    DPRINT("Allocated: %x\n", Peb);\r
-    RtlZeroMemory(Peb, sizeof(PEB));\r
-\r
-    /* Set up data */\r
-    DPRINT("Setting up PEB\n");\r
-    Peb->ImageBaseAddress = Process->SectionBaseAddress;\r
-    Peb->OSMajorVersion = NtMajorVersion;\r
-    Peb->OSMinorVersion = NtMinorVersion;\r
-    Peb->OSBuildNumber = 2195;\r
-    Peb->OSPlatformId = 2; //VER_PLATFORM_WIN32_NT;\r
-    Peb->OSCSDVersion = NtOSCSDVersion;\r
-    Peb->AnsiCodePageData = (char*)TableBase + NlsAnsiTableOffset;\r
-    Peb->OemCodePageData = (char*)TableBase + NlsOemTableOffset;\r
-    Peb->UnicodeCaseTableData = (char*)TableBase + NlsUnicodeTableOffset;\r
-    Peb->NumberOfProcessors = KeNumberProcessors;\r
-    Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE);\r
-\r
-    Process->Peb = Peb;\r
-    KeDetachProcess();\r
-\r
-    DPRINT("MmCreatePeb: Peb created at %p\n", Peb);\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-PTEB\r
-STDCALL\r
-MmCreateTeb(PEPROCESS Process,\r
-            PCLIENT_ID ClientId,\r
-            PINITIAL_TEB InitialTeb)\r
-{\r
-    PTEB Teb;\r
-    BOOLEAN Attached = FALSE;\r
-\r
-    /* Attach to the process */\r
-    DPRINT("MmCreateTeb\n");\r
-    if (Process != PsGetCurrentProcess())\r
-    {\r
-        /* Attach to Target */\r
-        KeAttachProcess(&Process->Pcb);\r
-        Attached = TRUE;\r
-    }\r
-\r
-    /* Allocate the TEB */\r
-    Teb = MiCreatePebOrTeb(Process, (PVOID)TEB_BASE);\r
-\r
-    /* Initialize the PEB */\r
-    RtlZeroMemory(Teb, sizeof(TEB));\r
-\r
-    /* Set TIB Data */\r
-    Teb->Tib.ExceptionList = (PVOID)0xFFFFFFFF;\r
-    Teb->Tib.Version = 1;\r
-    Teb->Tib.Self = (PNT_TIB)Teb;\r
-\r
-    /* Set TEB Data */\r
-    Teb->Cid = *ClientId;\r
-    Teb->RealClientId = *ClientId;\r
-    Teb->ProcessEnvironmentBlock = Process->Peb;\r
-    Teb->CurrentLocale = PsDefaultThreadLocaleId;\r
-\r
-    /* Store stack information from InitialTeb */\r
-    if(InitialTeb != NULL)\r
-    {\r
-        Teb->Tib.StackBase = InitialTeb->StackBase;\r
-        Teb->Tib.StackLimit = InitialTeb->StackLimit;\r
-        Teb->DeallocationStack = InitialTeb->AllocatedStackBase;\r
-    }\r
-\r
-    /* Return TEB Address */\r
-    DPRINT("Allocated: %x\n", Teb);\r
-    if (Attached) KeDetachProcess();\r
-    return Teb;\r
-}\r
-\r
-NTSTATUS\r
-STDCALL\r
-MmCreateProcessAddressSpace(IN PEPROCESS Process,\r
-                            IN PSECTION_OBJECT Section OPTIONAL)\r
-{\r
-    NTSTATUS Status;\r
-    PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;\r
-    PVOID BaseAddress;\r
-    PMEMORY_AREA MemoryArea;\r
-    PHYSICAL_ADDRESS BoundaryAddressMultiple;\r
-    ULONG ViewSize = 0;\r
-    PVOID ImageBase = 0;\r
-    BoundaryAddressMultiple.QuadPart = 0;\r
-\r
-    /* Initialize the Addresss Space */\r
-    MmInitializeAddressSpace(Process, ProcessAddressSpace);\r
-\r
-    /* Acquire the Lock */\r
-    MmLockAddressSpace(ProcessAddressSpace);\r
-\r
-    /* Protect the highest 64KB of the process address space */\r
-    BaseAddress = (PVOID)MmUserProbeAddress;\r
-    Status = MmCreateMemoryArea(Process,\r
-                                ProcessAddressSpace,\r
-                                MEMORY_AREA_NO_ACCESS,\r
-                                &BaseAddress,\r
-                                0x10000,\r
-                                PAGE_NOACCESS,\r
-                                &MemoryArea,\r
-                                FALSE,\r
-                                FALSE,\r
-                                BoundaryAddressMultiple);\r
-    if (!NT_SUCCESS(Status))\r
-    {\r
-        DPRINT1("Failed to protect last 64KB\n");\r
-        goto exit;\r
-     }\r
-\r
-    /* Protect the 60KB above the shared user page */\r
-    BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE;\r
-    Status = MmCreateMemoryArea(Process,\r
-                                ProcessAddressSpace,\r
-                                MEMORY_AREA_NO_ACCESS,\r
-                                &BaseAddress,\r
-                                0x10000 - PAGE_SIZE,\r
-                                PAGE_NOACCESS,\r
-                                &MemoryArea,\r
-                                FALSE,\r
-                                FALSE,\r
-                                BoundaryAddressMultiple);\r
-    if (!NT_SUCCESS(Status))\r
-    {\r
-        DPRINT1("Failed to protect the memory above the shared user page\n");\r
-        goto exit;\r
-     }\r
-\r
-    /* Create the shared data page */\r
-    BaseAddress = (PVOID)USER_SHARED_DATA;\r
-    Status = MmCreateMemoryArea(Process,\r
-                                ProcessAddressSpace,\r
-                                MEMORY_AREA_SHARED_DATA,\r
-                                &BaseAddress,\r
-                                PAGE_SIZE,\r
-                                PAGE_READONLY,\r
-                                &MemoryArea,\r
-                                FALSE,\r
-                                FALSE,\r
-                                BoundaryAddressMultiple);\r
-    if (!NT_SUCCESS(Status))\r
-    {\r
-        DPRINT1("Failed to create Shared User Data\n");\r
-        goto exit;\r
-     }\r
-\r
-    /* Check if there's a Section Object */\r
-    if (Section)\r
-    {\r
-        UNICODE_STRING FileName;\r
-        PWCHAR szSrc;\r
-        PCHAR szDest;\r
-        USHORT lnFName = 0;\r
-\r
-        /* Unlock the Address Space */\r
-        DPRINT("Unlocking\n");\r
-        MmUnlockAddressSpace(ProcessAddressSpace);\r
-\r
-        DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n",\r
-                 Section, Process, &ImageBase);\r
-        Status = MmMapViewOfSection(Section,\r
-                                    Process,\r
-                                    (PVOID*)&ImageBase,\r
-                                    0,\r
-                                    0,\r
-                                    NULL,\r
-                                    &ViewSize,\r
-                                    0,\r
-                                    MEM_COMMIT,\r
-                                    PAGE_READWRITE);\r
-        if (!NT_SUCCESS(Status))\r
-        {\r
-            DPRINT1("Failed to map process Image\n");\r
-            ObDereferenceObject(Section);\r
-            goto exit;\r
-        }\r
-        ObDereferenceObject(Section);\r
-\r
-        /* Save the pointer */\r
-        Process->SectionBaseAddress = ImageBase;\r
-\r
-        /* Determine the image file name and save it to EPROCESS */\r
-        DPRINT("Getting Image name\n");\r
-        FileName = Section->FileObject->FileName;\r
-        szSrc = (PWCHAR)(FileName.Buffer + (FileName.Length / sizeof(WCHAR)) - 1);\r
-\r
-        while(szSrc >= FileName.Buffer)\r
-        {\r
-            if(*szSrc == L'\\')\r
-            {\r
-                szSrc++;\r
-                break;\r
-            }\r
-            else\r
-            {\r
-                szSrc--;\r
-                lnFName++;\r
-            }\r
-        }\r
-\r
-        /* Copy the to the process and truncate it to 15 characters if necessary */\r
-        DPRINT("Copying and truncating\n");\r
-        szDest = Process->ImageFileName;\r
-        lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1);\r
-        while(lnFName-- > 0) *(szDest++) = (UCHAR)*(szSrc++);\r
-\r
-        /* Return status to caller */\r
-        return Status;\r
-    }\r
-\r
-exit:\r
-    /* Unlock the Address Space */\r
-    DPRINT("Unlocking\n");\r
-    MmUnlockAddressSpace(ProcessAddressSpace);\r
-\r
-    /* Return status to caller */\r
-    return Status;\r
-}\r
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/mm/process.c
+ * PURPOSE:         Memory functions related to Processes
+ *
+ * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <internal/debug.h>
+
+extern ULONG NtMajorVersion;
+extern ULONG NtMinorVersion;
+extern ULONG NtOSCSDVersion;
+extern ULONG NtGlobalFlag;
+
+#define MM_HIGHEST_VAD_ADDRESS \
+    (PVOID)((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (16 * PAGE_SIZE))
+
+/* FUNCTIONS *****************************************************************/
+
+PVOID
+STDCALL
+MiCreatePebOrTeb(PROS_EPROCESS Process,
+                 PVOID BaseAddress)
+{
+    NTSTATUS Status;
+    PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;
+    PMEMORY_AREA MemoryArea;
+    PHYSICAL_ADDRESS BoundaryAddressMultiple;
+    PVOID AllocatedBase = BaseAddress;
+    BoundaryAddressMultiple.QuadPart = 0;
+
+    /* Acquire the Lock */
+    MmLockAddressSpace(ProcessAddressSpace);
+
+    /*
+     * Create a Peb or Teb.
+     * Loop until it works, decreasing by PAGE_SIZE each time. The logic here
+     * is that a PEB allocation should never fail since the address is free,
+     * while TEB allocation can fail, and we should simply try the address
+     * below. Is there a nicer way of doing this automagically? (ie: findning)
+     * a gap region? -- Alex
+     */
+    do {
+        DPRINT("Trying to allocate: %x\n", AllocatedBase);
+        Status = MmCreateMemoryArea(ProcessAddressSpace,
+                                    MEMORY_AREA_PEB_OR_TEB,
+                                    &AllocatedBase,
+                                    PAGE_SIZE,
+                                    PAGE_READWRITE,
+                                    &MemoryArea,
+                                    TRUE,
+                                    0,
+                                    BoundaryAddressMultiple);
+        AllocatedBase = RVA(AllocatedBase, -PAGE_SIZE);
+    } while (Status != STATUS_SUCCESS);
+
+    /* Initialize the Region */
+    MmInitializeRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,
+                       PAGE_SIZE,
+                       MEM_COMMIT,
+                       PAGE_READWRITE);
+
+    /* Reserve the pages */
+    MmReserveSwapPages(PAGE_SIZE);
+
+    /* Unlock Address Space */
+    DPRINT("Returning\n");
+    MmUnlockAddressSpace(ProcessAddressSpace);
+    return RVA(AllocatedBase, PAGE_SIZE);
+}
+
+VOID
+MiFreeStackPage(PVOID Context,
+                MEMORY_AREA* MemoryArea,
+                PVOID Address,
+                PFN_TYPE Page,
+                SWAPENTRY SwapEntry,
+                BOOLEAN Dirty)
+{
+    ASSERT(SwapEntry == 0);
+    if (Page) MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
+}
+
+VOID
+STDCALL
+MmDeleteKernelStack(PVOID Stack,
+                    BOOLEAN GuiStack)
+{
+    /* Lock the Address Space */
+    MmLockAddressSpace(MmGetKernelAddressSpace());
+
+    /* Delete the Stack */
+    MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
+                          Stack,
+                          MiFreeStackPage,
+                          NULL);
+
+    /* Unlock the Address Space */
+    MmUnlockAddressSpace(MmGetKernelAddressSpace());
+}
+
+VOID
+STDCALL
+MmDeleteTeb(PROS_EPROCESS Process,
+            PTEB Teb)
+{
+    PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;
+    PMEMORY_AREA MemoryArea;
+
+    /* Lock the Address Space */
+    MmLockAddressSpace(ProcessAddressSpace);
+    
+    MemoryArea = MmLocateMemoryAreaByAddress(ProcessAddressSpace, (PVOID)Teb);
+    if (MemoryArea)
+    {
+       /* Delete the Teb */
+       MmFreeVirtualMemory(Process, MemoryArea);
+    }
+
+    /* Unlock the Address Space */
+    MmUnlockAddressSpace(ProcessAddressSpace);
+}
+
+PVOID
+STDCALL
+MmCreateKernelStack(BOOLEAN GuiStack)
+{
+    PMEMORY_AREA StackArea;
+    ULONG i;
+    PHYSICAL_ADDRESS BoundaryAddressMultiple;
+    ULONG StackSize = GuiStack ? KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE;
+    PFN_TYPE Page[KERNEL_LARGE_STACK_SIZE / PAGE_SIZE];
+    PVOID KernelStack = NULL;
+    NTSTATUS Status;
+
+    /* Initialize the Boundary Address */
+    BoundaryAddressMultiple.QuadPart = 0;
+
+    /* Lock the Kernel Address Space */
+    MmLockAddressSpace(MmGetKernelAddressSpace());
+
+    /* Create a MAREA for the Kernel Stack */
+    Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
+                                MEMORY_AREA_KERNEL_STACK,
+                                &KernelStack,
+                                StackSize,
+                                PAGE_READWRITE,
+                                &StackArea,
+                                FALSE,
+                                0,
+                                BoundaryAddressMultiple);
+
+    /* Unlock the Address Space */
+    MmUnlockAddressSpace(MmGetKernelAddressSpace());
+
+    /* Check for Success */
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to create thread stack\n");
+        KEBUGCHECK(0);
+    }
+
+    /*
+     * Mark the Stack in use.
+     * Note: Currently we mark all 60KB in use for a GUI Thread.
+     * We should only do this inside MmGrowKernelStack. TODO!
+     */
+    for (i = 0; i < (StackSize / PAGE_SIZE); i++)
+    {
+        Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]);
+    }
+
+    /* Create a Virtual Mapping for it */
+    Status = MmCreateVirtualMapping(NULL,
+                                    KernelStack,
+                                    PAGE_READWRITE,
+                                    Page,
+                                    StackSize / PAGE_SIZE);
+
+    /* Check for success */
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Could not create Virtual Mapping for Kernel Stack\n");
+        KEBUGCHECK(0);
+    }
+
+    /* Return the stack */
+    return KernelStack;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+STDCALL
+MmGrowKernelStack(PVOID StackPointer)
+{
+    PETHREAD Thread = PsGetCurrentThread();
+
+    /* Make sure we have reserved space for our grow */
+    ASSERT(((PCHAR)Thread->Tcb.StackBase - (PCHAR)Thread->Tcb.StackLimit) <=
+           (KERNEL_LARGE_STACK_SIZE + PAGE_SIZE));
+
+    /* 
+     * We'll give you three more pages.
+     * NOTE: See note in MmCreateKernelStack. These pages are already being reserved.
+     * It would be more efficient to only grow them (commit them) here.
+     */
+    Thread->Tcb.StackLimit -= KERNEL_STACK_SIZE;
+
+    /* Return success */
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+STDCALL
+MmCreatePeb(PROS_EPROCESS Process)
+{
+    PPEB Peb = NULL;
+    LARGE_INTEGER SectionOffset;
+    SIZE_T ViewSize = 0;
+    PVOID TableBase = NULL;
+    PIMAGE_NT_HEADERS NtHeaders;
+    PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
+    NTSTATUS Status;
+    KAFFINITY ProcessAffinityMask = 0;
+    SectionOffset.QuadPart = (ULONGLONG)0;
+    DPRINT("MmCreatePeb\n");
+
+    /* Allocate the PEB */
+    Peb = MiCreatePebOrTeb(Process,
+                           (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
+    ASSERT(Peb == (PVOID)0x7FFDF000);
+
+    /* Map NLS Tables */
+    DPRINT("Mapping NLS\n");
+    Status = MmMapViewOfSection(NlsSectionObject,
+                                (PEPROCESS)Process,
+                                &TableBase,
+                                0,
+                                0,
+                                &SectionOffset,
+                                &ViewSize,
+                                ViewShare,
+                                MEM_TOP_DOWN,
+                                PAGE_READONLY);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);
+        return(Status);
+    }
+    DPRINT("TableBase %p  ViewSize %lx\n", TableBase, ViewSize);
+
+    /* Attach to Process */
+    KeAttachProcess(&Process->Pcb);
+
+    /* Initialize the PEB */
+    DPRINT("Allocated: %x\n", Peb);
+    RtlZeroMemory(Peb, sizeof(PEB));
+
+    /* Set up data */
+    DPRINT("Setting up PEB\n");
+    Peb->ImageBaseAddress = Process->SectionBaseAddress;
+    Peb->InheritedAddressSpace = 0;
+    Peb->Mutant = NULL;
+
+    /* NLS */
+    Peb->AnsiCodePageData = (char*)TableBase + NlsAnsiTableOffset;
+    Peb->OemCodePageData = (char*)TableBase + NlsOemTableOffset;
+    Peb->UnicodeCaseTableData = (char*)TableBase + NlsUnicodeTableOffset;
+
+    /* Default Version Data (could get changed below) */
+    Peb->OSMajorVersion = NtMajorVersion;
+    Peb->OSMinorVersion = NtMinorVersion;
+    Peb->OSBuildNumber = 2195;
+    Peb->OSPlatformId = 2; /* VER_PLATFORM_WIN32_NT */
+    Peb->OSCSDVersion = NtOSCSDVersion;
+
+    /* Heap and Debug Data */
+    Peb->NumberOfProcessors = KeNumberProcessors;
+    Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE);
+    Peb->NtGlobalFlag = NtGlobalFlag;
+    /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
+    Peb->HeapSegmentCommit = MmHeapSegmentCommit;
+    Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
+    Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;*/
+    Peb->NumberOfHeaps = 0;
+    Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID);
+    Peb->ProcessHeaps = (PVOID*)Peb + 1;
+
+    /* Image Data */
+    if ((NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress)))
+    {
+        /* Get the Image Config Data too */
+        ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
+                                                       TRUE,
+                                                       IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
+                                                       &ViewSize);
+
+        /* Write subsystem data */
+        Peb->ImageSubSystem = NtHeaders->OptionalHeader.Subsystem;
+        Peb->ImageSubSystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
+        Peb->ImageSubSystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
+
+        /* Write Version Data */
+        if (NtHeaders->OptionalHeader.Win32VersionValue)
+        {
+            Peb->OSMajorVersion = NtHeaders->OptionalHeader.Win32VersionValue & 0xFF;
+            Peb->OSMinorVersion = (NtHeaders->OptionalHeader.Win32VersionValue >> 8) & 0xFF;
+            Peb->OSBuildNumber = (NtHeaders->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF;
+
+            /* Lie about the version if requested */
+            if (ImageConfigData && ImageConfigData->CSDVersion)
+            {
+                Peb->OSCSDVersion = ImageConfigData->CSDVersion;
+            }
+
+            /* Set the Platform ID */
+            Peb->OSPlatformId = (NtHeaders->OptionalHeader.Win32VersionValue >> 30) ^ 2;
+        }
+
+        /* Check for affinity override */
+        if (ImageConfigData && ImageConfigData->ProcessAffinityMask)
+        {
+            ProcessAffinityMask = ImageConfigData->ProcessAffinityMask;
+        }
+
+        /* Check if the image is not safe for SMP */
+        if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
+        {
+            /* FIXME: Choose one randomly */
+            Peb->ImageProcessAffinityMask = 1;
+        }
+        else
+        {
+            /* Use affinity from Image Header */
+            Peb->ImageProcessAffinityMask = ProcessAffinityMask;
+        }
+    }
+
+    /* Misc data */
+    Peb->SessionId = Process->Session;
+    Process->Peb = Peb;
+
+    /* Detach from the Process */
+    KeDetachProcess();
+
+    DPRINT("MmCreatePeb: Peb created at %p\n", Peb);
+    return STATUS_SUCCESS;
+}
+
+PTEB
+STDCALL
+MmCreateTeb(PROS_EPROCESS Process,
+            PCLIENT_ID ClientId,
+            PINITIAL_TEB InitialTeb)
+{
+    PTEB Teb;
+    BOOLEAN Attached = FALSE;
+
+    /* Attach to the process */
+    DPRINT("MmCreateTeb\n");
+    if (Process != (PROS_EPROCESS)PsGetCurrentProcess())
+    {
+        /* Attach to Target */
+        KeAttachProcess(&Process->Pcb);
+        Attached = TRUE;
+    }
+
+    /* Allocate the TEB */
+    Teb = MiCreatePebOrTeb(Process,
+                           (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
+
+    /* Initialize the PEB */
+    RtlZeroMemory(Teb, sizeof(TEB));
+
+    /* Set TIB Data */
+    Teb->Tib.ExceptionList = (PVOID)0xFFFFFFFF;
+    Teb->Tib.Version = 1;
+    Teb->Tib.Self = (PNT_TIB)Teb;
+
+    /* Set TEB Data */
+    Teb->Cid = *ClientId;
+    Teb->RealClientId = *ClientId;
+    Teb->ProcessEnvironmentBlock = Process->Peb;
+    Teb->CurrentLocale = PsDefaultThreadLocaleId;
+
+    /* Store stack information from InitialTeb */
+    if(InitialTeb != NULL)
+    {
+        Teb->Tib.StackBase = InitialTeb->StackBase;
+        Teb->Tib.StackLimit = InitialTeb->StackLimit;
+        Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
+    }
+
+    /* Return TEB Address */
+    DPRINT("Allocated: %x\n", Teb);
+    if (Attached) KeDetachProcess();
+    return Teb;
+}
+
+NTSTATUS
+STDCALL
+MmCreateProcessAddressSpace(IN PROS_EPROCESS Process,
+                            IN PROS_SECTION_OBJECT Section OPTIONAL)
+{
+    NTSTATUS Status;
+    PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;
+    PVOID BaseAddress;
+    PMEMORY_AREA MemoryArea;
+    PHYSICAL_ADDRESS BoundaryAddressMultiple;
+    SIZE_T ViewSize = 0;
+    PVOID ImageBase = 0;
+    BoundaryAddressMultiple.QuadPart = 0;
+
+    /* Initialize the Addresss Space */
+    MmInitializeAddressSpace(Process, ProcessAddressSpace);
+
+    /* Acquire the Lock */
+    MmLockAddressSpace(ProcessAddressSpace);
+
+    /* Protect the highest 64KB of the process address space */
+    BaseAddress = (PVOID)MmUserProbeAddress;
+    Status = MmCreateMemoryArea(ProcessAddressSpace,
+                                MEMORY_AREA_NO_ACCESS,
+                                &BaseAddress,
+                                0x10000,
+                                PAGE_NOACCESS,
+                                &MemoryArea,
+                                FALSE,
+                                0,
+                                BoundaryAddressMultiple);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to protect last 64KB\n");
+        goto exit;
+     }
+
+    /* Protect the 60KB above the shared user page */
+    BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE;
+    Status = MmCreateMemoryArea(ProcessAddressSpace,
+                                MEMORY_AREA_NO_ACCESS,
+                                &BaseAddress,
+                                0x10000 - PAGE_SIZE,
+                                PAGE_NOACCESS,
+                                &MemoryArea,
+                                FALSE,
+                                0,
+                                BoundaryAddressMultiple);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to protect the memory above the shared user page\n");
+        goto exit;
+     }
+
+    /* Create the shared data page */
+    BaseAddress = (PVOID)USER_SHARED_DATA;
+    Status = MmCreateMemoryArea(ProcessAddressSpace,
+                                MEMORY_AREA_SHARED_DATA,
+                                &BaseAddress,
+                                PAGE_SIZE,
+                                PAGE_EXECUTE_READ,
+                                &MemoryArea,
+                                FALSE,
+                                0,
+                                BoundaryAddressMultiple);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to create Shared User Data\n");
+        goto exit;
+     }
+
+    /* Check if there's a Section Object */
+    if (Section)
+    {
+        UNICODE_STRING FileName;
+        PWCHAR szSrc;
+        PCHAR szDest;
+        USHORT lnFName = 0;
+
+        /* Unlock the Address Space */
+        DPRINT("Unlocking\n");
+        MmUnlockAddressSpace(ProcessAddressSpace);
+
+        DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n",
+                 Section, Process, &ImageBase);
+        Status = MmMapViewOfSection(Section,
+                                    (PEPROCESS)Process,
+                                    (PVOID*)&ImageBase,
+                                    0,
+                                    0,
+                                    NULL,
+                                    &ViewSize,
+                                    0,
+                                    MEM_COMMIT,
+                                    PAGE_READWRITE);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to map process Image\n");
+            return Status;
+        }
+
+        /* Save the pointer */
+        Process->SectionBaseAddress = ImageBase;
+
+        /* Determine the image file name and save it to EPROCESS */
+        DPRINT("Getting Image name\n");
+        FileName = Section->FileObject->FileName;
+        szSrc = (PWCHAR)(FileName.Buffer + (FileName.Length / sizeof(WCHAR)) - 1);
+
+        while(szSrc >= FileName.Buffer)
+        {
+            if(*szSrc == L'\\')
+            {
+                szSrc++;
+                break;
+            }
+            else
+            {
+                szSrc--;
+                lnFName++;
+            }
+        }
+
+        /* Copy the to the process and truncate it to 15 characters if necessary */
+        DPRINT("Copying and truncating\n");
+        szDest = Process->ImageFileName;
+        lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1);
+        while(lnFName-- > 0) *(szDest++) = (UCHAR)*(szSrc++);
+
+        /* Return status to caller */
+        return Status;
+    }
+
+exit:
+    /* Unlock the Address Space */
+    DPRINT("Unlocking\n");
+    MmUnlockAddressSpace(ProcessAddressSpace);
+
+    /* Return status to caller */
+    return Status;
+}