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
,
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
, 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
);
675 * Return some information to the caller
677 if (WasDirty
!= NULL
)
679 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
691 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
695 if (WasDirty
!= NULL
)
707 * Atomically set the entry to zero and get the old value.
709 Pte
= InterlockedExchangeUL(Pt
, 0);
711 MiFlushTlb(Pt
, Address
);
713 WasValid
= (PAGE_MASK(Pte
) != 0);
716 Pfn
= PTE_TO_PFN(Pte
);
717 MmMarkPageUnmapped(Pfn
);
725 * Return some information to the caller
727 if (WasDirty
!= NULL
)
729 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
737 * Decrement the reference count for this page table.
739 if (Process
!= NULL
&& WasValid
&&
740 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
741 Address
< MmSystemRangeStart
)
746 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
747 Idx
= Ke386Pae
? PAE_ADDR_TO_PAGE_TABLE(Address
) : ADDR_TO_PAGE_TABLE(Address
);
752 MmFreePageTable(Process
, Address
);
759 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
760 SWAPENTRY
* SwapEntry
)
762 * FUNCTION: Delete a virtual mapping
770 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
778 * Atomically set the entry to zero and get the old value.
781 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
783 MiFlushTlb((PULONG
)Pt
, Address
);
786 * Decrement the reference count for this page table.
788 if (Process
!= NULL
&& Pte
&&
789 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
790 Address
< MmSystemRangeStart
)
794 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
796 Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Address
)]--;
797 if (Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Address
)] == 0)
799 MmFreePageTable(Process
, Address
);
805 * Return some information to the caller
807 *SwapEntry
= Pte
>> 1;
814 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
823 * Atomically set the entry to zero and get the old value.
825 Pte
= InterlockedExchangeUL(Pt
, 0);
827 MiFlushTlb(Pt
, Address
);
830 * Decrement the reference count for this page table.
832 if (Process
!= NULL
&& Pte
&&
833 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
834 Address
< MmSystemRangeStart
)
838 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
840 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]--;
841 if (Ptrc
[ADDR_TO_PAGE_TABLE(Address
)] == 0)
843 MmFreePageTable(Process
, Address
);
849 * Return some information to the caller
851 *SwapEntry
= Pte
>> 1;
856 Mmi386MakeKernelPageTableGlobal(PVOID PAddress
)
862 Pde
= PAE_ADDR_TO_PDE(PAddress
);
865 Pt
= MmGetPageTableForProcessForPAE(NULL
, PAddress
, FALSE
);
867 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
868 FLASH_TLB_ONE(PAddress
);
879 Pde
= ADDR_TO_PDE(PAddress
);
882 Pt
= MmGetPageTableForProcess(NULL
, PAddress
, FALSE
);
884 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
885 FLASH_TLB_ONE(PAddress
);
898 MmIsDirtyPage(PEPROCESS Process
, PVOID Address
)
902 return MmGetPageEntryForProcessForPAE(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
906 return MmGetPageEntryForProcess(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
912 MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
914 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
916 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
925 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
935 tmpPte
= Pte
& ~PA_DIRTY
;
936 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
940 MiFlushTlb((PULONG
)Pt
, Address
);
944 MmUnmapPageTable((PULONG
)Pt
);
952 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
962 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_DIRTY
, Pte
));
966 MiFlushTlb(Pt
, Address
);
970 MmUnmapPageTable(Pt
);
977 MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
979 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
981 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
990 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
999 tmpPte
= Pte
| PA_DIRTY
;
1000 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1001 if (!(Pte
& PA_DIRTY
))
1003 MiFlushTlb((PULONG
)Pt
, Address
);
1007 MmUnmapPageTable((PULONG
)Pt
);
1015 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1024 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
| PA_DIRTY
, Pte
));
1025 if (!(Pte
& PA_DIRTY
))
1027 MiFlushTlb(Pt
, Address
);
1031 MmUnmapPageTable(Pt
);
1038 MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
1042 return MmGetPageEntryForProcessForPAE(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
1046 return MmGetPageEntryForProcess(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
1052 MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
1057 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
1058 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
1063 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1064 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
1070 MmCreatePageFileMapping(PEPROCESS Process
,
1072 SWAPENTRY SwapEntry
)
1074 if (Process
== NULL
&& Address
< MmSystemRangeStart
)
1076 DPRINT1("No process\n");
1079 if (Process
!= NULL
&& Address
>= MmSystemRangeStart
)
1081 DPRINT1("Setting kernel address with process context\n");
1084 if (SwapEntry
& (1 << 31))
1095 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, TRUE
);
1100 tmpPte
= SwapEntry
<< 1;
1101 Pte
= ExfpInterlockedExchange64UL(Pt
, &tmpPte
);
1102 if (PAE_PAGE_MASK((Pte
)) != 0)
1104 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte
)));
1109 MiFlushTlb((PULONG
)Pt
, Address
);
1113 MmUnmapPageTable((PULONG
)Pt
);
1121 Pt
= MmGetPageTableForProcess(Process
, Address
, TRUE
);
1127 if (PAGE_MASK((Pte
)) != 0)
1129 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1131 (void)InterlockedExchangeUL(Pt
, SwapEntry
<< 1);
1134 MiFlushTlb(Pt
, Address
);
1138 MmUnmapPageTable(Pt
);
1141 if (Process
!= NULL
&&
1142 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
1143 Address
< MmSystemRangeStart
)
1148 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
1149 Idx
= Ke386Pae
? PAE_ADDR_TO_PAGE_TABLE(Address
) : ADDR_TO_PAGE_TABLE(Address
);
1152 return(STATUS_SUCCESS
);
1158 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
1167 ULONG oldPdeOffset
, PdeOffset
;
1168 BOOLEAN NoExecute
= FALSE
;
1170 DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
1171 Process
, Address
, flProtect
, Pages
, *Pages
, PageCount
);
1173 if (Process
== NULL
)
1175 if (Address
< MmSystemRangeStart
)
1177 DPRINT1("No process\n");
1180 if (PageCount
> 0x10000 ||
1181 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> 0x100000)
1183 DPRINT1("Page count to large\n");
1189 if (Address
>= MmSystemRangeStart
)
1191 DPRINT1("Setting kernel address with process context\n");
1194 if (PageCount
> (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
||
1195 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
>
1196 (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
)
1198 DPRINT1("Page Count to large\n");
1203 Attributes
= ProtectToPTE(flProtect
);
1204 if (Attributes
& 0x80000000)
1208 Attributes
&= 0xfff;
1209 if (Address
>= MmSystemRangeStart
)
1211 Attributes
&= ~PA_USER
;
1212 if (Ke386GlobalPagesEnabled
)
1214 Attributes
|= PA_GLOBAL
;
1219 Attributes
|= PA_USER
;
1226 ULONGLONG Pte
, tmpPte
;
1227 PULONGLONG Pt
= NULL
;
1229 oldPdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
) + 1;
1230 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
1232 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1234 DPRINT1("Setting physical address but not allowing access at address "
1235 "0x%.8X with attributes %x/%x.\n",
1236 Addr
, Attributes
, flProtect
);
1239 PdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
);
1240 if (oldPdeOffset
!= PdeOffset
)
1242 MmUnmapPageTable((PULONG
)Pt
);
1243 Pt
= MmGetPageTableForProcessForPAE(Process
, Addr
, TRUE
);
1253 oldPdeOffset
= PdeOffset
;
1255 MmMarkPageMapped(Pages
[i
]);
1256 tmpPte
= PAE_PFN_TO_PTE(Pages
[i
]) | Attributes
;
1259 tmpPte
|= 0x8000000000000000LL
;
1261 Pte
= ExfpInterlockedExchange64UL(Pt
, &tmpPte
);
1262 if (PAE_PAGE_MASK((Pte
)) != 0LL && !((Pte
) & PA_PRESENT
))
1266 if (PAE_PAGE_MASK((Pte
)) != 0LL)
1268 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte
)));
1270 if (Address
< MmSystemRangeStart
&&
1271 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
1272 Attributes
& PA_PRESENT
)
1276 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
1278 Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Addr
)]++;
1282 if (Address
> MmSystemRangeStart
||
1283 (Pt
>= (PULONGLONG
)PAGETABLE_MAP
&& Pt
< (PULONGLONG
)PAGETABLE_MAP
+ 4*512*512))
1285 MiFlushTlb((PULONG
)Pt
, Address
);
1291 MmUnmapPageTable((PULONG
)Pt
);
1298 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
) + 1;
1299 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
1301 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1303 DPRINT1("Setting physical address but not allowing access at address "
1304 "0x%.8X with attributes %x/%x.\n",
1305 Addr
, Attributes
, flProtect
);
1308 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1309 if (oldPdeOffset
!= PdeOffset
)
1311 MmUnmapPageTable(Pt
);
1312 Pt
= MmGetPageTableForProcess(Process
, Addr
, TRUE
);
1322 oldPdeOffset
= PdeOffset
;
1325 MmMarkPageMapped(Pages
[i
]);
1326 if (PAGE_MASK((Pte
)) != 0 && !((Pte
) & PA_PRESENT
))
1330 if (PAGE_MASK((Pte
)) != 0)
1332 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1334 (void)InterlockedExchangeUL(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
1335 if (Address
< MmSystemRangeStart
&&
1336 ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
!= NULL
&&
1337 Attributes
& PA_PRESENT
)
1341 Ptrc
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->PageTableRefCountTable
;
1343 Ptrc
[ADDR_TO_PAGE_TABLE(Addr
)]++;
1347 if (Address
> MmSystemRangeStart
||
1348 (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024))
1350 MiFlushTlb(Pt
, Address
);
1356 MmUnmapPageTable(Pt
);
1359 return(STATUS_SUCCESS
);
1364 MmCreateVirtualMapping(PEPROCESS Process
,
1372 for (i
= 0; i
< PageCount
; i
++)
1374 if (!MmIsPageInUse(Pages
[i
]))
1376 DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages
[i
]));
1381 return(MmCreateVirtualMappingUnsafe(Process
,
1390 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
1396 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
1400 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1403 if (!(Entry
& PA_PRESENT
))
1405 Protect
= PAGE_NOACCESS
;
1409 if (Entry
& PA_READWRITE
)
1411 Protect
= PAGE_READWRITE
;
1415 Protect
= PAGE_EXECUTE_READ
;
1419 Protect
|= PAGE_NOCACHE
;
1423 Protect
|= PAGE_WRITETHROUGH
;
1425 if (!(Entry
& PA_USER
))
1427 Protect
|= PAGE_SYSTEM
;
1436 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
1438 ULONG Attributes
= 0;
1439 BOOLEAN NoExecute
= FALSE
;
1441 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
1442 Process
, Address
, flProtect
);
1444 Attributes
= ProtectToPTE(flProtect
);
1445 if (Attributes
& 0x80000000)
1449 Attributes
&= 0xfff;
1450 if (Address
>= MmSystemRangeStart
)
1452 Attributes
&= ~PA_USER
;
1453 if (Ke386GlobalPagesEnabled
)
1455 Attributes
|= PA_GLOBAL
;
1460 Attributes
|= PA_USER
;
1465 ULONGLONG tmpPte
, Pte
;
1467 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1470 DPRINT1("Address %x\n", Address
);
1476 tmpPte
= PAE_PAGE_MASK(Pte
) | Attributes
| (Pte
& (PA_ACCESSED
|PA_DIRTY
));
1479 tmpPte
|= 0x8000000000000000LL
;
1483 tmpPte
&= ~0x8000000000000000LL
;
1485 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1487 MiFlushTlb((PULONG
)Pt
, Address
);
1493 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1498 InterlockedExchange((PLONG
)Pt
, PAGE_MASK(*Pt
) | Attributes
| (*Pt
& (PA_ACCESSED
|PA_DIRTY
)));
1499 MiFlushTlb(Pt
, Address
);
1505 MmCreateHyperspaceMapping(PFN_NUMBER Page
)
1513 ULONGLONG ZeroEntry
= 0LL;
1516 Entry
= PFN_TO_PTE(Page
) | PA_PRESENT
| PA_READWRITE
;
1517 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
) + Page
% 1024;
1521 for (i
= Page
%1024; i
< 1024; i
++, Pte
++)
1523 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
1530 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
);
1531 for (i
= 0; i
< Page
% 1024; i
++, Pte
++)
1533 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
1538 if (i
>= Page
% 1024)
1546 for (i
= Page
%1024; (LONG
)i
>= 0; i
--, Pte
--)
1548 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
1555 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
) + 1023;
1556 for (i
= 1023; i
> Page
% 1024; i
--, Pte
--)
1558 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
1563 if (i
<= Page
% 1024)
1574 Entry
= PFN_TO_PTE(Page
) | PA_PRESENT
| PA_READWRITE
;
1575 Pte
= ADDR_TO_PTE(HYPERSPACE
) + Page
% 1024;
1578 for (i
= Page
% 1024; i
< 1024; i
++, Pte
++)
1580 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1587 Pte
= ADDR_TO_PTE(HYPERSPACE
);
1588 for (i
= 0; i
< Page
% 1024; i
++, Pte
++)
1590 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1595 if (i
>= Page
% 1024)
1603 for (i
= Page
% 1024; (LONG
)i
>= 0; i
--, Pte
--)
1605 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1612 Pte
= ADDR_TO_PTE(HYPERSPACE
) + 1023;
1613 for (i
= 1023; i
> Page
% 1024; i
--, Pte
--)
1615 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1620 if (i
<= Page
% 1024)
1627 Address
= (PVOID
)((ULONG_PTR
)HYPERSPACE
+ i
* PAGE_SIZE
);
1634 MmDeleteHyperspaceMapping(PVOID Address
)
1637 ASSERT (IS_HYPERSPACE(Address
));
1640 ULONGLONG Entry
= 0LL;
1641 Entry
= (ULONG
)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PTE(Address
), &Entry
);
1642 Pfn
= PAE_PTE_TO_PFN(Entry
);
1647 Entry
= InterlockedExchange((PLONG
)ADDR_TO_PTE(Address
), 0);
1648 Pfn
= PTE_TO_PFN(Entry
);
1657 MmInitGlobalKernelPageDirectory(VOID
)
1661 DPRINT("MmInitGlobalKernelPageDirectory()\n");
1665 PULONGLONG CurrentPageDirectory
= (PULONGLONG
)PAE_PAGEDIRECTORY_MAP
;
1666 for (i
= PAE_ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
< 4 * 512; i
++)
1668 if (!(i
>= PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) && i
< PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) + 4) &&
1669 !(i
>= PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
) && i
< PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
) + 2) &&
1670 0LL == MmGlobalKernelPageDirectoryForPAE
[i
] && 0LL != CurrentPageDirectory
[i
])
1672 (void)ExfpInterlockedExchange64UL(&MmGlobalKernelPageDirectoryForPAE
[i
], &CurrentPageDirectory
[i
]);
1673 if (Ke386GlobalPagesEnabled
)
1675 MmGlobalKernelPageDirectoryForPAE
[i
] |= PA_GLOBAL
;
1676 CurrentPageDirectory
[i
] |= PA_GLOBAL
;
1683 PULONG CurrentPageDirectory
= (PULONG
)PAGEDIRECTORY_MAP
;
1684 for (i
= ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
< 1024; i
++)
1686 if (i
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) &&
1687 i
!= ADDR_TO_PDE_OFFSET(HYPERSPACE
) &&
1688 0 == MmGlobalKernelPageDirectory
[i
] && 0 != CurrentPageDirectory
[i
])
1690 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];
1691 if (Ke386GlobalPagesEnabled
)
1693 MmGlobalKernelPageDirectory
[i
] |= PA_GLOBAL
;
1694 CurrentPageDirectory
[i
] |= PA_GLOBAL
;