3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/i386/page.c
6 * PURPOSE: Low level memory managment manipulation
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
11 /* INCLUDES ***************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS *****************************************************************/
19 #define PA_BIT_PRESENT (0)
20 #define PA_BIT_READWRITE (1)
21 #define PA_BIT_USER (2)
24 #define PA_BIT_ACCESSED (5)
25 #define PA_BIT_DIRTY (6)
26 #define PA_BIT_GLOBAL (8)
28 #define PA_PRESENT (1 << PA_BIT_PRESENT)
29 #define PA_READWRITE (1 << PA_BIT_READWRITE)
30 #define PA_USER (1 << PA_BIT_USER)
31 #define PA_DIRTY (1 << PA_BIT_DIRTY)
32 #define PA_WT (1 << PA_BIT_WT)
33 #define PA_CD (1 << PA_BIT_CD)
34 #define PA_ACCESSED (1 << PA_BIT_ACCESSED)
35 #define PA_GLOBAL (1 << PA_BIT_GLOBAL)
37 #define PAGETABLE_MAP (0xf0000000)
38 #define PAGEDIRECTORY_MAP (0xf0000000 + (PAGETABLE_MAP / (1024)))
40 #define PAE_PAGEDIRECTORY_MAP (0xf0000000 + (PAGETABLE_MAP / (512)))
42 #define HYPERSPACE (0xf0800000)
43 #define IS_HYPERSPACE(v) (((ULONG)(v) >= 0xF0800000 && (ULONG)(v) < 0xF0C00000))
45 ULONG MmGlobalKernelPageDirectory
[1024];
46 ULONGLONG MmGlobalKernelPageDirectoryForPAE
[2048];
48 #define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT)
49 #define PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
51 #define PAE_PTE_TO_PFN(X) (PAE_PAGE_MASK(X) >> PAGE_SHIFT)
52 #define PAE_PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
55 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
57 __inline LARGE_INTEGER
PTE_TO_PAGE(ULONG npage
)
60 dummy
.QuadPart
= (LONGLONG
)(PAGE_MASK(npage
));
65 extern BOOLEAN Ke386Pae
;
66 extern BOOLEAN Ke386NoExecute
;
67 extern BOOLEAN Ke386GlobalPagesEnabled
;
69 /* FUNCTIONS ***************************************************************/
71 BOOLEAN
MmUnmapPageTable(PULONG Pt
);
75 MiFlushTlbIpiRoutine(PVOID Address
)
77 if (Address
== (PVOID
)0xffffffff)
81 else if (Address
== (PVOID
)0xfffffffe)
87 FLUSH_TLB_ONE(Address
);
92 MiFlushTlb(PULONG Pt
, PVOID Address
)
99 if (KeNumberProcessors
>1)
101 KeIpiGenericCall(MiFlushTlbIpiRoutine
, Address
);
105 MiFlushTlbIpiRoutine(Address
);
108 if ((Pt
&& MmUnmapPageTable(Pt
)) || Address
>= (PVOID
)KERNEL_BASE
)
110 FLUSH_TLB_ONE(Address
);
118 MmGetPageDirectory(VOID
)
120 unsigned int page_dir
=0;
121 Ke386GetPageTableDirectory(page_dir
);
122 return((PULONG
)page_dir
);
126 ProtectToPTE(ULONG flProtect
)
128 ULONG Attributes
= 0;
130 if (flProtect
& (PAGE_NOACCESS
|PAGE_GUARD
))
134 else if (flProtect
& PAGE_IS_WRITABLE
)
136 Attributes
= PA_PRESENT
| PA_READWRITE
;
138 else if (flProtect
& (PAGE_IS_READABLE
| PAGE_IS_EXECUTABLE
))
140 Attributes
= PA_PRESENT
;
144 DPRINT1("Unknown main protection type.\n");
147 if (Ke386NoExecute
&&
148 !(flProtect
& PAGE_IS_EXECUTABLE
))
150 Attributes
= Attributes
| 0x80000000;
153 if (flProtect
& PAGE_SYSTEM
)
158 Attributes
= Attributes
| PA_USER
;
160 if (flProtect
& PAGE_NOCACHE
)
162 Attributes
= Attributes
| PA_CD
;
164 if (flProtect
& PAGE_WRITETHROUGH
)
166 Attributes
= Attributes
| PA_WT
;
171 #define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (1024 * PAGE_SIZE))
173 #define ADDR_TO_PDE(v) (PULONG)(PAGEDIRECTORY_MAP + \
174 ((((ULONG)(v)) / (1024 * 1024))&(~0x3)))
175 #define ADDR_TO_PTE(v) (PULONG)(PAGETABLE_MAP + ((((ULONG)(v) / 1024))&(~0x3)))
177 #define ADDR_TO_PDE_OFFSET(v) ((((ULONG)(v)) / (1024 * PAGE_SIZE)))
179 #define ADDR_TO_PTE_OFFSET(v) ((((ULONG)(v)) % (1024 * PAGE_SIZE)) / PAGE_SIZE)
182 #define PAE_ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (512 * PAGE_SIZE))
184 #define PAE_ADDR_TO_PDE(v) (PULONGLONG) (PAE_PAGEDIRECTORY_MAP + \
185 ((((ULONG_PTR)(v)) / (512 * 512))&(~0x7)))
186 #define PAE_ADDR_TO_PTE(v) (PULONGLONG) (PAGETABLE_MAP + ((((ULONG_PTR)(v) / 512))&(~0x7)))
189 #define PAE_ADDR_TO_PDTE_OFFSET(v) (((ULONG_PTR)(v)) / (512 * 512 * PAGE_SIZE))
191 #define PAE_ADDR_TO_PDE_PAGE_OFFSET(v) ((((ULONG_PTR)(v)) % (512 * 512 * PAGE_SIZE)) / (512 * PAGE_SIZE))
193 #define PAE_ADDR_TO_PDE_OFFSET(v) (((ULONG_PTR)(v))/ (512 * PAGE_SIZE))
195 #define PAE_ADDR_TO_PTE_OFFSET(v) ((((ULONG_PTR)(v)) % (512 * PAGE_SIZE)) / PAGE_SIZE)
198 NTSTATUS
Mmi386ReleaseMmInfo(PEPROCESS Process
)
200 PUSHORT LdtDescriptor
;
204 DPRINT("Mmi386ReleaseMmInfo(Process %x)\n",Process
);
206 LdtDescriptor
= (PUSHORT
) &Process
->Pcb
.LdtDescriptor
[0];
207 LdtBase
= LdtDescriptor
[1] |
208 ((LdtDescriptor
[2] & 0xff) << 16) |
209 ((LdtDescriptor
[3] & ~0xff) << 16);
211 DPRINT("LdtBase: %x\n", LdtBase
);
215 ExFreePool((PVOID
) LdtBase
);
220 PULONGLONG PageDirTable
;
225 PageDirTable
= (PULONGLONG
)MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
226 for (i
= 0; i
< 4; i
++)
228 PageDir
= (PULONGLONG
)MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDirTable
[i
]));
229 if (i
< PAE_ADDR_TO_PDTE_OFFSET(KERNEL_BASE
))
231 for (j
= 0; j
< 512; j
++)
233 if (PageDir
[j
] != 0LL)
235 DPRINT1("ProcessId %d, Pde for %08x - %08x is not freed, RefCount %d\n",
236 Process
->UniqueProcessId
,
237 (i
* 512 + j
) * 512 * PAGE_SIZE
, (i
* 512 + j
+ 1) * 512 * PAGE_SIZE
- 1,
238 Process
->AddressSpace
.PageTableRefCountTable
[i
*512 + j
]);
239 Pde
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDir
[j
]));
240 for (k
= 0; k
< 512; k
++)
244 if (Pde
[k
] & PA_PRESENT
)
246 DPRINT1("Page at %08x is not freed\n",
247 (i
* 512 + j
) * 512 * PAGE_SIZE
+ k
* PAGE_SIZE
);
251 DPRINT1("Swapentry %x at %x is not freed\n",
252 (i
* 512 + j
) * 512 * PAGE_SIZE
+ k
* PAGE_SIZE
);
256 MmDeleteHyperspaceMapping(Pde
);
257 MmReleasePageMemoryConsumer(MC_NPPOOL
, PAE_PTE_TO_PFN(PageDir
[j
]));
261 if (i
== PAE_ADDR_TO_PDTE_OFFSET(HYPERSPACE
))
263 MmReleasePageMemoryConsumer(MC_NPPOOL
, PAE_PTE_TO_PFN(PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)]));
264 MmReleasePageMemoryConsumer(MC_NPPOOL
, PAE_PTE_TO_PFN(PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)+1]));
266 MmDeleteHyperspaceMapping(PageDir
);
267 MmReleasePageMemoryConsumer(MC_NPPOOL
, PAE_PTE_TO_PFN(PageDirTable
[i
]));
269 MmDeleteHyperspaceMapping((PVOID
)PageDirTable
);
270 MmReleasePageMemoryConsumer(MC_NPPOOL
, PAE_PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
276 PageDir
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.u
.LowPart
));
277 for (i
= 0; i
< ADDR_TO_PDE_OFFSET(KERNEL_BASE
); i
++)
281 DPRINT1("Pde for %08x - %08x is not freed, RefCount %d\n",
282 i
* 4 * 1024 * 1024, (i
+ 1) * 4 * 1024 * 1024 - 1,
283 Process
->AddressSpace
.PageTableRefCountTable
[i
]);
284 Pde
= MmCreateHyperspaceMapping(PTE_TO_PFN(PageDir
[i
]));
285 for (j
= 0; j
< 1024; j
++)
289 if (Pde
[j
] & PA_PRESENT
)
291 DPRINT1("Page at %08x is not freed\n",
292 i
* 4 * 1024 * 1024 + j
* PAGE_SIZE
);
296 DPRINT1("Swapentry %x at %x is not freed\n",
297 Pde
[j
], i
* 4 * 1024 * 1024 + j
* PAGE_SIZE
);
301 MmDeleteHyperspaceMapping(Pde
);
302 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(PageDir
[i
]));
305 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(PageDir
[ADDR_TO_PDE_OFFSET(HYPERSPACE
)]));
306 MmDeleteHyperspaceMapping(PageDir
);
307 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.u
.LowPart
));
310 #if defined(__GNUC__)
312 Process
->Pcb
.DirectoryTableBase
.QuadPart
= 0LL;
315 Process
->Pcb
.DirectoryTableBase
.QuadPart
= 0;
318 DPRINT("Finished Mmi386ReleaseMmInfo()\n");
319 return(STATUS_SUCCESS
);
322 NTSTATUS
MmCopyMmInfo(PEPROCESS Src
, PEPROCESS Dest
)
324 PKPROCESS KProcess
= &Dest
->Pcb
;
330 DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", Src
, Dest
);
332 Count
= Ke386Pae
? 7 : 2;
334 for (i
= 0; i
< Count
; i
++)
336 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
[i
]);
337 if (!NT_SUCCESS(Status
))
339 for (j
= 0; j
< i
; j
++)
341 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
[j
]);
349 PULONGLONG PageDirTable
;
352 PageDirTable
= MmCreateHyperspaceMapping(Pfn
[0]);
353 for (i
= 0; i
< 4; i
++)
355 PageDirTable
[i
] = PAE_PFN_TO_PTE(Pfn
[1+i
]) | PA_PRESENT
;
357 MmDeleteHyperspaceMapping(PageDirTable
);
358 for (i
= PAE_ADDR_TO_PDTE_OFFSET(KERNEL_BASE
); i
< 4; i
++)
360 PageDir
= (PULONGLONG
)MmCreateHyperspaceMapping(Pfn
[i
+1]);
361 memcpy(PageDir
, &MmGlobalKernelPageDirectoryForPAE
[i
* 512], 512 * sizeof(ULONGLONG
));
362 if (PAE_ADDR_TO_PDTE_OFFSET(PAGETABLE_MAP
) == i
)
364 for (j
= 0; j
< 4; j
++)
366 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(PAGETABLE_MAP
) + j
] = PAE_PFN_TO_PTE(Pfn
[1+j
]) | PA_PRESENT
| PA_READWRITE
;
369 if (PAE_ADDR_TO_PDTE_OFFSET(HYPERSPACE
) == i
)
371 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)] = PAE_PFN_TO_PTE(Pfn
[5]) | PA_PRESENT
| PA_READWRITE
;
372 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)+1] = PAE_PFN_TO_PTE(Pfn
[6]) | PA_PRESENT
| PA_READWRITE
;
374 MmDeleteHyperspaceMapping(PageDir
);
379 PULONG PageDirectory
;
380 PageDirectory
= MmCreateHyperspaceMapping(Pfn
[0]);
382 memcpy(PageDirectory
+ ADDR_TO_PDE_OFFSET(KERNEL_BASE
),
383 MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(KERNEL_BASE
),
384 (1024 - ADDR_TO_PDE_OFFSET(KERNEL_BASE
)) * sizeof(ULONG
));
386 DPRINT("Addr %x\n",ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
));
387 PageDirectory
[ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
)] = PFN_TO_PTE(Pfn
[0]) | PA_PRESENT
| PA_READWRITE
;
388 PageDirectory
[ADDR_TO_PDE_OFFSET(HYPERSPACE
)] = PFN_TO_PTE(Pfn
[1]) | PA_PRESENT
| PA_READWRITE
;
390 MmDeleteHyperspaceMapping(PageDirectory
);
392 KProcess
->DirectoryTableBase
.QuadPart
= PFN_TO_PTE(Pfn
[0]);
393 DPRINT("Finished MmCopyMmInfo()\n");
394 return(STATUS_SUCCESS
);
397 VOID
MmDeletePageTable(PEPROCESS Process
, PVOID Address
)
399 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
401 if (Process
!= NULL
&& Process
!= CurrentProcess
)
403 KeAttachProcess(&Process
->Pcb
);
408 ULONGLONG ZeroPde
= 0LL;
409 ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address
), &ZeroPde
);
413 *(ADDR_TO_PDE(Address
)) = 0;
415 if (Address
>= (PVOID
)KERNEL_BASE
)
418 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
420 MiFlushTlb(NULL
, Address
);
421 if (Process
!= NULL
&& Process
!= CurrentProcess
)
427 VOID
MmFreePageTable(PEPROCESS Process
, PVOID Address
)
429 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
433 DPRINT("ProcessId %d, Address %x\n", Process
->UniqueProcessId
, Address
);
434 if (Process
!= NULL
&& Process
!= CurrentProcess
)
436 KeAttachProcess(&Process
->Pcb
);
440 PULONGLONG PageTable
;
441 ULONGLONG ZeroPte
= 0LL;
442 PageTable
= (PULONGLONG
)PAGE_ROUND_DOWN((PVOID
)PAE_ADDR_TO_PTE(Address
));
443 for (i
= 0; i
< 512; i
++)
445 if (PageTable
[i
] != 0LL)
447 DbgPrint("Page table entry not clear at %x/%x (is %I64x)\n",
448 ((ULONG
)Address
/ (4*1024*1024)), i
, PageTable
[i
]);
452 Pfn
= PAE_PTE_TO_PFN(*(PAE_ADDR_TO_PDE(Address
)));
453 ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address
), &ZeroPte
);
458 PageTable
= (PULONG
)PAGE_ROUND_DOWN((PVOID
)ADDR_TO_PTE(Address
));
459 for (i
= 0; i
< 1024; i
++)
461 if (PageTable
[i
] != 0)
463 DbgPrint("Page table entry not clear at %x/%x (is %x)\n",
464 ((ULONG
)Address
/ (4*1024*1024)), i
, PageTable
[i
]);
468 Pfn
= PTE_TO_PFN(*(ADDR_TO_PDE(Address
)));
469 *(ADDR_TO_PDE(Address
)) = 0;
471 MiFlushTlb(NULL
, Address
);
473 if (Address
>= (PVOID
)KERNEL_BASE
)
475 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
480 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
482 if (Process
!= NULL
&& Process
!= CurrentProcess
)
489 MmGetPageTableForProcessForPAE(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
494 ULONGLONG ZeroEntry
= 0LL;
497 PULONGLONG PageDirTable
;
499 DPRINT("MmGetPageTableForProcessForPAE(%x %x %d)\n",
500 Process
, Address
, Create
);
501 if (Address
>= (PVOID
)PAGETABLE_MAP
&& Address
< (PVOID
)PAGETABLE_MAP
+ 0x800000)
505 if (Address
< (PVOID
)KERNEL_BASE
&& Process
&& Process
!= PsGetCurrentProcess())
507 PageDirTable
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
508 if (PageDirTable
== NULL
)
512 PageDir
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDirTable
[PAE_ADDR_TO_PDTE_OFFSET(Address
)]));
513 MmDeleteHyperspaceMapping(PageDirTable
);
518 PageDir
+= PAE_ADDR_TO_PDE_PAGE_OFFSET(Address
);
519 Entry
= ExfInterlockedCompareExchange64UL(PageDir
, &ZeroEntry
, &ZeroEntry
);
524 MmDeleteHyperspaceMapping(PageDir
);
527 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
528 if (!NT_SUCCESS(Status
))
532 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
;
533 Entry
= ExfInterlockedCompareExchange64UL(PageDir
, &Entry
, &ZeroEntry
);
536 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
537 Pfn
= PAE_PTE_TO_PFN(Entry
);
542 Pfn
= PAE_PTE_TO_PFN(Entry
);
544 MmDeleteHyperspaceMapping(PageDir
);
545 Pt
= MmCreateHyperspaceMapping(Pfn
);
550 return Pt
+ PAE_ADDR_TO_PTE_OFFSET(Address
);
552 PageDir
= PAE_ADDR_TO_PDE(Address
);
553 if (0LL == ExfInterlockedCompareExchange64UL(PageDir
, &ZeroEntry
, &ZeroEntry
))
555 if (Address
>= (PVOID
)KERNEL_BASE
)
557 if (MmGlobalKernelPageDirectoryForPAE
[PAE_ADDR_TO_PDE_OFFSET(Address
)] == 0LL)
563 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
564 if (!NT_SUCCESS(Status
))
568 Entry
= PAE_PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
;
569 if (Ke386GlobalPagesEnabled
)
573 if (0LL != ExfInterlockedCompareExchange64UL(&MmGlobalKernelPageDirectoryForPAE
[PAE_ADDR_TO_PDE_OFFSET(Address
)], &Entry
, &ZeroEntry
))
575 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
578 ExfInterlockedCompareExchange64UL(PageDir
, &MmGlobalKernelPageDirectoryForPAE
[PAE_ADDR_TO_PDE_OFFSET(Address
)], &ZeroEntry
);
586 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
587 if (!NT_SUCCESS(Status
))
591 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
;
592 Entry
= ExfInterlockedCompareExchange64UL(PageDir
, &Entry
, &ZeroEntry
);
595 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
599 return (PULONGLONG
)PAE_ADDR_TO_PTE(Address
);
603 MmGetPageTableForProcess(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
605 ULONG PdeOffset
= ADDR_TO_PDE_OFFSET(Address
);
611 if (Address
< (PVOID
)KERNEL_BASE
&& Process
&& Process
!= PsGetCurrentProcess())
613 PageDir
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
618 if (0 == InterlockedCompareExchangeUL(&PageDir
[PdeOffset
], 0, 0))
622 MmDeleteHyperspaceMapping(PageDir
);
625 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
626 if (!NT_SUCCESS(Status
) || Pfn
== 0)
630 Entry
= InterlockedCompareExchangeUL(&PageDir
[PdeOffset
], PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
633 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
634 Pfn
= PTE_TO_PFN(Entry
);
639 Pfn
= PTE_TO_PFN(PageDir
[PdeOffset
]);
641 MmDeleteHyperspaceMapping(PageDir
);
642 Pt
= MmCreateHyperspaceMapping(Pfn
);
647 return Pt
+ ADDR_TO_PTE_OFFSET(Address
);
649 PageDir
= ADDR_TO_PDE(Address
);
650 if (0 == InterlockedCompareExchangeUL(PageDir
, 0, 0))
652 if (Address
>= (PVOID
)KERNEL_BASE
)
654 if (0 == InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory
[PdeOffset
], 0, 0))
660 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
661 if (!NT_SUCCESS(Status
) || Pfn
== 0)
665 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
;
666 if (Ke386GlobalPagesEnabled
)
670 if(0 != InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory
[PdeOffset
], Entry
, 0))
672 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
675 InterlockedExchangeUL(PageDir
, MmGlobalKernelPageDirectory
[PdeOffset
]);
683 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
684 if (!NT_SUCCESS(Status
) || Pfn
== 0)
688 Entry
= InterlockedCompareExchangeUL(PageDir
, PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
691 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
695 return (PULONG
)ADDR_TO_PTE(Address
);
698 BOOLEAN
MmUnmapPageTable(PULONG Pt
)
702 if ((PULONGLONG
)Pt
>= (PULONGLONG
)PAGETABLE_MAP
&& (PULONGLONG
)Pt
< (PULONGLONG
)PAGETABLE_MAP
+ 4*512*512)
709 if (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024)
716 MmDeleteHyperspaceMapping((PVOID
)PAGE_ROUND_DOWN(Pt
));
721 static ULONGLONG
MmGetPageEntryForProcessForPAE(PEPROCESS Process
, PVOID Address
)
726 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
730 MmUnmapPageTable((PULONG
)Pt
);
736 static ULONG
MmGetPageEntryForProcess(PEPROCESS Process
, PVOID Address
)
741 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
745 MmUnmapPageTable(Pt
);
752 MmGetPfnForProcess(PEPROCESS Process
,
759 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
760 if (!(Entry
& PA_PRESENT
))
764 return(PAE_PTE_TO_PFN(Entry
));
769 Entry
= MmGetPageEntryForProcess(Process
, Address
);
770 if (!(Entry
& PA_PRESENT
))
774 return(PTE_TO_PFN(Entry
));
779 MmDisableVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOL
* WasDirty
, PPFN_TYPE Page
)
781 * FUNCTION: Delete a virtual mapping
791 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
797 * Atomically disable the present bit and get the old value.
802 tmpPte
= Pte
& ~PA_PRESENT
;
803 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
805 MiFlushTlb((PULONG
)Pt
, Address
);
806 WasValid
= PAE_PAGE_MASK(Pte
) != 0LL ? TRUE
: FALSE
;
813 * Return some information to the caller
815 if (WasDirty
!= NULL
)
817 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
821 *Page
= PAE_PTE_TO_PFN(Pte
);
829 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
835 * Atomically disable the present bit and get the old value.
840 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_PRESENT
, Pte
));
842 MiFlushTlb(Pt
, Address
);
843 WasValid
= (PAGE_MASK(Pte
) != 0);
850 * Return some information to the caller
852 if (WasDirty
!= NULL
)
854 *WasDirty
= Pte
& PA_DIRTY
;
858 *Page
= PTE_TO_PFN(Pte
);
864 MmRawDeleteVirtualMapping(PVOID Address
)
869 ULONGLONG ZeroPte
= 0LL;
870 Pt
= MmGetPageTableForProcessForPAE(NULL
, Address
, FALSE
);
874 * Set the entry to zero
876 ExfpInterlockedExchange64UL(Pt
, &ZeroPte
);
877 MiFlushTlb((PULONG
)Pt
, Address
);
884 Pt
= MmGetPageTableForProcess(NULL
, Address
, FALSE
);
888 * Set the entry to zero
890 InterlockedExchangeUL(Pt
, 0);
891 MiFlushTlb(Pt
, Address
);
897 MmDeleteVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOL FreePage
,
898 BOOL
* WasDirty
, PPFN_TYPE Page
)
900 * FUNCTION: Delete a virtual mapping
903 BOOLEAN WasValid
= FALSE
;
906 DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
907 Process
, Address
, FreePage
, WasDirty
, Page
);
913 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
916 if (WasDirty
!= NULL
)
928 * Atomically set the entry to zero and get the old value.
931 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
933 MiFlushTlb((PULONG
)Pt
, Address
);
935 WasValid
= PAE_PAGE_MASK(Pte
) != 0 ? TRUE
: FALSE
;
938 Pfn
= PAE_PTE_TO_PFN(Pte
);
939 MmMarkPageUnmapped(Pfn
);
946 if (FreePage
&& WasValid
)
948 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
952 * Return some information to the caller
954 if (WasDirty
!= NULL
)
956 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
968 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
972 if (WasDirty
!= NULL
)
984 * Atomically set the entry to zero and get the old value.
986 Pte
= InterlockedExchangeUL(Pt
, 0);
988 MiFlushTlb(Pt
, Address
);
990 WasValid
= (PAGE_MASK(Pte
) != 0);
993 Pfn
= PTE_TO_PFN(Pte
);
994 MmMarkPageUnmapped(Pfn
);
1001 if (FreePage
&& WasValid
)
1003 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
1007 * Return some information to the caller
1009 if (WasDirty
!= NULL
)
1011 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
1019 * Decrement the reference count for this page table.
1021 if (Process
!= NULL
&& WasValid
&&
1022 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1023 Address
< (PVOID
)KERNEL_BASE
)
1028 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1029 Idx
= Ke386Pae
? PAE_ADDR_TO_PAGE_TABLE(Address
) : ADDR_TO_PAGE_TABLE(Address
);
1034 MmFreePageTable(Process
, Address
);
1040 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
1041 SWAPENTRY
* SwapEntry
)
1043 * FUNCTION: Delete a virtual mapping
1051 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1059 * Atomically set the entry to zero and get the old value.
1062 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
1064 MiFlushTlb((PULONG
)Pt
, Address
);
1067 * Decrement the reference count for this page table.
1069 if (Process
!= NULL
&& Pte
&&
1070 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1071 Address
< (PVOID
)KERNEL_BASE
)
1075 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1077 Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Address
)]--;
1078 if (Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Address
)] == 0)
1080 MmFreePageTable(Process
, Address
);
1086 * Return some information to the caller
1088 *SwapEntry
= Pte
>> 1;
1095 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1104 * Atomically set the entry to zero and get the old value.
1106 Pte
= InterlockedExchangeUL(Pt
, 0);
1108 MiFlushTlb(Pt
, Address
);
1111 * Decrement the reference count for this page table.
1113 if (Process
!= NULL
&& Pte
&&
1114 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1115 Address
< (PVOID
)KERNEL_BASE
)
1119 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1121 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]--;
1122 if (Ptrc
[ADDR_TO_PAGE_TABLE(Address
)] == 0)
1124 MmFreePageTable(Process
, Address
);
1130 * Return some information to the caller
1132 *SwapEntry
= Pte
>> 1;
1137 Mmi386MakeKernelPageTableGlobal(PVOID PAddress
)
1143 Pde
= PAE_ADDR_TO_PDE(PAddress
);
1146 Pt
= MmGetPageTableForProcessForPAE(NULL
, PAddress
, FALSE
);
1148 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
1149 FLASH_TLB_ONE(PAddress
);
1160 Pde
= ADDR_TO_PDE(PAddress
);
1163 Pt
= MmGetPageTableForProcess(NULL
, PAddress
, FALSE
);
1165 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
1166 FLASH_TLB_ONE(PAddress
);
1177 BOOLEAN
MmIsDirtyPage(PEPROCESS Process
, PVOID Address
)
1181 return MmGetPageEntryForProcessForPAE(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
1185 return MmGetPageEntryForProcess(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
1190 MmIsAccessedAndResetAccessPage(PEPROCESS Process
, PVOID Address
)
1192 if (Address
< (PVOID
)KERNEL_BASE
&& Process
== NULL
)
1194 DPRINT1("MmIsAccessedAndResetAccessPage is called for user space without a process.\n");
1203 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1212 tmpPte
= Pte
& ~PA_ACCESSED
;
1213 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1215 if (Pte
& PA_ACCESSED
)
1217 MiFlushTlb((PULONG
)Pt
, Address
);
1222 MmUnmapPageTable((PULONG
)Pt
);
1231 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1240 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_ACCESSED
, Pte
));
1242 if (Pte
& PA_ACCESSED
)
1244 MiFlushTlb(Pt
, Address
);
1249 MmUnmapPageTable(Pt
);
1255 VOID
MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
1257 if (Address
< (PVOID
)KERNEL_BASE
&& Process
== NULL
)
1259 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
1268 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1278 tmpPte
= Pte
& ~PA_DIRTY
;
1279 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1283 MiFlushTlb((PULONG
)Pt
, Address
);
1287 MmUnmapPageTable((PULONG
)Pt
);
1295 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1305 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_DIRTY
, Pte
));
1309 MiFlushTlb(Pt
, Address
);
1313 MmUnmapPageTable(Pt
);
1318 VOID
MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
1320 if (Address
< (PVOID
)KERNEL_BASE
&& Process
== NULL
)
1322 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
1331 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1340 tmpPte
= Pte
| PA_DIRTY
;
1341 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1342 if (!(Pte
& PA_DIRTY
))
1344 MiFlushTlb((PULONG
)Pt
, Address
);
1348 MmUnmapPageTable((PULONG
)Pt
);
1356 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1365 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
| PA_DIRTY
, Pte
));
1366 if (!(Pte
& PA_DIRTY
))
1368 MiFlushTlb(Pt
, Address
);
1372 MmUnmapPageTable(Pt
);
1377 VOID
MmEnableVirtualMapping(PEPROCESS Process
, PVOID Address
)
1385 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1394 tmpPte
= Pte
| PA_PRESENT
;
1395 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1396 if (!(Pte
& PA_PRESENT
))
1398 MiFlushTlb((PULONG
)Pt
, Address
);
1402 MmUnmapPageTable((PULONG
)Pt
);
1410 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1419 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
| PA_PRESENT
, Pte
));
1420 if (!(Pte
& PA_PRESENT
))
1422 MiFlushTlb(Pt
, Address
);
1426 MmUnmapPageTable(Pt
);
1431 BOOLEAN
MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
1435 return MmGetPageEntryForProcessForPAE(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
1439 return MmGetPageEntryForProcess(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
1443 BOOLEAN
MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
1448 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
1449 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
1454 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1455 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
1460 MmCreateVirtualMappingForKernel(PVOID Address
,
1468 ULONG PdeOffset
, oldPdeOffset
;
1469 BOOLEAN NoExecute
= FALSE
;
1471 DPRINT("MmCreateVirtualMappingForKernel(%x, %x, %x, %d)\n",
1472 Address
, flProtect
, Pages
, PageCount
);
1474 if (Address
< (PVOID
)KERNEL_BASE
)
1476 DPRINT1("MmCreateVirtualMappingForKernel is called for user space\n");
1480 Attributes
= ProtectToPTE(flProtect
);
1481 if (Attributes
& 0x80000000)
1485 Attributes
&= 0xfff;
1486 if (Ke386GlobalPagesEnabled
)
1488 Attributes
|= PA_GLOBAL
;
1495 PULONGLONG Pt
= NULL
;
1498 oldPdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
) + 1;
1499 for (i
= 0; i
< PageCount
; i
++, Addr
+= PAGE_SIZE
)
1501 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1503 DPRINT1("Setting physical address but not allowing access at address "
1504 "0x%.8X with attributes %x/%x.\n",
1505 Addr
, Attributes
, flProtect
);
1509 PdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
);
1510 if (oldPdeOffset
!= PdeOffset
)
1512 Pt
= MmGetPageTableForProcessForPAE(NULL
, Addr
, TRUE
);
1522 oldPdeOffset
= PdeOffset
;
1524 Pte
= PFN_TO_PTE(Pages
[i
]) | Attributes
;
1527 Pte
|= 0x8000000000000000LL
;
1529 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
1541 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1542 Pt
= MmGetPageTableForProcess(NULL
, Addr
, TRUE
);
1549 for (i
= 0; i
< PageCount
; i
++, Addr
+= PAGE_SIZE
)
1551 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1553 DPRINT1("Setting physical address but not allowing access at address "
1554 "0x%.8X with attributes %x/%x.\n",
1555 Addr
, Attributes
, flProtect
);
1559 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1560 if (oldPdeOffset
!= PdeOffset
)
1562 Pt
= MmGetPageTableForProcess(NULL
, Addr
, TRUE
);
1572 oldPdeOffset
= PdeOffset
;
1579 InterlockedExchangeUL(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
1583 return(STATUS_SUCCESS
);
1587 MmCreatePageFileMapping(PEPROCESS Process
,
1589 SWAPENTRY SwapEntry
)
1591 if (Process
== NULL
&& Address
< (PVOID
)KERNEL_BASE
)
1593 DPRINT1("No process\n");
1596 if (Process
!= NULL
&& Address
>= (PVOID
)KERNEL_BASE
)
1598 DPRINT1("Setting kernel address with process context\n");
1601 if (SwapEntry
& (1 << 31))
1612 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, TRUE
);
1617 tmpPte
= SwapEntry
<< 1;
1618 Pte
= ExfpInterlockedExchange64UL(Pt
, &tmpPte
);
1619 if (PAE_PAGE_MASK((Pte
)) != 0)
1621 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte
)));
1626 MiFlushTlb((PULONG
)Pt
, Address
);
1630 MmUnmapPageTable((PULONG
)Pt
);
1638 Pt
= MmGetPageTableForProcess(Process
, Address
, TRUE
);
1644 if (PAGE_MASK((Pte
)) != 0)
1646 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1648 InterlockedExchangeUL(Pt
, SwapEntry
<< 1);
1651 MiFlushTlb(Pt
, Address
);
1655 MmUnmapPageTable(Pt
);
1658 if (Process
!= NULL
&&
1659 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1660 Address
< (PVOID
)KERNEL_BASE
)
1665 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1666 Idx
= Ke386Pae
? PAE_ADDR_TO_PAGE_TABLE(Address
) : ADDR_TO_PAGE_TABLE(Address
);
1669 return(STATUS_SUCCESS
);
1674 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
1683 ULONG oldPdeOffset
, PdeOffset
;
1684 BOOLEAN NoExecute
= FALSE
;
1686 DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
1687 Process
, Address
, flProtect
, Pages
, *Pages
, PageCount
);
1689 if (Process
== NULL
)
1691 if (Address
< (PVOID
)KERNEL_BASE
)
1693 DPRINT1("No process\n");
1696 if (PageCount
> 0x10000 ||
1697 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> 0x100000)
1699 DPRINT1("Page count to large\n");
1705 if (Address
>= (PVOID
)KERNEL_BASE
)
1707 DPRINT1("Setting kernel address with process context\n");
1710 if (PageCount
> KERNEL_BASE
/ PAGE_SIZE
||
1711 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> KERNEL_BASE
/ PAGE_SIZE
)
1713 DPRINT1("Page Count to large\n");
1718 Attributes
= ProtectToPTE(flProtect
);
1719 if (Attributes
& 0x80000000)
1723 Attributes
&= 0xfff;
1724 if (Address
>= (PVOID
)KERNEL_BASE
)
1726 Attributes
&= ~PA_USER
;
1727 if (Ke386GlobalPagesEnabled
)
1729 Attributes
|= PA_GLOBAL
;
1734 Attributes
|= PA_USER
;
1741 ULONGLONG Pte
, tmpPte
;
1742 PULONGLONG Pt
= NULL
;
1744 oldPdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
) + 1;
1745 for (i
= 0; i
< PageCount
; i
++, Addr
+= PAGE_SIZE
)
1747 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1749 DPRINT1("Setting physical address but not allowing access at address "
1750 "0x%.8X with attributes %x/%x.\n",
1751 Addr
, Attributes
, flProtect
);
1754 PdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
);
1755 if (oldPdeOffset
!= PdeOffset
)
1757 MmUnmapPageTable((PULONG
)Pt
);
1758 Pt
= MmGetPageTableForProcessForPAE(Process
, Addr
, TRUE
);
1768 oldPdeOffset
= PdeOffset
;
1770 MmMarkPageMapped(Pages
[i
]);
1771 tmpPte
= PAE_PFN_TO_PTE(Pages
[i
]) | Attributes
;
1774 tmpPte
|= 0x8000000000000000LL
;
1776 Pte
= ExfpInterlockedExchange64UL(Pt
, &tmpPte
);
1777 if (PAE_PAGE_MASK((Pte
)) != 0LL && !((Pte
) & PA_PRESENT
))
1781 if (PAE_PAGE_MASK((Pte
)) != 0LL)
1783 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte
)));
1785 if (Address
< (PVOID
)KERNEL_BASE
&&
1786 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1787 Attributes
& PA_PRESENT
)
1791 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1793 Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Addr
)]++;
1797 if (Address
> (PVOID
)KERNEL_BASE
||
1798 (Pt
>= (PULONGLONG
)PAGETABLE_MAP
&& Pt
< (PULONGLONG
)PAGETABLE_MAP
+ 4*512*512))
1800 MiFlushTlb((PULONG
)Pt
, Address
);
1806 MmUnmapPageTable((PULONG
)Pt
);
1813 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
) + 1;
1814 for (i
= 0; i
< PageCount
; i
++, Addr
+= PAGE_SIZE
)
1816 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1818 DPRINT1("Setting physical address but not allowing access at address "
1819 "0x%.8X with attributes %x/%x.\n",
1820 Addr
, Attributes
, flProtect
);
1823 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1824 if (oldPdeOffset
!= PdeOffset
)
1826 MmUnmapPageTable(Pt
);
1827 Pt
= MmGetPageTableForProcess(Process
, Addr
, TRUE
);
1837 oldPdeOffset
= PdeOffset
;
1840 MmMarkPageMapped(Pages
[i
]);
1841 if (PAGE_MASK((Pte
)) != 0 && !((Pte
) & PA_PRESENT
))
1845 if (PAGE_MASK((Pte
)) != 0)
1847 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1849 InterlockedExchangeUL(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
1850 if (Address
< (PVOID
)KERNEL_BASE
&&
1851 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1852 Attributes
& PA_PRESENT
)
1856 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1858 Ptrc
[ADDR_TO_PAGE_TABLE(Addr
)]++;
1862 if (Address
> (PVOID
)KERNEL_BASE
||
1863 (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024))
1865 MiFlushTlb(Pt
, Address
);
1871 MmUnmapPageTable(Pt
);
1874 return(STATUS_SUCCESS
);
1878 MmCreateVirtualMapping(PEPROCESS Process
,
1886 for (i
= 0; i
< PageCount
; i
++)
1888 if (!MmIsUsablePage(Pages
[i
]))
1890 DPRINT1("Page at address %x not usable\n", PFN_TO_PTE(Pages
[i
]));
1895 return(MmCreateVirtualMappingUnsafe(Process
,
1903 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
1909 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
1913 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1916 if (!(Entry
& PA_PRESENT
))
1918 Protect
= PAGE_NOACCESS
;
1922 if (Entry
& PA_READWRITE
)
1924 Protect
= PAGE_READWRITE
;
1928 Protect
= PAGE_EXECUTE_READ
;
1932 Protect
|= PAGE_NOCACHE
;
1936 Protect
|= PAGE_WRITETHROUGH
;
1938 if (!(Entry
& PA_USER
))
1940 Protect
|= PAGE_SYSTEM
;
1948 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
1950 ULONG Attributes
= 0;
1951 BOOLEAN NoExecute
= FALSE
;
1953 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
1954 Process
, Address
, flProtect
);
1956 Attributes
= ProtectToPTE(flProtect
);
1957 if (Attributes
& 0x80000000)
1961 Attributes
&= 0xfff;
1962 if (Address
>= (PVOID
)KERNEL_BASE
)
1964 Attributes
&= ~PA_USER
;
1965 if (Ke386GlobalPagesEnabled
)
1967 Attributes
|= PA_GLOBAL
;
1972 Attributes
|= PA_USER
;
1977 ULONGLONG tmpPte
, Pte
;
1979 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1982 DPRINT1("Address %x\n", Address
);
1988 tmpPte
= PAE_PAGE_MASK(Pte
) | Attributes
| (Pte
& (PA_ACCESSED
|PA_DIRTY
));
1991 tmpPte
|= 0x8000000000000000LL
;
1995 tmpPte
&= ~0x8000000000000000LL
;
1997 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1999 MiFlushTlb((PULONG
)Pt
, Address
);
2005 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
2010 InterlockedExchange(Pt
, PAGE_MASK(*Pt
) | Attributes
| (*Pt
& (PA_ACCESSED
|PA_DIRTY
)));
2011 MiFlushTlb(Pt
, Address
);
2018 PHYSICAL_ADDRESS STDCALL
2019 MmGetPhysicalAddress(PVOID vaddr
)
2021 * FUNCTION: Returns the physical address corresponding to a virtual address
2026 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr
);
2030 Pte
= MmGetPageEntryForProcessForPAE(NULL
, vaddr
);
2031 if (Pte
!= 0 && Pte
& PA_PRESENT
)
2033 p
.QuadPart
= PAE_PAGE_MASK(Pte
);
2034 p
.u
.LowPart
|= (ULONG_PTR
)vaddr
& (PAGE_SIZE
- 1);
2044 Pte
= MmGetPageEntryForProcess(NULL
, vaddr
);
2045 if (Pte
!= 0 && Pte
& PA_PRESENT
)
2047 p
.QuadPart
= PAGE_MASK(Pte
);
2048 p
.u
.LowPart
|= (ULONG_PTR
)vaddr
& (PAGE_SIZE
- 1);
2059 MmCreateHyperspaceMapping(PFN_TYPE Page
)
2067 ULONGLONG ZeroEntry
= 0LL;
2070 Entry
= PFN_TO_PTE(Page
) | PA_PRESENT
| PA_READWRITE
;
2071 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
) + Page
% 1024;
2075 for (i
= Page
%1024; i
< 1024; i
++, Pte
++)
2077 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2084 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
);
2085 for (i
= 0; i
< Page
% 1024; i
++, Pte
++)
2087 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2092 if (i
>= Page
% 1024)
2100 for (i
= Page
%1024; i
>= 0; i
--, Pte
--)
2102 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2109 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
) + 1023;
2110 for (i
= 1023; i
> Page
% 1024; i
--, Pte
--)
2112 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2117 if (i
<= Page
% 1024)
2128 Entry
= PFN_TO_PTE(Page
) | PA_PRESENT
| PA_READWRITE
;
2129 Pte
= ADDR_TO_PTE(HYPERSPACE
) + Page
% 1024;
2132 for (i
= Page
% 1024; i
< 1024; i
++, Pte
++)
2134 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2141 Pte
= ADDR_TO_PTE(HYPERSPACE
);
2142 for (i
= 0; i
< Page
% 1024; i
++, Pte
++)
2144 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2149 if (i
>= Page
% 1024)
2157 for (i
= Page
% 1024; i
>= 0; i
--, Pte
--)
2159 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2166 Pte
= ADDR_TO_PTE(HYPERSPACE
) + 1023;
2167 for (i
= 1023; i
> Page
% 1024; i
--, Pte
--)
2169 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2174 if (i
<= Page
% 1024)
2181 Address
= (PVOID
)HYPERSPACE
+ i
* PAGE_SIZE
;
2182 FLUSH_TLB_ONE(Address
);
2187 MmChangeHyperspaceMapping(PVOID Address
, PFN_TYPE NewPage
)
2190 ASSERT (IS_HYPERSPACE(Address
));
2193 ULONGLONG Entry
= PAE_PFN_TO_PTE(NewPage
) | PA_PRESENT
| PA_READWRITE
;
2194 Entry
= (ULONG
)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PTE(Address
), &Entry
);
2195 Pfn
= PAE_PTE_TO_PFN(Entry
);
2200 Entry
= InterlockedExchange(ADDR_TO_PTE(Address
), PFN_TO_PTE(NewPage
) | PA_PRESENT
| PA_READWRITE
);
2201 Pfn
= PTE_TO_PFN(Entry
);
2203 FLUSH_TLB_ONE(Address
);
2208 MmDeleteHyperspaceMapping(PVOID Address
)
2211 ASSERT (IS_HYPERSPACE(Address
));
2214 ULONGLONG Entry
= 0LL;
2215 Entry
= (ULONG
)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PTE(Address
), &Entry
);
2216 Pfn
= PAE_PTE_TO_PFN(Entry
);
2221 Entry
= InterlockedExchange(ADDR_TO_PTE(Address
), 0);
2222 Pfn
= PTE_TO_PFN(Entry
);
2224 FLUSH_TLB_ONE(Address
);
2228 VOID
MmUpdatePageDir(PEPROCESS Process
, PVOID Address
, ULONG Size
)
2230 ULONG StartOffset
, EndOffset
, Offset
;
2232 if (Address
< (PVOID
)KERNEL_BASE
)
2238 PULONGLONG PageDirTable
;
2240 ULONGLONG ZeroPde
= 0LL;
2243 for (i
= PAE_ADDR_TO_PDTE_OFFSET(Address
); i
<= PAE_ADDR_TO_PDTE_OFFSET(Address
+ Size
); i
++)
2245 if (i
== PAE_ADDR_TO_PDTE_OFFSET(Address
))
2247 StartOffset
= PAE_ADDR_TO_PDE_PAGE_OFFSET(Address
);
2253 if (i
== PAE_ADDR_TO_PDTE_OFFSET(Address
+ Size
))
2255 EndOffset
= PAE_ADDR_TO_PDE_PAGE_OFFSET(Address
+ Size
);
2262 if (Process
!= NULL
&& Process
!= PsGetCurrentProcess())
2264 PageDirTable
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
2265 Pde
= (PULONGLONG
)MmCreateHyperspaceMapping(PTE_TO_PFN(PageDirTable
[i
]));
2266 MmDeleteHyperspaceMapping(PageDirTable
);
2270 Pde
= (PULONGLONG
)PAE_PAGEDIRECTORY_MAP
+ i
*512;
2273 for (Offset
= StartOffset
; Offset
<= EndOffset
; Offset
++)
2275 if (i
* 512 + Offset
< PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) || i
* 512 + Offset
>= PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
)+4)
2277 ExfInterlockedCompareExchange64UL(&Pde
[Offset
], &MmGlobalKernelPageDirectoryForPAE
[i
*512 + Offset
], &ZeroPde
);
2280 MmUnmapPageTable((PULONG
)Pde
);
2286 StartOffset
= ADDR_TO_PDE_OFFSET(Address
);
2287 EndOffset
= ADDR_TO_PDE_OFFSET(Address
+ Size
);
2289 if (Process
!= NULL
&& Process
!= PsGetCurrentProcess())
2291 Pde
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.u
.LowPart
));
2295 Pde
= (PULONG
)PAGEDIRECTORY_MAP
;
2297 for (Offset
= StartOffset
; Offset
<= EndOffset
; Offset
++)
2299 if (Offset
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
))
2301 InterlockedCompareExchangeUL(&Pde
[Offset
], MmGlobalKernelPageDirectory
[Offset
], 0);
2304 if (Pde
!= (PULONG
)PAGEDIRECTORY_MAP
)
2306 MmDeleteHyperspaceMapping(Pde
);
2312 MmInitGlobalKernelPageDirectory(VOID
)
2316 DPRINT("MmInitGlobalKernelPageDirectory()\n");
2320 PULONGLONG CurrentPageDirectory
= (PULONGLONG
)PAE_PAGEDIRECTORY_MAP
;
2321 for (i
= PAE_ADDR_TO_PDE_OFFSET(KERNEL_BASE
); i
< 4 * 512; i
++)
2323 if (!(i
>= PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) && i
< PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) + 4) &&
2324 !(i
>= PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
) && i
< PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
) + 2) &&
2325 0LL == MmGlobalKernelPageDirectoryForPAE
[i
] && 0LL != CurrentPageDirectory
[i
])
2327 ExfpInterlockedExchange64UL(&MmGlobalKernelPageDirectoryForPAE
[i
], &CurrentPageDirectory
[i
]);
2328 if (Ke386GlobalPagesEnabled
)
2330 MmGlobalKernelPageDirectoryForPAE
[i
] |= PA_GLOBAL
;
2331 CurrentPageDirectory
[i
] |= PA_GLOBAL
;
2338 PULONG CurrentPageDirectory
= (PULONG
)PAGEDIRECTORY_MAP
;
2339 for (i
= ADDR_TO_PDE_OFFSET(KERNEL_BASE
); i
< 1024; i
++)
2341 if (i
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) &&
2342 i
!= ADDR_TO_PDE_OFFSET(HYPERSPACE
) &&
2343 0 == MmGlobalKernelPageDirectory
[i
] && 0 != CurrentPageDirectory
[i
])
2345 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];
2346 if (Ke386GlobalPagesEnabled
)
2348 MmGlobalKernelPageDirectory
[i
] |= PA_GLOBAL
;
2349 CurrentPageDirectory
[i
] |= PA_GLOBAL
;
2357 MiGetUserPageDirectoryCount(VOID
)
2359 return Ke386Pae
? PAE_ADDR_TO_PDE_OFFSET(KERNEL_BASE
) : ADDR_TO_PDE_OFFSET(KERNEL_BASE
);
2363 MiInitPageDirectoryMap(VOID
)
2365 MEMORY_AREA
* kernel_map_desc
= NULL
;
2366 MEMORY_AREA
* hyperspace_desc
= NULL
;
2367 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
2370 DPRINT("MiInitPageDirectoryMap()\n");
2372 BoundaryAddressMultiple
.QuadPart
= 0;
2373 BaseAddress
= (PVOID
)PAGETABLE_MAP
;
2374 MmCreateMemoryArea(NULL
,
2375 MmGetKernelAddressSpace(),
2378 Ke386Pae
? 0x800000 : 0x400000,
2383 BoundaryAddressMultiple
);
2384 BaseAddress
= (PVOID
)HYPERSPACE
;
2385 MmCreateMemoryArea(NULL
,
2386 MmGetKernelAddressSpace(),
2394 BoundaryAddressMultiple
);