From a1908d10b4fe376d5ebc4036fdf74b562ca8060b Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Sun, 8 Nov 2009 02:39:47 +0000 Subject: [PATCH] [MM] Implement amd64 versions for MiIsHyperspaceAddress, MiFlushTlb, MiGetPteForProcess, MiGetPteValueForProcess, MmGetPfnForProcess, MmGetPhysicalAddress, MmIsPagePresent, MmIsPageSwapEntry, MmIsDirtyPage, MmGetPageProtect, MmSetPageProtect, MmSetCleanPage, MmSetDirtyPage, MmDeleteVirtualMapping svn path=/branches/ros-amd64-bringup/; revision=44024 --- reactos/ntoskrnl/mm/amd64/page.c | 436 ++++++++++++++++++++++++------- 1 file changed, 344 insertions(+), 92 deletions(-) diff --git a/reactos/ntoskrnl/mm/amd64/page.c b/reactos/ntoskrnl/mm/amd64/page.c index a517f006fcc..29e76537158 100644 --- a/reactos/ntoskrnl/mm/amd64/page.c +++ b/reactos/ntoskrnl/mm/amd64/page.c @@ -1,5 +1,5 @@ /* - * COPYRIGHT: See COPYING in the top level directory + * COPYRIGHT: GPL, See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/mm/amd64/page.c * PURPOSE: Low level memory managment manipulation @@ -26,9 +26,292 @@ ULONG64 MmGlobalKernelPageDirectory[512]; /* PRIVATE FUNCTIONS *******************************************************/ +BOOLEAN +FORCEINLINE +MiIsHyperspaceAddress(PVOID Address) +{ + return ((ULONG64)Address >= MI_HYPER_SPACE_START && + (ULONG64)Address <= MI_HYPER_SPACE_END); +} + +VOID +MiFlushTlb(PMMPTE Pte, PVOID Address) +{ + if (MiIsHyperspaceAddress(Pte)) + { + MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pte)); + } + else + { + __invlpg(Address); + } +} + +static +PMMPTE +MiGetPteForProcess( + PEPROCESS Process, + PVOID Address, + BOOLEAN Create) +{ + PMMPTE Pte; + + /* Check if we need hypersapce mapping */ + if (Address < MmSystemRangeStart && + Process && Process != PsGetCurrentProcess()) + { + UNIMPLEMENTED; + return NULL; + } + else if (Create) + { + /* Get the PXE */ + Pte = MiAddressToPxe(Address); + if (!Pte->u.Hard.Valid) + InterlockedBitTestAndSet64(&Pte->u.Long, 0); + + /* Get the PPE */ + Pte = MiAddressToPpe(Address); + if (!Pte->u.Hard.Valid) + InterlockedBitTestAndSet64(&Pte->u.Long, 0); + + /* Get the PDE */ + Pte = MiAddressToPde(Address); + if (!Pte->u.Hard.Valid) + InterlockedBitTestAndSet64(&Pte->u.Long, 0); + + /* Get the PTE */ + Pte = MiAddressToPte(Address); + + return Pte; + } + else + { + /* Get the PXE */ + Pte = MiAddressToPxe(Address); + if (!Pte->u.Hard.Valid) + return NULL; + + /* Get the PPE */ + Pte = MiAddressToPpe(Address); + if (Pte->u.Hard.Valid) + return NULL; + + /* Get the PDE */ + Pte = MiAddressToPde(Address); + if (Pte->u.Hard.Valid) + return NULL; + + /* Get the PTE */ + Pte = MiAddressToPte(Address); + + return Pte; + } + + return 0; +} + +static +ULONG64 +MiGetPteValueForProcess( + PEPROCESS Process, + PVOID Address) +{ + PMMPTE Pte; + ULONG64 PteValue; + + Pte = MiGetPteForProcess(Process, Address, FALSE); + PteValue = Pte ? Pte->u.Long : 0; + + if (MiIsHyperspaceAddress(Pte)) + MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pte)); + + return PteValue; +} + /* FUNCTIONS ***************************************************************/ +PFN_TYPE +NTAPI +MmGetPfnForProcess(PEPROCESS Process, + PVOID Address) +{ + MMPTE Pte; + Pte.u.Long = MiGetPteValueForProcess(Process, Address); + return Pte.u.Hard.Valid ? Pte.u.Hard.PageFrameNumber : 0; +} + +PHYSICAL_ADDRESS +NTAPI +MmGetPhysicalAddress(PVOID Address) +{ + PHYSICAL_ADDRESS p; + MMPTE Pte; + + Pte.u.Long = MiGetPteValueForProcess(NULL, Address); + if (Pte.u.Hard.Valid) + { + p.QuadPart = Pte.u.Hard.PageFrameNumber * PAGE_SIZE; + p.u.LowPart |= (ULONG_PTR)Address & (PAGE_SIZE - 1); + } + else + { + p.QuadPart = 0; + } + + return p; +} + +BOOLEAN +NTAPI +MmIsPagePresent(PEPROCESS Process, PVOID Address) +{ + MMPTE Pte; + Pte.u.Long = MiGetPteValueForProcess(Process, Address); + return Pte.u.Hard.Valid; +} + +BOOLEAN +NTAPI +MmIsPageSwapEntry(PEPROCESS Process, PVOID Address) +{ + MMPTE Pte; + Pte.u.Long = MiGetPteValueForProcess(Process, Address); + return Pte.u.Hard.Valid && Pte.u.Soft.Transition; +} + +BOOLEAN +NTAPI +MmIsDirtyPage(PEPROCESS Process, PVOID Address) +{ + MMPTE Pte; + Pte.u.Long = MiGetPteValueForProcess(Process, Address); + return Pte.u.Hard.Valid && Pte.u.Hard.Dirty; +} + +ULONG +NTAPI +MmGetPageProtect(PEPROCESS Process, PVOID Address) +{ + MMPTE Pte; + ULONG Protect; + + Pte.u.Long = MiGetPteValueForProcess(Process, Address); + + if (!Pte.u.Flush.Valid) + { + Protect = PAGE_NOACCESS; + } + else if (Pte.u.Flush.NoExecute) + { + if (Pte.u.Flush.CopyOnWrite) + Protect = PAGE_WRITECOPY; + else if (Pte.u.Flush.Write) + Protect = PAGE_READWRITE; + else + Protect = PAGE_READONLY; + } + else + { + if (Pte.u.Flush.CopyOnWrite) + Protect = PAGE_EXECUTE_WRITECOPY; + else if (Pte.u.Flush.Write) + Protect = PAGE_EXECUTE_READWRITE; + else + Protect = PAGE_EXECUTE_READ; + } + + if (Pte.u.Flush.CacheDisable) + Protect |= PAGE_NOCACHE; + + if (Pte.u.Flush.WriteThrough) + Protect |= PAGE_WRITETHROUGH; + + // PAGE_GUARD ? + + return Protect; +} + +#define PAGE_EXECUTE_ANY (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY) + +VOID +NTAPI +MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect) +{ + PMMPTE Pte; + MMPTE NewPte; + + if (!(flProtect & PAGE_EXECUTE_ANY)) + NewPte.u.Flush.NoExecute = 1; + + if (flProtect & (PAGE_EXECUTE_WRITECOPY|PAGE_WRITECOPY)) + { + NewPte.u.Flush.Write = 1; + NewPte.u.Flush.CopyOnWrite = 1; + } + + if (flProtect & (PAGE_EXECUTE_READWRITE|PAGE_READWRITE)) + NewPte.u.Flush.Write = 1; + + if (flProtect & PAGE_NOCACHE) + NewPte.u.Flush.CacheDisable = 1; + + if (flProtect & PAGE_WRITETHROUGH) + NewPte.u.Flush.WriteThrough = 1; + + Pte = MiGetPteForProcess(Process, Address, FALSE); + + InterlockedExchange64(&Pte->u.Long, NewPte.u.Long); + + MiFlushTlb(Pte, Address); +} + +VOID +NTAPI +MmSetCleanPage(PEPROCESS Process, PVOID Address) +{ + PMMPTE Pte; + + Pte = MiGetPteForProcess(Process, Address, FALSE); + if (!Pte) + { + KeBugCheckEx(MEMORY_MANAGEMENT, 0x1234, (ULONG64)Address, 0, 0); + } + + /* Ckear the dirty bit */ + if (InterlockedBitTestAndReset64((PVOID)Pte, 6)) + { + if (!MiIsHyperspaceAddress(Pte)) + __invlpg(Address); + } + + MiFlushTlb(Pte, Address); +} + +VOID +NTAPI +MmSetDirtyPage(PEPROCESS Process, PVOID Address) +{ + PMMPTE Pte; + + Pte = MiGetPteForProcess(Process, Address, FALSE); + if (!Pte) + { + KeBugCheckEx(MEMORY_MANAGEMENT, 0x1234, (ULONG64)Address, 0, 0); + } + + /* Ckear the dirty bit */ + if (InterlockedBitTestAndSet64((PVOID)Pte, 6)) + { + if (!MiIsHyperspaceAddress(Pte)) + __invlpg(Address); + } + + MiFlushTlb(Pte, Address); +} + + NTSTATUS NTAPI Mmi386ReleaseMmInfo(PEPROCESS Process) @@ -37,34 +320,6 @@ Mmi386ReleaseMmInfo(PEPROCESS Process) return STATUS_UNSUCCESSFUL; } -NTSTATUS -NTAPI -MmInitializeHandBuiltProcess(IN PEPROCESS Process, - IN PULONG_PTR DirectoryTableBase) -{ - UNIMPLEMENTED; - return STATUS_UNSUCCESSFUL; -} - -BOOLEAN -NTAPI -MmCreateProcessAddressSpace(IN ULONG MinWs, - IN PEPROCESS Process, - IN PULONG_PTR DirectoryTableBase) -{ - UNIMPLEMENTED; - return 0; -} - -PFN_TYPE -NTAPI -MmGetPfnForProcess(PEPROCESS Process, - PVOID Address) -{ - UNIMPLEMENTED; - return 0; -} - VOID NTAPI MmDisableVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN* WasDirty, PPFN_TYPE Page) @@ -81,10 +336,48 @@ MmRawDeleteVirtualMapping(PVOID Address) VOID NTAPI -MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN FreePage, - BOOLEAN* WasDirty, PPFN_TYPE Page) +MmDeleteVirtualMapping( + PEPROCESS Process, + PVOID Address, + BOOLEAN FreePage, + BOOLEAN* WasDirty, + PPFN_TYPE Page) { - UNIMPLEMENTED; + PFN_NUMBER Pfn; + PMMPTE Pte; + MMPTE OldPte; + + Pte = MiGetPteForProcess(Process, Address, FALSE); + + if (Pte) + { + /* Atomically set the entry to zero and get the old value. */ + OldPte.u.Long = InterlockedExchange64(&Pte->u.Long, 0); + + if (OldPte.u.Hard.Valid) + { + Pfn = OldPte.u.Hard.PageFrameNumber; + + if (FreePage) + MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn); + } + else + Pfn = 0; + } + else + { + OldPte.u.Long = 0; + Pfn = 0; + } + + /* Return information to the caller */ + if (WasDirty) + *WasDirty = OldPte.u.Hard.Dirty;; + + if (Page) + *Page = Pfn; + + MiFlushTlb(Pte, Address); } VOID @@ -95,27 +388,6 @@ MmDeletePageFileMapping(PEPROCESS Process, PVOID Address, UNIMPLEMENTED; } -BOOLEAN -NTAPI -MmIsDirtyPage(PEPROCESS Process, PVOID Address) -{ - UNIMPLEMENTED; - return FALSE; -} - -VOID -NTAPI -MmSetCleanPage(PEPROCESS Process, PVOID Address) -{ - UNIMPLEMENTED; -} - -VOID -NTAPI -MmSetDirtyPage(PEPROCESS Process, PVOID Address) -{ - UNIMPLEMENTED; -} VOID NTAPI @@ -124,21 +396,6 @@ MmEnableVirtualMapping(PEPROCESS Process, PVOID Address) UNIMPLEMENTED; } -BOOLEAN -NTAPI -MmIsPagePresent(PEPROCESS Process, PVOID Address) -{ - UNIMPLEMENTED; - return 0; -} - -BOOLEAN -NTAPI -MmIsPageSwapEntry(PEPROCESS Process, PVOID Address) -{ - UNIMPLEMENTED; - return 0; -} NTSTATUS NTAPI @@ -175,30 +432,6 @@ MmCreateVirtualMapping(PEPROCESS Process, return STATUS_UNSUCCESSFUL; } -ULONG -NTAPI -MmGetPageProtect(PEPROCESS Process, PVOID Address) -{ - UNIMPLEMENTED; - return 0; -} - -VOID -NTAPI -MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect) -{ - UNIMPLEMENTED; -} - -PHYSICAL_ADDRESS -NTAPI -MmGetPhysicalAddress(PVOID vaddr) -{ - PHYSICAL_ADDRESS ret = {{0}}; - UNIMPLEMENTED; - return ret; -} - VOID NTAPI MmUpdatePageDir(PEPROCESS Process, PVOID Address, ULONG Size) @@ -244,5 +477,24 @@ MmInitGlobalKernelPageDirectory(VOID) UNIMPLEMENTED; } +NTSTATUS +NTAPI +MmInitializeHandBuiltProcess(IN PEPROCESS Process, + IN PULONG_PTR DirectoryTableBase) +{ + UNIMPLEMENTED; + return STATUS_UNSUCCESSFUL; +} + +BOOLEAN +NTAPI +MmCreateProcessAddressSpace(IN ULONG MinWs, + IN PEPROCESS Process, + IN PULONG_PTR DirectoryTableBase) +{ + UNIMPLEMENTED; + return 0; +} + /* EOF */