[CMAKE]
[reactos.git] / ntoskrnl / mm / ARM3 / procsup.c
index e12ad48..aec5af6 100644 (file)
 #define MODULE_INVOLVED_IN_ARM3
 #include "../ARM3/miarm.h"
 
-extern MM_SYSTEMSIZE MmSystemSize;
+/* GLOBALS ********************************************************************/
 
-PVOID
-NTAPI
-MiCreatePebOrTeb(PEPROCESS Process,
-                 PVOID BaseAddress);
+ULONG MmProcessColorSeed = 0x12345678;
+PMMWSL MmWorkingSetList;
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
+VOID
+NTAPI
+MiRosTakeOverPebTebRanges(IN PEPROCESS Process)
+{
+    NTSTATUS Status;
+    PMEMORY_AREA MemoryArea;
+    PHYSICAL_ADDRESS BoundaryAddressMultiple;
+    PVOID AllocatedBase = (PVOID)USER_SHARED_DATA;
+    BoundaryAddressMultiple.QuadPart = 0;
+
+    Status = MmCreateMemoryArea(&Process->Vm,
+                                MEMORY_AREA_OWNED_BY_ARM3,
+                                &AllocatedBase,
+                                ((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - 1) -
+                                (ULONG_PTR)USER_SHARED_DATA,
+                                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;
+    TABLE_SEARCH_RESULT Result = TableFoundNode;
+    PMMADDRESS_NODE Parent;
+    
+    /* 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;
+
+        /* Try to find something below the random upper margin */
+        Result = MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size),
+                                                 EndAddress,
+                                                 PAGE_SIZE,
+                                                 &Process->VadRoot,
+                                                 Base,
+                                                 &Parent);
+    }
+
+    /* Check for success. TableFoundNode means nothing free. */
+    if (Result == TableFoundNode)
+    {
+        /* For TEBs, or if a PEB location couldn't be found, scan the VAD root */
+        Result = MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size),
+                                                 (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1,
+                                                 PAGE_SIZE,
+                                                 &Process->VadRoot,
+                                                 Base,
+                                                 &Parent);
+        /* Bail out, if still nothing free was found */
+        if (Result == TableFoundNode) return STATUS_NO_MEMORY;
+    }
+    
+    /* 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);
+    Vad->u1.Parent = NULL;
+    
+    /* 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;
+    Vad->ControlArea = NULL; // For Memory-Area hack
+    Vad->FirstPrototypePte = NULL;
+    DPRINT("VAD: %p\n", Vad);
+    DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base, Process->ImageFileName);
+    MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
+
+    /* Release the working set */
+    MiUnlockProcessWorkingSet(Process, Thread);
+
+    /* Release the address space lock */
+    KeReleaseGuardedMutex(&Process->AddressCreationLock);
+
+    /* Return the status */
+    return Status;
+}
+
+VOID
+NTAPI
+MmDeleteTeb(IN PEPROCESS Process,
+            IN PTEB Teb)
+{
+    ULONG_PTR TebEnd;
+    PETHREAD Thread = PsGetCurrentThread();
+    PMMVAD Vad;
+    PMM_AVL_TABLE VadTree = &Process->VadRoot;
+    DPRINT("Deleting TEB: %p in %16s\n", Teb, Process->ImageFileName);
+    
+    /* TEB is one page */
+    TebEnd = (ULONG_PTR)Teb + ROUND_TO_PAGES(sizeof(TEB)) - 1;
+    
+    /* Attach to the process */
+    KeAttachProcess(&Process->Pcb);
+    
+    /* Lock the process address space */
+    KeAcquireGuardedMutex(&Process->AddressCreationLock);
+    
+    /* Find the VAD, make sure it's a TEB VAD */
+    Vad = MiLocateAddress(Teb);
+    DPRINT("Removing node for VAD: %lx %lx\n", Vad->StartingVpn, Vad->EndingVpn);
+    ASSERT(Vad != NULL);    
+    if (Vad->StartingVpn != ((ULONG_PTR)Teb >> PAGE_SHIFT))
+    {
+        /* Bug in the AVL code? */
+        DPRINT1("Corrupted VAD!\n");
+    }
+    else
+    {
+        /* Sanity checks for a valid TEB VAD */
+        ASSERT((Vad->StartingVpn == ((ULONG_PTR)Teb >> PAGE_SHIFT) &&
+               (Vad->EndingVpn == (TebEnd >> PAGE_SHIFT))));
+        ASSERT(Vad->u.VadFlags.NoChange == TRUE);
+        ASSERT(Vad->u2.VadFlags2.OneSecured == TRUE);
+        ASSERT(Vad->u2.VadFlags2.MultipleSecured == FALSE);
+
+        /* Lock the working set */
+        MiLockProcessWorkingSet(Process, Thread);
+
+        /* Remove this VAD from the tree */
+        ASSERT(VadTree->NumberGenericTableElements >= 1);
+        MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
+    
+        /* Release the working set */
+        MiUnlockProcessWorkingSet(Process, Thread);
+    
+        /* Remove the VAD */
+        ExFreePool(Vad);
+    }
+
+    /* Release the address space lock */
+    KeReleaseGuardedMutex(&Process->AddressCreationLock);
+    
+    /* Detach */
+    KeDetachProcess();
+}
+
 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
