[NTOS]: Reimplement MmCreateProcessAddressSpace in ARM3. Basically the same as before...
[reactos.git] / reactos / ntoskrnl / mm / ARM3 / procsup.c
index 919b3e4..946485a 100644 (file)
 #define MODULE_INVOLVED_IN_ARM3
 #include "../ARM3/miarm.h"
 
+extern MM_SYSTEMSIZE MmSystemSize;
+
 /* PRIVATE FUNCTIONS **********************************************************/
 
+VOID
+NTAPI
+MiRosTakeOverPebTebRanges(IN PEPROCESS Process)
+{
+    NTSTATUS Status;
+    PMEMORY_AREA MemoryArea;
+    PHYSICAL_ADDRESS BoundaryAddressMultiple;
+    PVOID AllocatedBase = (PVOID)MI_LOWEST_VAD_ADDRESS;
+    BoundaryAddressMultiple.QuadPart = 0;
+
+    Status = MmCreateMemoryArea(&Process->Vm,
+                                MEMORY_AREA_OWNED_BY_ARM3,
+                                &AllocatedBase,
+                                ((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - 1) -
+                                (ULONG_PTR)MI_LOWEST_VAD_ADDRESS,
+                                PAGE_READWRITE,
+                                &MemoryArea,
+                                TRUE,
+                                0,
+                                BoundaryAddressMultiple);
+    ASSERT(NT_SUCCESS(Status));
+}
+
+NTSTATUS
+NTAPI
+MiCreatePebOrTeb(IN PEPROCESS Process,
+                 IN ULONG Size,
+                 OUT PULONG_PTR Base)
+{
+    PETHREAD Thread = PsGetCurrentThread();
+    PMMVAD_LONG Vad;
+    NTSTATUS Status;
+    ULONG RandomCoeff;
+    ULONG_PTR StartAddress, EndAddress;
+    LARGE_INTEGER CurrentTime;
+    
+    /* Allocate a VAD */
+    Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV');
+    if (!Vad) return STATUS_NO_MEMORY;
+    
+    /* Setup the primary flags with the size, and make it commited, private, RW */
+    Vad->u.LongFlags = 0;
+    Vad->u.VadFlags.CommitCharge = BYTES_TO_PAGES(Size);
+    Vad->u.VadFlags.MemCommit = TRUE;
+    Vad->u.VadFlags.PrivateMemory = TRUE;
+    Vad->u.VadFlags.Protection = MM_READWRITE;
+    Vad->u.VadFlags.NoChange = TRUE;
+    
+    /* Setup the secondary flags to make it a secured, writable, long VAD */
+    Vad->u2.LongFlags2 = 0;
+    Vad->u2.VadFlags2.OneSecured = TRUE;
+    Vad->u2.VadFlags2.LongVad = TRUE;
+    Vad->u2.VadFlags2.ReadOnly = FALSE;
+    
+    /* Lock the process address space */
+    KeAcquireGuardedMutex(&Process->AddressCreationLock);
+
+    /* Check if this is a PEB creation */
+    if (Size == sizeof(PEB))
+    {
+        /* Start at the highest valid address */
+        StartAddress = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1;
+
+        /* Select the random coefficient */
+        KeQueryTickCount(&CurrentTime);
+        CurrentTime.LowPart &= ((64 * _1KB) >> PAGE_SHIFT) - 1;
+        if (CurrentTime.LowPart <= 1) CurrentTime.LowPart = 2;
+        RandomCoeff = CurrentTime.LowPart << PAGE_SHIFT;
+
+        /* Select the highest valid address minus the random coefficient */
+        StartAddress -= RandomCoeff;
+        EndAddress = StartAddress + ROUND_TO_PAGES(Size) - 1;
+
+        /* See if this VA range can be obtained */
+        if (!MiCheckForConflictingNode(StartAddress >> PAGE_SHIFT,
+                                       EndAddress >> PAGE_SHIFT,
+                                       &Process->VadRoot))
+        {
+            /* No conflict, use this address */
+            *Base = StartAddress;
+            goto AfterFound;
+        }
+    }
+    
+    /* For TEBs, or if a PEB location couldn't be found, scan the VAD root */
+    Status = MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size),
+                                             (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1,
+                                             PAGE_SIZE,
+                                             &Process->VadRoot,
+                                             Base);
+    ASSERT(NT_SUCCESS(Status));
+    
+AfterFound:
+    /* Validate that it came from the VAD ranges */
+    ASSERT(*Base >= (ULONG_PTR)MI_LOWEST_VAD_ADDRESS);
+    
+    /* Build the rest of the VAD now */
+    Vad->StartingVpn = (*Base) >> PAGE_SHIFT;
+    Vad->EndingVpn =  ((*Base) + Size - 1) >> PAGE_SHIFT;
+    Vad->u3.Secured.StartVpn = *Base;
+    Vad->u3.Secured.EndVpn = (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1);
+    
+    /* FIXME: Should setup VAD bitmap */
+    Status = STATUS_SUCCESS;
+
+    /* Pretend as if we own the working set */
+    MiLockProcessWorkingSet(Process, Thread);
+    
+    /* Insert the VAD */
+    ASSERT(Vad->EndingVpn >= Vad->StartingVpn);
+    Process->VadRoot.NodeHint = Vad;
+    MiInsertNode((PVOID)Vad, &Process->VadRoot);
+    
+    /* Release the working set */
+    MiUnlockProcessWorkingSet(Process, Thread);
+
+    /* Release the address space lock */
+    KeReleaseGuardedMutex(&Process->AddressCreationLock);
+
+    /* Return the status */
+    DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base, Process->ImageFileName);
+    return Status;
+}
+
+VOID
+NTAPI
+MmDeleteTeb(IN PEPROCESS Process,
+            IN PTEB Teb)
+{
+    /* Oops J */
+    DPRINT("Leaking 4KB at thread exit, this will be fixed later\n");
+}
+
 VOID
 NTAPI
 MmDeleteKernelStack(IN PVOID StackBase,
                     IN BOOLEAN GuiStack)
 {
     PMMPTE PointerPte;
-    PFN_NUMBER StackPages;
+    PFN_NUMBER StackPages, PageFrameNumber;//, PageTableFrameNumber;
+    PMMPFN Pfn1;//, Pfn2;
     ULONG i;
+    KIRQL OldIrql;
     
     //
     // This should be the guard page, so decrement by one
@@ -39,6 +176,9 @@ MmDeleteKernelStack(IN PVOID StackBase,
     StackPages = BYTES_TO_PAGES(GuiStack ?
                                 KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE);
     
+    /* Acquire the PFN lock */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+                            
     //
     // Loop them
     //
@@ -49,10 +189,22 @@ MmDeleteKernelStack(IN PVOID StackBase,
         //
         if (PointerPte->u.Hard.Valid == 1)
         {
-            //
-            // Nuke it
-            //
-            MmReleasePageMemoryConsumer(MC_NPPOOL, PFN_FROM_PTE(PointerPte));
+            /* Get the PTE's page */
+            PageFrameNumber = PFN_FROM_PTE(PointerPte);
+            Pfn1 = MiGetPfnEntry(PageFrameNumber);
+#if 0 // ARM3 might not own the page table, so don't take this risk. Leak it instead!
+            /* Now get the page of the page table mapping it */
+            PageTableFrameNumber = Pfn1->u4.PteFrame;
+            Pfn2 = MiGetPfnEntry(PageTableFrameNumber);
+            
+            /* Remove a shared reference, since the page is going away */
+            MiDecrementShareCount(Pfn2, PageTableFrameNumber);
+#endif
+            /* Set the special pending delete marker */
+            Pfn1->PteAddress = (PMMPTE)((ULONG_PTR)Pfn1->PteAddress | 1);
+            
+            /* And now delete the actual stack page */
+            MiDecrementShareCount(Pfn1, PageFrameNumber);
         }
         
         //
@@ -66,6 +218,9 @@ MmDeleteKernelStack(IN PVOID StackBase,
     //
     ASSERT(PointerPte->u.Hard.Valid == 0);
     
+    /* Release the PFN lock */
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
     //
     // Release the PTEs
     //
@@ -80,7 +235,7 @@ MmCreateKernelStack(IN BOOLEAN GuiStack,
     PFN_NUMBER StackPtes, StackPages;
     PMMPTE PointerPte, StackPte;
     PVOID BaseAddress;
-    MMPTE TempPte;
+    MMPTE TempPte, InvalidPte;
     KIRQL OldIrql;
     PFN_NUMBER PageFrameIndex;
     ULONG i;
@@ -124,13 +279,12 @@ MmCreateKernelStack(IN BOOLEAN GuiStack,
     if (GuiStack) PointerPte += BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE -
                                                KERNEL_LARGE_STACK_COMMIT);
     
-    //
-    // Setup the template stack PTE
-    //
-    TempPte = HyperTemplatePte;
-    MI_MAKE_LOCAL_PAGE(&TempPte);
-    MI_MAKE_DIRTY_PAGE(&TempPte);
-    TempPte.u.Hard.PageFrameNumber = 0;
+
+    /* Setup the temporary invalid PTE */
+    MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
+
+    /* Setup the template stack PTE */
+    MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, PointerPte + 1, MM_READWRITE, 0);
     
     //
     // Acquire the PFN DB lock
@@ -146,20 +300,22 @@ MmCreateKernelStack(IN BOOLEAN GuiStack,
         // Next PTE
         //
         PointerPte++;
-        ASSERT(PointerPte->u.Hard.Valid == 0);
         
-        //
-        // Get a page
-        //
-        PageFrameIndex = MmAllocPage(MC_NPPOOL, 0);
-        TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
+        /* Get a page and write the current invalid PTE */
+        PageFrameIndex = MiRemoveAnyPage(0);
+        MI_WRITE_INVALID_PTE(PointerPte, InvalidPte);
+
+        /* Initialize the PFN entry for this page */
+        MiInitializePfn(PageFrameIndex, PointerPte, 1);
         
-        //
-        // Write it
-        //
-        *PointerPte = TempPte;
+        /* Write the valid PTE */
+        TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
+        MI_WRITE_VALID_PTE(PointerPte, TempPte);
     }
-    
+
+    // Bug #4835
+    (VOID)InterlockedExchangeAddUL(&MiMemoryConsumers[MC_NPPOOL].PagesUsed, StackPages);
+
     //
     // Release the PFN lock
     //
@@ -180,7 +336,7 @@ MmGrowKernelStackEx(IN PVOID StackPointer,
     PMMPTE LimitPte, NewLimitPte, LastPte;
     PFN_NUMBER StackPages;
     KIRQL OldIrql;
-    MMPTE TempPte;
+    MMPTE TempPte, InvalidPte;
     PFN_NUMBER PageFrameIndex;
     
     //
@@ -221,39 +377,31 @@ MmGrowKernelStackEx(IN PVOID StackPointer,
     LimitPte--;
     StackPages = (LimitPte - NewLimitPte + 1);
     
-    //
-    // Setup the template stack PTE
-    //
-    TempPte = HyperTemplatePte;
-    MI_MAKE_LOCAL_PAGE(&TempPte);
-    MI_MAKE_DIRTY_PAGE(&TempPte);
-    TempPte.u.Hard.PageFrameNumber = 0;
+    /* Setup the temporary invalid PTE */
+    MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
     
     //
     // Acquire the PFN DB lock
     //
     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-    
+
     //
     // Loop each stack page
     //
     while (LimitPte >= NewLimitPte)
     {
-        //
-        // Sanity check
-        //
-        ASSERT(LimitPte->u.Hard.Valid == 0);
+        /* Get a page and write the current invalid PTE */
+        PageFrameIndex = MiRemoveAnyPage(0);
+        MI_WRITE_INVALID_PTE(LimitPte, InvalidPte);
+
+        /* Initialize the PFN entry for this page */
+        MiInitializePfn(PageFrameIndex, LimitPte, 1);
         
-        //
-        // Get a page
-        //
-        PageFrameIndex = MmAllocPage(MC_NPPOOL, 0);
-        TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
+        /* Setup the template stack PTE */
+        MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, LimitPte, MM_READWRITE, PageFrameIndex);
         
-        //
-        // Write it
-        //
-        *LimitPte-- = TempPte;
+        /* Write the valid PTE */
+        MI_WRITE_VALID_PTE(LimitPte--, TempPte);
     }
     
     //
@@ -278,4 +426,703 @@ MmGrowKernelStack(IN PVOID StackPointer)
     return MmGrowKernelStackEx(StackPointer, KERNEL_LARGE_STACK_COMMIT);
 }
 
+NTSTATUS
+NTAPI
+MmSetMemoryPriorityProcess(IN PEPROCESS Process,
+                           IN UCHAR MemoryPriority)
+{
+    UCHAR OldPriority;
+    
+    //
+    // Check if we have less then 16MB of Physical Memory
+    //
+    if ((MmSystemSize == MmSmallSystem) &&
+        (MmNumberOfPhysicalPages < ((15 * 1024 * 1024) / PAGE_SIZE)))
+    {
+        //
+        // Always use background priority
+        //
+        MemoryPriority = MEMORY_PRIORITY_BACKGROUND;
+    }
+    
+    //
+    // Save the old priority and update it
+    //
+    OldPriority = (UCHAR)Process->Vm.Flags.MemoryPriority;
+    Process->Vm.Flags.MemoryPriority = MemoryPriority;
+    
+    //
+    // Return the old priority
+    //
+    return OldPriority;
+}
+
+LCID
+NTAPI
+MmGetSessionLocaleId(VOID)
+{
+    PEPROCESS Process;
+    PAGED_CODE();
+    
+    //
+    // Get the current process
+    //
+    Process = PsGetCurrentProcess();
+    
+    //
+    // Check if it's the Session Leader
+    //
+    if (Process->Vm.Flags.SessionLeader)
+    {
+        //
+        // Make sure it has a valid Session
+        //
+        if (Process->Session)
+        {
+            //
+            // Get the Locale ID
+            //
+#if ROS_HAS_SESSIONS
+            return ((PMM_SESSION_SPACE)Process->Session)->LocaleId;
+#endif
+        }
+    }
+    
+    //
+    // Not a session leader, return the default
+    //
+    return PsDefaultThreadLocaleId;
+}
+
+NTSTATUS
+NTAPI
+MmCreatePeb(IN PEPROCESS Process,
+            IN PINITIAL_PEB InitialPeb,
+            OUT PPEB *BasePeb)
+{
+    PPEB Peb = NULL;
+    LARGE_INTEGER SectionOffset;
+    SIZE_T ViewSize = 0;
+    PVOID TableBase = NULL;
+    PIMAGE_NT_HEADERS NtHeaders;
+    PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
+    NTSTATUS Status;
+    USHORT Characteristics;
+    KAFFINITY ProcessAffinityMask = 0;
+    SectionOffset.QuadPart = (ULONGLONG)0;
+    *BasePeb = NULL;
+    
+    //
+    // Attach to Process
+    //
+    KeAttachProcess(&Process->Pcb);
+       
+    //
+    // Allocate the PEB
+    //
+    Status = MiCreatePebOrTeb(Process, sizeof(PEB), (PULONG_PTR)&Peb);
+    ASSERT(NT_SUCCESS(Status));
+
+    //
+    // Map NLS Tables
+    //
+    Status = MmMapViewOfSection(ExpNlsSectionPointer,
+                                (PEPROCESS)Process,
+                                &TableBase,
+                                0,
+                                0,
+                                &SectionOffset,
+                                &ViewSize,
+                                ViewShare,
+                                MEM_TOP_DOWN,
+                                PAGE_READONLY);
+    if (!NT_SUCCESS(Status)) return Status;
+    
+    //
+    // Use SEH in case we can't load the PEB
+    //
+    _SEH2_TRY
+    {
+        //
+        // Initialize the PEB
+        //
+        RtlZeroMemory(Peb, sizeof(PEB));
+        
+        //
+        // Set up data
+        //
+        Peb->ImageBaseAddress = Process->SectionBaseAddress;
+        Peb->InheritedAddressSpace = InitialPeb->InheritedAddressSpace;
+        Peb->Mutant = InitialPeb->Mutant;
+        Peb->ImageUsesLargePages = InitialPeb->ImageUsesLargePages;
+        
+        //
+        // NLS
+        //
+        Peb->AnsiCodePageData = (PCHAR)TableBase + ExpAnsiCodePageDataOffset;
+        Peb->OemCodePageData = (PCHAR)TableBase + ExpOemCodePageDataOffset;
+        Peb->UnicodeCaseTableData = (PCHAR)TableBase + ExpUnicodeCaseTableDataOffset;
+        
+        //
+        // Default Version Data (could get changed below)
+        //
+        Peb->OSMajorVersion = NtMajorVersion;
+        Peb->OSMinorVersion = NtMinorVersion;
+        Peb->OSBuildNumber = (USHORT)(NtBuildNumber & 0x3FFF);
+        Peb->OSPlatformId = 2; /* VER_PLATFORM_WIN32_NT */
+        Peb->OSCSDVersion = (USHORT)CmNtCSDVersion;
+        
+        //
+        // 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->CriticalSectionTimeout = MmCriticalSectionTimeout;
+         Peb->MinimumStackCommit = MmMinimumStackCommitInBytes;
+         */
+        Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID);
+        Peb->ProcessHeaps = (PVOID*)(Peb + 1);
+        
+        //
+        // Session ID
+        //
+        if (Process->Session) Peb->SessionId = 0; // MmGetSessionId(Process);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        //
+        // Fail
+        //
+        KeDetachProcess();
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+    
+    //
+    // Use SEH in case we can't load the image
+    //
+    _SEH2_TRY
+    {
+        //
+        // Get NT Headers
+        //
+        NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
+        Characteristics = NtHeaders->FileHeader.Characteristics;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        //
+        // Fail
+        //
+        KeDetachProcess();
+        _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT);
+    }
+    _SEH2_END;
+    
+    //
+    // Parse the headers
+    //
+    if (NtHeaders)
+    {
+        //
+        // Use SEH in case we can't load the headers
+        //
+        _SEH2_TRY
+        {
+            //
+            // Get the Image Config Data too
+            //
+            ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
+                                                           TRUE,
+                                                           IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
+                                                           (PULONG)&ViewSize);
+            if (ImageConfigData)
+            {
+                //
+                // Probe it
+                //
+                ProbeForRead(ImageConfigData,
+                             sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
+                             sizeof(ULONG));
+            }
+            
+            //
+            // Write subsystem data
+            //
+            Peb->ImageSubsystem = NtHeaders->OptionalHeader.Subsystem;
+            Peb->ImageSubsystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
+            Peb->ImageSubsystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
+
+            //
+            // Check for version data
+            //
+            if (NtHeaders->OptionalHeader.Win32VersionValue)
+            {
+                //
+                // Extract values and write them
+                //
+                Peb->OSMajorVersion = NtHeaders->OptionalHeader.Win32VersionValue & 0xFF;
+                Peb->OSMinorVersion = (NtHeaders->OptionalHeader.Win32VersionValue >> 8) & 0xFF;
+                Peb->OSBuildNumber = (NtHeaders->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF;
+                Peb->OSPlatformId = (NtHeaders->OptionalHeader.Win32VersionValue >> 30) ^ 2;
+            }
+            
+            //
+            // Process the image config data overrides if specfied
+            //
+            if (ImageConfigData != NULL)
+            {
+                //
+                // Process CSD version override
+                //
+                if (ImageConfigData->CSDVersion)
+                {
+                    //
+                    // Set new data
+                    //
+                    Peb->OSCSDVersion = ImageConfigData->CSDVersion;
+                }
+                
+                //
+                // Process affinity mask ovverride
+                //
+                if (ImageConfigData->ProcessAffinityMask)
+                {
+                    //
+                    // Set new data
+                    //
+                    ProcessAffinityMask = ImageConfigData->ProcessAffinityMask;
+                }
+            }
+            
+            //
+            // Check if this is a UP image
+            if (Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
+            {
+                //
+                // Force it to use CPU 0
+                //
+                Peb->ImageProcessAffinityMask = 0;
+            }
+            else
+            {
+                //
+                // Whatever was configured
+                //
+                Peb->ImageProcessAffinityMask = ProcessAffinityMask;
+            }
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            //
+            // Fail
+            //
+            KeDetachProcess();
+            _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT);
+        }
+        _SEH2_END;
+    }
+    
+    //
+    // Detach from the Process
+    //
+    KeDetachProcess();
+    *BasePeb = Peb;
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+MmCreateTeb(IN PEPROCESS Process,
+            IN PCLIENT_ID ClientId,
+            IN PINITIAL_TEB InitialTeb,
+            OUT PTEB *BaseTeb)
+{
+    PTEB Teb;
+    NTSTATUS Status = STATUS_SUCCESS;
+    *BaseTeb = NULL;
+    
+    //
+    // Attach to Target
+    //
+    KeAttachProcess(&Process->Pcb);
+    
+    //
+    // Allocate the TEB
+    //
+    Status = MiCreatePebOrTeb(Process, sizeof(TEB), (PULONG_PTR)&Teb);
+    ASSERT(NT_SUCCESS(Status));
+    
+    //
+    // Use SEH in case we can't load the TEB
+    //
+    _SEH2_TRY
+    {
+        //
+        // Initialize the PEB
+        //
+        RtlZeroMemory(Teb, sizeof(TEB));
+        
+        //
+        // Set TIB Data
+        //
+        Teb->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
+        Teb->NtTib.Self = (PNT_TIB)Teb;
+        
+        //
+        // Identify this as an OS/2 V3.0 ("Cruiser") TIB
+        //
+        Teb->NtTib.Version = 30 << 8;
+        
+        //
+        // Set TEB Data
+        //
+        Teb->ClientId = *ClientId;
+        Teb->RealClientId = *ClientId;
+        Teb->ProcessEnvironmentBlock = Process->Peb;
+        Teb->CurrentLocale = PsDefaultThreadLocaleId;
+        
+        //
+        // Check if we have a grandparent TEB
+        //
+        if ((InitialTeb->PreviousStackBase == NULL) &&
+            (InitialTeb->PreviousStackLimit == NULL))
+        {
+            //
+            // Use initial TEB values
+            //
+            Teb->NtTib.StackBase = InitialTeb->StackBase;
+            Teb->NtTib.StackLimit = InitialTeb->StackLimit;
+            Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
+        }
+        else
+        {
+            //
+            // Use grandparent TEB values
+            //
+            Teb->NtTib.StackBase = InitialTeb->PreviousStackBase;
+            Teb->NtTib.StackLimit = InitialTeb->PreviousStackLimit;
+        }
+
+        //
+        // Initialize the static unicode string
+        //
+        Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);
+        Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        //
+        // Get error code
+        //
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+
+    //
+    // Return
+    //
+    KeDetachProcess();
+    *BaseTeb = Teb;
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+MmInitializeProcessAddressSpace(IN PEPROCESS Process,
+                                IN PEPROCESS ProcessClone OPTIONAL,
+                                IN PVOID Section OPTIONAL,
+                                IN OUT PULONG Flags,
+                                IN POBJECT_NAME_INFORMATION *AuditName OPTIONAL)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    SIZE_T ViewSize = 0;
+    PVOID ImageBase = 0;
+    PROS_SECTION_OBJECT SectionObject = Section;
+    PMMPTE PointerPte;
+    KIRQL OldIrql;
+    PMMPDE PointerPde;
+    PFN_NUMBER PageFrameNumber;
+    UNICODE_STRING FileName;
+    PWCHAR Source;
+    PCHAR Destination;
+    USHORT Length = 0;
+    
+    /* We should have a PDE */
+    ASSERT(Process->Pcb.DirectoryTableBase[0] != 0);
+    ASSERT(Process->PdeUpdateNeeded == FALSE);
+
+    /* Attach to the process */
+    KeAttachProcess(&Process->Pcb);
+    
+    /* The address space should now been in phase 1 or 0 */
+    ASSERT(Process->AddressSpaceInitialized <= 1);
+    Process->AddressSpaceInitialized = 2;
+
+    /* Initialize the Addresss Space lock */
+    KeInitializeGuardedMutex(&Process->AddressCreationLock);
+    Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
+
+    /* Initialize AVL tree */
+    ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
+    Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
+
+    /* Lock PFN database */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+    /* Setup the PFN for the PDE base of this process */
+    PointerPte = MiAddressToPte(PDE_BASE);
+    PageFrameNumber = PFN_FROM_PTE(PointerPte);
+    MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
+
+    /* Do the same for hyperspace */
+    PointerPde = MiAddressToPde(HYPER_SPACE);
+    PageFrameNumber = PFN_FROM_PTE(PointerPde);
+    MiInitializePfn(PageFrameNumber, PointerPde, TRUE);
+
+    /* Release PFN lock */
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+    /* Lock the VAD, ARM3-owned ranges away */
+    MiRosTakeOverPebTebRanges(Process);
+
+    /* Check if there's a Section Object */
+    if (SectionObject)
+    {
+        /* Determine the image file name and save it to EPROCESS */
+        FileName = SectionObject->FileObject->FileName;
+        Source = (PWCHAR)((PCHAR)FileName.Buffer + FileName.Length);
+        if (FileName.Buffer)
+        {
+            /* Loop the file name*/
+            while (Source > FileName.Buffer)
+            {
+                /* Make sure this isn't a backslash */
+                if (*--Source == OBJ_NAME_PATH_SEPARATOR)
+                {
+                    /* If so, stop it here */
+                    Source++;
+                    break;
+                }
+                else
+                {
+                    /* Otherwise, keep going */
+                    Length++;
+                }
+            }
+        }
+
+        /* Copy the to the process and truncate it to 15 characters if necessary */
+        Destination = Process->ImageFileName;
+        Length = min(Length, sizeof(Process->ImageFileName) - 1);
+        while (Length--) *Destination++ = (UCHAR)*Source++;
+        *Destination = ANSI_NULL;
+
+        /* Check if caller wants an audit name */
+        if (AuditName)
+        {
+            /* Setup the audit name */
+            Status = SeInitializeProcessAuditName(SectionObject->FileObject,
+                                                  FALSE,
+                                                  AuditName);
+            if (!NT_SUCCESS(Status))
+            {
+                /* Fail */
+                KeDetachProcess();
+                return Status;
+            }
+        }
+
+        /* Map the section */
+        Status = MmMapViewOfSection(Section,
+                                    Process,
+                                    (PVOID*)&ImageBase,
+                                    0,
+                                    0,
+                                    NULL,
+                                    &ViewSize,
+                                    0,
+                                    MEM_COMMIT,
+                                    PAGE_READWRITE);
+
+        /* Save the pointer */
+        Process->SectionBaseAddress = ImageBase;
+    }
+    
+    /* Be nice and detach */
+    KeDetachProcess();
+
+    /* Return status to caller */
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+MmInitializeHandBuiltProcess(IN PEPROCESS Process,
+                             IN PULONG_PTR DirectoryTableBase)
+{
+    /* Share the directory base with the idle process */
+    DirectoryTableBase[0] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[0];
+    DirectoryTableBase[1] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[1];
+
+    /* Initialize the Addresss Space */
+    KeInitializeGuardedMutex(&Process->AddressCreationLock);
+    KeInitializeSpinLock(&Process->HyperSpaceLock);
+    Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
+    ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
+    Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
+
+    /* Done */
+    Process->HasAddressSpace = TRUE;//??
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+MmInitializeHandBuiltProcess2(IN PEPROCESS Process)
+{
+    /* Lock the VAD, ARM3-owned ranges away */                            
+    MiRosTakeOverPebTebRanges(Process);
+    return STATUS_SUCCESS;
+}
+
+/* FIXME: Evaluate ways to make this portable yet arch-specific */
+BOOLEAN
+NTAPI
+MmCreateProcessAddressSpace(IN ULONG MinWs,
+                            IN PEPROCESS Process,
+                            OUT PULONG_PTR DirectoryTableBase)
+{
+    KIRQL OldIrql;
+    PFN_NUMBER PdeIndex, HyperIndex;
+    PMMPTE PointerPte;
+    MMPTE TempPte, PdePte;
+    ULONG PdeOffset;
+    PMMPTE SystemTable;
+
+    /* No page colors yet */
+    Process->NextPageColor = 0;
+    
+    /* Setup the hyperspace lock */
+    KeInitializeSpinLock(&Process->HyperSpaceLock);
+
+    /* Lock PFN database */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+    
+    /* Get a page for the PDE */
+    PdeIndex = MiRemoveAnyPage(0);
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+    MiZeroPhysicalPage(PdeIndex);
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+    /* Get a page for hyperspace */
+    HyperIndex = MiRemoveAnyPage(0);
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+    MiZeroPhysicalPage(HyperIndex);
+
+    /* Switch to phase 1 initialization */
+    ASSERT(Process->AddressSpaceInitialized == 0);
+    Process->AddressSpaceInitialized = 1;
+
+    /* Set the base directory pointers */
+    DirectoryTableBase[0] = PdeIndex << PAGE_SHIFT;
+    DirectoryTableBase[1] = HyperIndex << PAGE_SHIFT;
+
+    /* Make sure we don't already have a page directory setup */
+    ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
+
+    /* Insert us into the Mm process list */
+    InsertTailList(&MmProcessList, &Process->MmProcessLinks);
+
+    /* Get a PTE to map the page directory */
+    PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
+    ASSERT(PointerPte != NULL);
+
+    /* Build it */
+    MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte,
+                                PointerPte,
+                                MM_READWRITE,
+                                PdeIndex);
+
+    /* Set it dirty and map it */
+    PdePte.u.Hard.Dirty = TRUE;
+    MI_WRITE_VALID_PTE(PointerPte, PdePte);
+
+    /* Now get the page directory (which we'll double map, so call it a page table */
+    SystemTable = MiPteToAddress(PointerPte);
+
+    /* Copy all the kernel mappings */
+    PdeOffset = MiGetPdeOffset(MmSystemRangeStart);
+
+    RtlCopyMemory(&SystemTable[PdeOffset],
+                  MiAddressToPde(MmSystemRangeStart),
+                  PAGE_SIZE - PdeOffset * sizeof(MMPTE));
+
+    /* Now write the PTE/PDE entry for hyperspace itself */
+    TempPte = ValidKernelPte;
+    TempPte.u.Hard.PageFrameNumber = HyperIndex;
+    PdeOffset = MiGetPdeOffset(HYPER_SPACE);
+    SystemTable[PdeOffset] = TempPte;
+
+    /* Sanity check */
+    PdeOffset++;
+    ASSERT(MiGetPdeOffset(MmHyperSpaceEnd) >= PdeOffset);
+
+    /* Now do the x86 trick of making the PDE a page table itself */
+    PdeOffset = MiGetPdeOffset(PTE_BASE);
+    TempPte.u.Hard.PageFrameNumber = PdeIndex;
+    SystemTable[PdeOffset] = TempPte;
+
+    /* Let go of the system PTE */
+    MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
+    return TRUE;
+}
+
+/* SYSTEM CALLS ***************************************************************/
+
+NTSTATUS
+NTAPI
+NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle,
+                            IN OUT PULONG_PTR NumberOfPages,
+                            IN OUT PULONG_PTR UserPfnArray)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+NtMapUserPhysicalPages(IN PVOID VirtualAddresses,
+                       IN ULONG_PTR NumberOfPages,
+                       IN OUT PULONG_PTR UserPfnArray)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+NtMapUserPhysicalPagesScatter(IN PVOID *VirtualAddresses,
+                              IN ULONG_PTR NumberOfPages,
+                              IN OUT PULONG_PTR UserPfnArray)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+NtFreeUserPhysicalPages(IN HANDLE ProcessHandle,
+                        IN OUT PULONG_PTR NumberOfPages,
+                        IN OUT PULONG_PTR UserPfnArray)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
 /* EOF */