From afd88373ce5abea17e7ded450c2b4952b4d28bb2 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Sat, 4 Feb 2012 12:13:53 +0000 Subject: [PATCH] [NTOSKRNL/MM/AMD64] - Implement more of MmCreateProcessAddressSpace - Acquire pfn lock and use MiRemoveZeroPage in MiGetPteForProcess svn path=/trunk/; revision=55407 --- reactos/ntoskrnl/mm/amd64/page.c | 192 ++++++++++++++++++++++--------- 1 file changed, 139 insertions(+), 53 deletions(-) diff --git a/reactos/ntoskrnl/mm/amd64/page.c b/reactos/ntoskrnl/mm/amd64/page.c index 14000c83ca2..485919bffac 100644 --- a/reactos/ntoskrnl/mm/amd64/page.c +++ b/reactos/ntoskrnl/mm/amd64/page.c @@ -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; - /* No page colors yet */ - Process->NextPageColor = 0; + /* 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); + + /* 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); + SystemPte = MiReserveSystemPtes(1, SystemPteSpace); + ASSERT(SystemPte != NULL); - /* Build it */ - MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte, - PointerPte, - MM_READWRITE, - TableBasePfn); + /* Get its address */ + PageTablePointer = MiPteToAddress(SystemPte); - /* Set it dirty and map it */ - PdePte.u.Hard.Dirty = TRUE; - MI_WRITE_VALID_PTE(PointerPte, PdePte); + /* Build the PTE for the page directory and map it */ + PdePte = ValidKernelPte; + PdePte.u.Hard.PageFrameNumber = TableBasePfn; + *SystemPte = PdePte; - /* Now get the page directory (which we'll double map, so call it a page table */ - SystemTable = MiPteToAddress(PointerPte); +/// architecture specific + //MiInitializePageDirectoryForProcess( - /* Copy all the kernel mappings */ - TableIndex = MiAddressToPxi(MmSystemRangeStart); - - 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 */ - TempPte = ValidKernelPte; - TempPte.u.Hard.PageFrameNumber = HyperPfn; - TableIndex = MiAddressToPxi((PVOID)HYPER_SPACE); - SystemTable[TableIndex] = TempPte; - /* Sanity check */ - ASSERT(MiAddressToPxi(MmHyperSpaceEnd) > TableIndex); + ASSERT(MiAddressToPxi(MmHyperSpaceEnd) >= TableIndex); - /* Now do the x86 trick of making the PDE a page table itself */ - TableIndex = MiAddressToPxi((PVOID)PTE_BASE); + /* Setup a PTE for the page directory mappings */ + TempPte = ValidKernelPte; + + /* Update the self mapping of the PML4 */ + TableIndex = MiAddressToPxi((PVOID)PXE_SELFMAP); TempPte.u.Hard.PageFrameNumber = TableBasePfn; - SystemTable[TableIndex] = TempPte; + PageTablePointer[TableIndex] = TempPte; - /* Let go of the system PTE */ - MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace); + /* Write the PML4 entry for hyperspace */ + TableIndex = MiAddressToPxi((PVOID)HYPER_SPACE); + TempPte.u.Hard.PageFrameNumber = HyperPfn; + PageTablePointer[TableIndex] = TempPte; + + /* Map the hyperspace PDPT to the system PTE */ + PdePte.u.Hard.PageFrameNumber = HyperPfn; + *SystemPte = PdePte; + __invlpg(PageTablePointer); + + /* 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 + + /* Release the system PTE */ + MiReleaseSystemPtes(SystemPte, 1, SystemPteSpace); /* Switch to phase 1 initialization */ ASSERT(Process->AddressSpaceInitialized == 0);