@@ -46,6 +238,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
     //
@@ -56,10 +251,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 */
+            MI_SET_PFN_DELETED(Pfn1);
+            
+            /* And now delete the actual stack page */
+            MiDecrementShareCount(Pfn1, PageFrameNumber);
         }
         
         //
@@ -73,6 +280,9 @@ MmDeleteKernelStack(IN PVOID StackBase,
     //
     ASSERT(PointerPte->u.Hard.Valid == 0);
     
+    /* Release the PFN lock */
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
     //
     // Release the PTEs
     //
@@ -87,7 +297,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;
@@ -131,13 +341,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 = ValidKernelPte;
-    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
@@ -153,23 +362,21 @@ MmCreateKernelStack(IN BOOLEAN GuiStack,
         // Next PTE
         //
         PointerPte++;
-        ASSERT(PointerPte->u.Hard.Valid == 0);
         
-        //
-        // Get a page
-        //
-        PageFrameIndex = MmAllocPage(MC_NPPOOL);
-        TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
+        /* Get a page and write the current invalid PTE */
+        MI_SET_USAGE(MI_USAGE_KERNEL_STACK);
+        MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
+        PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
+        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
     //
@@ -188,9 +395,8 @@ MmGrowKernelStackEx(IN PVOID StackPointer,
 {
     PKTHREAD Thread = KeGetCurrentThread();
     PMMPTE LimitPte, NewLimitPte, LastPte;
-    PFN_NUMBER StackPages;
     KIRQL OldIrql;
-    MMPTE TempPte;
+    MMPTE TempPte, InvalidPte;
     PFN_NUMBER PageFrameIndex;
     
     //
@@ -229,41 +435,34 @@ MmGrowKernelStackEx(IN PVOID StackPointer,
     // Calculate the number of new pages
     //
     LimitPte--;
-    StackPages = (LimitPte - NewLimitPte + 1);
     
-    //
-    // Setup the template stack PTE
-    //
-    TempPte = ValidKernelPte;
-    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 */
+        MI_SET_USAGE(MI_USAGE_KERNEL_STACK_EXPANSION);
+        MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
+        PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
+        MI_WRITE_INVALID_PTE(LimitPte, InvalidPte);
+
+        /* Initialize the PFN entry for this page */
+        MiInitializePfn(PageFrameIndex, LimitPte, 1);
         
-        //
-        // Get a page
-        //
-        PageFrameIndex = MmAllocPage(MC_NPPOOL);
-        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);
     }
     
     //
@@ -382,10 +581,9 @@ MmCreatePeb(IN PEPROCESS Process,
     //
     // Allocate the PEB
     //
-    Peb = MiCreatePebOrTeb(Process,
-                           (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
-    ASSERT(Peb == (PVOID)0x7FFDF000);
-    
+    Status = MiCreatePebOrTeb(Process, sizeof(PEB), (PULONG_PTR)&Peb);
+    ASSERT(NT_SUCCESS(Status));
+
     //
     // Map NLS Tables
     //
@@ -503,7 +701,7 @@ MmCreatePeb(IN PEPROCESS Process,
             ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
                                                            TRUE,
                                                            IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
-                                                           &ViewSize);
+                                                           (PULONG)&ViewSize);
             if (ImageConfigData)
             {
                 //
@@ -517,9 +715,9 @@ MmCreatePeb(IN PEPROCESS Process,
             //
             // Write subsystem data
             //
-            Peb->ImageSubSystem = NtHeaders->OptionalHeader.Subsystem;
-            Peb->ImageSubSystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
-            Peb->ImageSubSystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
+            Peb->ImageSubsystem = NtHeaders->OptionalHeader.Subsystem;
+            Peb->ImageSubsystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
+            Peb->ImageSubsystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
 
             //
             // Check for version data
@@ -618,9 +816,8 @@ MmCreateTeb(IN PEPROCESS Process,
     //
     // Allocate the TEB
     //
-    Teb = MiCreatePebOrTeb(Process,
-                           (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
-    if (!Teb) return STATUS_INSUFFICIENT_RESOURCES;
+    Status = MiCreatePebOrTeb(Process, sizeof(TEB), (PULONG_PTR)&Teb);
+    ASSERT(NT_SUCCESS(Status));
     
     //
     // Use SEH in case we can't load the TEB
@@ -635,13 +832,13 @@ MmCreateTeb(IN PEPROCESS Process,
         //
         // Set TIB Data
         //
-        Teb->Tib.ExceptionList = EXCEPTION_CHAIN_END;
-        Teb->Tib.Self = (PNT_TIB)Teb;
+        Teb->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
+        Teb->NtTib.Self = (PNT_TIB)Teb;
         
         //
         // Identify this as an OS/2 V3.0 ("Cruiser") TIB
         //
-        Teb->Tib.Version = 30 << 8;
+        Teb->NtTib.Version = 30 << 8;
         
         //
         // Set TEB Data
@@ -660,8 +857,8 @@ MmCreateTeb(IN PEPROCESS Process,
             //
             // Use initial TEB values
             //
-            Teb->Tib.StackBase = InitialTeb->StackBase;
-            Teb->Tib.StackLimit = InitialTeb->StackLimit;
+            Teb->NtTib.StackBase = InitialTeb->StackBase;
+            Teb->NtTib.StackLimit = InitialTeb->StackLimit;
             Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
         }
         else
@@ -669,8 +866,8 @@ MmCreateTeb(IN PEPROCESS Process,
             //
             // Use grandparent TEB values
             //
-            Teb->Tib.StackBase = InitialTeb->PreviousStackBase;
-            Teb->Tib.StackLimit = InitialTeb->PreviousStackLimit;
+            Teb->NtTib.StackBase = InitialTeb->PreviousStackBase;
+            Teb->NtTib.StackLimit = InitialTeb->PreviousStackLimit;
         }
 
         //
@@ -696,6 +893,441 @@ MmCreateTeb(IN PEPROCESS Process,
     return Status;
 }
 
+VOID
+NTAPI
+MiInitializeWorkingSetList(IN PEPROCESS CurrentProcess)
+{
+    PMMPFN Pfn1;
+
+    /* Setup some bogus list data */
+    MmWorkingSetList->LastEntry = CurrentProcess->Vm.MinimumWorkingSetSize;
+    MmWorkingSetList->HashTable = NULL;
+    MmWorkingSetList->HashTableSize = 0;
+    MmWorkingSetList->NumberOfImageWaiters = 0;
+    MmWorkingSetList->Wsle = (PVOID)0xDEADBABE;
+    MmWorkingSetList->VadBitMapHint = 1;
+    MmWorkingSetList->HashTableStart = (PVOID)0xBADAB00B;
+    MmWorkingSetList->HighestPermittedHashAddress = (PVOID)0xCAFEBABE;
+    MmWorkingSetList->FirstFree = 1;
+    MmWorkingSetList->FirstDynamic = 2;
+    MmWorkingSetList->NextSlot = 3;
+    MmWorkingSetList->LastInitializedWsle = 4;
+    
+    /* The rule is that the owner process is always in the FLINK of the PDE's PFN entry */
+    Pfn1 = MiGetPfnEntry(MiAddressToPte(PDE_BASE)->u.Hard.PageFrameNumber);
+    ASSERT(Pfn1->u4.PteFrame == MiGetPfnEntryIndex(Pfn1));
+    Pfn1->u1.Event = (PKEVENT)CurrentProcess;
+}
+
+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;
+    MMPTE TempPte;
+    
+    /* 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);
+    
+    /* Setup the PFN for the PTE for the working set */
+    PointerPte = MiAddressToPte(MI_WORKING_SET_LIST);
+    MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, MM_READWRITE, 0);
+    ASSERT(PointerPte->u.Long != 0);
+    PageFrameNumber = PFN_FROM_PTE(PointerPte);
+    MI_WRITE_INVALID_PTE(PointerPte, DemandZeroPte);
+    MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
+    TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
+    MI_WRITE_VALID_PTE(PointerPte, TempPte);
+
+    /* Now initialize the working set list */
+    MiInitializeWorkingSetList(Process);
+
+    /* Sanity check */
+    ASSERT(Process->PhysicalVadRoot == NULL);
+
+    /* 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
+INIT_FUNCTION
+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
+INIT_FUNCTION
+MmInitializeHandBuiltProcess2(IN PEPROCESS Process)
+{
+    /* Lock the VAD, ARM3-owned ranges away */                            
+    MiRosTakeOverPebTebRanges(Process);
+    return STATUS_SUCCESS;
+}
+
+#ifdef _M_IX86
+/* 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, WsListIndex;
+    PMMPTE PointerPte;
+    MMPTE TempPte, PdePte;
+    ULONG PdeOffset;
+    PMMPTE SystemTable, HyperTable;
+    ULONG Color;
+    PMMPFN Pfn1;
+
+    /* Choose a process color */
+    Process->NextPageColor = RtlRandom(&MmProcessColorSeed);
+    
+    /* Setup the hyperspace lock */
+    KeInitializeSpinLock(&Process->HyperSpaceLock);
+
+    /* Lock PFN database */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+    
+    /* Get a zero page for the PDE, if possible */
+    Color = MI_GET_NEXT_PROCESS_COLOR(Process);
+    MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY);
+    PdeIndex = MiRemoveZeroPageSafe(Color);
+    if (!PdeIndex)
+    {
+        /* No zero pages, grab a free one */
+        PdeIndex = MiRemoveAnyPage(Color);
+        
+        /* Zero it outside the PFN lock */
+        KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+        MiZeroPhysicalPage(PdeIndex);
+        OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+    }
+    
+    /* Get a zero page for hyperspace, if possible */
+    MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY);
+    Color = MI_GET_NEXT_PROCESS_COLOR(Process);
+    HyperIndex = MiRemoveZeroPageSafe(Color);
+    if (!HyperIndex)
+    {
+        /* No zero pages, grab a free one */
+        HyperIndex = MiRemoveAnyPage(Color);
+        
+        /* Zero it outside the PFN lock */
+        KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+        MiZeroPhysicalPage(HyperIndex);
+        OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+    }
+
+    /* Get a zero page for the woring set list, if possible */
+    MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
+    Color = MI_GET_NEXT_PROCESS_COLOR(Process);
+    WsListIndex = MiRemoveZeroPageSafe(Color);
+    if (!WsListIndex)
+    {
+        /* No zero pages, grab a free one */
+        WsListIndex = MiRemoveAnyPage(Color);
+        
+        /* Zero it outside the PFN lock */
+        KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+        MiZeroPhysicalPage(WsListIndex);
+    }
+    else
+    {
+        /* Release the PFN lock */
+        KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+    }
+
+    /* Switch to phase 1 initialization */
+    ASSERT(Process->AddressSpaceInitialized == 0);
+    Process->AddressSpaceInitialized = 1;
+
+    /* Set the base directory pointers */
+    Process->WorkingSetPage = WsListIndex;
+    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);
+    
+    /* Get a PTE to map hyperspace */
+    PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
+    ASSERT(PointerPte != NULL);
+
+    /* Build it */
+    MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte,
+                                PointerPte,
+                                MM_READWRITE,
+                                HyperIndex);
+
+    /* Set it dirty and map it */
+    PdePte.u.Hard.Dirty = TRUE;
+    MI_WRITE_VALID_PTE(PointerPte, PdePte);
+
+    /* Now get hyperspace's page table */
+    HyperTable = MiPteToAddress(PointerPte);
+
+    /* Now write the PTE/PDE entry for the working set list index itself */
+    TempPte = ValidKernelPte;
+    TempPte.u.Hard.PageFrameNumber = WsListIndex;
+    PdeOffset = MiAddressToPteOffset(MmWorkingSetList);
+    HyperTable[PdeOffset] = TempPte;
+
+    /* Let go of the system PTE */
+    MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
+
+    /* Save the PTE address of the page directory itself */
+    Pfn1 = MiGetPfnEntry(PdeIndex);
+    Pfn1->PteAddress = (PMMPTE)PDE_BASE;
+
+    /* 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;
+}
+#endif
+
+VOID
+NTAPI
+MmCleanProcessAddressSpace(IN PEPROCESS Process)
+{
+    PMMVAD Vad;
+    PMM_AVL_TABLE VadTree;
+    PETHREAD Thread = PsGetCurrentThread();
+    
+    /* Only support this */
+    ASSERT(Process->AddressSpaceInitialized == 2);
+    
+    /* Lock the process address space from changes */
+    MmLockAddressSpace(&Process->Vm);
+    
+    /* VM is deleted now */
+    Process->VmDeleted = TRUE;
+    
+    /* Enumerate the VADs */
+    VadTree = &Process->VadRoot;
+    while (VadTree->NumberGenericTableElements)
+    {
+        /* Grab the current VAD */
+        Vad = (PMMVAD)VadTree->BalancedRoot.RightChild;
+
+        /* Lock the working set */
+        MiLockProcessWorkingSet(Process, Thread);
+
+        /* Remove this VAD from the tree */
+        ASSERT(VadTree->NumberGenericTableElements >= 1);
+        MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
+
+        /* Only regular VADs supported for now */
+        ASSERT(Vad->u.VadFlags.VadType == VadNone);
+        
+        /* Check if this is a section VAD */
+        if (!(Vad->u.VadFlags.PrivateMemory) && (Vad->ControlArea))
+        {
+            /* Remove the view */
+            MiRemoveMappedView(Process, Vad);
+        }
+        else
+        {
+            /* Delete the addresses */
+            MiDeleteVirtualAddresses(Vad->StartingVpn << PAGE_SHIFT,
+                                     (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1),
+                                     Vad);
+        
+            /* Release the working set */
+            MiUnlockProcessWorkingSet(Process, Thread);
+        }
+        
+        /* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */
+        if (Vad->u.VadFlags.Spare == 1)
+        {
+            /* Set a flag so MmDeleteMemoryArea knows to free, but not to remove */
+            Vad->u.VadFlags.Spare = 2;
+            continue;
+        }
+        
+        /* Free the VAD memory */
+        ExFreePool(Vad);
+    }
+    
+    /* Release the address space */
+    MmUnlockAddressSpace(&Process->Vm);
+}
+
 /* SYSTEM CALLS ***************************************************************/
 
 NTSTATUS