diff --git a/reactos/ntoskrnl/include/internal/i386/mm.h b/reactos/ntoskrnl/include/internal/i386/mm.h index 44867629e4b..67a4ddff817 100644 --- a/reactos/ntoskrnl/include/internal/i386/mm.h +++ b/reactos/ntoskrnl/include/internal/i386/mm.h @@ -20,6 +20,8 @@ PULONG MmGetPageDirectory(VOID); ((PMMPTE)(((((ULONG)(x)) >> 22) << 2) + PAGEDIRECTORY_MAP)) #define MiAddressToPte(x) \ ((PMMPTE)(((((ULONG)(x)) >> 12) << 2) + PAGETABLE_MAP)) +#define MiAddressToPteOffset(x) \ + ((((ULONG)(x)) << 10) >> 22) #define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (1024 * PAGE_SIZE)) #define ADDR_TO_PDE_OFFSET(v) ((((ULONG)(v)) / (1024 * PAGE_SIZE))) diff --git a/reactos/ntoskrnl/include/internal/mm.h b/reactos/ntoskrnl/include/internal/mm.h index ca0ef374933..327c8be9c71 100644 --- a/reactos/ntoskrnl/include/internal/mm.h +++ b/reactos/ntoskrnl/include/internal/mm.h @@ -59,6 +59,13 @@ typedef ULONG PFN_TYPE, *PPFN_TYPE; /* Number of list heads to use */ #define MI_FREE_POOL_LISTS 4 +#define HYPER_SPACE (0xC0400000) + +#define MI_HYPERSPACE_PTES (256 - 1) +#define MI_MAPPING_RANGE_START (ULONG)HYPER_SPACE +#define MI_MAPPING_RANGE_END (MI_MAPPING_RANGE_START + \ + MI_HYPERSPACE_PTES * PAGE_SIZE) + /* Signature of free pool blocks */ #define MM_FREE_POOL_TAG TAG('F', 'r', 'p', 'l') @@ -1060,15 +1067,45 @@ MmZeroPageThreadMain( PVOID Context ); -/* i386/page.c *********************************************************/ +/* hypermap.c *****************************************************************/ + +extern PEPROCESS HyperProcess; +extern KIRQL HyperIrql; PVOID NTAPI -MmCreateHyperspaceMapping(PFN_TYPE Page); +MiMapPageInHyperSpace(IN PEPROCESS Process, + IN PFN_NUMBER Page, + IN PKIRQL OldIrql); -PFN_TYPE +VOID NTAPI -MmDeleteHyperspaceMapping(PVOID Address); +MiUnmapPageInHyperSpace(IN PEPROCESS Process, + IN PVOID Address, + IN KIRQL OldIrql); + +PVOID +NTAPI +MiMapPagesToZeroInHyperSpace(IN PFN_NUMBER Page); + +VOID +NTAPI +MiUnmapPagesInZeroSpace(IN PVOID Address); + +// +// ReactOS Compatibility Layer +// +PVOID +FORCEINLINE +MmCreateHyperspaceMapping(IN PFN_NUMBER Page) +{ + HyperProcess = (PEPROCESS)KeGetCurrentThread()->ApcState.Process; + return MiMapPageInHyperSpace(HyperProcess, Page, &HyperIrql); +} + +#define MmDeleteHyperspaceMapping(x) MiUnmapPageInHyperSpace(HyperProcess, x, HyperIrql); + +/* i386/page.c *********************************************************/ NTSTATUS NTAPI diff --git a/reactos/ntoskrnl/mm/hypermap.c b/reactos/ntoskrnl/mm/hypermap.c new file mode 100644 index 00000000000..6e501249a1c --- /dev/null +++ b/reactos/ntoskrnl/mm/hypermap.c @@ -0,0 +1,197 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: ntoskrnl/mm/hypermap.c + * PURPOSE: Hyperspace Mapping Functionality + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES *******************************************************************/ + +#include +#define NDEBUG +#include + +/* GLOBALS ********************************************************************/ + +PMMPTE MmFirstReservedMappingPte; +PMMPTE MmLastReservedMappingPte; +MMPTE HyperTemplatePte; +PEPROCESS HyperProcess; +KIRQL HyperIrql; + +/* PRIVATE FUNCTIONS **********************************************************/ + +VOID +NTAPI +MiInitHyperSpace(VOID) +{ + PMMPTE PointerPte; + + // + // Get the hyperspace PTE and zero out the page table + // + PointerPte = MiAddressToPte(HYPER_SPACE); + RtlZeroMemory(PointerPte, PAGE_SIZE); + + // + // Setup mapping PTEs + // + MmFirstReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_START); + MmLastReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_END); + MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES; +} + +PVOID +NTAPI +MiMapPageInHyperSpace(IN PEPROCESS Process, + IN PFN_NUMBER Page, + IN PKIRQL OldIrql) +{ + MMPTE TempPte; + PMMPTE PointerPte; + PFN_NUMBER Offset; + PVOID Address; + + // + // Never accept page 0 + // + ASSERT(Page != 0); + + // + // Build the PTE + // + TempPte = HyperTemplatePte; + TempPte.u.Hard.PageFrameNumber = Page; + + // + // Pick the first hyperspace PTE + // + PointerPte = MmFirstReservedMappingPte; + + // + // Acquire the hyperlock + // + ASSERT(Process == PsGetCurrentProcess()); + KeAcquireSpinLock(&Process->HyperSpaceLock, OldIrql); + + // + // Now get the first free PTE + // + Offset = PFN_FROM_PTE(PointerPte); + if (!Offset) + { + // + // Reset the PTEs + // + Offset = MI_HYPERSPACE_PTES; + KeFlushProcessTb(); + } + + // + // Prepare the next PTE + // + PointerPte->u.Hard.PageFrameNumber = Offset - 1; + + // + // Write the current PTE + // + PointerPte += Offset; + ASSERT(PointerPte->u.Hard.Valid == 0); + ASSERT(TempPte.u.Hard.Valid == 1); + *PointerPte = TempPte; + + // + // Return the address + // + Address = (PVOID)((ULONG_PTR)PointerPte << 10); + return Address; +} + +VOID +NTAPI +MiUnmapPageInHyperSpace(IN PEPROCESS Process, + IN PVOID Address, + IN KIRQL OldIrql) +{ + ASSERT(Process == PsGetCurrentProcess()); + + // + // Blow away the mapping + // + MiAddressToPte(Address)->u.Long = 0; + + // + // Release the hyperlock + // + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + KeReleaseSpinLock(&Process->HyperSpaceLock, OldIrql); +} + +PVOID +NTAPI +MiMapPagesToZeroInHyperSpace(IN PFN_NUMBER Page) +{ + MMPTE TempPte; + PMMPTE PointerPte; + PFN_NUMBER Offset; + PVOID Address; + + // + // Never accept page 0 + // + ASSERT(Page != 0); + + // + // Build the PTE + // + TempPte = HyperTemplatePte; + TempPte.u.Hard.PageFrameNumber = Page; + + // + // Pick the first hyperspace PTE + // + PointerPte = MmFirstReservedMappingPte; + + // + // Now get the first free PTE + // + Offset = PFN_FROM_PTE(PointerPte); + if (!Offset) + { + // + // Reset the PTEs + // + Offset = MI_HYPERSPACE_PTES; + KeFlushProcessTb(); + } + + // + // Prepare the next PTE + // + PointerPte->u.Hard.PageFrameNumber = Offset - 1; + + // + // Write the current PTE + // + PointerPte += Offset; + ASSERT(PointerPte->u.Hard.Valid == 0); + ASSERT(TempPte.u.Hard.Valid == 1); + *PointerPte = TempPte; + + // + // Return the address + // + Address = (PVOID)((ULONG_PTR)PointerPte << 10); + return Address; +} + +VOID +NTAPI +MiUnmapPagesInZeroSpace(IN PVOID Address) +{ + // + // Blow away the mapping + // + MiAddressToPte(Address)->u.Long = 0; +} diff --git a/reactos/ntoskrnl/mm/i386/page.c b/reactos/ntoskrnl/mm/i386/page.c index 1ded8dad448..03876d50bfc 100644 --- a/reactos/ntoskrnl/mm/i386/page.c +++ b/reactos/ntoskrnl/mm/i386/page.c @@ -1069,88 +1069,6 @@ MmGetPhysicalAddress(PVOID vaddr) return p; } -PVOID -NTAPI -MmCreateHyperspaceMapping(PFN_TYPE Page) -{ - PVOID Address; - ULONG i; - - ULONG Entry; - PULONG Pte; - Entry = PFN_TO_PTE(Page) | PA_PRESENT | PA_READWRITE; - Pte = (PULONG)MiAddressToPte(HYPERSPACE) + Page % 1024; - if (Page & 1024) - { - for (i = Page % 1024; i < 1024; i++, Pte++) - { - if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0)) - { - break; - } - } - if (i >= 1024) - { - Pte = (PULONG)MiAddressToPte(HYPERSPACE); - for (i = 0; i < Page % 1024; i++, Pte++) - { - if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0)) - { - break; - } - } - if (i >= Page % 1024) - { - KeBugCheck(MEMORY_MANAGEMENT); - } - } - } - else - { - for (i = Page % 1024; (LONG)i >= 0; i--, Pte--) - { - if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0)) - { - break; - } - } - if ((LONG)i < 0) - { - Pte = (PULONG)MiAddressToPte(HYPERSPACE) + 1023; - for (i = 1023; i > Page % 1024; i--, Pte--) - { - if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0)) - { - break; - } - } - if (i <= Page % 1024) - { - KeBugCheck(MEMORY_MANAGEMENT); - } - } - } - Address = (PVOID)((ULONG_PTR)HYPERSPACE + i * PAGE_SIZE); - __invlpg(Address); - return Address; -} - -PFN_TYPE -NTAPI -MmDeleteHyperspaceMapping(PVOID Address) -{ - PFN_TYPE Pfn; - ULONG Entry; - - ASSERT (IS_HYPERSPACE(Address)); - - Entry = InterlockedExchangePte(MiAddressToPte(Address), 0); - Pfn = PTE_TO_PFN(Entry); - - __invlpg(Address); - return Pfn; -} - VOID NTAPI MmUpdatePageDir(PEPROCESS Process, PVOID Address, ULONG Size) @@ -1187,6 +1105,8 @@ MmUpdatePageDir(PEPROCESS Process, PVOID Address, ULONG Size) } } +extern MMPTE HyperTemplatePte; + VOID INIT_FUNCTION NTAPI @@ -1197,6 +1117,12 @@ MmInitGlobalKernelPageDirectory(VOID) DPRINT("MmInitGlobalKernelPageDirectory()\n"); + // + // Setup template + // + HyperTemplatePte.u.Long = (PA_PRESENT | PA_READWRITE | PA_DIRTY | PA_ACCESSED); + if (Ke386GlobalPagesEnabled) HyperTemplatePte.u.Long |= PA_BIT_GLOBAL; + for (i = ADDR_TO_PDE_OFFSET(MmSystemRangeStart); i < 1024; i++) { if (i != ADDR_TO_PDE_OFFSET(PAGETABLE_MAP) && diff --git a/reactos/ntoskrnl/mm/kmap.c b/reactos/ntoskrnl/mm/kmap.c index 16ee67007f6..21ef067d52a 100644 --- a/reactos/ntoskrnl/mm/kmap.c +++ b/reactos/ntoskrnl/mm/kmap.c @@ -22,13 +22,13 @@ MiZeroPage(PFN_TYPE Page) { PVOID TempAddress; - TempAddress = MmCreateHyperspaceMapping(Page); + TempAddress = MiMapPagesToZeroInHyperSpace(Page); if (TempAddress == NULL) { return(STATUS_NO_MEMORY); } memset(TempAddress, 0, PAGE_SIZE); - MmDeleteHyperspaceMapping(TempAddress); + MiUnmapPagesInZeroSpace(TempAddress); return(STATUS_SUCCESS); } diff --git a/reactos/ntoskrnl/mm/mminit.c b/reactos/ntoskrnl/mm/mminit.c index b7ad48b1b1e..319791a69fc 100644 --- a/reactos/ntoskrnl/mm/mminit.c +++ b/reactos/ntoskrnl/mm/mminit.c @@ -351,6 +351,11 @@ MiGetLastKernelAddress(VOID) return LastKrnlPhysAddr << PAGE_SHIFT; } + +VOID +NTAPI +MiInitHyperSpace(VOID); + VOID INIT_FUNCTION NTAPI @@ -434,6 +439,9 @@ MmInit1(VOID) /* Unmap low memory */ MmDeletePageTable(NULL, 0); + + /* Initialize hyperspace */ + MiInitHyperSpace(); /* Intialize memory areas */ MmInitVirtualMemory(); diff --git a/reactos/ntoskrnl/ntoskrnl-generic.rbuild b/reactos/ntoskrnl/ntoskrnl-generic.rbuild index 2f29554d611..273e4824ac0 100644 --- a/reactos/ntoskrnl/ntoskrnl-generic.rbuild +++ b/reactos/ntoskrnl/ntoskrnl-generic.rbuild @@ -365,6 +365,7 @@ cont.c drvlck.c freelist.c + hypermap.c iospace.c kmap.c marea.c