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 PAGETABLE_MAP (0xc0000000)
42 #define PAGEDIRECTORY_MAP (0xc0000000 + (PAGETABLE_MAP / (1024)))
44 #define PAE_PAGEDIRECTORY_MAP (0xc0000000 + (PAGETABLE_MAP / (512)))
46 #define HYPERSPACE (Ke386Pae ? 0xc0800000 : 0xc0400000)
47 #define IS_HYPERSPACE(v) (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
49 ULONG MmGlobalKernelPageDirectory
[1024];
50 ULONGLONG MmGlobalKernelPageDirectoryForPAE
[2048];
52 #define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT)
53 #define PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
55 #define PAE_PTE_TO_PFN(X) (PAE_PAGE_MASK(X) >> PAGE_SHIFT)
56 #define PAE_PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
58 extern BOOLEAN Ke386Pae
;
59 extern BOOLEAN Ke386NoExecute
;
61 /* FUNCTIONS ***************************************************************/
63 BOOLEAN
MmUnmapPageTable(PULONG Pt
);
67 MiFlushTlbIpiRoutine(ULONG_PTR Address
)
69 if (Address
== (ULONGLONG
)-1)
73 else if (Address
== (ULONGLONG
)-2)
79 __invlpg((PVOID
)Address
);
85 MiFlushTlb(PULONG Pt
, PVOID Address
)
92 if (KeNumberProcessors
> 1)
94 KeIpiGenericCall(MiFlushTlbIpiRoutine
, (ULONG_PTR
)Address
);
98 MiFlushTlbIpiRoutine((ULONG_PTR
)Address
);
101 if ((Pt
&& MmUnmapPageTable(Pt
)) || Address
>= MmSystemRangeStart
)
111 MmGetPageDirectory(VOID
)
113 return (PULONG
)__readcr3();
117 ProtectToPTE(ULONG flProtect
)
119 ULONG Attributes
= 0;
121 if (flProtect
& (PAGE_NOACCESS
|PAGE_GUARD
))
125 else if (flProtect
& PAGE_IS_WRITABLE
)
127 Attributes
= PA_PRESENT
| PA_READWRITE
;
129 else if (flProtect
& (PAGE_IS_READABLE
| PAGE_IS_EXECUTABLE
))
131 Attributes
= PA_PRESENT
;
135 DPRINT1("Unknown main protection type.\n");
138 if (Ke386NoExecute
&&
139 !(flProtect
& PAGE_IS_EXECUTABLE
))
141 Attributes
= Attributes
| 0x80000000;
144 if (flProtect
& PAGE_SYSTEM
)
149 Attributes
= Attributes
| PA_USER
;
151 if (flProtect
& PAGE_NOCACHE
)
153 Attributes
= Attributes
| PA_CD
;
155 if (flProtect
& PAGE_WRITETHROUGH
)
157 Attributes
= Attributes
| PA_WT
;
162 #define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (1024 * PAGE_SIZE))
164 #define ADDR_TO_PDE(v) (PULONG)(PAGEDIRECTORY_MAP + \
165 ((((ULONG)(v)) / (1024 * 1024))&(~0x3)))
166 #define ADDR_TO_PTE(v) (PULONG)(PAGETABLE_MAP + ((((ULONG)(v) / 1024))&(~0x3)))
168 #define ADDR_TO_PDE_OFFSET(v) ((((ULONG)(v)) / (1024 * PAGE_SIZE)))
170 #define ADDR_TO_PTE_OFFSET(v) ((((ULONG)(v)) % (1024 * PAGE_SIZE)) / PAGE_SIZE)
173 #define PAE_ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (512 * PAGE_SIZE))
175 #define PAE_ADDR_TO_PDE(v) (PULONGLONG) (PAE_PAGEDIRECTORY_MAP + \
176 ((((ULONG_PTR)(v)) / (512 * 512))&(~0x7)))
177 #define PAE_ADDR_TO_PTE(v) (PULONGLONG) (PAGETABLE_MAP + ((((ULONG_PTR)(v) / 512))&(~0x7)))
180 #define PAE_ADDR_TO_PDTE_OFFSET(v) (((ULONG_PTR)(v)) / (512 * 512 * PAGE_SIZE))
182 #define PAE_ADDR_TO_PDE_PAGE_OFFSET(v) ((((ULONG_PTR)(v)) % (512 * 512 * PAGE_SIZE)) / (512 * PAGE_SIZE))
184 #define PAE_ADDR_TO_PDE_OFFSET(v) (((ULONG_PTR)(v))/ (512 * PAGE_SIZE))
186 #define PAE_ADDR_TO_PTE_OFFSET(v) ((((ULONG_PTR)(v)) % (512 * PAGE_SIZE)) / PAGE_SIZE)
190 MmCreateProcessAddressSpace(IN ULONG MinWs
,
191 IN PEPROCESS Process
,
192 IN PLARGE_INTEGER DirectoryTableBase
)
199 DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", MinWs
, Process
);
201 Count
= Ke386Pae
? 7 : 2;
203 for (i
= 0; i
< Count
; i
++)
205 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
[i
]);
206 if (!NT_SUCCESS(Status
))
208 for (j
= 0; j
< i
; j
++)
210 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
[j
]);
219 PULONGLONG PageDirTable
;
222 PageDirTable
= MmCreateHyperspaceMapping(Pfn
[0]);
223 for (i
= 0; i
< 4; i
++)
225 PageDirTable
[i
] = PAE_PFN_TO_PTE(Pfn
[1+i
]) | PA_PRESENT
;
227 MmDeleteHyperspaceMapping(PageDirTable
);
228 for (i
= PAE_ADDR_TO_PDTE_OFFSET(MmSystemRangeStart
); i
< 4; i
++)
230 PageDir
= (PULONGLONG
)MmCreateHyperspaceMapping(Pfn
[i
+1]);
231 memcpy(PageDir
, &MmGlobalKernelPageDirectoryForPAE
[i
* 512], 512 * sizeof(ULONGLONG
));
232 if (PAE_ADDR_TO_PDTE_OFFSET(PAGETABLE_MAP
) == i
)
234 for (j
= 0; j
< 4; j
++)
236 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(PAGETABLE_MAP
) + j
] = PAE_PFN_TO_PTE(Pfn
[1+j
]) | PA_PRESENT
| PA_READWRITE
;
239 if (PAE_ADDR_TO_PDTE_OFFSET(HYPERSPACE
) == i
)
241 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)] = PAE_PFN_TO_PTE(Pfn
[5]) | PA_PRESENT
| PA_READWRITE
;
242 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)+1] = PAE_PFN_TO_PTE(Pfn
[6]) | PA_PRESENT
| PA_READWRITE
;
244 MmDeleteHyperspaceMapping(PageDir
);
249 PULONG PageDirectory
;
250 PageDirectory
= MmCreateHyperspaceMapping(Pfn
[0]);
252 memcpy(PageDirectory
+ ADDR_TO_PDE_OFFSET(MmSystemRangeStart
),
253 MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(MmSystemRangeStart
),
254 (1024 - ADDR_TO_PDE_OFFSET(MmSystemRangeStart
)) * sizeof(ULONG
));
256 DPRINT("Addr %x\n",ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
));
257 PageDirectory
[ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
)] = PFN_TO_PTE(Pfn
[0]) | PA_PRESENT
| PA_READWRITE
;
258 PageDirectory
[ADDR_TO_PDE_OFFSET(HYPERSPACE
)] = PFN_TO_PTE(Pfn
[1]) | PA_PRESENT
| PA_READWRITE
;
260 MmDeleteHyperspaceMapping(PageDirectory
);
263 DirectoryTableBase
->QuadPart
= PFN_TO_PTE(Pfn
[0]);
264 DPRINT("Finished MmCopyMmInfo(): %I64x\n", DirectoryTableBase
->QuadPart
);
270 MmFreePageTable(PEPROCESS Process
, PVOID Address
)
272 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
276 DPRINT("ProcessId %d, Address %x\n", Process
->UniqueProcessId
, Address
);
277 if (Process
!= NULL
&& Process
!= CurrentProcess
)
279 KeAttachProcess(&Process
->Pcb
);
283 PULONGLONG PageTable
;
284 ULONGLONG ZeroPte
= 0LL;
285 PageTable
= (PULONGLONG
)PAGE_ROUND_DOWN((PVOID
)PAE_ADDR_TO_PTE(Address
));
286 for (i
= 0; i
< 512; i
++)
288 if (PageTable
[i
] != 0LL)
290 DbgPrint("Page table entry not clear at %x/%x (is %I64x)\n",
291 ((ULONG
)Address
/ (4*1024*1024)), i
, PageTable
[i
]);
295 Pfn
= PAE_PTE_TO_PFN(*(PAE_ADDR_TO_PDE(Address
)));
296 (void)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address
), &ZeroPte
);
297 MiFlushTlb((PULONG
)PAE_ADDR_TO_PDE(Address
), PAE_ADDR_TO_PTE(Address
));
302 PageTable
= (PULONG
)PAGE_ROUND_DOWN((PVOID
)ADDR_TO_PTE(Address
));
303 for (i
= 0; i
< 1024; i
++)
305 if (PageTable
[i
] != 0)
307 DbgPrint("Page table entry not clear at %x/%x (is %x)\n",
308 ((ULONG
)Address
/ (4*1024*1024)), i
, PageTable
[i
]);
312 Pfn
= PTE_TO_PFN(*(ADDR_TO_PDE(Address
)));
313 *(ADDR_TO_PDE(Address
)) = 0;
314 MiFlushTlb(ADDR_TO_PDE(Address
), ADDR_TO_PTE(Address
));
317 if (Address
>= MmSystemRangeStart
)
319 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
324 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
326 if (Process
!= NULL
&& Process
!= CurrentProcess
)
333 MmGetPageTableForProcessForPAE(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
338 ULONGLONG ZeroEntry
= 0LL;
341 PULONGLONG PageDirTable
;
343 DPRINT("MmGetPageTableForProcessForPAE(%x %x %d)\n",
344 Process
, Address
, Create
);
345 if (Address
>= (PVOID
)PAGETABLE_MAP
&& Address
< (PVOID
)((ULONG_PTR
)PAGETABLE_MAP
+ 0x800000))
349 if (Address
< MmSystemRangeStart
&& Process
&& Process
!= PsGetCurrentProcess())
351 PageDirTable
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
352 if (PageDirTable
== NULL
)
356 PageDir
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDirTable
[PAE_ADDR_TO_PDTE_OFFSET(Address
)]));
357 MmDeleteHyperspaceMapping(PageDirTable
);
362 PageDir
+= PAE_ADDR_TO_PDE_PAGE_OFFSET(Address
);
363 Entry
= ExfInterlockedCompareExchange64UL(PageDir
, &ZeroEntry
, &ZeroEntry
);
368 MmDeleteHyperspaceMapping(PageDir
);
371 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
372 if (!NT_SUCCESS(Status
))
376 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
;
377 Entry
= ExfInterlockedCompareExchange64UL(PageDir
, &Entry
, &ZeroEntry
);
380 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
381 Pfn
= PAE_PTE_TO_PFN(Entry
);
386 Pfn
= PAE_PTE_TO_PFN(Entry
);
388 MmDeleteHyperspaceMapping(PageDir
);
389 Pt
= MmCreateHyperspaceMapping(Pfn
);
394 return Pt
+ PAE_ADDR_TO_PTE_OFFSET(Address
);
396 PageDir
= PAE_ADDR_TO_PDE(Address
);
397 if (0LL == ExfInterlockedCompareExchange64UL(PageDir
, &ZeroEntry
, &ZeroEntry
))
399 if (Address
>= MmSystemRangeStart
)
401 if (MmGlobalKernelPageDirectoryForPAE
[PAE_ADDR_TO_PDE_OFFSET(Address
)] == 0LL)
407 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
408 if (!NT_SUCCESS(Status
))
412 Entry
= PAE_PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
;
413 if (Ke386GlobalPagesEnabled
)
417 if (0LL != ExfInterlockedCompareExchange64UL(&MmGlobalKernelPageDirectoryForPAE
[PAE_ADDR_TO_PDE_OFFSET(Address
)], &Entry
, &ZeroEntry
))
419 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
422 (void)ExfInterlockedCompareExchange64UL(PageDir
, &MmGlobalKernelPageDirectoryForPAE
[PAE_ADDR_TO_PDE_OFFSET(Address
)], &ZeroEntry
);
430 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
431 if (!NT_SUCCESS(Status
))
435 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
;
436 Entry
= ExfInterlockedCompareExchange64UL(PageDir
, &Entry
, &ZeroEntry
);
439 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
443 return (PULONGLONG
)PAE_ADDR_TO_PTE(Address
);
447 MmGetPageTableForProcess(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
449 ULONG PdeOffset
= ADDR_TO_PDE_OFFSET(Address
);
455 if (Address
< MmSystemRangeStart
&& Process
&& Process
!= PsGetCurrentProcess())
457 PageDir
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.LowPart
));
462 if (0 == InterlockedCompareExchangeUL(&PageDir
[PdeOffset
], 0, 0))
466 MmDeleteHyperspaceMapping(PageDir
);
469 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
470 if (!NT_SUCCESS(Status
) || Pfn
== 0)
474 Entry
= InterlockedCompareExchangeUL(&PageDir
[PdeOffset
], PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
477 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
478 Pfn
= PTE_TO_PFN(Entry
);
483 Pfn
= PTE_TO_PFN(PageDir
[PdeOffset
]);
485 MmDeleteHyperspaceMapping(PageDir
);
486 Pt
= MmCreateHyperspaceMapping(Pfn
);
491 return Pt
+ ADDR_TO_PTE_OFFSET(Address
);
493 PageDir
= ADDR_TO_PDE(Address
);
494 if (0 == InterlockedCompareExchangeUL(PageDir
, 0, 0))
496 if (Address
>= MmSystemRangeStart
)
498 if (0 == InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory
[PdeOffset
], 0, 0))
504 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
505 if (!NT_SUCCESS(Status
) || Pfn
== 0)
509 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
;
510 if (Ke386GlobalPagesEnabled
)
514 if(0 != InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory
[PdeOffset
], Entry
, 0))
516 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
519 (void)InterlockedExchangeUL(PageDir
, MmGlobalKernelPageDirectory
[PdeOffset
]);
527 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
528 if (!NT_SUCCESS(Status
) || Pfn
== 0)
532 Entry
= InterlockedCompareExchangeUL(PageDir
, PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
535 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
539 return (PULONG
)ADDR_TO_PTE(Address
);
542 BOOLEAN
MmUnmapPageTable(PULONG Pt
)
546 if ((PULONGLONG
)Pt
>= (PULONGLONG
)PAGETABLE_MAP
&& (PULONGLONG
)Pt
< (PULONGLONG
)PAGETABLE_MAP
+ 4*512*512)
553 if (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024)
560 MmDeleteHyperspaceMapping((PVOID
)PAGE_ROUND_DOWN(Pt
));
565 static ULONGLONG
MmGetPageEntryForProcessForPAE(PEPROCESS Process
, PVOID Address
)
570 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
574 MmUnmapPageTable((PULONG
)Pt
);
580 static ULONG
MmGetPageEntryForProcess(PEPROCESS Process
, PVOID Address
)
585 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
589 MmUnmapPageTable(Pt
);
597 MmGetPfnForProcess(PEPROCESS Process
,
604 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
605 if (!(Entry
& PA_PRESENT
))
609 return(PAE_PTE_TO_PFN(Entry
));
614 Entry
= MmGetPageEntryForProcess(Process
, Address
);
615 if (!(Entry
& PA_PRESENT
))
619 return(PTE_TO_PFN(Entry
));
625 MmDeleteVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOLEAN FreePage
,
626 BOOLEAN
* WasDirty
, PPFN_NUMBER Page
)
628 * FUNCTION: Delete a virtual mapping
631 BOOLEAN WasValid
= FALSE
;
634 DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
635 Process
, Address
, FreePage
, WasDirty
, Page
);
641 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
644 if (WasDirty
!= NULL
)
656 * Atomically set the entry to zero and get the old value.
659 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
661 MiFlushTlb((PULONG
)Pt
, Address
);
663 WasValid
= PAE_PAGE_MASK(Pte
) != 0 ? TRUE
: FALSE
;
666 Pfn
= PAE_PTE_TO_PFN(Pte
);
667 MmMarkPageUnmapped(Pfn
);
674 if (FreePage
&& WasValid
)
676 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
680 * Return some information to the caller
682 if (WasDirty
!= NULL
)
684 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
696 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
700 if (WasDirty
!= NULL
)
712 * Atomically set the entry to zero and get the old value.
714 Pte
= InterlockedExchangeUL(Pt
, 0);
716 MiFlushTlb(Pt
, Address
);
718 WasValid
= (PAGE_MASK(Pte
) != 0);
721 Pfn
= PTE_TO_PFN(Pte
);
722 MmMarkPageUnmapped(Pfn
);
729 if (FreePage
&& WasValid
)
731 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
735 * Return some information to the caller
737 if (WasDirty
!= NULL
)
739 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
747 * Decrement the reference count for this page table.
749 if (Process
!= NULL
&& WasValid
&&
750 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
751 Address
< MmSystemRangeStart
)
756 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
757 Idx
= Ke386Pae
? PAE_ADDR_TO_PAGE_TABLE(Address
) : ADDR_TO_PAGE_TABLE(Address
);
762 MmFreePageTable(Process
, Address
);
769 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
770 SWAPENTRY
* SwapEntry
)
772 * FUNCTION: Delete a virtual mapping
780 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
788 * Atomically set the entry to zero and get the old value.
791 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
793 MiFlushTlb((PULONG
)Pt
, Address
);
796 * Decrement the reference count for this page table.
798 if (Process
!= NULL
&& Pte
&&
799 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
800 Address
< MmSystemRangeStart
)
804 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
806 Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Address
)]--;
807 if (Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Address
)] == 0)
809 MmFreePageTable(Process
, Address
);
815 * Return some information to the caller
817 *SwapEntry
= Pte
>> 1;
824 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
833 * Atomically set the entry to zero and get the old value.
835 Pte
= InterlockedExchangeUL(Pt
, 0);
837 MiFlushTlb(Pt
, Address
);
840 * Decrement the reference count for this page table.
842 if (Process
!= NULL
&& Pte
&&
843 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
844 Address
< MmSystemRangeStart
)
848 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
850 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]--;
851 if (Ptrc
[ADDR_TO_PAGE_TABLE(Address
)] == 0)
853 MmFreePageTable(Process
, Address
);
859 * Return some information to the caller
861 *SwapEntry
= Pte
>> 1;
866 Mmi386MakeKernelPageTableGlobal(PVOID PAddress
)
872 Pde
= PAE_ADDR_TO_PDE(PAddress
);
875 Pt
= MmGetPageTableForProcessForPAE(NULL
, PAddress
, FALSE
);
877 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
878 FLASH_TLB_ONE(PAddress
);
889 Pde
= ADDR_TO_PDE(PAddress
);
892 Pt
= MmGetPageTableForProcess(NULL
, PAddress
, FALSE
);
894 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
895 FLASH_TLB_ONE(PAddress
);
908 MmIsDirtyPage(PEPROCESS Process
, PVOID Address
)
912 return MmGetPageEntryForProcessForPAE(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
916 return MmGetPageEntryForProcess(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
922 MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
924 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
926 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
935 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
945 tmpPte
= Pte
& ~PA_DIRTY
;
946 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
950 MiFlushTlb((PULONG
)Pt
, Address
);
954 MmUnmapPageTable((PULONG
)Pt
);
962 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
972 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_DIRTY
, Pte
));
976 MiFlushTlb(Pt
, Address
);
980 MmUnmapPageTable(Pt
);
987 MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
989 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
991 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
1000 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1009 tmpPte
= Pte
| PA_DIRTY
;
1010 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1011 if (!(Pte
& PA_DIRTY
))
1013 MiFlushTlb((PULONG
)Pt
, Address
);
1017 MmUnmapPageTable((PULONG
)Pt
);
1025 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1034 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
| PA_DIRTY
, Pte
));
1035 if (!(Pte
& PA_DIRTY
))
1037 MiFlushTlb(Pt
, Address
);
1041 MmUnmapPageTable(Pt
);
1048 MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
1052 return MmGetPageEntryForProcessForPAE(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
1056 return MmGetPageEntryForProcess(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
1062 MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
1067 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
1068 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
1073 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1074 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
1080 MmCreatePageFileMapping(PEPROCESS Process
,
1082 SWAPENTRY SwapEntry
)
1084 if (Process
== NULL
&& Address
< MmSystemRangeStart
)
1086 DPRINT1("No process\n");
1089 if (Process
!= NULL
&& Address
>= MmSystemRangeStart
)
1091 DPRINT1("Setting kernel address with process context\n");
1094 if (SwapEntry
& (1 << 31))
1105 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, TRUE
);
1110 tmpPte
= SwapEntry
<< 1;
1111 Pte
= ExfpInterlockedExchange64UL(Pt
, &tmpPte
);
1112 if (PAE_PAGE_MASK((Pte
)) != 0)
1114 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte
)));
1119 MiFlushTlb((PULONG
)Pt
, Address
);
1123 MmUnmapPageTable((PULONG
)Pt
);
1131 Pt
= MmGetPageTableForProcess(Process
, Address
, TRUE
);
1137 if (PAGE_MASK((Pte
)) != 0)
1139 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1141 (void)InterlockedExchangeUL(Pt
, SwapEntry
<< 1);
1144 MiFlushTlb(Pt
, Address
);
1148 MmUnmapPageTable(Pt
);
1151 if (Process
!= NULL
&&
1152 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
1153 Address
< MmSystemRangeStart
)
1158 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
1159 Idx
= Ke386Pae
? PAE_ADDR_TO_PAGE_TABLE(Address
) : ADDR_TO_PAGE_TABLE(Address
);
1162 return(STATUS_SUCCESS
);
1168 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
1177 ULONG oldPdeOffset
, PdeOffset
;
1178 BOOLEAN NoExecute
= FALSE
;
1180 DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
1181 Process
, Address
, flProtect
, Pages
, *Pages
, PageCount
);
1183 if (Process
== NULL
)
1185 if (Address
< MmSystemRangeStart
)
1187 DPRINT1("No process\n");
1190 if (PageCount
> 0x10000 ||
1191 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> 0x100000)
1193 DPRINT1("Page count to large\n");
1199 if (Address
>= MmSystemRangeStart
)
1201 DPRINT1("Setting kernel address with process context\n");
1204 if (PageCount
> (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
||
1205 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
>
1206 (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
)
1208 DPRINT1("Page Count to large\n");
1213 Attributes
= ProtectToPTE(flProtect
);
1214 if (Attributes
& 0x80000000)
1218 Attributes
&= 0xfff;
1219 if (Address
>= MmSystemRangeStart
)
1221 Attributes
&= ~PA_USER
;
1222 if (Ke386GlobalPagesEnabled
)
1224 Attributes
|= PA_GLOBAL
;
1229 Attributes
|= PA_USER
;
1236 ULONGLONG Pte
, tmpPte
;
1237 PULONGLONG Pt
= NULL
;
1239 oldPdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
) + 1;
1240 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
1242 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1244 DPRINT1("Setting physical address but not allowing access at address "
1245 "0x%.8X with attributes %x/%x.\n",
1246 Addr
, Attributes
, flProtect
);
1249 PdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
);
1250 if (oldPdeOffset
!= PdeOffset
)
1252 MmUnmapPageTable((PULONG
)Pt
);
1253 Pt
= MmGetPageTableForProcessForPAE(Process
, Addr
, TRUE
);
1263 oldPdeOffset
= PdeOffset
;
1265 MmMarkPageMapped(Pages
[i
]);
1266 tmpPte
= PAE_PFN_TO_PTE(Pages
[i
]) | Attributes
;
1269 tmpPte
|= 0x8000000000000000LL
;
1271 Pte
= ExfpInterlockedExchange64UL(Pt
, &tmpPte
);
1272 if (PAE_PAGE_MASK((Pte
)) != 0LL && !((Pte
) & PA_PRESENT
))
1276 if (PAE_PAGE_MASK((Pte
)) != 0LL)
1278 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte
)));
1280 if (Address
< MmSystemRangeStart
&&
1281 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
1282 Attributes
& PA_PRESENT
)
1286 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
1288 Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Addr
)]++;
1292 if (Address
> MmSystemRangeStart
||
1293 (Pt
>= (PULONGLONG
)PAGETABLE_MAP
&& Pt
< (PULONGLONG
)PAGETABLE_MAP
+ 4*512*512))
1295 MiFlushTlb((PULONG
)Pt
, Address
);
1301 MmUnmapPageTable((PULONG
)Pt
);
1308 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
) + 1;
1309 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
1311 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1313 DPRINT1("Setting physical address but not allowing access at address "
1314 "0x%.8X with attributes %x/%x.\n",
1315 Addr
, Attributes
, flProtect
);
1318 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1319 if (oldPdeOffset
!= PdeOffset
)
1321 MmUnmapPageTable(Pt
);
1322 Pt
= MmGetPageTableForProcess(Process
, Addr
, TRUE
);
1332 oldPdeOffset
= PdeOffset
;
1335 MmMarkPageMapped(Pages
[i
]);
1336 if (PAGE_MASK((Pte
)) != 0 && !((Pte
) & PA_PRESENT
))
1340 if (PAGE_MASK((Pte
)) != 0)
1342 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1344 (void)InterlockedExchangeUL(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
1345 if (Address
< MmSystemRangeStart
&&
1346 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
1347 Attributes
& PA_PRESENT
)
1351 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
1353 Ptrc
[ADDR_TO_PAGE_TABLE(Addr
)]++;
1357 if (Address
> MmSystemRangeStart
||
1358 (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024))
1360 MiFlushTlb(Pt
, Address
);
1366 MmUnmapPageTable(Pt
);
1369 return(STATUS_SUCCESS
);
1374 MmCreateVirtualMapping(PEPROCESS Process
,
1382 for (i
= 0; i
< PageCount
; i
++)
1384 if (!MmIsPageInUse(Pages
[i
]))
1386 DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages
[i
]));
1391 return(MmCreateVirtualMappingUnsafe(Process
,
1400 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
1406 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
1410 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1413 if (!(Entry
& PA_PRESENT
))
1415 Protect
= PAGE_NOACCESS
;
1419 if (Entry
& PA_READWRITE
)
1421 Protect
= PAGE_READWRITE
;
1425 Protect
= PAGE_EXECUTE_READ
;
1429 Protect
|= PAGE_NOCACHE
;
1433 Protect
|= PAGE_WRITETHROUGH
;
1435 if (!(Entry
& PA_USER
))
1437 Protect
|= PAGE_SYSTEM
;
1446 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
1448 ULONG Attributes
= 0;
1449 BOOLEAN NoExecute
= FALSE
;
1451 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
1452 Process
, Address
, flProtect
);
1454 Attributes
= ProtectToPTE(flProtect
);
1455 if (Attributes
& 0x80000000)
1459 Attributes
&= 0xfff;
1460 if (Address
>= MmSystemRangeStart
)
1462 Attributes
&= ~PA_USER
;
1463 if (Ke386GlobalPagesEnabled
)
1465 Attributes
|= PA_GLOBAL
;
1470 Attributes
|= PA_USER
;
1475 ULONGLONG tmpPte
, Pte
;
1477 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1480 DPRINT1("Address %x\n", Address
);
1486 tmpPte
= PAE_PAGE_MASK(Pte
) | Attributes
| (Pte
& (PA_ACCESSED
|PA_DIRTY
));
1489 tmpPte
|= 0x8000000000000000LL
;
1493 tmpPte
&= ~0x8000000000000000LL
;
1495 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1497 MiFlushTlb((PULONG
)Pt
, Address
);
1503 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1508 InterlockedExchange((PLONG
)Pt
, PAGE_MASK(*Pt
) | Attributes
| (*Pt
& (PA_ACCESSED
|PA_DIRTY
)));
1509 MiFlushTlb(Pt
, Address
);
1515 MmCreateHyperspaceMapping(PFN_NUMBER Page
)
1523 ULONGLONG ZeroEntry
= 0LL;
1526 Entry
= PFN_TO_PTE(Page
) | PA_PRESENT
| PA_READWRITE
;
1527 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
) + Page
% 1024;
1531 for (i
= Page
%1024; i
< 1024; i
++, Pte
++)
1533 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
1540 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
);
1541 for (i
= 0; i
< Page
% 1024; i
++, Pte
++)
1543 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
1548 if (i
>= Page
% 1024)
1556 for (i
= Page
%1024; (LONG
)i
>= 0; i
--, Pte
--)
1558 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
1565 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
) + 1023;
1566 for (i
= 1023; i
> Page
% 1024; i
--, Pte
--)
1568 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
1573 if (i
<= Page
% 1024)
1584 Entry
= PFN_TO_PTE(Page
) | PA_PRESENT
| PA_READWRITE
;
1585 Pte
= ADDR_TO_PTE(HYPERSPACE
) + Page
% 1024;
1588 for (i
= Page
% 1024; i
< 1024; i
++, Pte
++)
1590 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1597 Pte
= ADDR_TO_PTE(HYPERSPACE
);
1598 for (i
= 0; i
< Page
% 1024; i
++, Pte
++)
1600 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1605 if (i
>= Page
% 1024)
1613 for (i
= Page
% 1024; (LONG
)i
>= 0; i
--, Pte
--)
1615 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1622 Pte
= ADDR_TO_PTE(HYPERSPACE
) + 1023;
1623 for (i
= 1023; i
> Page
% 1024; i
--, Pte
--)
1625 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1630 if (i
<= Page
% 1024)
1637 Address
= (PVOID
)((ULONG_PTR
)HYPERSPACE
+ i
* PAGE_SIZE
);
1644 MmDeleteHyperspaceMapping(PVOID Address
)
1647 ASSERT (IS_HYPERSPACE(Address
));
1650 ULONGLONG Entry
= 0LL;
1651 Entry
= (ULONG
)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PTE(Address
), &Entry
);
1652 Pfn
= PAE_PTE_TO_PFN(Entry
);
1657 Entry
= InterlockedExchange((PLONG
)ADDR_TO_PTE(Address
), 0);
1658 Pfn
= PTE_TO_PFN(Entry
);
1667 MmInitGlobalKernelPageDirectory(VOID
)
1671 DPRINT("MmInitGlobalKernelPageDirectory()\n");
1675 PULONGLONG CurrentPageDirectory
= (PULONGLONG
)PAE_PAGEDIRECTORY_MAP
;
1676 for (i
= PAE_ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
< 4 * 512; i
++)
1678 if (!(i
>= PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) && i
< PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) + 4) &&
1679 !(i
>= PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
) && i
< PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
) + 2) &&
1680 0LL == MmGlobalKernelPageDirectoryForPAE
[i
] && 0LL != CurrentPageDirectory
[i
])
1682 (void)ExfpInterlockedExchange64UL(&MmGlobalKernelPageDirectoryForPAE
[i
], &CurrentPageDirectory
[i
]);
1683 if (Ke386GlobalPagesEnabled
)
1685 MmGlobalKernelPageDirectoryForPAE
[i
] |= PA_GLOBAL
;
1686 CurrentPageDirectory
[i
] |= PA_GLOBAL
;
1693 PULONG CurrentPageDirectory
= (PULONG
)PAGEDIRECTORY_MAP
;
1694 for (i
= ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
< 1024; i
++)
1696 if (i
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) &&
1697 i
!= ADDR_TO_PDE_OFFSET(HYPERSPACE
) &&
1698 0 == MmGlobalKernelPageDirectory
[i
] && 0 != CurrentPageDirectory
[i
])
1700 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];
1701 if (Ke386GlobalPagesEnabled
)
1703 MmGlobalKernelPageDirectory
[i
] |= PA_GLOBAL
;
1704 CurrentPageDirectory
[i
] |= PA_GLOBAL
;