2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/i386/page.c
5 * PURPOSE: Low level memory managment manipulation
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
10 /* INCLUDES ***************************************************************/
15 #include "../ARM3/miarm.h"
17 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, MmInitGlobalKernelPageDirectory)
19 #pragma alloc_text(INIT, MiInitPageDirectoryMap)
23 /* GLOBALS *****************************************************************/
25 #define PA_BIT_PRESENT (0)
26 #define PA_BIT_READWRITE (1)
27 #define PA_BIT_USER (2)
30 #define PA_BIT_ACCESSED (5)
31 #define PA_BIT_DIRTY (6)
32 #define PA_BIT_GLOBAL (8)
34 #define PA_PRESENT (1 << PA_BIT_PRESENT)
35 #define PA_READWRITE (1 << PA_BIT_READWRITE)
36 #define PA_USER (1 << PA_BIT_USER)
37 #define PA_DIRTY (1 << PA_BIT_DIRTY)
38 #define PA_WT (1 << PA_BIT_WT)
39 #define PA_CD (1 << PA_BIT_CD)
40 #define PA_ACCESSED (1 << PA_BIT_ACCESSED)
41 #define PA_GLOBAL (1 << PA_BIT_GLOBAL)
43 #define HYPERSPACE (0xc0400000)
44 #define IS_HYPERSPACE(v) (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
46 ULONG MmGlobalKernelPageDirectory
[1024];
48 #define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT)
49 #define PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
52 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
54 __inline LARGE_INTEGER
PTE_TO_PAGE(ULONG npage
)
57 dummy
.QuadPart
= (LONGLONG
)(PAGE_MASK(npage
));
64 MmProtectToPteMask
[32] =
67 // These are the base MM_ protection flags
70 PTE_READONLY
| PTE_ENABLE_CACHE
,
71 PTE_EXECUTE
| PTE_ENABLE_CACHE
,
72 PTE_EXECUTE_READ
| PTE_ENABLE_CACHE
,
73 PTE_READWRITE
| PTE_ENABLE_CACHE
,
74 PTE_WRITECOPY
| PTE_ENABLE_CACHE
,
75 PTE_EXECUTE_READWRITE
| PTE_ENABLE_CACHE
,
76 PTE_EXECUTE_WRITECOPY
| PTE_ENABLE_CACHE
,
78 // These OR in the MM_NOCACHE flag
81 PTE_READONLY
| PTE_DISABLE_CACHE
,
82 PTE_EXECUTE
| PTE_DISABLE_CACHE
,
83 PTE_EXECUTE_READ
| PTE_DISABLE_CACHE
,
84 PTE_READWRITE
| PTE_DISABLE_CACHE
,
85 PTE_WRITECOPY
| PTE_DISABLE_CACHE
,
86 PTE_EXECUTE_READWRITE
| PTE_DISABLE_CACHE
,
87 PTE_EXECUTE_WRITECOPY
| PTE_DISABLE_CACHE
,
89 // These OR in the MM_DECOMMIT flag, which doesn't seem supported on x86/64/ARM
92 PTE_READONLY
| PTE_ENABLE_CACHE
,
93 PTE_EXECUTE
| PTE_ENABLE_CACHE
,
94 PTE_EXECUTE_READ
| PTE_ENABLE_CACHE
,
95 PTE_READWRITE
| PTE_ENABLE_CACHE
,
96 PTE_WRITECOPY
| PTE_ENABLE_CACHE
,
97 PTE_EXECUTE_READWRITE
| PTE_ENABLE_CACHE
,
98 PTE_EXECUTE_WRITECOPY
| PTE_ENABLE_CACHE
,
100 // These OR in the MM_NOACCESS flag, which seems to enable WriteCombining?
103 PTE_READONLY
| PTE_WRITECOMBINED_CACHE
,
104 PTE_EXECUTE
| PTE_WRITECOMBINED_CACHE
,
105 PTE_EXECUTE_READ
| PTE_WRITECOMBINED_CACHE
,
106 PTE_READWRITE
| PTE_WRITECOMBINED_CACHE
,
107 PTE_WRITECOPY
| PTE_WRITECOMBINED_CACHE
,
108 PTE_EXECUTE_READWRITE
| PTE_WRITECOMBINED_CACHE
,
109 PTE_EXECUTE_WRITECOPY
| PTE_WRITECOMBINED_CACHE
,
113 ULONG MmProtectToValue
[32] =
121 PAGE_EXECUTE_READWRITE
,
122 PAGE_EXECUTE_WRITECOPY
,
124 PAGE_NOCACHE
| PAGE_READONLY
,
125 PAGE_NOCACHE
| PAGE_EXECUTE
,
126 PAGE_NOCACHE
| PAGE_EXECUTE_READ
,
127 PAGE_NOCACHE
| PAGE_READWRITE
,
128 PAGE_NOCACHE
| PAGE_WRITECOPY
,
129 PAGE_NOCACHE
| PAGE_EXECUTE_READWRITE
,
130 PAGE_NOCACHE
| PAGE_EXECUTE_WRITECOPY
,
132 PAGE_GUARD
| PAGE_READONLY
,
133 PAGE_GUARD
| PAGE_EXECUTE
,
134 PAGE_GUARD
| PAGE_EXECUTE_READ
,
135 PAGE_GUARD
| PAGE_READWRITE
,
136 PAGE_GUARD
| PAGE_WRITECOPY
,
137 PAGE_GUARD
| PAGE_EXECUTE_READWRITE
,
138 PAGE_GUARD
| PAGE_EXECUTE_WRITECOPY
,
140 PAGE_WRITECOMBINE
| PAGE_READONLY
,
141 PAGE_WRITECOMBINE
| PAGE_EXECUTE
,
142 PAGE_WRITECOMBINE
| PAGE_EXECUTE_READ
,
143 PAGE_WRITECOMBINE
| PAGE_READWRITE
,
144 PAGE_WRITECOMBINE
| PAGE_WRITECOPY
,
145 PAGE_WRITECOMBINE
| PAGE_EXECUTE_READWRITE
,
146 PAGE_WRITECOMBINE
| PAGE_EXECUTE_WRITECOPY
149 /* FUNCTIONS ***************************************************************/
151 BOOLEAN
MmUnmapPageTable(PULONG Pt
);
154 MiFlushTlb(PULONG Pt
, PVOID Address
)
156 if ((Pt
&& MmUnmapPageTable(Pt
)) || Address
>= MmSystemRangeStart
)
158 KeInvalidateTlbEntry(Address
);
163 ProtectToPTE(ULONG flProtect
)
165 ULONG Attributes
= 0;
167 if (flProtect
& (PAGE_NOACCESS
|PAGE_GUARD
))
171 else if (flProtect
& PAGE_IS_WRITABLE
)
173 Attributes
= PA_PRESENT
| PA_READWRITE
;
175 else if (flProtect
& (PAGE_IS_READABLE
| PAGE_IS_EXECUTABLE
))
177 Attributes
= PA_PRESENT
;
181 DPRINT1("Unknown main protection type.\n");
182 KeBugCheck(MEMORY_MANAGEMENT
);
185 if (flProtect
& PAGE_SYSTEM
)
190 Attributes
= Attributes
| PA_USER
;
192 if (flProtect
& PAGE_NOCACHE
)
194 Attributes
= Attributes
| PA_CD
;
196 if (flProtect
& PAGE_WRITETHROUGH
)
198 Attributes
= Attributes
| PA_WT
;
204 MmGetPageTableForProcess(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
206 ULONG PdeOffset
= ADDR_TO_PDE_OFFSET(Address
);
212 if (Address
< MmSystemRangeStart
)
214 /* We should have a process for user land addresses */
215 ASSERT(Process
!= NULL
);
217 if(Process
!= PsGetCurrentProcess())
219 PageDir
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
[0]));
222 KeBugCheck(MEMORY_MANAGEMENT
);
224 if (0 == InterlockedCompareExchangePte(&PageDir
[PdeOffset
], 0, 0))
228 MmDeleteHyperspaceMapping(PageDir
);
231 MI_SET_USAGE(MI_USAGE_LEGACY_PAGE_DIRECTORY
);
233 MI_SET_PROCESS2(Process
->ImageFileName
);
235 Status
= MmRequestPageMemoryConsumer(MC_SYSTEM
, FALSE
, &Pfn
);
236 if (!NT_SUCCESS(Status
) || Pfn
== 0)
238 KeBugCheck(MEMORY_MANAGEMENT
);
240 Entry
= InterlockedCompareExchangePte(&PageDir
[PdeOffset
], PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
243 MmReleasePageMemoryConsumer(MC_SYSTEM
, Pfn
);
244 Pfn
= PTE_TO_PFN(Entry
);
249 Pfn
= PTE_TO_PFN(PageDir
[PdeOffset
]);
251 MmDeleteHyperspaceMapping(PageDir
);
252 Pt
= MmCreateHyperspaceMapping(Pfn
);
255 KeBugCheck(MEMORY_MANAGEMENT
);
257 return Pt
+ MiAddressToPteOffset(Address
);
259 /* This is for our process */
260 PageDir
= (PULONG
)MiAddressToPde(Address
);
261 if (0 == InterlockedCompareExchangePte(PageDir
, 0, 0))
267 MI_SET_USAGE(MI_USAGE_LEGACY_PAGE_DIRECTORY
);
268 MI_SET_PROCESS2(Process
->ImageFileName
);
270 Status
= MmRequestPageMemoryConsumer(MC_SYSTEM
, FALSE
, &Pfn
);
271 if (!NT_SUCCESS(Status
) || Pfn
== 0)
273 KeBugCheck(MEMORY_MANAGEMENT
);
275 Entry
= InterlockedCompareExchangePte(PageDir
, PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
278 MmReleasePageMemoryConsumer(MC_SYSTEM
, Pfn
);
281 return (PULONG
)MiAddressToPte(Address
);
284 /* This is for kernel land address */
285 PageDir
= (PULONG
)MiAddressToPde(Address
);
286 if (0 == InterlockedCompareExchangePte(PageDir
, 0, 0))
288 if (0 == InterlockedCompareExchangePte(&MmGlobalKernelPageDirectory
[PdeOffset
], 0, 0))
294 MI_SET_USAGE(MI_USAGE_LEGACY_PAGE_DIRECTORY
);
295 if (Process
) MI_SET_PROCESS2(Process
->ImageFileName
);
296 if (!Process
) MI_SET_PROCESS2("Kernel Legacy");
297 Status
= MmRequestPageMemoryConsumer(MC_SYSTEM
, FALSE
, &Pfn
);
298 if (!NT_SUCCESS(Status
) || Pfn
== 0)
300 KeBugCheck(MEMORY_MANAGEMENT
);
302 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
;
303 if(0 != InterlockedCompareExchangePte(&MmGlobalKernelPageDirectory
[PdeOffset
], Entry
, 0))
305 MmReleasePageMemoryConsumer(MC_SYSTEM
, Pfn
);
307 InterlockedExchangePte(PageDir
, MmGlobalKernelPageDirectory
[PdeOffset
]);
308 return (PULONG
)MiAddressToPte(Address
);
310 InterlockedExchangePte(PageDir
, MmGlobalKernelPageDirectory
[PdeOffset
]);
312 return (PULONG
)MiAddressToPte(Address
);
315 BOOLEAN
MmUnmapPageTable(PULONG Pt
)
317 if (!IS_HYPERSPACE(Pt
))
324 MmDeleteHyperspaceMapping((PVOID
)PAGE_ROUND_DOWN(Pt
));
329 static ULONG
MmGetPageEntryForProcess(PEPROCESS Process
, PVOID Address
)
334 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
338 MmUnmapPageTable(Pt
);
346 MmGetPfnForProcess(PEPROCESS Process
,
350 Entry
= MmGetPageEntryForProcess(Process
, Address
);
351 if (!(Entry
& PA_PRESENT
))
355 return(PTE_TO_PFN(Entry
));
360 MmDisableVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOLEAN
* WasDirty
, PPFN_NUMBER Page
)
362 * FUNCTION: Delete a virtual mapping
369 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
372 KeBugCheck(MEMORY_MANAGEMENT
);
376 * Atomically disable the present bit and get the old value.
381 } while (Pte
!= InterlockedCompareExchangePte(Pt
, Pte
& ~PA_PRESENT
, Pte
));
383 MiFlushTlb(Pt
, Address
);
385 WasValid
= (Pte
& PA_PRESENT
);
388 KeBugCheck(MEMORY_MANAGEMENT
);
392 * Return some information to the caller
394 if (WasDirty
!= NULL
)
396 *WasDirty
= Pte
& PA_DIRTY
;
400 *Page
= PTE_TO_PFN(Pte
);
406 MmRawDeleteVirtualMapping(PVOID Address
)
410 Pt
= MmGetPageTableForProcess(NULL
, Address
, FALSE
);
414 * Set the entry to zero
416 InterlockedExchangePte(Pt
, 0);
417 MiFlushTlb(Pt
, Address
);
423 MmDeleteVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOLEAN FreePage
,
424 BOOLEAN
* WasDirty
, PPFN_NUMBER Page
)
426 * FUNCTION: Delete a virtual mapping
429 BOOLEAN WasValid
= FALSE
;
434 DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
435 Process
, Address
, FreePage
, WasDirty
, Page
);
437 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
441 if (WasDirty
!= NULL
)
453 * Atomically set the entry to zero and get the old value.
455 Pte
= InterlockedExchangePte(Pt
, 0);
457 WasValid
= (Pte
& PA_PRESENT
);
460 /* Flush the TLB since we transitioned this PTE
461 * from valid to invalid so any stale translations
462 * are removed from the cache */
463 MiFlushTlb(Pt
, Address
);
465 Pfn
= PTE_TO_PFN(Pte
);
469 MmReleasePageMemoryConsumer(MC_SYSTEM
, Pfn
);
475 MmUnmapPageTable(Pt
);
480 * Return some information to the caller
482 if (WasDirty
!= NULL
)
484 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
494 MmGetPageFileMapping(PEPROCESS Process
, PVOID Address
,
495 SWAPENTRY
* SwapEntry
)
497 * FUNCTION: Get a page file mapping
500 ULONG Entry
= MmGetPageEntryForProcess(Process
, Address
);
501 *SwapEntry
= Entry
>> 1;
506 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
507 SWAPENTRY
* SwapEntry
)
509 * FUNCTION: Delete a virtual mapping
515 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
524 * Atomically set the entry to zero and get the old value.
526 Pte
= InterlockedExchangePte(Pt
, 0);
528 /* We don't need to flush here because page file entries
529 * are invalid translations, so the processor won't cache them */
530 MmUnmapPageTable(Pt
);
532 if (Pte
& PA_PRESENT
)
534 KeBugCheck(MEMORY_MANAGEMENT
);
538 * Return some information to the caller
540 *SwapEntry
= Pte
>> 1;
544 Mmi386MakeKernelPageTableGlobal(PVOID PAddress
)
547 Pde
= (PULONG
)MiAddressToPde(PAddress
);
550 Pt
= MmGetPageTableForProcess(NULL
, PAddress
, FALSE
);
561 MmIsDirtyPage(PEPROCESS Process
, PVOID Address
)
563 return MmGetPageEntryForProcess(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
568 MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
573 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
575 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
576 KeBugCheck(MEMORY_MANAGEMENT
);
579 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
582 KeBugCheck(MEMORY_MANAGEMENT
);
588 } while (Pte
!= InterlockedCompareExchangePte(Pt
, Pte
& ~PA_DIRTY
, Pte
));
590 if (!(Pte
& PA_PRESENT
))
592 KeBugCheck(MEMORY_MANAGEMENT
);
594 else if (Pte
& PA_DIRTY
)
596 MiFlushTlb(Pt
, Address
);
600 MmUnmapPageTable(Pt
);
606 MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
611 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
613 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
614 KeBugCheck(MEMORY_MANAGEMENT
);
617 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
620 KeBugCheck(MEMORY_MANAGEMENT
);
626 } while (Pte
!= InterlockedCompareExchangePte(Pt
, Pte
| PA_DIRTY
, Pte
));
628 if (!(Pte
& PA_PRESENT
))
630 KeBugCheck(MEMORY_MANAGEMENT
);
632 else if (!(Pte
& PA_DIRTY
))
634 MiFlushTlb(Pt
, Address
);
638 MmUnmapPageTable(Pt
);
644 MmEnableVirtualMapping(PEPROCESS Process
, PVOID Address
)
649 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
652 //HACK to get DPH working, waiting for MM rewrite :-/
653 //KeBugCheck(MEMORY_MANAGEMENT);
657 /* Do not mark a 0 page as present */
658 if(0 == InterlockedCompareExchangePte(Pt
, 0, 0))
664 } while (Pte
!= InterlockedCompareExchangePte(Pt
, Pte
| PA_PRESENT
, Pte
));
666 /* We don't need to flush the TLB here because it
667 * won't cache translations for non-present pages */
668 MmUnmapPageTable(Pt
);
673 MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
675 return MmGetPageEntryForProcess(Process
, Address
) & PA_PRESENT
;
680 MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
683 Entry
= MmGetPageEntryForProcess(Process
, Address
);
684 return !(Entry
& PA_PRESENT
) && Entry
!= 0;
689 MmCreatePageFileMapping(PEPROCESS Process
,
696 if (Process
== NULL
&& Address
< MmSystemRangeStart
)
698 DPRINT1("No process\n");
699 KeBugCheck(MEMORY_MANAGEMENT
);
701 if (Process
!= NULL
&& Address
>= MmSystemRangeStart
)
703 DPRINT1("Setting kernel address with process context\n");
704 KeBugCheck(MEMORY_MANAGEMENT
);
707 if (SwapEntry
& (1 << 31))
709 KeBugCheck(MEMORY_MANAGEMENT
);
712 Pt
= MmGetPageTableForProcess(Process
, Address
, TRUE
);
715 KeBugCheck(MEMORY_MANAGEMENT
);
717 Pte
= InterlockedExchangePte(Pt
, SwapEntry
<< 1);
720 KeBugCheck(MEMORY_MANAGEMENT
);
723 /* We don't need to flush the TLB here because it
724 * only caches valid translations and a zero PTE
725 * is not a valid translation */
726 MmUnmapPageTable(Pt
);
728 return(STATUS_SUCCESS
);
734 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
743 ULONG oldPdeOffset
, PdeOffset
;
746 DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
747 Process
, Address
, flProtect
, Pages
, *Pages
, PageCount
);
749 ASSERT(((ULONG_PTR
)Address
% PAGE_SIZE
) == 0);
753 if (Address
< MmSystemRangeStart
)
755 DPRINT1("No process\n");
756 KeBugCheck(MEMORY_MANAGEMENT
);
758 if (PageCount
> 0x10000 ||
759 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> 0x100000)
761 DPRINT1("Page count too large\n");
762 KeBugCheck(MEMORY_MANAGEMENT
);
767 if (Address
>= MmSystemRangeStart
)
769 DPRINT1("Setting kernel address with process context\n");
770 KeBugCheck(MEMORY_MANAGEMENT
);
772 if (PageCount
> (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
||
773 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
>
774 (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
)
776 DPRINT1("Page Count too large\n");
777 KeBugCheck(MEMORY_MANAGEMENT
);
781 Attributes
= ProtectToPTE(flProtect
);
783 if (Address
>= MmSystemRangeStart
)
785 Attributes
&= ~PA_USER
;
789 Attributes
|= PA_USER
;
793 /* MmGetPageTableForProcess should be called on the first run, so
794 * let this trigger it */
795 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
) + 1;
796 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
798 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
800 DPRINT1("Setting physical address but not allowing access at address "
801 "0x%.8X with attributes %x/%x.\n",
802 Addr
, Attributes
, flProtect
);
803 KeBugCheck(MEMORY_MANAGEMENT
);
805 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
806 if (oldPdeOffset
!= PdeOffset
)
808 if(Pt
) MmUnmapPageTable(Pt
);
809 Pt
= MmGetPageTableForProcess(Process
, Addr
, TRUE
);
812 KeBugCheck(MEMORY_MANAGEMENT
);
819 oldPdeOffset
= PdeOffset
;
821 Pte
= InterlockedExchangePte(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
823 /* There should not be anything valid here */
826 DPRINT1("Bad PTE %lx\n", Pte
);
827 KeBugCheck(MEMORY_MANAGEMENT
);
830 /* We don't need to flush the TLB here because it only caches valid translations
831 * and we're moving this PTE from invalid to valid so it can't be cached right now */
834 ASSERT(Addr
> Address
);
835 MmUnmapPageTable(Pt
);
837 return(STATUS_SUCCESS
);
842 MmCreateVirtualMapping(PEPROCESS Process
,
850 for (i
= 0; i
< PageCount
; i
++)
852 if (!MmIsPageInUse(Pages
[i
]))
854 DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages
[i
]));
855 KeBugCheck(MEMORY_MANAGEMENT
);
859 return(MmCreateVirtualMappingUnsafe(Process
,
868 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
873 Entry
= MmGetPageEntryForProcess(Process
, Address
);
876 if (!(Entry
& PA_PRESENT
))
878 Protect
= PAGE_NOACCESS
;
882 if (Entry
& PA_READWRITE
)
884 Protect
= PAGE_READWRITE
;
888 Protect
= PAGE_EXECUTE_READ
;
892 Protect
|= PAGE_NOCACHE
;
896 Protect
|= PAGE_WRITETHROUGH
;
898 if (!(Entry
& PA_USER
))
900 Protect
|= PAGE_SYSTEM
;
909 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
911 ULONG Attributes
= 0;
915 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
916 Process
, Address
, flProtect
);
918 Attributes
= ProtectToPTE(flProtect
);
921 if (Address
>= MmSystemRangeStart
)
923 Attributes
&= ~PA_USER
;
927 Attributes
|= PA_USER
;
930 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
933 KeBugCheck(MEMORY_MANAGEMENT
);
935 Pte
= InterlockedExchangePte(Pt
, PAGE_MASK(*Pt
) | Attributes
| (*Pt
& (PA_ACCESSED
|PA_DIRTY
)));
937 if (!(Pte
& PA_PRESENT
))
939 DPRINT1("Invalid Pte %lx\n", Pte
);
940 KeBugCheck(MEMORY_MANAGEMENT
);
943 if((Pte
& Attributes
) != Attributes
)
944 MiFlushTlb(Pt
, Address
);
946 MmUnmapPageTable(Pt
);
952 PHYSICAL_ADDRESS NTAPI
953 MmGetPhysicalAddress(PVOID vaddr
)
955 * FUNCTION: Returns the physical address corresponding to a virtual address
961 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr
);
962 Pte
= MmGetPageEntryForProcess(NULL
, vaddr
);
963 if (Pte
!= 0 && (Pte
& PA_PRESENT
))
965 p
.QuadPart
= PAGE_MASK(Pte
);
966 p
.u
.LowPart
|= (ULONG_PTR
)vaddr
& (PAGE_SIZE
- 1);
978 MmInitGlobalKernelPageDirectory(VOID
)
981 PULONG CurrentPageDirectory
= (PULONG
)PAGEDIRECTORY_MAP
;
983 DPRINT("MmInitGlobalKernelPageDirectory()\n");
985 for (i
= ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
< 1024; i
++)
987 if (i
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) &&
988 i
!= ADDR_TO_PDE_OFFSET(HYPERSPACE
) &&
989 0 == MmGlobalKernelPageDirectory
[i
] && 0 != CurrentPageDirectory
[i
])
991 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];