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 #define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT)
47 #define PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
50 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
52 __inline LARGE_INTEGER
PTE_TO_PAGE(ULONG npage
)
55 dummy
.QuadPart
= (LONGLONG
)(PAGE_MASK(npage
));
62 MmProtectToPteMask
[32] =
65 // These are the base MM_ protection flags
68 PTE_READONLY
| PTE_ENABLE_CACHE
,
69 PTE_EXECUTE
| PTE_ENABLE_CACHE
,
70 PTE_EXECUTE_READ
| PTE_ENABLE_CACHE
,
71 PTE_READWRITE
| PTE_ENABLE_CACHE
,
72 PTE_WRITECOPY
| PTE_ENABLE_CACHE
,
73 PTE_EXECUTE_READWRITE
| PTE_ENABLE_CACHE
,
74 PTE_EXECUTE_WRITECOPY
| PTE_ENABLE_CACHE
,
76 // These OR in the MM_NOCACHE flag
79 PTE_READONLY
| PTE_DISABLE_CACHE
,
80 PTE_EXECUTE
| PTE_DISABLE_CACHE
,
81 PTE_EXECUTE_READ
| PTE_DISABLE_CACHE
,
82 PTE_READWRITE
| PTE_DISABLE_CACHE
,
83 PTE_WRITECOPY
| PTE_DISABLE_CACHE
,
84 PTE_EXECUTE_READWRITE
| PTE_DISABLE_CACHE
,
85 PTE_EXECUTE_WRITECOPY
| PTE_DISABLE_CACHE
,
87 // These OR in the MM_DECOMMIT flag, which doesn't seem supported on x86/64/ARM
90 PTE_READONLY
| PTE_ENABLE_CACHE
,
91 PTE_EXECUTE
| PTE_ENABLE_CACHE
,
92 PTE_EXECUTE_READ
| PTE_ENABLE_CACHE
,
93 PTE_READWRITE
| PTE_ENABLE_CACHE
,
94 PTE_WRITECOPY
| PTE_ENABLE_CACHE
,
95 PTE_EXECUTE_READWRITE
| PTE_ENABLE_CACHE
,
96 PTE_EXECUTE_WRITECOPY
| PTE_ENABLE_CACHE
,
98 // These OR in the MM_NOACCESS flag, which seems to enable WriteCombining?
101 PTE_READONLY
| PTE_WRITECOMBINED_CACHE
,
102 PTE_EXECUTE
| PTE_WRITECOMBINED_CACHE
,
103 PTE_EXECUTE_READ
| PTE_WRITECOMBINED_CACHE
,
104 PTE_READWRITE
| PTE_WRITECOMBINED_CACHE
,
105 PTE_WRITECOPY
| PTE_WRITECOMBINED_CACHE
,
106 PTE_EXECUTE_READWRITE
| PTE_WRITECOMBINED_CACHE
,
107 PTE_EXECUTE_WRITECOPY
| PTE_WRITECOMBINED_CACHE
,
111 ULONG MmProtectToValue
[32] =
119 PAGE_EXECUTE_READWRITE
,
120 PAGE_EXECUTE_WRITECOPY
,
122 PAGE_NOCACHE
| PAGE_READONLY
,
123 PAGE_NOCACHE
| PAGE_EXECUTE
,
124 PAGE_NOCACHE
| PAGE_EXECUTE_READ
,
125 PAGE_NOCACHE
| PAGE_READWRITE
,
126 PAGE_NOCACHE
| PAGE_WRITECOPY
,
127 PAGE_NOCACHE
| PAGE_EXECUTE_READWRITE
,
128 PAGE_NOCACHE
| PAGE_EXECUTE_WRITECOPY
,
130 PAGE_GUARD
| PAGE_READONLY
,
131 PAGE_GUARD
| PAGE_EXECUTE
,
132 PAGE_GUARD
| PAGE_EXECUTE_READ
,
133 PAGE_GUARD
| PAGE_READWRITE
,
134 PAGE_GUARD
| PAGE_WRITECOPY
,
135 PAGE_GUARD
| PAGE_EXECUTE_READWRITE
,
136 PAGE_GUARD
| PAGE_EXECUTE_WRITECOPY
,
138 PAGE_WRITECOMBINE
| PAGE_READONLY
,
139 PAGE_WRITECOMBINE
| PAGE_EXECUTE
,
140 PAGE_WRITECOMBINE
| PAGE_EXECUTE_READ
,
141 PAGE_WRITECOMBINE
| PAGE_READWRITE
,
142 PAGE_WRITECOMBINE
| PAGE_WRITECOPY
,
143 PAGE_WRITECOMBINE
| PAGE_EXECUTE_READWRITE
,
144 PAGE_WRITECOMBINE
| PAGE_EXECUTE_WRITECOPY
147 /* FUNCTIONS ***************************************************************/
149 static BOOLEAN
MmUnmapPageTable(PULONG Pt
);
152 MiFlushTlb(PULONG Pt
, PVOID Address
)
154 if ((Pt
&& MmUnmapPageTable(Pt
)) || Address
>= MmSystemRangeStart
)
156 KeInvalidateTlbEntry(Address
);
161 ProtectToPTE(ULONG flProtect
)
163 ULONG Attributes
= 0;
165 if (flProtect
& (PAGE_NOACCESS
|PAGE_GUARD
))
169 else if (flProtect
& PAGE_IS_WRITABLE
)
171 Attributes
= PA_PRESENT
| PA_READWRITE
;
173 else if (flProtect
& (PAGE_IS_READABLE
| PAGE_IS_EXECUTABLE
))
175 Attributes
= PA_PRESENT
;
179 DPRINT1("Unknown main protection type.\n");
180 KeBugCheck(MEMORY_MANAGEMENT
);
183 if (flProtect
& PAGE_SYSTEM
)
188 Attributes
= Attributes
| PA_USER
;
190 if (flProtect
& PAGE_NOCACHE
)
192 Attributes
= Attributes
| PA_CD
;
194 if (flProtect
& PAGE_WRITETHROUGH
)
196 Attributes
= Attributes
| PA_WT
;
201 /* Taken from ARM3/pagfault.c */
204 MiSynchronizeSystemPde(PMMPDE PointerPde
)
209 /* Get the Index from the PDE */
210 Index
= ((ULONG_PTR
)PointerPde
& (SYSTEM_PD_SIZE
- 1)) / sizeof(MMPTE
);
212 /* Copy the PDE from the double-mapped system page directory */
213 SystemPde
= MmSystemPagePtes
[Index
];
214 *PointerPde
= SystemPde
;
216 /* Make sure we re-read the PDE and PTE */
217 KeMemoryBarrierWithoutFence();
219 /* Return, if we had success */
220 return SystemPde
.u
.Hard
.Valid
!= 0;
225 MiDispatchFault(IN BOOLEAN StoreInstruction
,
227 IN PMMPTE PointerPte
,
228 IN PMMPTE PointerProtoPte
,
229 IN BOOLEAN Recursive
,
230 IN PEPROCESS Process
,
231 IN PVOID TrapInformation
,
236 MiFillSystemPageDirectory(IN PVOID Base
,
237 IN SIZE_T NumberOfBytes
);
240 MmGetPageTableForProcess(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
246 if (Address
< MmSystemRangeStart
)
248 /* We should have a process for user land addresses */
249 ASSERT(Process
!= NULL
);
251 if(Process
!= PsGetCurrentProcess())
254 ULONG PdeOffset
= MiGetPdeOffset(Address
);
256 /* Nobody but page fault should ask for creating the PDE,
257 * Which imples that Process is the current one */
258 ASSERT(Create
== FALSE
);
260 PdeBase
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
[0]));
263 KeBugCheck(MEMORY_MANAGEMENT
);
265 PointerPde
= PdeBase
+ PdeOffset
;
266 if (PointerPde
->u
.Hard
.Valid
== 0)
268 MmDeleteHyperspaceMapping(PdeBase
);
273 Pfn
= PointerPde
->u
.Hard
.PageFrameNumber
;
275 MmDeleteHyperspaceMapping(PdeBase
);
276 Pt
= MmCreateHyperspaceMapping(Pfn
);
279 KeBugCheck(MEMORY_MANAGEMENT
);
281 return Pt
+ MiAddressToPteOffset(Address
);
283 /* This is for our process */
284 PointerPde
= MiAddressToPde(Address
);
285 Pt
= (PULONG
)MiAddressToPte(Address
);
286 if (PointerPde
->u
.Hard
.Valid
== 0)
293 ASSERT(PointerPde
->u
.Long
== 0);
295 MI_WRITE_INVALID_PTE(PointerPde
, DemandZeroPde
);
296 Status
= MiDispatchFault(TRUE
,
301 PsGetCurrentProcess(),
304 DBG_UNREFERENCED_LOCAL_VARIABLE(Status
);
305 ASSERT(KeAreAllApcsDisabled() == TRUE
);
306 ASSERT(PointerPde
->u
.Hard
.Valid
== 1);
308 return (PULONG
)MiAddressToPte(Address
);
311 /* This is for kernel land address */
312 ASSERT(Process
== NULL
);
313 PointerPde
= MiAddressToPde(Address
);
314 Pt
= (PULONG
)MiAddressToPte(Address
);
315 if (PointerPde
->u
.Hard
.Valid
== 0)
317 /* Let ARM3 synchronize the PDE */
318 if(!MiSynchronizeSystemPde(PointerPde
))
320 /* PDE (still) not valid, let ARM3 allocate one if asked */
323 MiFillSystemPageDirectory(Address
, PAGE_SIZE
);
329 static BOOLEAN
MmUnmapPageTable(PULONG Pt
)
331 if (!IS_HYPERSPACE(Pt
))
338 MmDeleteHyperspaceMapping((PVOID
)PAGE_ROUND_DOWN(Pt
));
343 static ULONG
MmGetPageEntryForProcess(PEPROCESS Process
, PVOID Address
)
348 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
352 MmUnmapPageTable(Pt
);
360 MmGetPfnForProcess(PEPROCESS Process
,
364 Entry
= MmGetPageEntryForProcess(Process
, Address
);
365 if (!(Entry
& PA_PRESENT
))
369 return(PTE_TO_PFN(Entry
));
374 MmDeleteVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOLEAN FreePage
,
375 BOOLEAN
* WasDirty
, PPFN_NUMBER Page
)
377 * FUNCTION: Delete a virtual mapping
380 BOOLEAN WasValid
= FALSE
;
385 DPRINT("MmDeleteVirtualMapping(%p, %p, %u, %p, %p)\n",
386 Process
, Address
, FreePage
, WasDirty
, Page
);
388 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
392 if (WasDirty
!= NULL
)
404 * Atomically set the entry to zero and get the old value.
406 Pte
= InterlockedExchangePte(Pt
, 0);
408 /* We count a mapping as valid if it's a present page, or it's a nonzero pfn with
409 * the swap bit unset, indicating a valid page protected to PAGE_NOACCESS. */
410 WasValid
= (Pte
& PA_PRESENT
) || ((Pte
>> PAGE_SHIFT
) && !(Pte
& 0x800));
413 /* Flush the TLB since we transitioned this PTE
414 * from valid to invalid so any stale translations
415 * are removed from the cache */
416 MiFlushTlb(Pt
, Address
);
418 if (Address
< MmSystemRangeStart
)
420 /* Remove PDE reference */
421 Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)]--;
422 ASSERT(Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)] < PTE_COUNT
);
425 Pfn
= PTE_TO_PFN(Pte
);
429 MmReleasePageMemoryConsumer(MC_SYSTEM
, Pfn
);
435 MmUnmapPageTable(Pt
);
440 * Return some information to the caller
442 if (WasDirty
!= NULL
)
444 *WasDirty
= ((Pte
& PA_DIRTY
) && (Pte
& PA_PRESENT
)) ? TRUE
: FALSE
;
454 MmGetPageFileMapping(PEPROCESS Process
, PVOID Address
,
455 SWAPENTRY
* SwapEntry
)
457 * FUNCTION: Get a page file mapping
460 ULONG Entry
= MmGetPageEntryForProcess(Process
, Address
);
461 *SwapEntry
= Entry
>> 1;
466 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
467 SWAPENTRY
* SwapEntry
)
469 * FUNCTION: Delete a virtual mapping
475 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
484 * Atomically set the entry to zero and get the old value.
486 Pte
= InterlockedExchangePte(Pt
, 0);
488 if (Address
< MmSystemRangeStart
)
490 /* Remove PDE reference */
491 Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)]--;
492 ASSERT(Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)] < PTE_COUNT
);
495 /* We don't need to flush here because page file entries
496 * are invalid translations, so the processor won't cache them */
497 MmUnmapPageTable(Pt
);
499 if ((Pte
& PA_PRESENT
) || !(Pte
& 0x800))
501 DPRINT1("Pte %x (want not 1 and 0x800)\n", Pte
);
502 KeBugCheck(MEMORY_MANAGEMENT
);
506 * Return some information to the caller
508 *SwapEntry
= Pte
>> 1;
512 Mmi386MakeKernelPageTableGlobal(PVOID Address
)
514 PMMPDE PointerPde
= MiAddressToPde(Address
);
515 PMMPTE PointerPte
= MiAddressToPte(Address
);
517 if (PointerPde
->u
.Hard
.Valid
== 0)
519 if(!MiSynchronizeSystemPde(PointerPde
))
521 return PointerPte
->u
.Hard
.Valid
!= 0;
528 MmIsDirtyPage(PEPROCESS Process
, PVOID Address
)
530 return MmGetPageEntryForProcess(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
535 MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
540 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
542 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
543 KeBugCheck(MEMORY_MANAGEMENT
);
546 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
549 KeBugCheck(MEMORY_MANAGEMENT
);
555 } while (Pte
!= InterlockedCompareExchangePte(Pt
, Pte
& ~PA_DIRTY
, Pte
));
557 if (!(Pte
& PA_PRESENT
))
559 KeBugCheck(MEMORY_MANAGEMENT
);
561 else if (Pte
& PA_DIRTY
)
563 MiFlushTlb(Pt
, Address
);
567 MmUnmapPageTable(Pt
);
573 MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
578 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
580 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
581 KeBugCheck(MEMORY_MANAGEMENT
);
584 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
587 KeBugCheck(MEMORY_MANAGEMENT
);
593 } while (Pte
!= InterlockedCompareExchangePte(Pt
, Pte
| PA_DIRTY
, Pte
));
595 if (!(Pte
& PA_PRESENT
))
597 KeBugCheck(MEMORY_MANAGEMENT
);
601 /* The processor will never clear this bit itself, therefore
602 * we do not need to flush the TLB here when setting it */
603 MmUnmapPageTable(Pt
);
609 MmEnableVirtualMapping(PEPROCESS Process
, PVOID Address
)
614 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
617 //HACK to get DPH working, waiting for MM rewrite :-/
618 //KeBugCheck(MEMORY_MANAGEMENT);
622 /* Do not mark a 0 page as present */
623 if(0 == InterlockedCompareExchangePte(Pt
, 0, 0))
629 } while (Pte
!= InterlockedCompareExchangePte(Pt
, Pte
| PA_PRESENT
, Pte
));
631 /* We don't need to flush the TLB here because it
632 * won't cache translations for non-present pages */
633 MmUnmapPageTable(Pt
);
638 MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
640 return MmGetPageEntryForProcess(Process
, Address
) & PA_PRESENT
;
645 MmIsDisabledPage(PEPROCESS Process
, PVOID Address
)
647 ULONG_PTR Entry
= MmGetPageEntryForProcess(Process
, Address
);
648 return !(Entry
& PA_PRESENT
) && !(Entry
& 0x800) && (Entry
>> PAGE_SHIFT
);
653 MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
656 Entry
= MmGetPageEntryForProcess(Process
, Address
);
657 return !(Entry
& PA_PRESENT
) && (Entry
& 0x800);
662 MmCreatePageFileMapping(PEPROCESS Process
,
669 if (Process
== NULL
&& Address
< MmSystemRangeStart
)
671 DPRINT1("No process\n");
672 KeBugCheck(MEMORY_MANAGEMENT
);
674 if (Process
!= NULL
&& Address
>= MmSystemRangeStart
)
676 DPRINT1("Setting kernel address with process context\n");
677 KeBugCheck(MEMORY_MANAGEMENT
);
680 if (SwapEntry
& (1 << 31))
682 KeBugCheck(MEMORY_MANAGEMENT
);
685 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
688 /* Nobody should page out an address that hasn't even been mapped */
689 /* But we might place a wait entry first, requiring the page table */
690 if (SwapEntry
!= MM_WAIT_ENTRY
)
692 KeBugCheck(MEMORY_MANAGEMENT
);
694 Pt
= MmGetPageTableForProcess(Process
, Address
, TRUE
);
696 Pte
= InterlockedExchangePte(Pt
, SwapEntry
<< 1);
699 KeBugCheckEx(MEMORY_MANAGEMENT
, SwapEntry
, (ULONG_PTR
)Process
, (ULONG_PTR
)Address
, 0);
702 if (Address
< MmSystemRangeStart
)
704 /* Add PDE reference */
705 Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)]++;
706 ASSERT(Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)] <= PTE_COUNT
);
709 /* We don't need to flush the TLB here because it
710 * only caches valid translations and a zero PTE
711 * is not a valid translation */
712 MmUnmapPageTable(Pt
);
714 return(STATUS_SUCCESS
);
720 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
729 ULONG oldPdeOffset
, PdeOffset
;
732 DPRINT("MmCreateVirtualMappingUnsafe(%p, %p, %lu, %p (%x), %lu)\n",
733 Process
, Address
, flProtect
, Pages
, *Pages
, PageCount
);
735 ASSERT(((ULONG_PTR
)Address
% PAGE_SIZE
) == 0);
739 if (Address
< MmSystemRangeStart
)
741 DPRINT1("No process\n");
742 KeBugCheck(MEMORY_MANAGEMENT
);
744 if (PageCount
> 0x10000 ||
745 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> 0x100000)
747 DPRINT1("Page count too large\n");
748 KeBugCheck(MEMORY_MANAGEMENT
);
753 if (Address
>= MmSystemRangeStart
)
755 DPRINT1("Setting kernel address with process context\n");
756 KeBugCheck(MEMORY_MANAGEMENT
);
758 if (PageCount
> (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
||
759 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
>
760 (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
)
762 DPRINT1("Page Count too large\n");
763 KeBugCheck(MEMORY_MANAGEMENT
);
767 Attributes
= ProtectToPTE(flProtect
);
769 if (Address
>= MmSystemRangeStart
)
771 Attributes
&= ~PA_USER
;
775 Attributes
|= PA_USER
;
779 /* MmGetPageTableForProcess should be called on the first run, so
780 * let this trigger it */
781 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
) + 1;
782 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
784 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
786 DPRINT1("Setting physical address but not allowing access at address "
787 "0x%p with attributes %x/%x.\n",
788 Addr
, Attributes
, flProtect
);
789 KeBugCheck(MEMORY_MANAGEMENT
);
791 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
792 if (oldPdeOffset
!= PdeOffset
)
794 if(Pt
) MmUnmapPageTable(Pt
);
795 Pt
= MmGetPageTableForProcess(Process
, Addr
, TRUE
);
798 KeBugCheck(MEMORY_MANAGEMENT
);
805 oldPdeOffset
= PdeOffset
;
807 Pte
= InterlockedExchangePte(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
809 /* There should not be anything valid here */
812 DPRINT1("Bad PTE %lx\n", Pte
);
813 KeBugCheck(MEMORY_MANAGEMENT
);
816 /* We don't need to flush the TLB here because it only caches valid translations
817 * and we're moving this PTE from invalid to valid so it can't be cached right now */
819 if (Addr
< MmSystemRangeStart
)
821 /* Add PDE reference */
822 Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Addr
)]++;
823 ASSERT(Process
->Vm
.VmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Addr
)] <= PTE_COUNT
);
827 ASSERT(Addr
> Address
);
828 MmUnmapPageTable(Pt
);
830 return(STATUS_SUCCESS
);
835 MmCreateVirtualMapping(PEPROCESS Process
,
843 ASSERT((ULONG_PTR
)Address
% PAGE_SIZE
== 0);
844 for (i
= 0; i
< PageCount
; i
++)
846 if (!MmIsPageInUse(Pages
[i
]))
848 DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages
[i
]));
849 KeBugCheck(MEMORY_MANAGEMENT
);
853 return(MmCreateVirtualMappingUnsafe(Process
,
862 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
867 Entry
= MmGetPageEntryForProcess(Process
, Address
);
870 if (!(Entry
& PA_PRESENT
))
872 Protect
= PAGE_NOACCESS
;
876 if (Entry
& PA_READWRITE
)
878 Protect
= PAGE_READWRITE
;
882 Protect
= PAGE_EXECUTE_READ
;
886 Protect
|= PAGE_NOCACHE
;
890 Protect
|= PAGE_WRITETHROUGH
;
892 if (!(Entry
& PA_USER
))
894 Protect
|= PAGE_SYSTEM
;
903 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
905 ULONG Attributes
= 0;
909 DPRINT("MmSetPageProtect(Process %p Address %p flProtect %x)\n",
910 Process
, Address
, flProtect
);
912 Attributes
= ProtectToPTE(flProtect
);
915 if (Address
>= MmSystemRangeStart
)
917 Attributes
&= ~PA_USER
;
921 Attributes
|= PA_USER
;
924 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
927 KeBugCheck(MEMORY_MANAGEMENT
);
929 Pte
= InterlockedExchangePte(Pt
, PAGE_MASK(*Pt
) | Attributes
| (*Pt
& (PA_ACCESSED
|PA_DIRTY
)));
931 // We should be able to bring a page back from PAGE_NOACCESS
932 if ((Pte
& 0x800) || !(Pte
>> PAGE_SHIFT
))
934 DPRINT1("Invalid Pte %lx\n", Pte
);
935 KeBugCheck(MEMORY_MANAGEMENT
);
938 if((Pte
& Attributes
) != Attributes
)
939 MiFlushTlb(Pt
, Address
);
941 MmUnmapPageTable(Pt
);
947 MmInitGlobalKernelPageDirectory(VOID
)
949 /* Nothing to do here */