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 (0xc0000000)
38 #define PAGEDIRECTORY_MAP (0xc0000000 + (PAGETABLE_MAP / (1024)))
40 #define PAE_PAGEDIRECTORY_MAP (0xc0000000 + (PAGETABLE_MAP / (512)))
42 #define HYPERSPACE (Ke386Pae ? 0xc0800000 : 0xc0400000)
43 #define IS_HYPERSPACE(v) (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
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
>= MmSystemRangeStart
)
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
;
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(MmSystemRangeStart
))
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(MmSystemRangeStart
); 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
);
324 MmCopyMmInfo(PEPROCESS Src
,
326 PPHYSICAL_ADDRESS DirectoryTableBase
)
333 DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", Src
, Dest
);
335 Count
= Ke386Pae
? 7 : 2;
337 for (i
= 0; i
< Count
; i
++)
339 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
[i
]);
340 if (!NT_SUCCESS(Status
))
342 for (j
= 0; j
< i
; j
++)
344 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
[j
]);
352 PULONGLONG PageDirTable
;
355 PageDirTable
= MmCreateHyperspaceMapping(Pfn
[0]);
356 for (i
= 0; i
< 4; i
++)
358 PageDirTable
[i
] = PAE_PFN_TO_PTE(Pfn
[1+i
]) | PA_PRESENT
;
360 MmDeleteHyperspaceMapping(PageDirTable
);
361 for (i
= PAE_ADDR_TO_PDTE_OFFSET(MmSystemRangeStart
); i
< 4; i
++)
363 PageDir
= (PULONGLONG
)MmCreateHyperspaceMapping(Pfn
[i
+1]);
364 memcpy(PageDir
, &MmGlobalKernelPageDirectoryForPAE
[i
* 512], 512 * sizeof(ULONGLONG
));
365 if (PAE_ADDR_TO_PDTE_OFFSET(PAGETABLE_MAP
) == i
)
367 for (j
= 0; j
< 4; j
++)
369 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(PAGETABLE_MAP
) + j
] = PAE_PFN_TO_PTE(Pfn
[1+j
]) | PA_PRESENT
| PA_READWRITE
;
372 if (PAE_ADDR_TO_PDTE_OFFSET(HYPERSPACE
) == i
)
374 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)] = PAE_PFN_TO_PTE(Pfn
[5]) | PA_PRESENT
| PA_READWRITE
;
375 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)+1] = PAE_PFN_TO_PTE(Pfn
[6]) | PA_PRESENT
| PA_READWRITE
;
377 MmDeleteHyperspaceMapping(PageDir
);
382 PULONG PageDirectory
;
383 PageDirectory
= MmCreateHyperspaceMapping(Pfn
[0]);
385 memcpy(PageDirectory
+ ADDR_TO_PDE_OFFSET(MmSystemRangeStart
),
386 MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(MmSystemRangeStart
),
387 (1024 - ADDR_TO_PDE_OFFSET(MmSystemRangeStart
)) * sizeof(ULONG
));
389 DPRINT("Addr %x\n",ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
));
390 PageDirectory
[ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
)] = PFN_TO_PTE(Pfn
[0]) | PA_PRESENT
| PA_READWRITE
;
391 PageDirectory
[ADDR_TO_PDE_OFFSET(HYPERSPACE
)] = PFN_TO_PTE(Pfn
[1]) | PA_PRESENT
| PA_READWRITE
;
393 MmDeleteHyperspaceMapping(PageDirectory
);
396 DirectoryTableBase
->QuadPart
= PFN_TO_PTE(Pfn
[0]);
397 DPRINT("Finished MmCopyMmInfo(): %I64x\n", DirectoryTableBase
->QuadPart
);
398 return(STATUS_SUCCESS
);
401 VOID
MmDeletePageTable(PEPROCESS Process
, PVOID Address
)
403 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
405 if (Process
!= NULL
&& Process
!= CurrentProcess
)
407 KeAttachProcess(&Process
->Pcb
);
412 ULONGLONG ZeroPde
= 0LL;
413 ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address
), &ZeroPde
);
414 MiFlushTlb((PULONG
)PAE_ADDR_TO_PDE(Address
), PAE_ADDR_TO_PTE(Address
));
418 *(ADDR_TO_PDE(Address
)) = 0;
419 MiFlushTlb(ADDR_TO_PDE(Address
), ADDR_TO_PTE(Address
));
421 if (Address
>= MmSystemRangeStart
)
424 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
426 if (Process
!= NULL
&& Process
!= CurrentProcess
)
432 VOID
MmFreePageTable(PEPROCESS Process
, PVOID Address
)
434 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
438 DPRINT("ProcessId %d, Address %x\n", Process
->UniqueProcessId
, Address
);
439 if (Process
!= NULL
&& Process
!= CurrentProcess
)
441 KeAttachProcess(&Process
->Pcb
);
445 PULONGLONG PageTable
;
446 ULONGLONG ZeroPte
= 0LL;
447 PageTable
= (PULONGLONG
)PAGE_ROUND_DOWN((PVOID
)PAE_ADDR_TO_PTE(Address
));
448 for (i
= 0; i
< 512; i
++)
450 if (PageTable
[i
] != 0LL)
452 DbgPrint("Page table entry not clear at %x/%x (is %I64x)\n",
453 ((ULONG
)Address
/ (4*1024*1024)), i
, PageTable
[i
]);
457 Pfn
= PAE_PTE_TO_PFN(*(PAE_ADDR_TO_PDE(Address
)));
458 ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address
), &ZeroPte
);
459 MiFlushTlb((PULONG
)PAE_ADDR_TO_PDE(Address
), PAE_ADDR_TO_PTE(Address
));
464 PageTable
= (PULONG
)PAGE_ROUND_DOWN((PVOID
)ADDR_TO_PTE(Address
));
465 for (i
= 0; i
< 1024; i
++)
467 if (PageTable
[i
] != 0)
469 DbgPrint("Page table entry not clear at %x/%x (is %x)\n",
470 ((ULONG
)Address
/ (4*1024*1024)), i
, PageTable
[i
]);
474 Pfn
= PTE_TO_PFN(*(ADDR_TO_PDE(Address
)));
475 *(ADDR_TO_PDE(Address
)) = 0;
476 MiFlushTlb(ADDR_TO_PDE(Address
), ADDR_TO_PTE(Address
));
479 if (Address
>= MmSystemRangeStart
)
481 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
486 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
488 if (Process
!= NULL
&& Process
!= CurrentProcess
)
495 MmGetPageTableForProcessForPAE(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
500 ULONGLONG ZeroEntry
= 0LL;
503 PULONGLONG PageDirTable
;
505 DPRINT("MmGetPageTableForProcessForPAE(%x %x %d)\n",
506 Process
, Address
, Create
);
507 if (Address
>= (PVOID
)PAGETABLE_MAP
&& Address
< (PVOID
)((ULONG_PTR
)PAGETABLE_MAP
+ 0x800000))
511 if (Address
< MmSystemRangeStart
&& Process
&& Process
!= PsGetCurrentProcess())
513 PageDirTable
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
514 if (PageDirTable
== NULL
)
518 PageDir
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDirTable
[PAE_ADDR_TO_PDTE_OFFSET(Address
)]));
519 MmDeleteHyperspaceMapping(PageDirTable
);
524 PageDir
+= PAE_ADDR_TO_PDE_PAGE_OFFSET(Address
);
525 Entry
= ExfInterlockedCompareExchange64UL(PageDir
, &ZeroEntry
, &ZeroEntry
);
530 MmDeleteHyperspaceMapping(PageDir
);
533 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
534 if (!NT_SUCCESS(Status
))
538 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
;
539 Entry
= ExfInterlockedCompareExchange64UL(PageDir
, &Entry
, &ZeroEntry
);
542 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
543 Pfn
= PAE_PTE_TO_PFN(Entry
);
548 Pfn
= PAE_PTE_TO_PFN(Entry
);
550 MmDeleteHyperspaceMapping(PageDir
);
551 Pt
= MmCreateHyperspaceMapping(Pfn
);
556 return Pt
+ PAE_ADDR_TO_PTE_OFFSET(Address
);
558 PageDir
= PAE_ADDR_TO_PDE(Address
);
559 if (0LL == ExfInterlockedCompareExchange64UL(PageDir
, &ZeroEntry
, &ZeroEntry
))
561 if (Address
>= MmSystemRangeStart
)
563 if (MmGlobalKernelPageDirectoryForPAE
[PAE_ADDR_TO_PDE_OFFSET(Address
)] == 0LL)
569 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
570 if (!NT_SUCCESS(Status
))
574 Entry
= PAE_PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
;
575 if (Ke386GlobalPagesEnabled
)
579 if (0LL != ExfInterlockedCompareExchange64UL(&MmGlobalKernelPageDirectoryForPAE
[PAE_ADDR_TO_PDE_OFFSET(Address
)], &Entry
, &ZeroEntry
))
581 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
584 ExfInterlockedCompareExchange64UL(PageDir
, &MmGlobalKernelPageDirectoryForPAE
[PAE_ADDR_TO_PDE_OFFSET(Address
)], &ZeroEntry
);
592 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
593 if (!NT_SUCCESS(Status
))
597 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
;
598 Entry
= ExfInterlockedCompareExchange64UL(PageDir
, &Entry
, &ZeroEntry
);
601 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
605 return (PULONGLONG
)PAE_ADDR_TO_PTE(Address
);
609 MmGetPageTableForProcess(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
611 ULONG PdeOffset
= ADDR_TO_PDE_OFFSET(Address
);
617 if (Address
< MmSystemRangeStart
&& Process
&& Process
!= PsGetCurrentProcess())
619 PageDir
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
624 if (0 == InterlockedCompareExchangeUL(&PageDir
[PdeOffset
], 0, 0))
628 MmDeleteHyperspaceMapping(PageDir
);
631 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
632 if (!NT_SUCCESS(Status
) || Pfn
== 0)
636 Entry
= InterlockedCompareExchangeUL(&PageDir
[PdeOffset
], PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
639 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
640 Pfn
= PTE_TO_PFN(Entry
);
645 Pfn
= PTE_TO_PFN(PageDir
[PdeOffset
]);
647 MmDeleteHyperspaceMapping(PageDir
);
648 Pt
= MmCreateHyperspaceMapping(Pfn
);
653 return Pt
+ ADDR_TO_PTE_OFFSET(Address
);
655 PageDir
= ADDR_TO_PDE(Address
);
656 if (0 == InterlockedCompareExchangeUL(PageDir
, 0, 0))
658 if (Address
>= MmSystemRangeStart
)
660 if (0 == InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory
[PdeOffset
], 0, 0))
666 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
667 if (!NT_SUCCESS(Status
) || Pfn
== 0)
671 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
;
672 if (Ke386GlobalPagesEnabled
)
676 if(0 != InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory
[PdeOffset
], Entry
, 0))
678 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
681 InterlockedExchangeUL(PageDir
, MmGlobalKernelPageDirectory
[PdeOffset
]);
689 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
690 if (!NT_SUCCESS(Status
) || Pfn
== 0)
694 Entry
= InterlockedCompareExchangeUL(PageDir
, PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
697 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
701 return (PULONG
)ADDR_TO_PTE(Address
);
704 BOOLEAN
MmUnmapPageTable(PULONG Pt
)
708 if ((PULONGLONG
)Pt
>= (PULONGLONG
)PAGETABLE_MAP
&& (PULONGLONG
)Pt
< (PULONGLONG
)PAGETABLE_MAP
+ 4*512*512)
715 if (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024)
722 MmDeleteHyperspaceMapping((PVOID
)PAGE_ROUND_DOWN(Pt
));
727 static ULONGLONG
MmGetPageEntryForProcessForPAE(PEPROCESS Process
, PVOID Address
)
732 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
736 MmUnmapPageTable((PULONG
)Pt
);
742 static ULONG
MmGetPageEntryForProcess(PEPROCESS Process
, PVOID Address
)
747 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
751 MmUnmapPageTable(Pt
);
758 MmGetPfnForProcess(PEPROCESS Process
,
765 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
766 if (!(Entry
& PA_PRESENT
))
770 return(PAE_PTE_TO_PFN(Entry
));
775 Entry
= MmGetPageEntryForProcess(Process
, Address
);
776 if (!(Entry
& PA_PRESENT
))
780 return(PTE_TO_PFN(Entry
));
785 MmDisableVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOL
* WasDirty
, PPFN_TYPE Page
)
787 * FUNCTION: Delete a virtual mapping
797 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
803 * Atomically disable the present bit and get the old value.
808 tmpPte
= Pte
& ~PA_PRESENT
;
809 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
811 MiFlushTlb((PULONG
)Pt
, Address
);
812 WasValid
= PAE_PAGE_MASK(Pte
) != 0LL ? TRUE
: FALSE
;
819 * Return some information to the caller
821 if (WasDirty
!= NULL
)
823 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
827 *Page
= PAE_PTE_TO_PFN(Pte
);
835 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
841 * Atomically disable the present bit and get the old value.
846 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_PRESENT
, Pte
));
848 MiFlushTlb(Pt
, Address
);
849 WasValid
= (PAGE_MASK(Pte
) != 0);
856 * Return some information to the caller
858 if (WasDirty
!= NULL
)
860 *WasDirty
= Pte
& PA_DIRTY
;
864 *Page
= PTE_TO_PFN(Pte
);
870 MmRawDeleteVirtualMapping(PVOID Address
)
875 ULONGLONG ZeroPte
= 0LL;
876 Pt
= MmGetPageTableForProcessForPAE(NULL
, Address
, FALSE
);
880 * Set the entry to zero
882 ExfpInterlockedExchange64UL(Pt
, &ZeroPte
);
883 MiFlushTlb((PULONG
)Pt
, Address
);
890 Pt
= MmGetPageTableForProcess(NULL
, Address
, FALSE
);
894 * Set the entry to zero
896 InterlockedExchangeUL(Pt
, 0);
897 MiFlushTlb(Pt
, Address
);
903 MmDeleteVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOL FreePage
,
904 BOOL
* WasDirty
, PPFN_TYPE Page
)
906 * FUNCTION: Delete a virtual mapping
909 BOOLEAN WasValid
= FALSE
;
912 DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
913 Process
, Address
, FreePage
, WasDirty
, Page
);
919 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
922 if (WasDirty
!= NULL
)
934 * Atomically set the entry to zero and get the old value.
937 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
939 MiFlushTlb((PULONG
)Pt
, Address
);
941 WasValid
= PAE_PAGE_MASK(Pte
) != 0 ? TRUE
: FALSE
;
944 Pfn
= PAE_PTE_TO_PFN(Pte
);
945 MmMarkPageUnmapped(Pfn
);
952 if (FreePage
&& WasValid
)
954 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
958 * Return some information to the caller
960 if (WasDirty
!= NULL
)
962 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
974 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
978 if (WasDirty
!= NULL
)
990 * Atomically set the entry to zero and get the old value.
992 Pte
= InterlockedExchangeUL(Pt
, 0);
994 MiFlushTlb(Pt
, Address
);
996 WasValid
= (PAGE_MASK(Pte
) != 0);
999 Pfn
= PTE_TO_PFN(Pte
);
1000 MmMarkPageUnmapped(Pfn
);
1007 if (FreePage
&& WasValid
)
1009 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
1013 * Return some information to the caller
1015 if (WasDirty
!= NULL
)
1017 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
1025 * Decrement the reference count for this page table.
1027 if (Process
!= NULL
&& WasValid
&&
1028 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1029 Address
< MmSystemRangeStart
)
1034 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1035 Idx
= Ke386Pae
? PAE_ADDR_TO_PAGE_TABLE(Address
) : ADDR_TO_PAGE_TABLE(Address
);
1040 MmFreePageTable(Process
, Address
);
1046 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
1047 SWAPENTRY
* SwapEntry
)
1049 * FUNCTION: Delete a virtual mapping
1057 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1065 * Atomically set the entry to zero and get the old value.
1068 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
1070 MiFlushTlb((PULONG
)Pt
, Address
);
1073 * Decrement the reference count for this page table.
1075 if (Process
!= NULL
&& Pte
&&
1076 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1077 Address
< MmSystemRangeStart
)
1081 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1083 Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Address
)]--;
1084 if (Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Address
)] == 0)
1086 MmFreePageTable(Process
, Address
);
1092 * Return some information to the caller
1094 *SwapEntry
= Pte
>> 1;
1101 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1110 * Atomically set the entry to zero and get the old value.
1112 Pte
= InterlockedExchangeUL(Pt
, 0);
1114 MiFlushTlb(Pt
, Address
);
1117 * Decrement the reference count for this page table.
1119 if (Process
!= NULL
&& Pte
&&
1120 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1121 Address
< MmSystemRangeStart
)
1125 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1127 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]--;
1128 if (Ptrc
[ADDR_TO_PAGE_TABLE(Address
)] == 0)
1130 MmFreePageTable(Process
, Address
);
1136 * Return some information to the caller
1138 *SwapEntry
= Pte
>> 1;
1143 Mmi386MakeKernelPageTableGlobal(PVOID PAddress
)
1149 Pde
= PAE_ADDR_TO_PDE(PAddress
);
1152 Pt
= MmGetPageTableForProcessForPAE(NULL
, PAddress
, FALSE
);
1154 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
1155 FLASH_TLB_ONE(PAddress
);
1166 Pde
= ADDR_TO_PDE(PAddress
);
1169 Pt
= MmGetPageTableForProcess(NULL
, PAddress
, FALSE
);
1171 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
1172 FLASH_TLB_ONE(PAddress
);
1183 BOOLEAN
MmIsDirtyPage(PEPROCESS Process
, PVOID Address
)
1187 return MmGetPageEntryForProcessForPAE(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
1191 return MmGetPageEntryForProcess(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
1196 MmIsAccessedAndResetAccessPage(PEPROCESS Process
, PVOID Address
)
1198 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
1200 DPRINT1("MmIsAccessedAndResetAccessPage is called for user space without a process.\n");
1209 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1218 tmpPte
= Pte
& ~PA_ACCESSED
;
1219 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1221 if (Pte
& PA_ACCESSED
)
1223 MiFlushTlb((PULONG
)Pt
, Address
);
1228 MmUnmapPageTable((PULONG
)Pt
);
1237 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1246 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_ACCESSED
, Pte
));
1248 if (Pte
& PA_ACCESSED
)
1250 MiFlushTlb(Pt
, Address
);
1255 MmUnmapPageTable(Pt
);
1261 VOID
MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
1263 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
1265 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
1274 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1284 tmpPte
= Pte
& ~PA_DIRTY
;
1285 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1289 MiFlushTlb((PULONG
)Pt
, Address
);
1293 MmUnmapPageTable((PULONG
)Pt
);
1301 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1311 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_DIRTY
, Pte
));
1315 MiFlushTlb(Pt
, Address
);
1319 MmUnmapPageTable(Pt
);
1324 VOID
MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
1326 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
1328 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
1337 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1346 tmpPte
= Pte
| PA_DIRTY
;
1347 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1348 if (!(Pte
& PA_DIRTY
))
1350 MiFlushTlb((PULONG
)Pt
, Address
);
1354 MmUnmapPageTable((PULONG
)Pt
);
1362 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1371 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
| PA_DIRTY
, Pte
));
1372 if (!(Pte
& PA_DIRTY
))
1374 MiFlushTlb(Pt
, Address
);
1378 MmUnmapPageTable(Pt
);
1383 VOID
MmEnableVirtualMapping(PEPROCESS Process
, PVOID Address
)
1391 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1400 tmpPte
= Pte
| PA_PRESENT
;
1401 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1402 if (!(Pte
& PA_PRESENT
))
1404 MiFlushTlb((PULONG
)Pt
, Address
);
1408 MmUnmapPageTable((PULONG
)Pt
);
1416 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1425 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
| PA_PRESENT
, Pte
));
1426 if (!(Pte
& PA_PRESENT
))
1428 MiFlushTlb(Pt
, Address
);
1432 MmUnmapPageTable(Pt
);
1437 BOOLEAN
MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
1441 return MmGetPageEntryForProcessForPAE(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
1445 return MmGetPageEntryForProcess(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
1449 BOOLEAN
MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
1454 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
1455 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
1460 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1461 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
1466 MmCreateVirtualMappingForKernel(PVOID Address
,
1474 ULONG PdeOffset
, oldPdeOffset
;
1475 BOOLEAN NoExecute
= FALSE
;
1477 DPRINT("MmCreateVirtualMappingForKernel(%x, %x, %x, %d)\n",
1478 Address
, flProtect
, Pages
, PageCount
);
1480 if (Address
< MmSystemRangeStart
)
1482 DPRINT1("MmCreateVirtualMappingForKernel is called for user space\n");
1486 Attributes
= ProtectToPTE(flProtect
);
1487 if (Attributes
& 0x80000000)
1491 Attributes
&= 0xfff;
1492 if (Ke386GlobalPagesEnabled
)
1494 Attributes
|= PA_GLOBAL
;
1501 PULONGLONG Pt
= NULL
;
1504 oldPdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
) + 1;
1505 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
1507 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1509 DPRINT1("Setting physical address but not allowing access at address "
1510 "0x%.8X with attributes %x/%x.\n",
1511 Addr
, Attributes
, flProtect
);
1515 PdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
);
1516 if (oldPdeOffset
!= PdeOffset
)
1518 Pt
= MmGetPageTableForProcessForPAE(NULL
, Addr
, TRUE
);
1528 oldPdeOffset
= PdeOffset
;
1530 Pte
= PFN_TO_PTE(Pages
[i
]) | Attributes
;
1533 Pte
|= 0x8000000000000000LL
;
1535 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
1547 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1548 Pt
= MmGetPageTableForProcess(NULL
, Addr
, TRUE
);
1555 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
1557 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1559 DPRINT1("Setting physical address but not allowing access at address "
1560 "0x%.8X with attributes %x/%x.\n",
1561 Addr
, Attributes
, flProtect
);
1565 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1566 if (oldPdeOffset
!= PdeOffset
)
1568 Pt
= MmGetPageTableForProcess(NULL
, Addr
, TRUE
);
1578 oldPdeOffset
= PdeOffset
;
1585 InterlockedExchangeUL(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
1589 return(STATUS_SUCCESS
);
1593 MmCreatePageFileMapping(PEPROCESS Process
,
1595 SWAPENTRY SwapEntry
)
1597 if (Process
== NULL
&& Address
< MmSystemRangeStart
)
1599 DPRINT1("No process\n");
1602 if (Process
!= NULL
&& Address
>= MmSystemRangeStart
)
1604 DPRINT1("Setting kernel address with process context\n");
1607 if (SwapEntry
& (1 << 31))
1618 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, TRUE
);
1623 tmpPte
= SwapEntry
<< 1;
1624 Pte
= ExfpInterlockedExchange64UL(Pt
, &tmpPte
);
1625 if (PAE_PAGE_MASK((Pte
)) != 0)
1627 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte
)));
1632 MiFlushTlb((PULONG
)Pt
, Address
);
1636 MmUnmapPageTable((PULONG
)Pt
);
1644 Pt
= MmGetPageTableForProcess(Process
, Address
, TRUE
);
1650 if (PAGE_MASK((Pte
)) != 0)
1652 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1654 InterlockedExchangeUL(Pt
, SwapEntry
<< 1);
1657 MiFlushTlb(Pt
, Address
);
1661 MmUnmapPageTable(Pt
);
1664 if (Process
!= NULL
&&
1665 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1666 Address
< MmSystemRangeStart
)
1671 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1672 Idx
= Ke386Pae
? PAE_ADDR_TO_PAGE_TABLE(Address
) : ADDR_TO_PAGE_TABLE(Address
);
1675 return(STATUS_SUCCESS
);
1680 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
1689 ULONG oldPdeOffset
, PdeOffset
;
1690 BOOLEAN NoExecute
= FALSE
;
1692 DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
1693 Process
, Address
, flProtect
, Pages
, *Pages
, PageCount
);
1695 if (Process
== NULL
)
1697 if (Address
< MmSystemRangeStart
)
1699 DPRINT1("No process\n");
1702 if (PageCount
> 0x10000 ||
1703 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> 0x100000)
1705 DPRINT1("Page count to large\n");
1711 if (Address
>= MmSystemRangeStart
)
1713 DPRINT1("Setting kernel address with process context\n");
1716 if (PageCount
> (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
||
1717 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
>
1718 (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
)
1720 DPRINT1("Page Count to large\n");
1725 Attributes
= ProtectToPTE(flProtect
);
1726 if (Attributes
& 0x80000000)
1730 Attributes
&= 0xfff;
1731 if (Address
>= MmSystemRangeStart
)
1733 Attributes
&= ~PA_USER
;
1734 if (Ke386GlobalPagesEnabled
)
1736 Attributes
|= PA_GLOBAL
;
1741 Attributes
|= PA_USER
;
1748 ULONGLONG Pte
, tmpPte
;
1749 PULONGLONG Pt
= NULL
;
1751 oldPdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
) + 1;
1752 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
1754 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1756 DPRINT1("Setting physical address but not allowing access at address "
1757 "0x%.8X with attributes %x/%x.\n",
1758 Addr
, Attributes
, flProtect
);
1761 PdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
);
1762 if (oldPdeOffset
!= PdeOffset
)
1764 MmUnmapPageTable((PULONG
)Pt
);
1765 Pt
= MmGetPageTableForProcessForPAE(Process
, Addr
, TRUE
);
1775 oldPdeOffset
= PdeOffset
;
1777 MmMarkPageMapped(Pages
[i
]);
1778 tmpPte
= PAE_PFN_TO_PTE(Pages
[i
]) | Attributes
;
1781 tmpPte
|= 0x8000000000000000LL
;
1783 Pte
= ExfpInterlockedExchange64UL(Pt
, &tmpPte
);
1784 if (PAE_PAGE_MASK((Pte
)) != 0LL && !((Pte
) & PA_PRESENT
))
1788 if (PAE_PAGE_MASK((Pte
)) != 0LL)
1790 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte
)));
1792 if (Address
< MmSystemRangeStart
&&
1793 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1794 Attributes
& PA_PRESENT
)
1798 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1800 Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Addr
)]++;
1804 if (Address
> MmSystemRangeStart
||
1805 (Pt
>= (PULONGLONG
)PAGETABLE_MAP
&& Pt
< (PULONGLONG
)PAGETABLE_MAP
+ 4*512*512))
1807 MiFlushTlb((PULONG
)Pt
, Address
);
1813 MmUnmapPageTable((PULONG
)Pt
);
1820 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
) + 1;
1821 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
1823 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1825 DPRINT1("Setting physical address but not allowing access at address "
1826 "0x%.8X with attributes %x/%x.\n",
1827 Addr
, Attributes
, flProtect
);
1830 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1831 if (oldPdeOffset
!= PdeOffset
)
1833 MmUnmapPageTable(Pt
);
1834 Pt
= MmGetPageTableForProcess(Process
, Addr
, TRUE
);
1844 oldPdeOffset
= PdeOffset
;
1847 MmMarkPageMapped(Pages
[i
]);
1848 if (PAGE_MASK((Pte
)) != 0 && !((Pte
) & PA_PRESENT
))
1852 if (PAGE_MASK((Pte
)) != 0)
1854 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1856 InterlockedExchangeUL(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
1857 if (Address
< MmSystemRangeStart
&&
1858 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1859 Attributes
& PA_PRESENT
)
1863 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1865 Ptrc
[ADDR_TO_PAGE_TABLE(Addr
)]++;
1869 if (Address
> MmSystemRangeStart
||
1870 (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024))
1872 MiFlushTlb(Pt
, Address
);
1878 MmUnmapPageTable(Pt
);
1881 return(STATUS_SUCCESS
);
1885 MmCreateVirtualMapping(PEPROCESS Process
,
1893 for (i
= 0; i
< PageCount
; i
++)
1895 if (!MmIsUsablePage(Pages
[i
]))
1897 DPRINT1("Page at address %x not usable\n", PFN_TO_PTE(Pages
[i
]));
1902 return(MmCreateVirtualMappingUnsafe(Process
,
1910 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
1916 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
1920 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1923 if (!(Entry
& PA_PRESENT
))
1925 Protect
= PAGE_NOACCESS
;
1929 if (Entry
& PA_READWRITE
)
1931 Protect
= PAGE_READWRITE
;
1935 Protect
= PAGE_EXECUTE_READ
;
1939 Protect
|= PAGE_NOCACHE
;
1943 Protect
|= PAGE_WRITETHROUGH
;
1945 if (!(Entry
& PA_USER
))
1947 Protect
|= PAGE_SYSTEM
;
1955 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
1957 ULONG Attributes
= 0;
1958 BOOLEAN NoExecute
= FALSE
;
1960 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
1961 Process
, Address
, flProtect
);
1963 Attributes
= ProtectToPTE(flProtect
);
1964 if (Attributes
& 0x80000000)
1968 Attributes
&= 0xfff;
1969 if (Address
>= MmSystemRangeStart
)
1971 Attributes
&= ~PA_USER
;
1972 if (Ke386GlobalPagesEnabled
)
1974 Attributes
|= PA_GLOBAL
;
1979 Attributes
|= PA_USER
;
1984 ULONGLONG tmpPte
, Pte
;
1986 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1989 DPRINT1("Address %x\n", Address
);
1995 tmpPte
= PAE_PAGE_MASK(Pte
) | Attributes
| (Pte
& (PA_ACCESSED
|PA_DIRTY
));
1998 tmpPte
|= 0x8000000000000000LL
;
2002 tmpPte
&= ~0x8000000000000000LL
;
2004 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
2006 MiFlushTlb((PULONG
)Pt
, Address
);
2012 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
2017 InterlockedExchange((PLONG
)Pt
, PAGE_MASK(*Pt
) | Attributes
| (*Pt
& (PA_ACCESSED
|PA_DIRTY
)));
2018 MiFlushTlb(Pt
, Address
);
2025 PHYSICAL_ADDRESS STDCALL
2026 MmGetPhysicalAddress(PVOID vaddr
)
2028 * FUNCTION: Returns the physical address corresponding to a virtual address
2033 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr
);
2037 Pte
= MmGetPageEntryForProcessForPAE(NULL
, vaddr
);
2038 if (Pte
!= 0 && Pte
& PA_PRESENT
)
2040 p
.QuadPart
= PAE_PAGE_MASK(Pte
);
2041 p
.u
.LowPart
|= (ULONG_PTR
)vaddr
& (PAGE_SIZE
- 1);
2051 Pte
= MmGetPageEntryForProcess(NULL
, vaddr
);
2052 if (Pte
!= 0 && Pte
& PA_PRESENT
)
2054 p
.QuadPart
= PAGE_MASK(Pte
);
2055 p
.u
.LowPart
|= (ULONG_PTR
)vaddr
& (PAGE_SIZE
- 1);
2066 MmCreateHyperspaceMapping(PFN_TYPE Page
)
2074 ULONGLONG ZeroEntry
= 0LL;
2077 Entry
= PFN_TO_PTE(Page
) | PA_PRESENT
| PA_READWRITE
;
2078 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
) + Page
% 1024;
2082 for (i
= Page
%1024; i
< 1024; i
++, Pte
++)
2084 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2091 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
);
2092 for (i
= 0; i
< Page
% 1024; i
++, Pte
++)
2094 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2099 if (i
>= Page
% 1024)
2107 for (i
= Page
%1024; (LONG
)i
>= 0; i
--, Pte
--)
2109 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2116 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
) + 1023;
2117 for (i
= 1023; i
> Page
% 1024; i
--, Pte
--)
2119 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2124 if (i
<= Page
% 1024)
2135 Entry
= PFN_TO_PTE(Page
) | PA_PRESENT
| PA_READWRITE
;
2136 Pte
= ADDR_TO_PTE(HYPERSPACE
) + Page
% 1024;
2139 for (i
= Page
% 1024; i
< 1024; i
++, Pte
++)
2141 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2148 Pte
= ADDR_TO_PTE(HYPERSPACE
);
2149 for (i
= 0; i
< Page
% 1024; i
++, Pte
++)
2151 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2156 if (i
>= Page
% 1024)
2164 for (i
= Page
% 1024; (LONG
)i
>= 0; i
--, Pte
--)
2166 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2173 Pte
= ADDR_TO_PTE(HYPERSPACE
) + 1023;
2174 for (i
= 1023; i
> Page
% 1024; i
--, Pte
--)
2176 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2181 if (i
<= Page
% 1024)
2188 Address
= (PVOID
)((ULONG_PTR
)HYPERSPACE
+ i
* PAGE_SIZE
);
2189 FLUSH_TLB_ONE(Address
);
2194 MmChangeHyperspaceMapping(PVOID Address
, PFN_TYPE NewPage
)
2197 ASSERT (IS_HYPERSPACE(Address
));
2200 ULONGLONG Entry
= PAE_PFN_TO_PTE(NewPage
) | PA_PRESENT
| PA_READWRITE
;
2201 Entry
= (ULONG
)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PTE(Address
), &Entry
);
2202 Pfn
= PAE_PTE_TO_PFN(Entry
);
2207 Entry
= InterlockedExchange((PLONG
)ADDR_TO_PTE(Address
), PFN_TO_PTE(NewPage
) | PA_PRESENT
| PA_READWRITE
);
2208 Pfn
= PTE_TO_PFN(Entry
);
2210 FLUSH_TLB_ONE(Address
);
2215 MmDeleteHyperspaceMapping(PVOID Address
)
2218 ASSERT (IS_HYPERSPACE(Address
));
2221 ULONGLONG Entry
= 0LL;
2222 Entry
= (ULONG
)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PTE(Address
), &Entry
);
2223 Pfn
= PAE_PTE_TO_PFN(Entry
);
2228 Entry
= InterlockedExchange((PLONG
)ADDR_TO_PTE(Address
), 0);
2229 Pfn
= PTE_TO_PFN(Entry
);
2231 FLUSH_TLB_ONE(Address
);
2235 VOID
MmUpdatePageDir(PEPROCESS Process
, PVOID Address
, ULONG Size
)
2237 ULONG StartOffset
, EndOffset
, Offset
;
2239 if (Address
< MmSystemRangeStart
)
2245 PULONGLONG PageDirTable
;
2247 ULONGLONG ZeroPde
= 0LL;
2250 for (i
= PAE_ADDR_TO_PDTE_OFFSET(Address
); i
<= PAE_ADDR_TO_PDTE_OFFSET((PVOID
)((ULONG_PTR
)Address
+ Size
)); i
++)
2252 if (i
== PAE_ADDR_TO_PDTE_OFFSET(Address
))
2254 StartOffset
= PAE_ADDR_TO_PDE_PAGE_OFFSET(Address
);
2260 if (i
== PAE_ADDR_TO_PDTE_OFFSET((PVOID
)((ULONG_PTR
)Address
+ Size
)))
2262 EndOffset
= PAE_ADDR_TO_PDE_PAGE_OFFSET((PVOID
)((ULONG_PTR
)Address
+ Size
));
2269 if (Process
!= NULL
&& Process
!= PsGetCurrentProcess())
2271 PageDirTable
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
2272 Pde
= (PULONGLONG
)MmCreateHyperspaceMapping(PTE_TO_PFN(PageDirTable
[i
]));
2273 MmDeleteHyperspaceMapping(PageDirTable
);
2277 Pde
= (PULONGLONG
)PAE_PAGEDIRECTORY_MAP
+ i
*512;
2280 for (Offset
= StartOffset
; Offset
<= EndOffset
; Offset
++)
2282 if (i
* 512 + Offset
< PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) || i
* 512 + Offset
>= PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
)+4)
2284 ExfInterlockedCompareExchange64UL(&Pde
[Offset
], &MmGlobalKernelPageDirectoryForPAE
[i
*512 + Offset
], &ZeroPde
);
2287 MmUnmapPageTable((PULONG
)Pde
);
2293 StartOffset
= ADDR_TO_PDE_OFFSET(Address
);
2294 EndOffset
= ADDR_TO_PDE_OFFSET((PVOID
)((ULONG_PTR
)Address
+ Size
));
2296 if (Process
!= NULL
&& Process
!= PsGetCurrentProcess())
2298 Pde
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.u
.LowPart
));
2302 Pde
= (PULONG
)PAGEDIRECTORY_MAP
;
2304 for (Offset
= StartOffset
; Offset
<= EndOffset
; Offset
++)
2306 if (Offset
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
))
2308 InterlockedCompareExchangeUL(&Pde
[Offset
], MmGlobalKernelPageDirectory
[Offset
], 0);
2311 if (Pde
!= (PULONG
)PAGEDIRECTORY_MAP
)
2313 MmDeleteHyperspaceMapping(Pde
);
2319 MmInitGlobalKernelPageDirectory(VOID
)
2323 DPRINT("MmInitGlobalKernelPageDirectory()\n");
2327 PULONGLONG CurrentPageDirectory
= (PULONGLONG
)PAE_PAGEDIRECTORY_MAP
;
2328 for (i
= PAE_ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
< 4 * 512; i
++)
2330 if (!(i
>= PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) && i
< PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) + 4) &&
2331 !(i
>= PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
) && i
< PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
) + 2) &&
2332 0LL == MmGlobalKernelPageDirectoryForPAE
[i
] && 0LL != CurrentPageDirectory
[i
])
2334 ExfpInterlockedExchange64UL(&MmGlobalKernelPageDirectoryForPAE
[i
], &CurrentPageDirectory
[i
]);
2335 if (Ke386GlobalPagesEnabled
)
2337 MmGlobalKernelPageDirectoryForPAE
[i
] |= PA_GLOBAL
;
2338 CurrentPageDirectory
[i
] |= PA_GLOBAL
;
2345 PULONG CurrentPageDirectory
= (PULONG
)PAGEDIRECTORY_MAP
;
2346 for (i
= ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
< 1024; i
++)
2348 if (i
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) &&
2349 i
!= ADDR_TO_PDE_OFFSET(HYPERSPACE
) &&
2350 0 == MmGlobalKernelPageDirectory
[i
] && 0 != CurrentPageDirectory
[i
])
2352 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];
2353 if (Ke386GlobalPagesEnabled
)
2355 MmGlobalKernelPageDirectory
[i
] |= PA_GLOBAL
;
2356 CurrentPageDirectory
[i
] |= PA_GLOBAL
;
2364 MiGetUserPageDirectoryCount(VOID
)
2366 return Ke386Pae
? PAE_ADDR_TO_PDE_OFFSET(MmSystemRangeStart
) : ADDR_TO_PDE_OFFSET(MmSystemRangeStart
);
2370 MiInitPageDirectoryMap(VOID
)
2372 MEMORY_AREA
* kernel_map_desc
= NULL
;
2373 MEMORY_AREA
* hyperspace_desc
= NULL
;
2374 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
2378 DPRINT("MiInitPageDirectoryMap()\n");
2380 BoundaryAddressMultiple
.QuadPart
= 0;
2381 BaseAddress
= (PVOID
)PAGETABLE_MAP
;
2382 Status
= MmCreateMemoryArea(NULL
,
2383 MmGetKernelAddressSpace(),
2386 Ke386Pae
? 0x800000 : 0x400000,
2391 BoundaryAddressMultiple
);
2392 if (!NT_SUCCESS(Status
))
2396 BaseAddress
= (PVOID
)HYPERSPACE
;
2397 Status
= MmCreateMemoryArea(NULL
,
2398 MmGetKernelAddressSpace(),
2406 BoundaryAddressMultiple
);
2407 if (!NT_SUCCESS(Status
))