[NTOSKRNL/MM/AMD64]
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Sat, 4 Feb 2012 12:13:53 +0000 (12:13 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Sat, 4 Feb 2012 12:13:53 +0000 (12:13 +0000)
- Implement more of MmCreateProcessAddressSpace
- Acquire pfn lock and use MiRemoveZeroPage in MiGetPteForProcess

svn path=/trunk/; revision=55407

reactos/ntoskrnl/mm/amd64/page.c

index 14000c8..485919b 100644 (file)
@@ -28,7 +28,7 @@ extern MMPTE HyperTemplatePte;
 /* GLOBALS *****************************************************************/
 
 const
-ULONG
+ULONG64
 MmProtectToPteMask[32] =
 {
     //
@@ -151,37 +151,48 @@ MiGetPteForProcess(
         Process && Process != PsGetCurrentProcess())
     {
         UNIMPLEMENTED;
+        __debugbreak();
         return NULL;
     }
     else if (Create)
     {
+        KIRQL OldIrql;
         TmplPte.u.Long = 0;
         TmplPte.u.Flush.Valid = 1;
         TmplPte.u.Flush.Write = 1;
 
+        /* All page table levels of user pages are user owned */
+        TmplPte.u.Flush.Owner = (Address < MmHighestUserAddress) ? 1 : 0;
+
+        /* Lock the PFN database */
+        OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
         /* Get the PXE */
         Pte = MiAddressToPxe(Address);
         if (!Pte->u.Hard.Valid)
         {
-//            TmplPte.u.Hard.PageFrameNumber = MiAllocPage(TRUE);
-            InterlockedExchangePte(Pte, TmplPte);
+            TmplPte.u.Hard.PageFrameNumber = MiRemoveZeroPage(0);
+            MI_WRITE_VALID_PTE(Pte, TmplPte);
         }
 
         /* Get the PPE */
         Pte = MiAddressToPpe(Address);
         if (!Pte->u.Hard.Valid)
         {
-//            TmplPte.u.Hard.PageFrameNumber = MiAllocPage(TRUE);
-            InterlockedExchangePte(Pte, TmplPte);
+            TmplPte.u.Hard.PageFrameNumber = MiRemoveZeroPage(1);
+            MI_WRITE_VALID_PTE(Pte, TmplPte);
         }
 
         /* Get the PDE */
         Pte = MiAddressToPde(Address);
         if (!Pte->u.Hard.Valid)
         {
-//            TmplPte.u.Hard.PageFrameNumber = MiAllocPage(TRUE);
-            InterlockedExchangePte(Pte, TmplPte);
+            TmplPte.u.Hard.PageFrameNumber = MiRemoveZeroPage(2);
+            MI_WRITE_VALID_PTE(Pte, TmplPte);
         }
+
+        /* Unlock PFN database */
+        KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
     }
     else
     {
@@ -529,6 +540,8 @@ MmCreateVirtualMappingUnsafe(
     TmplPte.u.Hard.Valid = 1;
     MiSetPteProtection(&TmplPte, PageProtection);
 
+    TmplPte.u.Flush.Owner = (Address < MmHighestUserAddress) ? 1 : 0;
+
 //__debugbreak();
 
     for (i = 0; i < PageCount; i++)
@@ -537,7 +550,7 @@ MmCreateVirtualMappingUnsafe(
 
         Pte = MiGetPteForProcess(Process, Address, TRUE);
 
-DPRINT1("MmCreateVirtualMappingUnsafe, Address=%p, TmplPte=%p, Pte=%p\n",
+DPRINT("MmCreateVirtualMappingUnsafe, Address=%p, TmplPte=%p, Pte=%p\n",
         Address, TmplPte.u.Long, Pte);
 
         if (InterlockedExchangePte(Pte, TmplPte))
@@ -577,6 +590,44 @@ MmCreateVirtualMapping(PEPROCESS Process,
     return MmCreateVirtualMappingUnsafe(Process, Address, Protect, Pages, PageCount);
 }
 
+static PMMPTE
+MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
+{
+    __debugbreak();
+    return 0;
+}
+
+BOOLEAN MmUnmapPageTable(PMMPTE Pt)
+{
+    ASSERT(FALSE);
+    return 0;
+}
+
+static ULONG64 MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
+{
+    MMPTE Pte, *PointerPte;
+
+    PointerPte = MmGetPageTableForProcess(Process, Address, FALSE);
+    if (PointerPte)
+    {
+        Pte = *PointerPte;
+        MmUnmapPageTable(PointerPte);
+        return Pte.u.Long;
+    }
+    return 0;
+}
+
+VOID
+NTAPI
+MmGetPageFileMapping(
+    PEPROCESS Process,
+    PVOID Address,
+    SWAPENTRY* SwapEntry)
+{
+       ULONG64 Entry = MmGetPageEntryForProcess(Process, Address);
+       *SwapEntry = Entry >> 1;
+}
+
 BOOLEAN
 NTAPI
 MmCreateProcessAddressSpace(IN ULONG MinWs,
@@ -584,14 +635,19 @@ MmCreateProcessAddressSpace(IN ULONG MinWs,
                             OUT PULONG_PTR DirectoryTableBase)
 {
     KIRQL OldIrql;
-    PFN_NUMBER TableBasePfn, HyperPfn;
-    PMMPTE PointerPte;
+    PFN_NUMBER TableBasePfn, HyperPfn, HyperPdPfn, HyperPtPfn, WorkingSetPfn;
+    PMMPTE SystemPte;
     MMPTE TempPte, PdePte;
     ULONG TableIndex;
-    PMMPTE SystemTable;
+    PMMPTE PageTablePointer;
+
+    /* Make sure we don't already have a page directory setup */
+    ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
+    ASSERT(Process->Pcb.DirectoryTableBase[1] == 0);
+    ASSERT(Process->WorkingSetPage == 0);
 
-    /* No page colors yet */
-    Process->NextPageColor = 0;
+    /* Choose a process color */
+    Process->NextPageColor = (USHORT)RtlRandom(&MmProcessColorSeed);
 
     /* Setup the hyperspace lock */
     KeInitializeSpinLock(&Process->HyperSpaceLock);
@@ -599,67 +655,97 @@ MmCreateProcessAddressSpace(IN ULONG MinWs,
     /* Lock PFN database */
     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
 
-    /* Get a page for the table base and for hyperspace */
-    TableBasePfn = MiRemoveAnyPage(0);
-    HyperPfn = MiRemoveAnyPage(0);
+    /* Get a page for the table base and one for hyper space. The PFNs for
+       these pages will be initialized in MmInitializeProcessAddressSpace,
+       when we are already attached to the process. */
+    TableBasePfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
+    HyperPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
+    HyperPdPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
+    HyperPtPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
+    WorkingSetPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
 
     /* Release PFN lock */
     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
 
-    /* Zero both pages */
-    MiZeroPhysicalPage(TableBasePfn);
+    /* Zero pages */ /// FIXME:
     MiZeroPhysicalPage(HyperPfn);
+    MiZeroPhysicalPage(WorkingSetPfn);
 
     /* Set the base directory pointers */
+    Process->WorkingSetPage = WorkingSetPfn;
     DirectoryTableBase[0] = TableBasePfn << PAGE_SHIFT;
     DirectoryTableBase[1] = HyperPfn << 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,
-                                TableBasePfn);
+    SystemPte = MiReserveSystemPtes(1, SystemPteSpace);
+    ASSERT(SystemPte != NULL);
 
-    /* Set it dirty and map it */
-    PdePte.u.Hard.Dirty = TRUE;
-    MI_WRITE_VALID_PTE(PointerPte, PdePte);
+    /* Get its address */
+    PageTablePointer = MiPteToAddress(SystemPte);
 
-    /* Now get the page directory (which we'll double map, so call it a page table */
-    SystemTable = MiPteToAddress(PointerPte);
+    /* Build the PTE for the page directory and map it */
+    PdePte = ValidKernelPte;
+    PdePte.u.Hard.PageFrameNumber = TableBasePfn;
+    *SystemPte = PdePte;
 
-    /* Copy all the kernel mappings */
-    TableIndex = MiAddressToPxi(MmSystemRangeStart);
+/// architecture specific
+    //MiInitializePageDirectoryForProcess(
 
-    RtlCopyMemory(&SystemTable[TableIndex],
-                  MiAddressToPxe(MmSystemRangeStart),
+    /* Copy the kernel mappings and zero out the rest */
+    TableIndex = PXE_PER_PAGE / 2;
+    RtlZeroMemory(PageTablePointer, TableIndex * sizeof(MMPTE));
+    RtlCopyMemory(PageTablePointer + TableIndex,
+                  MiAddressToPxe(0) + TableIndex,
                   PAGE_SIZE - TableIndex * sizeof(MMPTE));
 
-    /* Now write the PTE/PDE entry for hyperspace itself */
+    /* Sanity check */
+    ASSERT(MiAddressToPxi(MmHyperSpaceEnd) >= TableIndex);
+
+    /* Setup a PTE for the page directory mappings */
     TempPte = ValidKernelPte;
-    TempPte.u.Hard.PageFrameNumber = HyperPfn;
+
+    /* Update the self mapping of the PML4 */
+    TableIndex = MiAddressToPxi((PVOID)PXE_SELFMAP);
+    TempPte.u.Hard.PageFrameNumber = TableBasePfn;
+    PageTablePointer[TableIndex] = TempPte;
+
+    /* Write the PML4 entry for hyperspace */
     TableIndex = MiAddressToPxi((PVOID)HYPER_SPACE);
-    SystemTable[TableIndex] = TempPte;
+    TempPte.u.Hard.PageFrameNumber = HyperPfn;
+    PageTablePointer[TableIndex] = TempPte;
 
-    /* Sanity check */
-    ASSERT(MiAddressToPxi(MmHyperSpaceEnd) > TableIndex);
+    /* Map the hyperspace PDPT to the system PTE */
+    PdePte.u.Hard.PageFrameNumber = HyperPfn;
+    *SystemPte = PdePte;
+    __invlpg(PageTablePointer);
 
-    /* Now do the x86 trick of making the PDE a page table itself */
-    TableIndex = MiAddressToPxi((PVOID)PTE_BASE);
-    TempPte.u.Hard.PageFrameNumber = TableBasePfn;
-    SystemTable[TableIndex] = TempPte;
+    /* Write the hyperspace entry for the first PD */
+    TempPte.u.Hard.PageFrameNumber = HyperPdPfn;
+    PageTablePointer[0] = TempPte;
+
+    /* Map the hyperspace PD to the system PTE */
+    PdePte.u.Hard.PageFrameNumber = HyperPdPfn;
+    *SystemPte = PdePte;
+    __invlpg(PageTablePointer);
+
+    /* Write the hyperspace entry for the first PT */
+    TempPte.u.Hard.PageFrameNumber = HyperPtPfn;
+    PageTablePointer[0] = TempPte;
+
+    /* Map the hyperspace PT to the system PTE */
+    PdePte.u.Hard.PageFrameNumber = HyperPtPfn;
+    *SystemPte = PdePte;
+    __invlpg(PageTablePointer);
+
+    /* Write the hyperspace PTE for the working set list index */
+    TempPte.u.Hard.PageFrameNumber = WorkingSetPfn;
+    TableIndex = MiAddressToPti(MmWorkingSetList);
+    PageTablePointer[TableIndex] = TempPte;
+
+/// end architecture specific
 
-    /* Let go of the system PTE */
-    MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
+    /* Release the system PTE */
+    MiReleaseSystemPtes(SystemPte, 1, SystemPteSpace);
 
     /* Switch to phase 1 initialization */
     ASSERT(Process->AddressSpaceInitialized == 0);