[NTOS]: Reimplement MmCreateProcessAddressSpace in ARM3. Basically the same as before...
[reactos.git] / reactos / ntoskrnl / mm / ARM3 / procsup.c
index a2f215a..946485a 100644 (file)
 
 extern MM_SYSTEMSIZE MmSystemSize;
 
-PVOID
+/* PRIVATE FUNCTIONS **********************************************************/
+
+VOID
 NTAPI
-MiCreatePebOrTeb(PEPROCESS Process,
-                 PVOID BaseAddress);
+MiRosTakeOverPebTebRanges(IN PEPROCESS Process)
+{
+    NTSTATUS Status;
+    PMEMORY_AREA MemoryArea;
+    PHYSICAL_ADDRESS BoundaryAddressMultiple;
+    PVOID AllocatedBase = (PVOID)MI_LOWEST_VAD_ADDRESS;
+    BoundaryAddressMultiple.QuadPart = 0;
 
-/* PRIVATE FUNCTIONS **********************************************************/
+    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
@@ -31,8 +159,10 @@ 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 +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
     //
@@ -56,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);
         }
         
         //
@@ -73,6 +218,9 @@ MmDeleteKernelStack(IN PVOID StackBase,
     //
     ASSERT(PointerPte->u.Hard.Valid == 0);
     
+    /* Release the PFN lock */
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
     //
     // Release the PTEs
     //
@@ -87,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;
@@ -131,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 = 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,18 +300,17 @@ 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
@@ -190,7 +336,7 @@ MmGrowKernelStackEx(IN PVOID StackPointer,
     PMMPTE LimitPte, NewLimitPte, LastPte;
     PFN_NUMBER StackPages;
     KIRQL OldIrql;
-    MMPTE TempPte;
+    MMPTE TempPte, InvalidPte;
     PFN_NUMBER PageFrameIndex;
     
     //
@@ -231,39 +377,31 @@ MmGrowKernelStackEx(IN PVOID StackPointer,
     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 */
+        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);
     }
     
     //
@@ -382,10 +520,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 +640,7 @@ MmCreatePeb(IN PEPROCESS Process,
             ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
                                                            TRUE,
                                                            IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
-                                                           &ViewSize);
+                                                           (PULONG)&ViewSize);
             if (ImageConfigData)
             {
                 //
@@ -517,9 +654,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 +755,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 +771,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 +796,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 +805,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 +832,257 @@ MmCreateTeb(IN PEPROCESS Process,
     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