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 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, MmInitGlobalKernelPageDirectory)
19 #pragma alloc_text(INIT, MiInitPageDirectoryMap)
23 /* GLOBALS *****************************************************************/
25 #define PA_BIT_PRESENT (0)
26 #define PA_BIT_READWRITE (1)
27 #define PA_BIT_USER (2)
30 #define PA_BIT_ACCESSED (5)
31 #define PA_BIT_DIRTY (6)
32 #define PA_BIT_GLOBAL (8)
34 #define PA_PRESENT (1 << PA_BIT_PRESENT)
35 #define PA_READWRITE (1 << PA_BIT_READWRITE)
36 #define PA_USER (1 << PA_BIT_USER)
37 #define PA_DIRTY (1 << PA_BIT_DIRTY)
38 #define PA_WT (1 << PA_BIT_WT)
39 #define PA_CD (1 << PA_BIT_CD)
40 #define PA_ACCESSED (1 << PA_BIT_ACCESSED)
41 #define PA_GLOBAL (1 << PA_BIT_GLOBAL)
43 #define PAGETABLE_MAP (0xc0000000)
44 #define PAGEDIRECTORY_MAP (0xc0000000 + (PAGETABLE_MAP / (1024)))
46 #define PAE_PAGEDIRECTORY_MAP (0xc0000000 + (PAGETABLE_MAP / (512)))
48 #define HYPERSPACE (Ke386Pae ? 0xc0800000 : 0xc0400000)
49 #define IS_HYPERSPACE(v) (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
51 ULONG MmGlobalKernelPageDirectory
[1024];
52 ULONGLONG MmGlobalKernelPageDirectoryForPAE
[2048];
54 #define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT)
55 #define PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
57 #define PAE_PTE_TO_PFN(X) (PAE_PAGE_MASK(X) >> PAGE_SHIFT)
58 #define PAE_PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
61 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
63 __inline LARGE_INTEGER
PTE_TO_PAGE(ULONG npage
)
66 dummy
.QuadPart
= (LONGLONG
)(PAGE_MASK(npage
));
71 extern BOOLEAN Ke386Pae
;
72 extern BOOLEAN Ke386NoExecute
;
73 extern BOOLEAN Ke386GlobalPagesEnabled
;
75 /* FUNCTIONS ***************************************************************/
77 BOOLEAN
MmUnmapPageTable(PULONG Pt
);
81 MiFlushTlbIpiRoutine(PVOID Address
)
83 if (Address
== (PVOID
)0xffffffff)
87 else if (Address
== (PVOID
)0xfffffffe)
93 FLUSH_TLB_ONE(Address
);
98 MiFlushTlb(PULONG Pt
, PVOID Address
)
103 MmUnmapPageTable(Pt
);
105 if (KeNumberProcessors
>1)
107 KeIpiGenericCall(MiFlushTlbIpiRoutine
, Address
);
111 MiFlushTlbIpiRoutine(Address
);
114 if ((Pt
&& MmUnmapPageTable(Pt
)) || Address
>= MmSystemRangeStart
)
116 FLUSH_TLB_ONE(Address
);
124 MmGetPageDirectory(VOID
)
126 unsigned int page_dir
=0;
127 Ke386GetPageTableDirectory(page_dir
);
128 return((PULONG
)page_dir
);
132 ProtectToPTE(ULONG flProtect
)
134 ULONG Attributes
= 0;
136 if (flProtect
& (PAGE_NOACCESS
|PAGE_GUARD
))
140 else if (flProtect
& PAGE_IS_WRITABLE
)
142 Attributes
= PA_PRESENT
| PA_READWRITE
;
144 else if (flProtect
& (PAGE_IS_READABLE
| PAGE_IS_EXECUTABLE
))
146 Attributes
= PA_PRESENT
;
150 DPRINT1("Unknown main protection type.\n");
153 if (Ke386NoExecute
&&
154 !(flProtect
& PAGE_IS_EXECUTABLE
))
156 Attributes
= Attributes
| 0x80000000;
159 if (flProtect
& PAGE_SYSTEM
)
164 Attributes
= Attributes
| PA_USER
;
166 if (flProtect
& PAGE_NOCACHE
)
168 Attributes
= Attributes
| PA_CD
;
170 if (flProtect
& PAGE_WRITETHROUGH
)
172 Attributes
= Attributes
| PA_WT
;
177 #define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (1024 * PAGE_SIZE))
179 #define ADDR_TO_PDE(v) (PULONG)(PAGEDIRECTORY_MAP + \
180 ((((ULONG)(v)) / (1024 * 1024))&(~0x3)))
181 #define ADDR_TO_PTE(v) (PULONG)(PAGETABLE_MAP + ((((ULONG)(v) / 1024))&(~0x3)))
183 #define ADDR_TO_PDE_OFFSET(v) ((((ULONG)(v)) / (1024 * PAGE_SIZE)))
185 #define ADDR_TO_PTE_OFFSET(v) ((((ULONG)(v)) % (1024 * PAGE_SIZE)) / PAGE_SIZE)
188 #define PAE_ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (512 * PAGE_SIZE))
190 #define PAE_ADDR_TO_PDE(v) (PULONGLONG) (PAE_PAGEDIRECTORY_MAP + \
191 ((((ULONG_PTR)(v)) / (512 * 512))&(~0x7)))
192 #define PAE_ADDR_TO_PTE(v) (PULONGLONG) (PAGETABLE_MAP + ((((ULONG_PTR)(v) / 512))&(~0x7)))
195 #define PAE_ADDR_TO_PDTE_OFFSET(v) (((ULONG_PTR)(v)) / (512 * 512 * PAGE_SIZE))
197 #define PAE_ADDR_TO_PDE_PAGE_OFFSET(v) ((((ULONG_PTR)(v)) % (512 * 512 * PAGE_SIZE)) / (512 * PAGE_SIZE))
199 #define PAE_ADDR_TO_PDE_OFFSET(v) (((ULONG_PTR)(v))/ (512 * PAGE_SIZE))
201 #define PAE_ADDR_TO_PTE_OFFSET(v) ((((ULONG_PTR)(v)) % (512 * PAGE_SIZE)) / PAGE_SIZE)
206 Mmi386ReleaseMmInfo(PEPROCESS Process
)
208 PUSHORT LdtDescriptor
;
212 DPRINT("Mmi386ReleaseMmInfo(Process %x)\n",Process
);
214 LdtDescriptor
= (PUSHORT
) &Process
->Pcb
.LdtDescriptor
;
215 LdtBase
= LdtDescriptor
[1] |
216 ((LdtDescriptor
[2] & 0xff) << 16) |
217 ((LdtDescriptor
[3] & ~0xff) << 16);
219 DPRINT("LdtBase: %x\n", LdtBase
);
223 ExFreePool((PVOID
) LdtBase
);
228 PULONGLONG PageDirTable
;
233 PageDirTable
= (PULONGLONG
)MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
234 for (i
= 0; i
< 4; i
++)
236 PageDir
= (PULONGLONG
)MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDirTable
[i
]));
237 if (i
< PAE_ADDR_TO_PDTE_OFFSET(MmSystemRangeStart
))
239 for (j
= 0; j
< 512; j
++)
241 if (PageDir
[j
] != 0LL)
243 DPRINT1("ProcessId %d, Pde for %08x - %08x is not freed, RefCount %d\n",
244 Process
->UniqueProcessId
,
245 (i
* 512 + j
) * 512 * PAGE_SIZE
, (i
* 512 + j
+ 1) * 512 * PAGE_SIZE
- 1,
246 Process
->AddressSpace
.PageTableRefCountTable
[i
*512 + j
]);
247 Pde
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDir
[j
]));
248 for (k
= 0; k
< 512; k
++)
252 if (Pde
[k
] & PA_PRESENT
)
254 DPRINT1("Page at %08x is not freed\n",
255 (i
* 512 + j
) * 512 * PAGE_SIZE
+ k
* PAGE_SIZE
);
259 DPRINT1("Swapentry %x at %x is not freed\n",
260 (i
* 512 + j
) * 512 * PAGE_SIZE
+ k
* PAGE_SIZE
);
264 MmDeleteHyperspaceMapping(Pde
);
265 MmReleasePageMemoryConsumer(MC_NPPOOL
, PAE_PTE_TO_PFN(PageDir
[j
]));
269 if (i
== PAE_ADDR_TO_PDTE_OFFSET(HYPERSPACE
))
271 MmReleasePageMemoryConsumer(MC_NPPOOL
, PAE_PTE_TO_PFN(PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)]));
272 MmReleasePageMemoryConsumer(MC_NPPOOL
, PAE_PTE_TO_PFN(PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)+1]));
274 MmDeleteHyperspaceMapping(PageDir
);
275 MmReleasePageMemoryConsumer(MC_NPPOOL
, PAE_PTE_TO_PFN(PageDirTable
[i
]));
277 MmDeleteHyperspaceMapping((PVOID
)PageDirTable
);
278 MmReleasePageMemoryConsumer(MC_NPPOOL
, PAE_PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
284 PageDir
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.u
.LowPart
));
285 for (i
= 0; i
< ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
++)
289 DPRINT1("Pde for %08x - %08x is not freed, RefCount %d\n",
290 i
* 4 * 1024 * 1024, (i
+ 1) * 4 * 1024 * 1024 - 1,
291 Process
->AddressSpace
.PageTableRefCountTable
[i
]);
292 Pde
= MmCreateHyperspaceMapping(PTE_TO_PFN(PageDir
[i
]));
293 for (j
= 0; j
< 1024; j
++)
297 if (Pde
[j
] & PA_PRESENT
)
299 DPRINT1("Page at %08x is not freed\n",
300 i
* 4 * 1024 * 1024 + j
* PAGE_SIZE
);
304 DPRINT1("Swapentry %x at %x is not freed\n",
305 Pde
[j
], i
* 4 * 1024 * 1024 + j
* PAGE_SIZE
);
309 MmDeleteHyperspaceMapping(Pde
);
310 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(PageDir
[i
]));
313 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(PageDir
[ADDR_TO_PDE_OFFSET(HYPERSPACE
)]));
314 MmDeleteHyperspaceMapping(PageDir
);
315 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.u
.LowPart
));
318 #if defined(__GNUC__)
320 Process
->Pcb
.DirectoryTableBase
.QuadPart
= 0LL;
323 Process
->Pcb
.DirectoryTableBase
.QuadPart
= 0;
326 DPRINT("Finished Mmi386ReleaseMmInfo()\n");
327 return(STATUS_SUCCESS
);
332 MmCopyMmInfo(PEPROCESS Src
,
334 PPHYSICAL_ADDRESS DirectoryTableBase
)
341 DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", Src
, Dest
);
343 Count
= Ke386Pae
? 7 : 2;
345 for (i
= 0; i
< Count
; i
++)
347 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
[i
]);
348 if (!NT_SUCCESS(Status
))
350 for (j
= 0; j
< i
; j
++)
352 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
[j
]);
360 PULONGLONG PageDirTable
;
363 PageDirTable
= MmCreateHyperspaceMapping(Pfn
[0]);
364 for (i
= 0; i
< 4; i
++)
366 PageDirTable
[i
] = PAE_PFN_TO_PTE(Pfn
[1+i
]) | PA_PRESENT
;
368 MmDeleteHyperspaceMapping(PageDirTable
);
369 for (i
= PAE_ADDR_TO_PDTE_OFFSET(MmSystemRangeStart
); i
< 4; i
++)
371 PageDir
= (PULONGLONG
)MmCreateHyperspaceMapping(Pfn
[i
+1]);
372 memcpy(PageDir
, &MmGlobalKernelPageDirectoryForPAE
[i
* 512], 512 * sizeof(ULONGLONG
));
373 if (PAE_ADDR_TO_PDTE_OFFSET(PAGETABLE_MAP
) == i
)
375 for (j
= 0; j
< 4; j
++)
377 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(PAGETABLE_MAP
) + j
] = PAE_PFN_TO_PTE(Pfn
[1+j
]) | PA_PRESENT
| PA_READWRITE
;
380 if (PAE_ADDR_TO_PDTE_OFFSET(HYPERSPACE
) == i
)
382 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)] = PAE_PFN_TO_PTE(Pfn
[5]) | PA_PRESENT
| PA_READWRITE
;
383 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)+1] = PAE_PFN_TO_PTE(Pfn
[6]) | PA_PRESENT
| PA_READWRITE
;
385 MmDeleteHyperspaceMapping(PageDir
);
390 PULONG PageDirectory
;
391 PageDirectory
= MmCreateHyperspaceMapping(Pfn
[0]);
393 memcpy(PageDirectory
+ ADDR_TO_PDE_OFFSET(MmSystemRangeStart
),
394 MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(MmSystemRangeStart
),
395 (1024 - ADDR_TO_PDE_OFFSET(MmSystemRangeStart
)) * sizeof(ULONG
));
397 DPRINT("Addr %x\n",ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
));
398 PageDirectory
[ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
)] = PFN_TO_PTE(Pfn
[0]) | PA_PRESENT
| PA_READWRITE
;
399 PageDirectory
[ADDR_TO_PDE_OFFSET(HYPERSPACE
)] = PFN_TO_PTE(Pfn
[1]) | PA_PRESENT
| PA_READWRITE
;
401 MmDeleteHyperspaceMapping(PageDirectory
);
404 DirectoryTableBase
->QuadPart
= PFN_TO_PTE(Pfn
[0]);
405 DPRINT("Finished MmCopyMmInfo(): %I64x\n", DirectoryTableBase
->QuadPart
);
406 return(STATUS_SUCCESS
);
411 MmDeletePageTable(PEPROCESS Process
, PVOID Address
)
413 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
415 if (Process
!= NULL
&& Process
!= CurrentProcess
)
417 KeAttachProcess(&Process
->Pcb
);
422 ULONGLONG ZeroPde
= 0LL;
423 ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address
), &ZeroPde
);
424 MiFlushTlb((PULONG
)PAE_ADDR_TO_PDE(Address
), PAE_ADDR_TO_PTE(Address
));
428 *(ADDR_TO_PDE(Address
)) = 0;
429 MiFlushTlb(ADDR_TO_PDE(Address
), ADDR_TO_PTE(Address
));
431 if (Address
>= MmSystemRangeStart
)
434 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
436 if (Process
!= NULL
&& Process
!= CurrentProcess
)
444 MmFreePageTable(PEPROCESS Process
, PVOID Address
)
446 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
450 DPRINT("ProcessId %d, Address %x\n", Process
->UniqueProcessId
, Address
);
451 if (Process
!= NULL
&& Process
!= CurrentProcess
)
453 KeAttachProcess(&Process
->Pcb
);
457 PULONGLONG PageTable
;
458 ULONGLONG ZeroPte
= 0LL;
459 PageTable
= (PULONGLONG
)PAGE_ROUND_DOWN((PVOID
)PAE_ADDR_TO_PTE(Address
));
460 for (i
= 0; i
< 512; i
++)
462 if (PageTable
[i
] != 0LL)
464 DbgPrint("Page table entry not clear at %x/%x (is %I64x)\n",
465 ((ULONG
)Address
/ (4*1024*1024)), i
, PageTable
[i
]);
469 Pfn
= PAE_PTE_TO_PFN(*(PAE_ADDR_TO_PDE(Address
)));
470 ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address
), &ZeroPte
);
471 MiFlushTlb((PULONG
)PAE_ADDR_TO_PDE(Address
), PAE_ADDR_TO_PTE(Address
));
476 PageTable
= (PULONG
)PAGE_ROUND_DOWN((PVOID
)ADDR_TO_PTE(Address
));
477 for (i
= 0; i
< 1024; i
++)
479 if (PageTable
[i
] != 0)
481 DbgPrint("Page table entry not clear at %x/%x (is %x)\n",
482 ((ULONG
)Address
/ (4*1024*1024)), i
, PageTable
[i
]);
486 Pfn
= PTE_TO_PFN(*(ADDR_TO_PDE(Address
)));
487 *(ADDR_TO_PDE(Address
)) = 0;
488 MiFlushTlb(ADDR_TO_PDE(Address
), ADDR_TO_PTE(Address
));
491 if (Address
>= MmSystemRangeStart
)
493 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
498 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
500 if (Process
!= NULL
&& Process
!= CurrentProcess
)
507 MmGetPageTableForProcessForPAE(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
512 ULONGLONG ZeroEntry
= 0LL;
515 PULONGLONG PageDirTable
;
517 DPRINT("MmGetPageTableForProcessForPAE(%x %x %d)\n",
518 Process
, Address
, Create
);
519 if (Address
>= (PVOID
)PAGETABLE_MAP
&& Address
< (PVOID
)((ULONG_PTR
)PAGETABLE_MAP
+ 0x800000))
523 if (Address
< MmSystemRangeStart
&& Process
&& Process
!= PsGetCurrentProcess())
525 PageDirTable
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
526 if (PageDirTable
== NULL
)
530 PageDir
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDirTable
[PAE_ADDR_TO_PDTE_OFFSET(Address
)]));
531 MmDeleteHyperspaceMapping(PageDirTable
);
536 PageDir
+= PAE_ADDR_TO_PDE_PAGE_OFFSET(Address
);
537 Entry
= ExfInterlockedCompareExchange64UL(PageDir
, &ZeroEntry
, &ZeroEntry
);
542 MmDeleteHyperspaceMapping(PageDir
);
545 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
546 if (!NT_SUCCESS(Status
))
550 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
;
551 Entry
= ExfInterlockedCompareExchange64UL(PageDir
, &Entry
, &ZeroEntry
);
554 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
555 Pfn
= PAE_PTE_TO_PFN(Entry
);
560 Pfn
= PAE_PTE_TO_PFN(Entry
);
562 MmDeleteHyperspaceMapping(PageDir
);
563 Pt
= MmCreateHyperspaceMapping(Pfn
);
568 return Pt
+ PAE_ADDR_TO_PTE_OFFSET(Address
);
570 PageDir
= PAE_ADDR_TO_PDE(Address
);
571 if (0LL == ExfInterlockedCompareExchange64UL(PageDir
, &ZeroEntry
, &ZeroEntry
))
573 if (Address
>= MmSystemRangeStart
)
575 if (MmGlobalKernelPageDirectoryForPAE
[PAE_ADDR_TO_PDE_OFFSET(Address
)] == 0LL)
581 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
582 if (!NT_SUCCESS(Status
))
586 Entry
= PAE_PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
;
587 if (Ke386GlobalPagesEnabled
)
591 if (0LL != ExfInterlockedCompareExchange64UL(&MmGlobalKernelPageDirectoryForPAE
[PAE_ADDR_TO_PDE_OFFSET(Address
)], &Entry
, &ZeroEntry
))
593 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
596 ExfInterlockedCompareExchange64UL(PageDir
, &MmGlobalKernelPageDirectoryForPAE
[PAE_ADDR_TO_PDE_OFFSET(Address
)], &ZeroEntry
);
604 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
605 if (!NT_SUCCESS(Status
))
609 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
;
610 Entry
= ExfInterlockedCompareExchange64UL(PageDir
, &Entry
, &ZeroEntry
);
613 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
617 return (PULONGLONG
)PAE_ADDR_TO_PTE(Address
);
621 MmGetPageTableForProcess(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
623 ULONG PdeOffset
= ADDR_TO_PDE_OFFSET(Address
);
629 if (Address
< MmSystemRangeStart
&& Process
&& Process
!= PsGetCurrentProcess())
631 PageDir
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
636 if (0 == InterlockedCompareExchangeUL(&PageDir
[PdeOffset
], 0, 0))
640 MmDeleteHyperspaceMapping(PageDir
);
643 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
644 if (!NT_SUCCESS(Status
) || Pfn
== 0)
648 Entry
= InterlockedCompareExchangeUL(&PageDir
[PdeOffset
], PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
651 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
652 Pfn
= PTE_TO_PFN(Entry
);
657 Pfn
= PTE_TO_PFN(PageDir
[PdeOffset
]);
659 MmDeleteHyperspaceMapping(PageDir
);
660 Pt
= MmCreateHyperspaceMapping(Pfn
);
665 return Pt
+ ADDR_TO_PTE_OFFSET(Address
);
667 PageDir
= ADDR_TO_PDE(Address
);
668 if (0 == InterlockedCompareExchangeUL(PageDir
, 0, 0))
670 if (Address
>= MmSystemRangeStart
)
672 if (0 == InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory
[PdeOffset
], 0, 0))
678 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
679 if (!NT_SUCCESS(Status
) || Pfn
== 0)
683 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
;
684 if (Ke386GlobalPagesEnabled
)
688 if(0 != InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory
[PdeOffset
], Entry
, 0))
690 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
693 InterlockedExchangeUL(PageDir
, MmGlobalKernelPageDirectory
[PdeOffset
]);
701 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
702 if (!NT_SUCCESS(Status
) || Pfn
== 0)
706 Entry
= InterlockedCompareExchangeUL(PageDir
, PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
709 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
713 return (PULONG
)ADDR_TO_PTE(Address
);
716 BOOLEAN
MmUnmapPageTable(PULONG Pt
)
720 if ((PULONGLONG
)Pt
>= (PULONGLONG
)PAGETABLE_MAP
&& (PULONGLONG
)Pt
< (PULONGLONG
)PAGETABLE_MAP
+ 4*512*512)
727 if (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024)
734 MmDeleteHyperspaceMapping((PVOID
)PAGE_ROUND_DOWN(Pt
));
739 static ULONGLONG
MmGetPageEntryForProcessForPAE(PEPROCESS Process
, PVOID Address
)
744 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
748 MmUnmapPageTable((PULONG
)Pt
);
754 static ULONG
MmGetPageEntryForProcess(PEPROCESS Process
, PVOID Address
)
759 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
763 MmUnmapPageTable(Pt
);
771 MmGetPfnForProcess(PEPROCESS Process
,
778 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
779 if (!(Entry
& PA_PRESENT
))
783 return(PAE_PTE_TO_PFN(Entry
));
788 Entry
= MmGetPageEntryForProcess(Process
, Address
);
789 if (!(Entry
& PA_PRESENT
))
793 return(PTE_TO_PFN(Entry
));
799 MmDisableVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOLEAN
* WasDirty
, PPFN_TYPE Page
)
801 * FUNCTION: Delete a virtual mapping
811 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
817 * Atomically disable the present bit and get the old value.
822 tmpPte
= Pte
& ~PA_PRESENT
;
823 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
825 MiFlushTlb((PULONG
)Pt
, Address
);
826 WasValid
= PAE_PAGE_MASK(Pte
) != 0LL ? TRUE
: FALSE
;
833 * Return some information to the caller
835 if (WasDirty
!= NULL
)
837 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
841 *Page
= PAE_PTE_TO_PFN(Pte
);
849 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
855 * Atomically disable the present bit and get the old value.
860 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_PRESENT
, Pte
));
862 MiFlushTlb(Pt
, Address
);
863 WasValid
= (PAGE_MASK(Pte
) != 0);
870 * Return some information to the caller
872 if (WasDirty
!= NULL
)
874 *WasDirty
= Pte
& PA_DIRTY
;
878 *Page
= PTE_TO_PFN(Pte
);
885 MmRawDeleteVirtualMapping(PVOID Address
)
890 ULONGLONG ZeroPte
= 0LL;
891 Pt
= MmGetPageTableForProcessForPAE(NULL
, Address
, FALSE
);
895 * Set the entry to zero
897 ExfpInterlockedExchange64UL(Pt
, &ZeroPte
);
898 MiFlushTlb((PULONG
)Pt
, Address
);
905 Pt
= MmGetPageTableForProcess(NULL
, Address
, FALSE
);
909 * Set the entry to zero
911 InterlockedExchangeUL(Pt
, 0);
912 MiFlushTlb(Pt
, Address
);
919 MmDeleteVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOLEAN FreePage
,
920 BOOLEAN
* WasDirty
, PPFN_TYPE Page
)
922 * FUNCTION: Delete a virtual mapping
925 BOOLEAN WasValid
= FALSE
;
928 DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
929 Process
, Address
, FreePage
, WasDirty
, Page
);
935 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
938 if (WasDirty
!= NULL
)
950 * Atomically set the entry to zero and get the old value.
953 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
955 MiFlushTlb((PULONG
)Pt
, Address
);
957 WasValid
= PAE_PAGE_MASK(Pte
) != 0 ? TRUE
: FALSE
;
960 Pfn
= PAE_PTE_TO_PFN(Pte
);
961 MmMarkPageUnmapped(Pfn
);
968 if (FreePage
&& WasValid
)
970 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
974 * Return some information to the caller
976 if (WasDirty
!= NULL
)
978 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
990 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
994 if (WasDirty
!= NULL
)
1006 * Atomically set the entry to zero and get the old value.
1008 Pte
= InterlockedExchangeUL(Pt
, 0);
1010 MiFlushTlb(Pt
, Address
);
1012 WasValid
= (PAGE_MASK(Pte
) != 0);
1015 Pfn
= PTE_TO_PFN(Pte
);
1016 MmMarkPageUnmapped(Pfn
);
1023 if (FreePage
&& WasValid
)
1025 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
1029 * Return some information to the caller
1031 if (WasDirty
!= NULL
)
1033 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
1041 * Decrement the reference count for this page table.
1043 if (Process
!= NULL
&& WasValid
&&
1044 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1045 Address
< MmSystemRangeStart
)
1050 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1051 Idx
= Ke386Pae
? PAE_ADDR_TO_PAGE_TABLE(Address
) : ADDR_TO_PAGE_TABLE(Address
);
1056 MmFreePageTable(Process
, Address
);
1063 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
1064 SWAPENTRY
* SwapEntry
)
1066 * FUNCTION: Delete a virtual mapping
1074 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1082 * Atomically set the entry to zero and get the old value.
1085 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
1087 MiFlushTlb((PULONG
)Pt
, Address
);
1090 * Decrement the reference count for this page table.
1092 if (Process
!= NULL
&& Pte
&&
1093 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1094 Address
< MmSystemRangeStart
)
1098 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1100 Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Address
)]--;
1101 if (Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Address
)] == 0)
1103 MmFreePageTable(Process
, Address
);
1109 * Return some information to the caller
1111 *SwapEntry
= Pte
>> 1;
1118 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1127 * Atomically set the entry to zero and get the old value.
1129 Pte
= InterlockedExchangeUL(Pt
, 0);
1131 MiFlushTlb(Pt
, Address
);
1134 * Decrement the reference count for this page table.
1136 if (Process
!= NULL
&& Pte
&&
1137 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1138 Address
< MmSystemRangeStart
)
1142 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1144 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]--;
1145 if (Ptrc
[ADDR_TO_PAGE_TABLE(Address
)] == 0)
1147 MmFreePageTable(Process
, Address
);
1153 * Return some information to the caller
1155 *SwapEntry
= Pte
>> 1;
1160 Mmi386MakeKernelPageTableGlobal(PVOID PAddress
)
1166 Pde
= PAE_ADDR_TO_PDE(PAddress
);
1169 Pt
= MmGetPageTableForProcessForPAE(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 Pde
= ADDR_TO_PDE(PAddress
);
1186 Pt
= MmGetPageTableForProcess(NULL
, PAddress
, FALSE
);
1188 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
1189 FLASH_TLB_ONE(PAddress
);
1202 MmIsDirtyPage(PEPROCESS Process
, PVOID Address
)
1206 return MmGetPageEntryForProcessForPAE(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
1210 return MmGetPageEntryForProcess(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
1216 MmIsAccessedAndResetAccessPage(PEPROCESS Process
, PVOID Address
)
1218 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
1220 DPRINT1("MmIsAccessedAndResetAccessPage is called for user space without a process.\n");
1229 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1238 tmpPte
= Pte
& ~PA_ACCESSED
;
1239 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1241 if (Pte
& PA_ACCESSED
)
1243 MiFlushTlb((PULONG
)Pt
, Address
);
1248 MmUnmapPageTable((PULONG
)Pt
);
1257 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1266 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_ACCESSED
, Pte
));
1268 if (Pte
& PA_ACCESSED
)
1270 MiFlushTlb(Pt
, Address
);
1275 MmUnmapPageTable(Pt
);
1283 MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
1285 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
1287 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
1296 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1306 tmpPte
= Pte
& ~PA_DIRTY
;
1307 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1311 MiFlushTlb((PULONG
)Pt
, Address
);
1315 MmUnmapPageTable((PULONG
)Pt
);
1323 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1333 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_DIRTY
, Pte
));
1337 MiFlushTlb(Pt
, Address
);
1341 MmUnmapPageTable(Pt
);
1348 MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
1350 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
1352 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
1361 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1370 tmpPte
= Pte
| PA_DIRTY
;
1371 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1372 if (!(Pte
& PA_DIRTY
))
1374 MiFlushTlb((PULONG
)Pt
, Address
);
1378 MmUnmapPageTable((PULONG
)Pt
);
1386 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1395 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
| PA_DIRTY
, Pte
));
1396 if (!(Pte
& PA_DIRTY
))
1398 MiFlushTlb(Pt
, Address
);
1402 MmUnmapPageTable(Pt
);
1409 MmEnableVirtualMapping(PEPROCESS Process
, PVOID Address
)
1417 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1426 tmpPte
= Pte
| PA_PRESENT
;
1427 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1428 if (!(Pte
& PA_PRESENT
))
1430 MiFlushTlb((PULONG
)Pt
, Address
);
1434 MmUnmapPageTable((PULONG
)Pt
);
1442 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1451 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
| PA_PRESENT
, Pte
));
1452 if (!(Pte
& PA_PRESENT
))
1454 MiFlushTlb(Pt
, Address
);
1458 MmUnmapPageTable(Pt
);
1465 MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
1469 return MmGetPageEntryForProcessForPAE(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
1473 return MmGetPageEntryForProcess(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
1479 MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
1484 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
1485 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
1490 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1491 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
1497 MmCreateVirtualMappingForKernel(PVOID Address
,
1505 ULONG PdeOffset
, oldPdeOffset
;
1506 BOOLEAN NoExecute
= FALSE
;
1508 DPRINT("MmCreateVirtualMappingForKernel(%x, %x, %x, %d)\n",
1509 Address
, flProtect
, Pages
, PageCount
);
1511 if (Address
< MmSystemRangeStart
)
1513 DPRINT1("MmCreateVirtualMappingForKernel is called for user space\n");
1517 Attributes
= ProtectToPTE(flProtect
);
1518 if (Attributes
& 0x80000000)
1522 Attributes
&= 0xfff;
1523 if (Ke386GlobalPagesEnabled
)
1525 Attributes
|= PA_GLOBAL
;
1532 PULONGLONG Pt
= NULL
;
1535 oldPdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
) + 1;
1536 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
1538 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1540 DPRINT1("Setting physical address but not allowing access at address "
1541 "0x%.8X with attributes %x/%x.\n",
1542 Addr
, Attributes
, flProtect
);
1546 PdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
);
1547 if (oldPdeOffset
!= PdeOffset
)
1549 Pt
= MmGetPageTableForProcessForPAE(NULL
, Addr
, TRUE
);
1559 oldPdeOffset
= PdeOffset
;
1561 Pte
= PFN_TO_PTE(Pages
[i
]) | Attributes
;
1564 Pte
|= 0x8000000000000000LL
;
1566 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
1578 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1579 Pt
= MmGetPageTableForProcess(NULL
, Addr
, TRUE
);
1586 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
1588 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1590 DPRINT1("Setting physical address but not allowing access at address "
1591 "0x%.8X with attributes %x/%x.\n",
1592 Addr
, Attributes
, flProtect
);
1596 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1597 if (oldPdeOffset
!= PdeOffset
)
1599 Pt
= MmGetPageTableForProcess(NULL
, Addr
, TRUE
);
1609 oldPdeOffset
= PdeOffset
;
1616 InterlockedExchangeUL(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
1620 return(STATUS_SUCCESS
);
1625 MmCreatePageFileMapping(PEPROCESS Process
,
1627 SWAPENTRY SwapEntry
)
1629 if (Process
== NULL
&& Address
< MmSystemRangeStart
)
1631 DPRINT1("No process\n");
1634 if (Process
!= NULL
&& Address
>= MmSystemRangeStart
)
1636 DPRINT1("Setting kernel address with process context\n");
1639 if (SwapEntry
& (1 << 31))
1650 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, TRUE
);
1655 tmpPte
= SwapEntry
<< 1;
1656 Pte
= ExfpInterlockedExchange64UL(Pt
, &tmpPte
);
1657 if (PAE_PAGE_MASK((Pte
)) != 0)
1659 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte
)));
1664 MiFlushTlb((PULONG
)Pt
, Address
);
1668 MmUnmapPageTable((PULONG
)Pt
);
1676 Pt
= MmGetPageTableForProcess(Process
, Address
, TRUE
);
1682 if (PAGE_MASK((Pte
)) != 0)
1684 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1686 InterlockedExchangeUL(Pt
, SwapEntry
<< 1);
1689 MiFlushTlb(Pt
, Address
);
1693 MmUnmapPageTable(Pt
);
1696 if (Process
!= NULL
&&
1697 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1698 Address
< MmSystemRangeStart
)
1703 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1704 Idx
= Ke386Pae
? PAE_ADDR_TO_PAGE_TABLE(Address
) : ADDR_TO_PAGE_TABLE(Address
);
1707 return(STATUS_SUCCESS
);
1713 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
1722 ULONG oldPdeOffset
, PdeOffset
;
1723 BOOLEAN NoExecute
= FALSE
;
1725 DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
1726 Process
, Address
, flProtect
, Pages
, *Pages
, PageCount
);
1728 if (Process
== NULL
)
1730 if (Address
< MmSystemRangeStart
)
1732 DPRINT1("No process\n");
1735 if (PageCount
> 0x10000 ||
1736 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> 0x100000)
1738 DPRINT1("Page count to large\n");
1744 if (Address
>= MmSystemRangeStart
)
1746 DPRINT1("Setting kernel address with process context\n");
1749 if (PageCount
> (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
||
1750 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
>
1751 (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
)
1753 DPRINT1("Page Count to large\n");
1758 Attributes
= ProtectToPTE(flProtect
);
1759 if (Attributes
& 0x80000000)
1763 Attributes
&= 0xfff;
1764 if (Address
>= MmSystemRangeStart
)
1766 Attributes
&= ~PA_USER
;
1767 if (Ke386GlobalPagesEnabled
)
1769 Attributes
|= PA_GLOBAL
;
1774 Attributes
|= PA_USER
;
1781 ULONGLONG Pte
, tmpPte
;
1782 PULONGLONG Pt
= NULL
;
1784 oldPdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
) + 1;
1785 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
1787 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1789 DPRINT1("Setting physical address but not allowing access at address "
1790 "0x%.8X with attributes %x/%x.\n",
1791 Addr
, Attributes
, flProtect
);
1794 PdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
);
1795 if (oldPdeOffset
!= PdeOffset
)
1797 MmUnmapPageTable((PULONG
)Pt
);
1798 Pt
= MmGetPageTableForProcessForPAE(Process
, Addr
, TRUE
);
1808 oldPdeOffset
= PdeOffset
;
1810 MmMarkPageMapped(Pages
[i
]);
1811 tmpPte
= PAE_PFN_TO_PTE(Pages
[i
]) | Attributes
;
1814 tmpPte
|= 0x8000000000000000LL
;
1816 Pte
= ExfpInterlockedExchange64UL(Pt
, &tmpPte
);
1817 if (PAE_PAGE_MASK((Pte
)) != 0LL && !((Pte
) & PA_PRESENT
))
1821 if (PAE_PAGE_MASK((Pte
)) != 0LL)
1823 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte
)));
1825 if (Address
< MmSystemRangeStart
&&
1826 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1827 Attributes
& PA_PRESENT
)
1831 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1833 Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Addr
)]++;
1837 if (Address
> MmSystemRangeStart
||
1838 (Pt
>= (PULONGLONG
)PAGETABLE_MAP
&& Pt
< (PULONGLONG
)PAGETABLE_MAP
+ 4*512*512))
1840 MiFlushTlb((PULONG
)Pt
, Address
);
1846 MmUnmapPageTable((PULONG
)Pt
);
1853 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
) + 1;
1854 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
1856 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1858 DPRINT1("Setting physical address but not allowing access at address "
1859 "0x%.8X with attributes %x/%x.\n",
1860 Addr
, Attributes
, flProtect
);
1863 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1864 if (oldPdeOffset
!= PdeOffset
)
1866 MmUnmapPageTable(Pt
);
1867 Pt
= MmGetPageTableForProcess(Process
, Addr
, TRUE
);
1877 oldPdeOffset
= PdeOffset
;
1880 MmMarkPageMapped(Pages
[i
]);
1881 if (PAGE_MASK((Pte
)) != 0 && !((Pte
) & PA_PRESENT
))
1885 if (PAGE_MASK((Pte
)) != 0)
1887 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1889 InterlockedExchangeUL(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
1890 if (Address
< MmSystemRangeStart
&&
1891 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1892 Attributes
& PA_PRESENT
)
1896 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1898 Ptrc
[ADDR_TO_PAGE_TABLE(Addr
)]++;
1902 if (Address
> MmSystemRangeStart
||
1903 (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024))
1905 MiFlushTlb(Pt
, Address
);
1911 MmUnmapPageTable(Pt
);
1914 return(STATUS_SUCCESS
);
1919 MmCreateVirtualMapping(PEPROCESS Process
,
1927 for (i
= 0; i
< PageCount
; i
++)
1929 if (!MmIsUsablePage(Pages
[i
]))
1931 DPRINT1("Page at address %x not usable\n", PFN_TO_PTE(Pages
[i
]));
1936 return(MmCreateVirtualMappingUnsafe(Process
,
1945 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
1951 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
1955 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1958 if (!(Entry
& PA_PRESENT
))
1960 Protect
= PAGE_NOACCESS
;
1964 if (Entry
& PA_READWRITE
)
1966 Protect
= PAGE_READWRITE
;
1970 Protect
= PAGE_EXECUTE_READ
;
1974 Protect
|= PAGE_NOCACHE
;
1978 Protect
|= PAGE_WRITETHROUGH
;
1980 if (!(Entry
& PA_USER
))
1982 Protect
|= PAGE_SYSTEM
;
1991 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
1993 ULONG Attributes
= 0;
1994 BOOLEAN NoExecute
= FALSE
;
1996 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
1997 Process
, Address
, flProtect
);
1999 Attributes
= ProtectToPTE(flProtect
);
2000 if (Attributes
& 0x80000000)
2004 Attributes
&= 0xfff;
2005 if (Address
>= MmSystemRangeStart
)
2007 Attributes
&= ~PA_USER
;
2008 if (Ke386GlobalPagesEnabled
)
2010 Attributes
|= PA_GLOBAL
;
2015 Attributes
|= PA_USER
;
2020 ULONGLONG tmpPte
, Pte
;
2022 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
2025 DPRINT1("Address %x\n", Address
);
2031 tmpPte
= PAE_PAGE_MASK(Pte
) | Attributes
| (Pte
& (PA_ACCESSED
|PA_DIRTY
));
2034 tmpPte
|= 0x8000000000000000LL
;
2038 tmpPte
&= ~0x8000000000000000LL
;
2040 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
2042 MiFlushTlb((PULONG
)Pt
, Address
);
2048 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
2053 InterlockedExchange((PLONG
)Pt
, PAGE_MASK(*Pt
) | Attributes
| (*Pt
& (PA_ACCESSED
|PA_DIRTY
)));
2054 MiFlushTlb(Pt
, Address
);
2061 PHYSICAL_ADDRESS STDCALL
2062 MmGetPhysicalAddress(PVOID vaddr
)
2064 * FUNCTION: Returns the physical address corresponding to a virtual address
2069 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr
);
2073 Pte
= MmGetPageEntryForProcessForPAE(NULL
, vaddr
);
2074 if (Pte
!= 0 && Pte
& PA_PRESENT
)
2076 p
.QuadPart
= PAE_PAGE_MASK(Pte
);
2077 p
.u
.LowPart
|= (ULONG_PTR
)vaddr
& (PAGE_SIZE
- 1);
2087 Pte
= MmGetPageEntryForProcess(NULL
, vaddr
);
2088 if (Pte
!= 0 && Pte
& PA_PRESENT
)
2090 p
.QuadPart
= PAGE_MASK(Pte
);
2091 p
.u
.LowPart
|= (ULONG_PTR
)vaddr
& (PAGE_SIZE
- 1);
2103 MmCreateHyperspaceMapping(PFN_TYPE Page
)
2111 ULONGLONG ZeroEntry
= 0LL;
2114 Entry
= PFN_TO_PTE(Page
) | PA_PRESENT
| PA_READWRITE
;
2115 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
) + Page
% 1024;
2119 for (i
= Page
%1024; i
< 1024; i
++, Pte
++)
2121 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2128 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
);
2129 for (i
= 0; i
< Page
% 1024; i
++, Pte
++)
2131 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2136 if (i
>= Page
% 1024)
2144 for (i
= Page
%1024; (LONG
)i
>= 0; i
--, Pte
--)
2146 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2153 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
) + 1023;
2154 for (i
= 1023; i
> Page
% 1024; i
--, Pte
--)
2156 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2161 if (i
<= Page
% 1024)
2172 Entry
= PFN_TO_PTE(Page
) | PA_PRESENT
| PA_READWRITE
;
2173 Pte
= ADDR_TO_PTE(HYPERSPACE
) + Page
% 1024;
2176 for (i
= Page
% 1024; i
< 1024; i
++, Pte
++)
2178 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2185 Pte
= ADDR_TO_PTE(HYPERSPACE
);
2186 for (i
= 0; i
< Page
% 1024; i
++, Pte
++)
2188 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2193 if (i
>= Page
% 1024)
2201 for (i
= Page
% 1024; (LONG
)i
>= 0; i
--, Pte
--)
2203 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2210 Pte
= ADDR_TO_PTE(HYPERSPACE
) + 1023;
2211 for (i
= 1023; i
> Page
% 1024; i
--, Pte
--)
2213 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2218 if (i
<= Page
% 1024)
2225 Address
= (PVOID
)((ULONG_PTR
)HYPERSPACE
+ i
* PAGE_SIZE
);
2226 FLUSH_TLB_ONE(Address
);
2232 MmChangeHyperspaceMapping(PVOID Address
, PFN_TYPE NewPage
)
2235 ASSERT (IS_HYPERSPACE(Address
));
2238 ULONGLONG Entry
= PAE_PFN_TO_PTE(NewPage
) | PA_PRESENT
| PA_READWRITE
;
2239 Entry
= (ULONG
)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PTE(Address
), &Entry
);
2240 Pfn
= PAE_PTE_TO_PFN(Entry
);
2245 Entry
= InterlockedExchange((PLONG
)ADDR_TO_PTE(Address
), PFN_TO_PTE(NewPage
) | PA_PRESENT
| PA_READWRITE
);
2246 Pfn
= PTE_TO_PFN(Entry
);
2248 FLUSH_TLB_ONE(Address
);
2254 MmDeleteHyperspaceMapping(PVOID Address
)
2257 ASSERT (IS_HYPERSPACE(Address
));
2260 ULONGLONG Entry
= 0LL;
2261 Entry
= (ULONG
)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PTE(Address
), &Entry
);
2262 Pfn
= PAE_PTE_TO_PFN(Entry
);
2267 Entry
= InterlockedExchange((PLONG
)ADDR_TO_PTE(Address
), 0);
2268 Pfn
= PTE_TO_PFN(Entry
);
2270 FLUSH_TLB_ONE(Address
);
2276 MmUpdatePageDir(PEPROCESS Process
, PVOID Address
, ULONG Size
)
2278 ULONG StartOffset
, EndOffset
, Offset
;
2280 if (Address
< MmSystemRangeStart
)
2286 PULONGLONG PageDirTable
;
2288 ULONGLONG ZeroPde
= 0LL;
2291 for (i
= PAE_ADDR_TO_PDTE_OFFSET(Address
); i
<= PAE_ADDR_TO_PDTE_OFFSET((PVOID
)((ULONG_PTR
)Address
+ Size
)); i
++)
2293 if (i
== PAE_ADDR_TO_PDTE_OFFSET(Address
))
2295 StartOffset
= PAE_ADDR_TO_PDE_PAGE_OFFSET(Address
);
2301 if (i
== PAE_ADDR_TO_PDTE_OFFSET((PVOID
)((ULONG_PTR
)Address
+ Size
)))
2303 EndOffset
= PAE_ADDR_TO_PDE_PAGE_OFFSET((PVOID
)((ULONG_PTR
)Address
+ Size
));
2310 if (Process
!= NULL
&& Process
!= PsGetCurrentProcess())
2312 PageDirTable
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
2313 Pde
= (PULONGLONG
)MmCreateHyperspaceMapping(PTE_TO_PFN(PageDirTable
[i
]));
2314 MmDeleteHyperspaceMapping(PageDirTable
);
2318 Pde
= (PULONGLONG
)PAE_PAGEDIRECTORY_MAP
+ i
*512;
2321 for (Offset
= StartOffset
; Offset
<= EndOffset
; Offset
++)
2323 if (i
* 512 + Offset
< PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) || i
* 512 + Offset
>= PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
)+4)
2325 ExfInterlockedCompareExchange64UL(&Pde
[Offset
], &MmGlobalKernelPageDirectoryForPAE
[i
*512 + Offset
], &ZeroPde
);
2328 MmUnmapPageTable((PULONG
)Pde
);
2334 StartOffset
= ADDR_TO_PDE_OFFSET(Address
);
2335 EndOffset
= ADDR_TO_PDE_OFFSET((PVOID
)((ULONG_PTR
)Address
+ Size
));
2337 if (Process
!= NULL
&& Process
!= PsGetCurrentProcess())
2339 Pde
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.u
.LowPart
));
2343 Pde
= (PULONG
)PAGEDIRECTORY_MAP
;
2345 for (Offset
= StartOffset
; Offset
<= EndOffset
; Offset
++)
2347 if (Offset
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
))
2349 InterlockedCompareExchangeUL(&Pde
[Offset
], MmGlobalKernelPageDirectory
[Offset
], 0);
2352 if (Pde
!= (PULONG
)PAGEDIRECTORY_MAP
)
2354 MmDeleteHyperspaceMapping(Pde
);
2362 MmInitGlobalKernelPageDirectory(VOID
)
2366 DPRINT("MmInitGlobalKernelPageDirectory()\n");
2370 PULONGLONG CurrentPageDirectory
= (PULONGLONG
)PAE_PAGEDIRECTORY_MAP
;
2371 for (i
= PAE_ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
< 4 * 512; i
++)
2373 if (!(i
>= PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) && i
< PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) + 4) &&
2374 !(i
>= PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
) && i
< PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
) + 2) &&
2375 0LL == MmGlobalKernelPageDirectoryForPAE
[i
] && 0LL != CurrentPageDirectory
[i
])
2377 ExfpInterlockedExchange64UL(&MmGlobalKernelPageDirectoryForPAE
[i
], &CurrentPageDirectory
[i
]);
2378 if (Ke386GlobalPagesEnabled
)
2380 MmGlobalKernelPageDirectoryForPAE
[i
] |= PA_GLOBAL
;
2381 CurrentPageDirectory
[i
] |= PA_GLOBAL
;
2388 PULONG CurrentPageDirectory
= (PULONG
)PAGEDIRECTORY_MAP
;
2389 for (i
= ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
< 1024; i
++)
2391 if (i
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) &&
2392 i
!= ADDR_TO_PDE_OFFSET(HYPERSPACE
) &&
2393 0 == MmGlobalKernelPageDirectory
[i
] && 0 != CurrentPageDirectory
[i
])
2395 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];
2396 if (Ke386GlobalPagesEnabled
)
2398 MmGlobalKernelPageDirectory
[i
] |= PA_GLOBAL
;
2399 CurrentPageDirectory
[i
] |= PA_GLOBAL
;
2408 MiGetUserPageDirectoryCount(VOID
)
2410 return Ke386Pae
? PAE_ADDR_TO_PDE_OFFSET(MmSystemRangeStart
) : ADDR_TO_PDE_OFFSET(MmSystemRangeStart
);
2416 MiInitPageDirectoryMap(VOID
)
2418 MEMORY_AREA
* kernel_map_desc
= NULL
;
2419 MEMORY_AREA
* hyperspace_desc
= NULL
;
2420 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
2424 DPRINT("MiInitPageDirectoryMap()\n");
2426 BoundaryAddressMultiple
.QuadPart
= 0;
2427 BaseAddress
= (PVOID
)PAGETABLE_MAP
;
2428 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
2431 Ke386Pae
? 0x800000 : 0x400000,
2436 BoundaryAddressMultiple
);
2437 if (!NT_SUCCESS(Status
))
2441 BaseAddress
= (PVOID
)HYPERSPACE
;
2442 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
2450 BoundaryAddressMultiple
);
2451 if (!NT_SUCCESS(Status
))