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 ***************************************************************/
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, MmInitGlobalKernelPageDirectory)
21 /* GLOBALS *****************************************************************/
23 #define PA_BIT_PRESENT (0)
24 #define PA_BIT_READWRITE (1)
25 #define PA_BIT_USER (2)
28 #define PA_BIT_ACCESSED (5)
29 #define PA_BIT_DIRTY (6)
30 #define PA_BIT_GLOBAL (8)
32 #define PA_PRESENT (1 << PA_BIT_PRESENT)
33 #define PA_READWRITE (1 << PA_BIT_READWRITE)
34 #define PA_USER (1 << PA_BIT_USER)
35 #define PA_DIRTY (1 << PA_BIT_DIRTY)
36 #define PA_WT (1 << PA_BIT_WT)
37 #define PA_CD (1 << PA_BIT_CD)
38 #define PA_ACCESSED (1 << PA_BIT_ACCESSED)
39 #define PA_GLOBAL (1 << PA_BIT_GLOBAL)
41 #define PAGEDIRECTORY_MAP (0xc0000000 + (PTE_BASE / (1024)))
42 #define PAE_PAGEDIRECTORY_MAP (0xc0000000 + (PTE_BASE / (512)))
44 #define HYPERSPACE (Ke386Pae ? 0xc0800000 : 0xc0400000)
45 #define IS_HYPERSPACE(v) (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
47 static ULONG MmGlobalKernelPageDirectory
[1024];
48 static ULONGLONG MmGlobalKernelPageDirectoryForPAE
[2048];
50 #define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT)
51 #define PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
53 #define PAE_PTE_TO_PFN(X) (PAE_PAGE_MASK(X) >> PAGE_SHIFT)
54 #define PAE_PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
56 #define PAGE_MASK(x) ((x)&(~0xfff))
57 #define PAE_PAGE_MASK(x) ((x)&(~0xfffLL))
59 extern BOOLEAN Ke386Pae
;
60 extern BOOLEAN Ke386NoExecute
;
62 /* FUNCTIONS ***************************************************************/
64 BOOLEAN
MmUnmapPageTable(PULONG Pt
);
68 MiFlushTlbIpiRoutine(ULONG_PTR Address
)
70 if (Address
== (ULONGLONG
)-1)
74 else if (Address
== (ULONGLONG
)-2)
80 __invlpg((PVOID
)Address
);
86 MiFlushTlb(PULONG Pt
, PVOID Address
)
93 if (KeNumberProcessors
> 1)
95 KeIpiGenericCall(MiFlushTlbIpiRoutine
, (ULONG_PTR
)Address
);
99 MiFlushTlbIpiRoutine((ULONG_PTR
)Address
);
102 if ((Pt
&& MmUnmapPageTable(Pt
)) || Address
>= MmSystemRangeStart
)
110 ProtectToPTE(ULONG flProtect
)
112 ULONG Attributes
= 0;
114 if (flProtect
& (PAGE_NOACCESS
|PAGE_GUARD
))
118 else if (flProtect
& PAGE_IS_WRITABLE
)
120 Attributes
= PA_PRESENT
| PA_READWRITE
;
122 else if (flProtect
& (PAGE_IS_READABLE
| PAGE_IS_EXECUTABLE
))
124 Attributes
= PA_PRESENT
;
128 DPRINT1("Unknown main protection type.\n");
131 if (Ke386NoExecute
&&
132 !(flProtect
& PAGE_IS_EXECUTABLE
))
134 Attributes
= Attributes
| 0x80000000;
137 if (flProtect
& PAGE_SYSTEM
)
142 Attributes
= Attributes
| PA_USER
;
144 if (flProtect
& PAGE_NOCACHE
)
146 Attributes
= Attributes
| PA_CD
;
148 if (flProtect
& PAGE_WRITETHROUGH
)
150 Attributes
= Attributes
| PA_WT
;
155 #define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (1024 * PAGE_SIZE))
157 #define ADDR_TO_PDE(v) (PULONG)(PAGEDIRECTORY_MAP + \
158 ((((ULONG)(v)) / (1024 * 1024))&(~0x3)))
159 #define ADDR_TO_PTE(v) (PULONG)(PTE_BASE + ((((ULONG)(v) / 1024))&(~0x3)))
161 #define ADDR_TO_PDE_OFFSET(v) ((((ULONG)(v)) / (1024 * PAGE_SIZE)))
163 #define ADDR_TO_PTE_OFFSET(v) ((((ULONG)(v)) % (1024 * PAGE_SIZE)) / PAGE_SIZE)
166 #define PAE_ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (512 * PAGE_SIZE))
168 #define PAE_ADDR_TO_PDE(v) (PULONGLONG) (PAE_PAGEDIRECTORY_MAP + \
169 ((((ULONG_PTR)(v)) / (512 * 512))&(~0x7)))
170 #define PAE_ADDR_TO_PTE(v) (PULONGLONG) (PTE_BASE + ((((ULONG_PTR)(v) / 512))&(~0x7)))
173 #define PAE_ADDR_TO_PDTE_OFFSET(v) (((ULONG_PTR)(v)) / (512 * 512 * PAGE_SIZE))
175 #define PAE_ADDR_TO_PDE_PAGE_OFFSET(v) ((((ULONG_PTR)(v)) % (512 * 512 * PAGE_SIZE)) / (512 * PAGE_SIZE))
177 #define PAE_ADDR_TO_PDE_OFFSET(v) (((ULONG_PTR)(v))/ (512 * PAGE_SIZE))
179 #define PAE_ADDR_TO_PTE_OFFSET(v) ((((ULONG_PTR)(v)) % (512 * PAGE_SIZE)) / PAGE_SIZE)
183 MmCreateProcessAddressSpace(IN ULONG MinWs
,
184 IN PEPROCESS Process
,
185 IN PLARGE_INTEGER DirectoryTableBase
)
192 DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", MinWs
, Process
);
194 Count
= Ke386Pae
? 7 : 2;
196 for (i
= 0; i
< Count
; i
++)
198 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
[i
]);
199 if (!NT_SUCCESS(Status
))
201 for (j
= 0; j
< i
; j
++)
203 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
[j
]);
212 PULONGLONG PageDirTable
;
215 PageDirTable
= MmCreateHyperspaceMapping(Pfn
[0]);
216 for (i
= 0; i
< 4; i
++)
218 PageDirTable
[i
] = PAE_PFN_TO_PTE(Pfn
[1+i
]) | PA_PRESENT
;
220 MmDeleteHyperspaceMapping(PageDirTable
);
221 for (i
= PAE_ADDR_TO_PDTE_OFFSET(MmSystemRangeStart
); i
< 4; i
++)
223 PageDir
= (PULONGLONG
)MmCreateHyperspaceMapping(Pfn
[i
+1]);
224 memcpy(PageDir
, &MmGlobalKernelPageDirectoryForPAE
[i
* 512], 512 * sizeof(ULONGLONG
));
225 if (PAE_ADDR_TO_PDTE_OFFSET(PTE_BASE
) == i
)
227 for (j
= 0; j
< 4; j
++)
229 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(PTE_BASE
) + j
] = PAE_PFN_TO_PTE(Pfn
[1+j
]) | PA_PRESENT
| PA_READWRITE
;
232 if (PAE_ADDR_TO_PDTE_OFFSET(HYPERSPACE
) == i
)
234 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)] = PAE_PFN_TO_PTE(Pfn
[5]) | PA_PRESENT
| PA_READWRITE
;
235 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)+1] = PAE_PFN_TO_PTE(Pfn
[6]) | PA_PRESENT
| PA_READWRITE
;
237 MmDeleteHyperspaceMapping(PageDir
);
242 PULONG PageDirectory
;
243 PageDirectory
= MmCreateHyperspaceMapping(Pfn
[0]);
245 memcpy(PageDirectory
+ ADDR_TO_PDE_OFFSET(MmSystemRangeStart
),
246 MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(MmSystemRangeStart
),
247 (1024 - ADDR_TO_PDE_OFFSET(MmSystemRangeStart
)) * sizeof(ULONG
));
249 DPRINT("Addr %x\n",ADDR_TO_PDE_OFFSET(PTE_BASE
));
250 PageDirectory
[ADDR_TO_PDE_OFFSET(PTE_BASE
)] = PFN_TO_PTE(Pfn
[0]) | PA_PRESENT
| PA_READWRITE
;
251 PageDirectory
[ADDR_TO_PDE_OFFSET(HYPERSPACE
)] = PFN_TO_PTE(Pfn
[1]) | PA_PRESENT
| PA_READWRITE
;
253 MmDeleteHyperspaceMapping(PageDirectory
);
256 DirectoryTableBase
->QuadPart
= PFN_TO_PTE(Pfn
[0]);
257 DPRINT("Finished MmCopyMmInfo(): %I64x\n", DirectoryTableBase
->QuadPart
);
263 MmFreePageTable(PEPROCESS Process
, PVOID Address
)
265 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
269 DPRINT("ProcessId %d, Address %x\n", Process
->UniqueProcessId
, Address
);
270 if (Process
!= NULL
&& Process
!= CurrentProcess
)
272 KeAttachProcess(&Process
->Pcb
);
276 PULONGLONG PageTable
;
277 ULONGLONG ZeroPte
= 0LL;
278 PageTable
= (PULONGLONG
)PAGE_ROUND_DOWN((PVOID
)PAE_ADDR_TO_PTE(Address
));
279 for (i
= 0; i
< 512; i
++)
281 if (PageTable
[i
] != 0LL)
283 DbgPrint("Page table entry not clear at %x/%x (is %I64x)\n",
284 ((ULONG
)Address
/ (4*1024*1024)), i
, PageTable
[i
]);
288 Pfn
= PAE_PTE_TO_PFN(*(PAE_ADDR_TO_PDE(Address
)));
289 (void)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address
), &ZeroPte
);
290 MiFlushTlb((PULONG
)PAE_ADDR_TO_PDE(Address
), PAE_ADDR_TO_PTE(Address
));
295 PageTable
= (PULONG
)PAGE_ROUND_DOWN((PVOID
)ADDR_TO_PTE(Address
));
296 for (i
= 0; i
< 1024; i
++)
298 if (PageTable
[i
] != 0)
300 DbgPrint("Page table entry not clear at %x/%x (is %x)\n",
301 ((ULONG
)Address
/ (4*1024*1024)), i
, PageTable
[i
]);
305 Pfn
= PTE_TO_PFN(*(ADDR_TO_PDE(Address
)));
306 *(ADDR_TO_PDE(Address
)) = 0;
307 MiFlushTlb(ADDR_TO_PDE(Address
), ADDR_TO_PTE(Address
));
310 if (Address
>= MmSystemRangeStart
)
312 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
317 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
319 if (Process
!= NULL
&& Process
!= CurrentProcess
)
326 MmGetPageTableForProcessForPAE(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
331 ULONGLONG ZeroEntry
= 0LL;
334 PULONGLONG PageDirTable
;
336 DPRINT("MmGetPageTableForProcessForPAE(%x %x %d)\n",
337 Process
, Address
, Create
);
338 if (Address
>= (PVOID
)PTE_BASE
&& Address
< (PVOID
)((ULONG_PTR
)PTE_BASE
+ 0x800000))
342 if (Address
< MmSystemRangeStart
&& Process
&& Process
!= PsGetCurrentProcess())
344 PageDirTable
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
345 if (PageDirTable
== NULL
)
349 PageDir
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDirTable
[PAE_ADDR_TO_PDTE_OFFSET(Address
)]));
350 MmDeleteHyperspaceMapping(PageDirTable
);
355 PageDir
+= PAE_ADDR_TO_PDE_PAGE_OFFSET(Address
);
356 Entry
= ExfInterlockedCompareExchange64UL(PageDir
, &ZeroEntry
, &ZeroEntry
);
361 MmDeleteHyperspaceMapping(PageDir
);
364 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
365 if (!NT_SUCCESS(Status
))
369 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
;
370 Entry
= ExfInterlockedCompareExchange64UL(PageDir
, &Entry
, &ZeroEntry
);
373 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
374 Pfn
= PAE_PTE_TO_PFN(Entry
);
379 Pfn
= PAE_PTE_TO_PFN(Entry
);
381 MmDeleteHyperspaceMapping(PageDir
);
382 Pt
= MmCreateHyperspaceMapping(Pfn
);
387 return Pt
+ PAE_ADDR_TO_PTE_OFFSET(Address
);
389 PageDir
= PAE_ADDR_TO_PDE(Address
);
390 if (0LL == ExfInterlockedCompareExchange64UL(PageDir
, &ZeroEntry
, &ZeroEntry
))
392 if (Address
>= MmSystemRangeStart
)
394 if (MmGlobalKernelPageDirectoryForPAE
[PAE_ADDR_TO_PDE_OFFSET(Address
)] == 0LL)
400 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
401 if (!NT_SUCCESS(Status
))
405 Entry
= PAE_PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
;
406 if (Ke386GlobalPagesEnabled
)
410 if (0LL != ExfInterlockedCompareExchange64UL(&MmGlobalKernelPageDirectoryForPAE
[PAE_ADDR_TO_PDE_OFFSET(Address
)], &Entry
, &ZeroEntry
))
412 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
415 (void)ExfInterlockedCompareExchange64UL(PageDir
, &MmGlobalKernelPageDirectoryForPAE
[PAE_ADDR_TO_PDE_OFFSET(Address
)], &ZeroEntry
);
423 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
424 if (!NT_SUCCESS(Status
))
428 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
;
429 Entry
= ExfInterlockedCompareExchange64UL(PageDir
, &Entry
, &ZeroEntry
);
432 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
436 return (PULONGLONG
)PAE_ADDR_TO_PTE(Address
);
440 MmGetPageTableForProcess(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
442 ULONG PdeOffset
= ADDR_TO_PDE_OFFSET(Address
);
448 if (Address
< MmSystemRangeStart
&& Process
&& Process
!= PsGetCurrentProcess())
450 PageDir
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.LowPart
));
455 if (0 == InterlockedCompareExchangeUL(&PageDir
[PdeOffset
], 0, 0))
459 MmDeleteHyperspaceMapping(PageDir
);
462 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
463 if (!NT_SUCCESS(Status
) || Pfn
== 0)
467 Entry
= InterlockedCompareExchangeUL(&PageDir
[PdeOffset
], PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
470 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
471 Pfn
= PTE_TO_PFN(Entry
);
476 Pfn
= PTE_TO_PFN(PageDir
[PdeOffset
]);
478 MmDeleteHyperspaceMapping(PageDir
);
479 Pt
= MmCreateHyperspaceMapping(Pfn
);
484 return Pt
+ ADDR_TO_PTE_OFFSET(Address
);
486 PageDir
= ADDR_TO_PDE(Address
);
487 if (0 == InterlockedCompareExchangeUL(PageDir
, 0, 0))
489 if (Address
>= MmSystemRangeStart
)
491 if (0 == InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory
[PdeOffset
], 0, 0))
497 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
498 if (!NT_SUCCESS(Status
) || Pfn
== 0)
502 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
;
503 if (Ke386GlobalPagesEnabled
)
507 if(0 != InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory
[PdeOffset
], Entry
, 0))
509 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
512 (void)InterlockedExchangeUL(PageDir
, MmGlobalKernelPageDirectory
[PdeOffset
]);
520 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
521 if (!NT_SUCCESS(Status
) || Pfn
== 0)
525 Entry
= InterlockedCompareExchangeUL(PageDir
, PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
528 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
532 return (PULONG
)ADDR_TO_PTE(Address
);
535 BOOLEAN
MmUnmapPageTable(PULONG Pt
)
539 if ((PULONGLONG
)Pt
>= (PULONGLONG
)PTE_BASE
&& (PULONGLONG
)Pt
< (PULONGLONG
)PTE_BASE
+ 4*512*512)
546 if (Pt
>= (PULONG
)PTE_BASE
&& Pt
< (PULONG
)PTE_BASE
+ 1024*1024)
553 MmDeleteHyperspaceMapping((PVOID
)PAGE_ROUND_DOWN(Pt
));
558 static ULONGLONG
MmGetPageEntryForProcessForPAE(PEPROCESS Process
, PVOID Address
)
563 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
567 MmUnmapPageTable((PULONG
)Pt
);
573 static ULONG
MmGetPageEntryForProcess(PEPROCESS Process
, PVOID Address
)
578 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
582 MmUnmapPageTable(Pt
);
590 MmGetPfnForProcess(PEPROCESS Process
,
597 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
598 if (!(Entry
& PA_PRESENT
))
602 return(PAE_PTE_TO_PFN(Entry
));
607 Entry
= MmGetPageEntryForProcess(Process
, Address
);
608 if (!(Entry
& PA_PRESENT
))
612 return(PTE_TO_PFN(Entry
));
618 MmDeleteVirtualMapping(PEPROCESS Process
, PVOID Address
,
619 BOOLEAN
* WasDirty
, PPFN_NUMBER Page
)
621 * FUNCTION: Delete a virtual mapping
624 BOOLEAN WasValid
= FALSE
;
627 DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
628 Process
, Address
, WasDirty
, Page
);
634 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
637 if (WasDirty
!= NULL
)
649 * Atomically set the entry to zero and get the old value.
652 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
654 MiFlushTlb((PULONG
)Pt
, Address
);
656 WasValid
= PAE_PAGE_MASK(Pte
) != 0 ? TRUE
: FALSE
;
659 Pfn
= PAE_PTE_TO_PFN(Pte
);
660 MmMarkPageUnmapped(Pfn
);
668 * Return some information to the caller
670 if (WasDirty
!= NULL
)
672 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
684 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
688 if (WasDirty
!= NULL
)
700 * Atomically set the entry to zero and get the old value.
702 Pte
= InterlockedExchangeUL(Pt
, 0);
704 MiFlushTlb(Pt
, Address
);
706 WasValid
= (PAGE_MASK(Pte
) != 0);
709 Pfn
= PTE_TO_PFN(Pte
);
710 MmMarkPageUnmapped(Pfn
);
718 * Return some information to the caller
720 if (WasDirty
!= NULL
)
722 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
730 * Decrement the reference count for this page table.
732 if (Process
!= NULL
&& WasValid
&&
733 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
734 Address
< MmSystemRangeStart
)
739 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
740 Idx
= Ke386Pae
? PAE_ADDR_TO_PAGE_TABLE(Address
) : ADDR_TO_PAGE_TABLE(Address
);
745 MmFreePageTable(Process
, Address
);
752 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
753 SWAPENTRY
* SwapEntry
)
755 * FUNCTION: Delete a virtual mapping
763 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
771 * Atomically set the entry to zero and get the old value.
774 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
776 MiFlushTlb((PULONG
)Pt
, Address
);
779 * Decrement the reference count for this page table.
781 if (Process
!= NULL
&& Pte
&&
782 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
783 Address
< MmSystemRangeStart
)
787 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
789 Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Address
)]--;
790 if (Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Address
)] == 0)
792 MmFreePageTable(Process
, Address
);
798 * Return some information to the caller
800 *SwapEntry
= Pte
>> 1;
807 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
816 * Atomically set the entry to zero and get the old value.
818 Pte
= InterlockedExchangeUL(Pt
, 0);
820 MiFlushTlb(Pt
, Address
);
823 * Decrement the reference count for this page table.
825 if (Process
!= NULL
&& Pte
&&
826 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
827 Address
< MmSystemRangeStart
)
831 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
833 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]--;
834 if (Ptrc
[ADDR_TO_PAGE_TABLE(Address
)] == 0)
836 MmFreePageTable(Process
, Address
);
842 * Return some information to the caller
844 *SwapEntry
= Pte
>> 1;
849 Mmi386MakeKernelPageTableGlobal(PVOID PAddress
)
855 Pde
= PAE_ADDR_TO_PDE(PAddress
);
858 Pt
= MmGetPageTableForProcessForPAE(NULL
, PAddress
, FALSE
);
860 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
861 FLASH_TLB_ONE(PAddress
);
872 Pde
= ADDR_TO_PDE(PAddress
);
875 Pt
= MmGetPageTableForProcess(NULL
, PAddress
, FALSE
);
877 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
878 FLASH_TLB_ONE(PAddress
);
891 MmIsDirtyPage(PEPROCESS Process
, PVOID Address
)
895 return MmGetPageEntryForProcessForPAE(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
899 return MmGetPageEntryForProcess(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
905 MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
907 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
909 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
918 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
928 tmpPte
= Pte
& ~PA_DIRTY
;
929 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
933 MiFlushTlb((PULONG
)Pt
, Address
);
937 MmUnmapPageTable((PULONG
)Pt
);
945 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
955 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_DIRTY
, Pte
));
959 MiFlushTlb(Pt
, Address
);
963 MmUnmapPageTable(Pt
);
970 MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
972 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
974 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
983 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
992 tmpPte
= Pte
| PA_DIRTY
;
993 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
994 if (!(Pte
& PA_DIRTY
))
996 MiFlushTlb((PULONG
)Pt
, Address
);
1000 MmUnmapPageTable((PULONG
)Pt
);
1008 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1017 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
| PA_DIRTY
, Pte
));
1018 if (!(Pte
& PA_DIRTY
))
1020 MiFlushTlb(Pt
, Address
);
1024 MmUnmapPageTable(Pt
);
1031 MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
1035 return MmGetPageEntryForProcessForPAE(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
1039 return MmGetPageEntryForProcess(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
1045 MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
1050 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
1051 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
1056 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1057 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
1063 MmCreatePageFileMapping(PEPROCESS Process
,
1065 SWAPENTRY SwapEntry
)
1067 if (Process
== NULL
&& Address
< MmSystemRangeStart
)
1069 DPRINT1("No process\n");
1072 if (Process
!= NULL
&& Address
>= MmSystemRangeStart
)
1074 DPRINT1("Setting kernel address with process context\n");
1077 if (SwapEntry
& (1 << 31))
1088 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, TRUE
);
1093 tmpPte
= SwapEntry
<< 1;
1094 Pte
= ExfpInterlockedExchange64UL(Pt
, &tmpPte
);
1095 if (PAE_PAGE_MASK((Pte
)) != 0)
1097 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte
)));
1102 MiFlushTlb((PULONG
)Pt
, Address
);
1106 MmUnmapPageTable((PULONG
)Pt
);
1114 Pt
= MmGetPageTableForProcess(Process
, Address
, TRUE
);
1120 if (PAGE_MASK((Pte
)) != 0)
1122 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1124 (void)InterlockedExchangeUL(Pt
, SwapEntry
<< 1);
1127 MiFlushTlb(Pt
, Address
);
1131 MmUnmapPageTable(Pt
);
1134 if (Process
!= NULL
&&
1135 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
1136 Address
< MmSystemRangeStart
)
1141 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
1142 Idx
= Ke386Pae
? PAE_ADDR_TO_PAGE_TABLE(Address
) : ADDR_TO_PAGE_TABLE(Address
);
1145 return(STATUS_SUCCESS
);
1151 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
1160 ULONG oldPdeOffset
, PdeOffset
;
1161 BOOLEAN NoExecute
= FALSE
;
1163 DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
1164 Process
, Address
, flProtect
, Pages
, *Pages
, PageCount
);
1166 if (Process
== NULL
)
1168 if (Address
< MmSystemRangeStart
)
1170 DPRINT1("No process\n");
1173 if (PageCount
> 0x10000 ||
1174 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> 0x100000)
1176 DPRINT1("Page count to large\n");
1182 if (Address
>= MmSystemRangeStart
)
1184 DPRINT1("Setting kernel address with process context\n");
1187 if (PageCount
> (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
||
1188 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
>
1189 (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
)
1191 DPRINT1("Page Count to large\n");
1196 Attributes
= ProtectToPTE(flProtect
);
1197 if (Attributes
& 0x80000000)
1201 Attributes
&= 0xfff;
1202 if (Address
>= MmSystemRangeStart
)
1204 Attributes
&= ~PA_USER
;
1205 if (Ke386GlobalPagesEnabled
)
1207 Attributes
|= PA_GLOBAL
;
1212 Attributes
|= PA_USER
;
1219 ULONGLONG Pte
, tmpPte
;
1220 PULONGLONG Pt
= NULL
;
1222 oldPdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
) + 1;
1223 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
1225 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1227 DPRINT1("Setting physical address but not allowing access at address "
1228 "0x%.8X with attributes %x/%x.\n",
1229 Addr
, Attributes
, flProtect
);
1232 PdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
);
1233 if (oldPdeOffset
!= PdeOffset
)
1235 MmUnmapPageTable((PULONG
)Pt
);
1236 Pt
= MmGetPageTableForProcessForPAE(Process
, Addr
, TRUE
);
1246 oldPdeOffset
= PdeOffset
;
1248 MmMarkPageMapped(Pages
[i
]);
1249 tmpPte
= PAE_PFN_TO_PTE(Pages
[i
]) | Attributes
;
1252 tmpPte
|= 0x8000000000000000LL
;
1254 Pte
= ExfpInterlockedExchange64UL(Pt
, &tmpPte
);
1255 if (PAE_PAGE_MASK((Pte
)) != 0LL && !((Pte
) & PA_PRESENT
))
1259 if (PAE_PAGE_MASK((Pte
)) != 0LL)
1261 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte
)));
1263 if (Address
< MmSystemRangeStart
&&
1264 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
1265 Attributes
& PA_PRESENT
)
1269 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
1271 Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Addr
)]++;
1275 if (Address
> MmSystemRangeStart
||
1276 (Pt
>= (PULONGLONG
)PTE_BASE
&& Pt
< (PULONGLONG
)PTE_BASE
+ 4*512*512))
1278 MiFlushTlb((PULONG
)Pt
, Address
);
1284 MmUnmapPageTable((PULONG
)Pt
);
1291 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
) + 1;
1292 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
1294 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1296 DPRINT1("Setting physical address but not allowing access at address "
1297 "0x%.8X with attributes %x/%x.\n",
1298 Addr
, Attributes
, flProtect
);
1301 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1302 if (oldPdeOffset
!= PdeOffset
)
1304 MmUnmapPageTable(Pt
);
1305 Pt
= MmGetPageTableForProcess(Process
, Addr
, TRUE
);
1315 oldPdeOffset
= PdeOffset
;
1318 MmMarkPageMapped(Pages
[i
]);
1319 if (PAGE_MASK((Pte
)) != 0 && !((Pte
) & PA_PRESENT
))
1323 if (PAGE_MASK((Pte
)) != 0)
1325 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1327 (void)InterlockedExchangeUL(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
1328 if (Address
< MmSystemRangeStart
&&
1329 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
1330 Attributes
& PA_PRESENT
)
1334 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
1336 Ptrc
[ADDR_TO_PAGE_TABLE(Addr
)]++;
1340 if (Address
> MmSystemRangeStart
||
1341 (Pt
>= (PULONG
)PTE_BASE
&& Pt
< (PULONG
)PTE_BASE
+ 1024*1024))
1343 MiFlushTlb(Pt
, Address
);
1349 MmUnmapPageTable(Pt
);
1352 return(STATUS_SUCCESS
);
1357 MmCreateVirtualMapping(PEPROCESS Process
,
1365 for (i
= 0; i
< PageCount
; i
++)
1367 if (!MmIsPageInUse(Pages
[i
]))
1369 DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages
[i
]));
1374 return(MmCreateVirtualMappingUnsafe(Process
,
1383 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
1389 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
1393 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1396 if (!(Entry
& PA_PRESENT
))
1398 Protect
= PAGE_NOACCESS
;
1402 if (Entry
& PA_READWRITE
)
1404 Protect
= PAGE_READWRITE
;
1408 Protect
= PAGE_EXECUTE_READ
;
1412 Protect
|= PAGE_NOCACHE
;
1416 Protect
|= PAGE_WRITETHROUGH
;
1418 if (!(Entry
& PA_USER
))
1420 Protect
|= PAGE_SYSTEM
;
1429 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
1431 ULONG Attributes
= 0;
1432 BOOLEAN NoExecute
= FALSE
;
1434 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
1435 Process
, Address
, flProtect
);
1437 Attributes
= ProtectToPTE(flProtect
);
1438 if (Attributes
& 0x80000000)
1442 Attributes
&= 0xfff;
1443 if (Address
>= MmSystemRangeStart
)
1445 Attributes
&= ~PA_USER
;
1446 if (Ke386GlobalPagesEnabled
)
1448 Attributes
|= PA_GLOBAL
;
1453 Attributes
|= PA_USER
;
1458 ULONGLONG tmpPte
, Pte
;
1460 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1463 DPRINT1("Address %x\n", Address
);
1469 tmpPte
= PAE_PAGE_MASK(Pte
) | Attributes
| (Pte
& (PA_ACCESSED
|PA_DIRTY
));
1472 tmpPte
|= 0x8000000000000000LL
;
1476 tmpPte
&= ~0x8000000000000000LL
;
1478 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1480 MiFlushTlb((PULONG
)Pt
, Address
);
1486 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1491 InterlockedExchange((PLONG
)Pt
, PAGE_MASK(*Pt
) | Attributes
| (*Pt
& (PA_ACCESSED
|PA_DIRTY
)));
1492 MiFlushTlb(Pt
, Address
);
1499 MmInitGlobalKernelPageDirectory(VOID
)
1503 DPRINT("MmInitGlobalKernelPageDirectory()\n");
1507 PULONGLONG CurrentPageDirectory
= (PULONGLONG
)PAE_PAGEDIRECTORY_MAP
;
1508 for (i
= PAE_ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
< 4 * 512; i
++)
1510 if (!(i
>= PAE_ADDR_TO_PDE_OFFSET(PTE_BASE
) && i
< PAE_ADDR_TO_PDE_OFFSET(PTE_BASE
) + 4) &&
1511 !(i
>= PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
) && i
< PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
) + 2) &&
1512 0LL == MmGlobalKernelPageDirectoryForPAE
[i
] && 0LL != CurrentPageDirectory
[i
])
1514 (void)ExfpInterlockedExchange64UL(&MmGlobalKernelPageDirectoryForPAE
[i
], &CurrentPageDirectory
[i
]);
1515 if (Ke386GlobalPagesEnabled
)
1517 MmGlobalKernelPageDirectoryForPAE
[i
] |= PA_GLOBAL
;
1518 CurrentPageDirectory
[i
] |= PA_GLOBAL
;
1525 PULONG CurrentPageDirectory
= (PULONG
)PAGEDIRECTORY_MAP
;
1526 for (i
= ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
< 1024; i
++)
1528 if (i
!= ADDR_TO_PDE_OFFSET(PTE_BASE
) &&
1529 i
!= ADDR_TO_PDE_OFFSET(HYPERSPACE
) &&
1530 0 == MmGlobalKernelPageDirectory
[i
] && 0 != CurrentPageDirectory
[i
])
1532 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];
1533 if (Ke386GlobalPagesEnabled
)
1535 MmGlobalKernelPageDirectory
[i
] |= PA_GLOBAL
;
1536 CurrentPageDirectory
[i
] |= PA_GLOBAL
;