3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/i386/page.c
23 * PURPOSE: low level memory managment manipulation
24 * PROGRAMER: David Welch (welch@cwcom.net)
29 /* INCLUDES ***************************************************************/
33 #include <internal/debug.h>
35 /* GLOBALS *****************************************************************/
37 #define PA_BIT_PRESENT (0)
38 #define PA_BIT_READWRITE (1)
39 #define PA_BIT_USER (2)
42 #define PA_BIT_ACCESSED (5)
43 #define PA_BIT_DIRTY (6)
44 #define PA_BIT_GLOBAL (8)
46 #define PA_PRESENT (1 << PA_BIT_PRESENT)
47 #define PA_READWRITE (1 << PA_BIT_READWRITE)
48 #define PA_USER (1 << PA_BIT_USER)
49 #define PA_DIRTY (1 << PA_BIT_DIRTY)
50 #define PA_WT (1 << PA_BIT_WT)
51 #define PA_CD (1 << PA_BIT_CD)
52 #define PA_ACCESSED (1 << PA_BIT_ACCESSED)
53 #define PA_GLOBAL (1 << PA_BIT_GLOBAL)
55 #define PAGETABLE_MAP (0xf0000000)
56 #define PAGEDIRECTORY_MAP (0xf0000000 + (PAGETABLE_MAP / (1024)))
58 #define PAE_PAGEDIRECTORY_MAP (0xf0000000 + (PAGETABLE_MAP / (512)))
60 #define HYPERSPACE (0xf0800000)
61 #define IS_HYPERSPACE(v) (((ULONG)(v) >= 0xF0800000 && (ULONG)(v) < 0xF0C00000))
63 ULONG MmGlobalKernelPageDirectory
[1024];
64 ULONGLONG MmGlobalKernelPageDirectoryForPAE
[2048];
66 #define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT)
67 #define PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
69 #define PAE_PTE_TO_PFN(X) (PAE_PAGE_MASK(X) >> PAGE_SHIFT)
70 #define PAE_PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
73 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
75 __inline LARGE_INTEGER
PTE_TO_PAGE(ULONG npage
)
78 dummy
.QuadPart
= (LONGLONG
)(PAGE_MASK(npage
));
83 extern BOOLEAN Ke386Pae
;
84 extern BOOLEAN Ke386NoExecute
;
85 extern BOOLEAN Ke386GlobalPagesEnabled
;
87 /* FUNCTIONS ***************************************************************/
89 BOOLEAN
MmUnmapPageTable(PULONG Pt
);
93 MiFlushTlbIpiRoutine(PVOID Address
)
95 if (Address
== (PVOID
)0xffffffff)
99 else if (Address
== (PVOID
)0xfffffffe)
105 FLUSH_TLB_ONE(Address
);
110 MiFlushTlb(PULONG Pt
, PVOID Address
)
115 MmUnmapPageTable(Pt
);
117 if (KeNumberProcessors
>1)
119 KeIpiGenericCall(MiFlushTlbIpiRoutine
, Address
);
123 MiFlushTlbIpiRoutine(Address
);
126 if ((Pt
&& MmUnmapPageTable(Pt
)) || Address
>= (PVOID
)KERNEL_BASE
)
128 FLUSH_TLB_ONE(Address
);
136 MmGetPageDirectory(VOID
)
138 unsigned int page_dir
=0;
139 Ke386GetPageTableDirectory(page_dir
);
140 return((PULONG
)page_dir
);
144 ProtectToPTE(ULONG flProtect
)
146 ULONG Attributes
= 0;
148 if (flProtect
& (PAGE_NOACCESS
|PAGE_GUARD
))
152 else if (flProtect
& PAGE_IS_WRITABLE
)
154 Attributes
= PA_PRESENT
| PA_READWRITE
;
156 else if (flProtect
& (PAGE_IS_READABLE
| PAGE_IS_EXECUTABLE
))
158 Attributes
= PA_PRESENT
;
162 DPRINT1("Unknown main protection type.\n");
165 if (Ke386NoExecute
&&
166 !(flProtect
& PAGE_IS_EXECUTABLE
))
168 Attributes
= Attributes
| 0x80000000;
171 if (flProtect
& PAGE_SYSTEM
)
176 Attributes
= Attributes
| PA_USER
;
178 if (flProtect
& PAGE_NOCACHE
)
180 Attributes
= Attributes
| PA_CD
;
182 if (flProtect
& PAGE_WRITETHROUGH
)
184 Attributes
= Attributes
| PA_WT
;
189 #define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (1024 * PAGE_SIZE))
191 #define ADDR_TO_PDE(v) (PULONG)(PAGEDIRECTORY_MAP + \
192 ((((ULONG)(v)) / (1024 * 1024))&(~0x3)))
193 #define ADDR_TO_PTE(v) (PULONG)(PAGETABLE_MAP + ((((ULONG)(v) / 1024))&(~0x3)))
195 #define ADDR_TO_PDE_OFFSET(v) ((((ULONG)(v)) / (1024 * PAGE_SIZE)))
197 #define ADDR_TO_PTE_OFFSET(v) ((((ULONG)(v)) % (1024 * PAGE_SIZE)) / PAGE_SIZE)
200 #define PAE_ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (512 * PAGE_SIZE))
202 #define PAE_ADDR_TO_PDE(v) (PULONGLONG) (PAE_PAGEDIRECTORY_MAP + \
203 ((((ULONG_PTR)(v)) / (512 * 512))&(~0x7)))
204 #define PAE_ADDR_TO_PTE(v) (PULONGLONG) (PAGETABLE_MAP + ((((ULONG_PTR)(v) / 512))&(~0x7)))
207 #define PAE_ADDR_TO_PDTE_OFFSET(v) (((ULONG_PTR)(v)) / (512 * 512 * PAGE_SIZE))
209 #define PAE_ADDR_TO_PDE_PAGE_OFFSET(v) ((((ULONG_PTR)(v)) % (512 * 512 * PAGE_SIZE)) / (512 * PAGE_SIZE))
211 #define PAE_ADDR_TO_PDE_OFFSET(v) (((ULONG_PTR)(v))/ (512 * PAGE_SIZE))
213 #define PAE_ADDR_TO_PTE_OFFSET(v) ((((ULONG_PTR)(v)) % (512 * PAGE_SIZE)) / PAGE_SIZE)
216 NTSTATUS
Mmi386ReleaseMmInfo(PEPROCESS Process
)
218 PUSHORT LdtDescriptor
;
222 DPRINT("Mmi386ReleaseMmInfo(Process %x)\n",Process
);
224 LdtDescriptor
= (PUSHORT
) &Process
->Pcb
.LdtDescriptor
[0];
225 LdtBase
= LdtDescriptor
[1] |
226 ((LdtDescriptor
[2] & 0xff) << 16) |
227 ((LdtDescriptor
[3] & ~0xff) << 16);
229 DPRINT("LdtBase: %x\n", LdtBase
);
233 ExFreePool((PVOID
) LdtBase
);
238 PULONGLONG PageDirTable
;
243 PageDirTable
= (PULONGLONG
)MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
244 for (i
= 0; i
< 4; i
++)
246 PageDir
= (PULONGLONG
)MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDirTable
[i
]));
247 if (i
< PAE_ADDR_TO_PDTE_OFFSET(KERNEL_BASE
))
249 for (j
= 0; j
< 512; j
++)
251 if (PageDir
[j
] != 0LL)
253 DPRINT1("ProcessId %d, Pde for %08x - %08x is not freed, RefCount %d\n",
254 Process
->UniqueProcessId
,
255 (i
* 512 + j
) * 512 * PAGE_SIZE
, (i
* 512 + j
+ 1) * 512 * PAGE_SIZE
- 1,
256 Process
->AddressSpace
.PageTableRefCountTable
[i
*512 + j
]);
257 Pde
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDir
[j
]));
258 for (k
= 0; k
< 512; k
++)
262 if (Pde
[k
] & PA_PRESENT
)
264 DPRINT1("Page at %08x is not freed\n",
265 (i
* 512 + j
) * 512 * PAGE_SIZE
+ k
* PAGE_SIZE
);
269 DPRINT1("Swapentry %x at %x is not freed\n",
270 (i
* 512 + j
) * 512 * PAGE_SIZE
+ k
* PAGE_SIZE
);
274 MmDeleteHyperspaceMapping(Pde
);
275 MmReleasePageMemoryConsumer(MC_NPPOOL
, PAE_PTE_TO_PFN(PageDir
[j
]));
281 MmReleasePageMemoryConsumer(MC_NPPOOL
, PAE_PTE_TO_PFN(PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)]));
282 MmReleasePageMemoryConsumer(MC_NPPOOL
, PAE_PTE_TO_PFN(PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)+1]));
284 MmDeleteHyperspaceMapping(PageDir
);
285 MmReleasePageMemoryConsumer(MC_NPPOOL
, PAE_PTE_TO_PFN(PageDirTable
[i
]));
287 MmDeleteHyperspaceMapping((PVOID
)PageDirTable
);
288 MmReleasePageMemoryConsumer(MC_NPPOOL
, PAE_PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
294 PageDir
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.u
.LowPart
));
295 for (i
= 0; i
< ADDR_TO_PDE_OFFSET(KERNEL_BASE
); i
++)
299 DPRINT1("Pde for %08x - %08x is not freed, RefCount %d\n",
300 i
* 4 * 1024 * 1024, (i
+ 1) * 4 * 1024 * 1024 - 1,
301 Process
->AddressSpace
.PageTableRefCountTable
[i
]);
302 Pde
= MmCreateHyperspaceMapping(PTE_TO_PFN(PageDir
[i
]));
303 for (j
= 0; j
< 1024; j
++)
307 if (Pde
[j
] & PA_PRESENT
)
309 DPRINT1("Page at %08x is not freed\n",
310 i
* 4 * 1024 * 1024 + j
* PAGE_SIZE
);
314 DPRINT1("Swapentry %x at %x is not freed\n",
315 Pde
[j
], i
* 4 * 1024 * 1024 + j
* PAGE_SIZE
);
319 MmDeleteHyperspaceMapping(Pde
);
320 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(PageDir
[i
]));
323 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(PageDir
[ADDR_TO_PDE_OFFSET(HYPERSPACE
)]));
324 MmDeleteHyperspaceMapping(PageDir
);
325 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.u
.LowPart
));
328 #if defined(__GNUC__)
330 Process
->Pcb
.DirectoryTableBase
.QuadPart
= 0LL;
333 Process
->Pcb
.DirectoryTableBase
.QuadPart
= 0;
336 DPRINT("Finished Mmi386ReleaseMmInfo()\n");
337 return(STATUS_SUCCESS
);
340 NTSTATUS
MmCopyMmInfo(PEPROCESS Src
, PEPROCESS Dest
)
342 PKPROCESS KProcess
= &Dest
->Pcb
;
348 DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", Src
, Dest
);
350 Count
= Ke386Pae
? 7 : 2;
352 for (i
= 0; i
< Count
; i
++)
354 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
[i
]);
355 if (!NT_SUCCESS(Status
))
357 for (j
= 0; j
< i
; j
++)
359 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
[j
]);
367 PULONGLONG PageDirTable
;
370 PageDirTable
= MmCreateHyperspaceMapping(Pfn
[0]);
371 for (i
= 0; i
< 4; i
++)
373 PageDirTable
[i
] = PAE_PFN_TO_PTE(Pfn
[1+i
]) | PA_PRESENT
;
375 MmDeleteHyperspaceMapping(PageDirTable
);
376 for (i
= PAE_ADDR_TO_PDTE_OFFSET(KERNEL_BASE
); i
< 4; i
++)
378 PageDir
= (PULONGLONG
)MmCreateHyperspaceMapping(Pfn
[i
+1]);
379 memcpy(PageDir
, &MmGlobalKernelPageDirectoryForPAE
[i
* 512], 512 * sizeof(ULONGLONG
));
380 if (PAE_ADDR_TO_PDTE_OFFSET(PAGETABLE_MAP
) == i
)
382 for (j
= 0; j
< 4; j
++)
384 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(PAGETABLE_MAP
) + j
] = PAE_PFN_TO_PTE(Pfn
[1+j
]) | PA_PRESENT
| PA_READWRITE
;
387 if (PAE_ADDR_TO_PDTE_OFFSET(HYPERSPACE
) == i
)
389 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)] = PAE_PFN_TO_PTE(Pfn
[5]) | PA_PRESENT
| PA_READWRITE
;
390 PageDir
[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE
)+1] = PAE_PFN_TO_PTE(Pfn
[6]) | PA_PRESENT
| PA_READWRITE
;
392 MmDeleteHyperspaceMapping(PageDir
);
397 PULONG PageDirectory
;
398 PageDirectory
= MmCreateHyperspaceMapping(Pfn
[0]);
400 memcpy(PageDirectory
+ ADDR_TO_PDE_OFFSET(KERNEL_BASE
),
401 MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(KERNEL_BASE
),
402 (1024 - ADDR_TO_PDE_OFFSET(KERNEL_BASE
)) * sizeof(ULONG
));
404 DPRINT("Addr %x\n",ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
));
405 PageDirectory
[ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
)] = PFN_TO_PTE(Pfn
[0]) | PA_PRESENT
| PA_READWRITE
;
406 PageDirectory
[ADDR_TO_PDE_OFFSET(HYPERSPACE
)] = PFN_TO_PTE(Pfn
[1]) | PA_PRESENT
| PA_READWRITE
;
408 MmDeleteHyperspaceMapping(PageDirectory
);
410 KProcess
->DirectoryTableBase
.QuadPart
= PFN_TO_PTE(Pfn
[0]);
411 DPRINT("Finished MmCopyMmInfo()\n");
412 return(STATUS_SUCCESS
);
415 VOID
MmDeletePageTable(PEPROCESS Process
, PVOID Address
)
417 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
419 if (Process
!= NULL
&& Process
!= CurrentProcess
)
421 KeAttachProcess(&Process
->Pcb
);
426 ULONGLONG ZeroPde
= 0LL;
427 ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address
), &ZeroPde
);
431 *(ADDR_TO_PDE(Address
)) = 0;
433 if (Address
>= (PVOID
)KERNEL_BASE
)
436 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
438 MiFlushTlb(NULL
, Address
);
439 if (Process
!= NULL
&& Process
!= CurrentProcess
)
445 VOID
MmFreePageTable(PEPROCESS Process
, PVOID Address
)
447 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
451 DPRINT("ProcessId %d, Address %x\n", Process
->UniqueProcessId
, Address
);
452 if (Process
!= NULL
&& Process
!= CurrentProcess
)
454 KeAttachProcess(&Process
->Pcb
);
458 PULONGLONG PageTable
;
459 ULONGLONG ZeroPte
= 0LL;
460 PageTable
= (PULONGLONG
)PAGE_ROUND_DOWN((PVOID
)PAE_ADDR_TO_PTE(Address
));
461 for (i
= 0; i
< 512; i
++)
463 if (PageTable
[i
] != 0LL)
465 DbgPrint("Page table entry not clear at %x/%x (is %I64x)\n",
466 ((ULONG
)Address
/ (4*1024*1024)), i
, PageTable
[i
]);
470 Pfn
= PAE_PTE_TO_PFN(*(PAE_ADDR_TO_PDE(Address
)));
471 ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address
), &ZeroPte
);
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;
489 MiFlushTlb(NULL
, Address
);
491 if (Address
>= (PVOID
)KERNEL_BASE
)
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
)PAGETABLE_MAP
+ 0x800000)
523 if (Address
< (PVOID
)KERNEL_BASE
&& 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
>= (PVOID
)KERNEL_BASE
)
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
< (PVOID
)KERNEL_BASE
&& 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
>= (PVOID
)KERNEL_BASE
)
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
);
770 MmGetPfnForProcess(PEPROCESS Process
,
777 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
778 if (!(Entry
& PA_PRESENT
))
782 return(PAE_PTE_TO_PFN(Entry
));
787 Entry
= MmGetPageEntryForProcess(Process
, Address
);
788 if (!(Entry
& PA_PRESENT
))
792 return(PTE_TO_PFN(Entry
));
797 MmDisableVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOL
* WasDirty
, PPFN_TYPE Page
)
799 * FUNCTION: Delete a virtual mapping
809 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
815 * Atomically disable the present bit and get the old value.
820 tmpPte
= Pte
& ~PA_PRESENT
;
821 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
823 MiFlushTlb((PULONG
)Pt
, Address
);
824 WasValid
= PAE_PAGE_MASK(Pte
) != 0LL ? TRUE
: FALSE
;
831 * Return some information to the caller
833 if (WasDirty
!= NULL
)
835 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
839 *Page
= PAE_PTE_TO_PFN(Pte
);
847 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
853 * Atomically disable the present bit and get the old value.
858 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_PRESENT
, Pte
));
860 MiFlushTlb(Pt
, Address
);
861 WasValid
= (PAGE_MASK(Pte
) != 0);
868 * Return some information to the caller
870 if (WasDirty
!= NULL
)
872 *WasDirty
= Pte
& PA_DIRTY
;
876 *Page
= PTE_TO_PFN(Pte
);
882 MmRawDeleteVirtualMapping(PVOID Address
)
887 ULONGLONG ZeroPte
= 0LL;
888 Pt
= MmGetPageTableForProcessForPAE(NULL
, Address
, FALSE
);
892 * Set the entry to zero
894 ExfpInterlockedExchange64UL(Pt
, &ZeroPte
);
895 MiFlushTlb((PULONG
)Pt
, Address
);
902 Pt
= MmGetPageTableForProcess(NULL
, Address
, FALSE
);
906 * Set the entry to zero
908 InterlockedExchangeUL(Pt
, 0);
909 MiFlushTlb(Pt
, Address
);
915 MmDeleteVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOL FreePage
,
916 BOOL
* WasDirty
, PPFN_TYPE Page
)
918 * FUNCTION: Delete a virtual mapping
921 BOOLEAN WasValid
= FALSE
;
924 DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
925 Process
, Address
, FreePage
, WasDirty
, Page
);
931 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
934 if (WasDirty
!= NULL
)
946 * Atomically set the entry to zero and get the old value.
949 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
951 MiFlushTlb((PULONG
)Pt
, Address
);
953 WasValid
= PAE_PAGE_MASK(Pte
) != 0 ? TRUE
: FALSE
;
956 Pfn
= PAE_PTE_TO_PFN(Pte
);
957 MmMarkPageUnmapped(Pfn
);
964 if (FreePage
&& WasValid
)
966 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
970 * Return some information to the caller
972 if (WasDirty
!= NULL
)
974 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
986 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
990 if (WasDirty
!= NULL
)
1002 * Atomically set the entry to zero and get the old value.
1004 Pte
= InterlockedExchangeUL(Pt
, 0);
1006 MiFlushTlb(Pt
, Address
);
1008 WasValid
= (PAGE_MASK(Pte
) != 0);
1011 Pfn
= PTE_TO_PFN(Pte
);
1012 MmMarkPageUnmapped(Pfn
);
1019 if (FreePage
&& WasValid
)
1021 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
1025 * Return some information to the caller
1027 if (WasDirty
!= NULL
)
1029 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
1037 * Decrement the reference count for this page table.
1039 if (Process
!= NULL
&& WasValid
&&
1040 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1041 Address
< (PVOID
)KERNEL_BASE
)
1046 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1047 Idx
= Ke386Pae
? PAE_ADDR_TO_PAGE_TABLE(Address
) : ADDR_TO_PAGE_TABLE(Address
);
1052 MmFreePageTable(Process
, Address
);
1058 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
1059 SWAPENTRY
* SwapEntry
)
1061 * FUNCTION: Delete a virtual mapping
1069 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1077 * Atomically set the entry to zero and get the old value.
1080 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
1082 MiFlushTlb((PULONG
)Pt
, Address
);
1085 * Decrement the reference count for this page table.
1087 if (Process
!= NULL
&& Pte
&&
1088 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1089 Address
< (PVOID
)KERNEL_BASE
)
1093 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1095 Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Address
)]--;
1096 if (Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Address
)] == 0)
1098 MmFreePageTable(Process
, Address
);
1104 * Return some information to the caller
1106 *SwapEntry
= Pte
>> 1;
1113 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1122 * Atomically set the entry to zero and get the old value.
1124 Pte
= InterlockedExchangeUL(Pt
, 0);
1126 MiFlushTlb(Pt
, Address
);
1129 * Decrement the reference count for this page table.
1131 if (Process
!= NULL
&& Pte
&&
1132 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1133 Address
< (PVOID
)KERNEL_BASE
)
1137 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1139 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]--;
1140 if (Ptrc
[ADDR_TO_PAGE_TABLE(Address
)] == 0)
1142 MmFreePageTable(Process
, Address
);
1148 * Return some information to the caller
1150 *SwapEntry
= Pte
>> 1;
1155 Mmi386MakeKernelPageTableGlobal(PVOID PAddress
)
1161 Pde
= PAE_ADDR_TO_PDE(PAddress
);
1164 Pt
= MmGetPageTableForProcessForPAE(NULL
, PAddress
, FALSE
);
1166 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
1167 FLASH_TLB_ONE(PAddress
);
1178 Pde
= ADDR_TO_PDE(PAddress
);
1181 Pt
= MmGetPageTableForProcess(NULL
, PAddress
, FALSE
);
1183 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
1184 FLASH_TLB_ONE(PAddress
);
1195 BOOLEAN
MmIsDirtyPage(PEPROCESS Process
, PVOID Address
)
1199 return MmGetPageEntryForProcessForPAE(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
1203 return MmGetPageEntryForProcess(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
1208 MmIsAccessedAndResetAccessPage(PEPROCESS Process
, PVOID Address
)
1210 if (Address
< (PVOID
)KERNEL_BASE
&& Process
== NULL
)
1212 DPRINT1("MmIsAccessedAndResetAccessPage is called for user space without a process.\n");
1221 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1230 tmpPte
= Pte
& ~PA_ACCESSED
;
1231 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1233 if (Pte
& PA_ACCESSED
)
1235 MiFlushTlb((PULONG
)Pt
, Address
);
1240 MmUnmapPageTable((PULONG
)Pt
);
1249 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1258 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_ACCESSED
, Pte
));
1260 if (Pte
& PA_ACCESSED
)
1262 MiFlushTlb(Pt
, Address
);
1267 MmUnmapPageTable(Pt
);
1273 VOID
MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
1275 if (Address
< (PVOID
)KERNEL_BASE
&& Process
== NULL
)
1277 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
1286 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1296 tmpPte
= Pte
& ~PA_DIRTY
;
1297 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1301 MiFlushTlb((PULONG
)Pt
, Address
);
1305 MmUnmapPageTable((PULONG
)Pt
);
1313 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1323 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_DIRTY
, Pte
));
1327 MiFlushTlb(Pt
, Address
);
1331 MmUnmapPageTable(Pt
);
1336 VOID
MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
1338 if (Address
< (PVOID
)KERNEL_BASE
&& Process
== NULL
)
1340 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
1349 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1358 tmpPte
= Pte
| PA_DIRTY
;
1359 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1360 if (!(Pte
& PA_DIRTY
))
1362 MiFlushTlb((PULONG
)Pt
, Address
);
1366 MmUnmapPageTable((PULONG
)Pt
);
1374 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1383 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
| PA_DIRTY
, Pte
));
1384 if (!(Pte
& PA_DIRTY
))
1386 MiFlushTlb(Pt
, Address
);
1390 MmUnmapPageTable(Pt
);
1395 VOID
MmEnableVirtualMapping(PEPROCESS Process
, PVOID Address
)
1403 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
1412 tmpPte
= Pte
| PA_PRESENT
;
1413 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
1414 if (!(Pte
& PA_PRESENT
))
1416 MiFlushTlb((PULONG
)Pt
, Address
);
1420 MmUnmapPageTable((PULONG
)Pt
);
1428 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1437 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
| PA_PRESENT
, Pte
));
1438 if (!(Pte
& PA_PRESENT
))
1440 MiFlushTlb(Pt
, Address
);
1444 MmUnmapPageTable(Pt
);
1449 BOOLEAN
MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
1453 return MmGetPageEntryForProcessForPAE(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
1457 return MmGetPageEntryForProcess(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
1461 BOOLEAN
MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
1466 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
1467 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
1472 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1473 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
1478 MmCreateVirtualMappingForKernel(PVOID Address
,
1486 ULONG PdeOffset
, oldPdeOffset
;
1487 BOOLEAN NoExecute
= FALSE
;
1489 DPRINT("MmCreateVirtualMappingForKernel(%x, %x, %x, %d)\n",
1490 Address
, flProtect
, Pages
, PageCount
);
1492 if (Address
< (PVOID
)KERNEL_BASE
)
1494 DPRINT1("MmCreateVirtualMappingForKernel is called for user space\n");
1498 Attributes
= ProtectToPTE(flProtect
);
1499 if (Attributes
& 0x80000000)
1503 Attributes
&= 0xfff;
1504 if (Ke386GlobalPagesEnabled
)
1506 Attributes
|= PA_GLOBAL
;
1513 PULONGLONG Pt
= NULL
;
1516 oldPdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
) + 1;
1517 for (i
= 0; i
< PageCount
; i
++, Addr
+= PAGE_SIZE
)
1519 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1521 DPRINT1("Setting physical address but not allowing access at address "
1522 "0x%.8X with attributes %x/%x.\n",
1523 Addr
, Attributes
, flProtect
);
1527 PdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
);
1528 if (oldPdeOffset
!= PdeOffset
)
1530 Pt
= MmGetPageTableForProcessForPAE(NULL
, Addr
, TRUE
);
1540 oldPdeOffset
= PdeOffset
;
1542 Pte
= PFN_TO_PTE(Pages
[i
]) | Attributes
;
1545 Pte
|= 0x8000000000000000LL
;
1547 Pte
= ExfpInterlockedExchange64UL(Pt
, &Pte
);
1559 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1560 Pt
= MmGetPageTableForProcess(NULL
, Addr
, TRUE
);
1567 for (i
= 0; i
< PageCount
; i
++, Addr
+= PAGE_SIZE
)
1569 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1571 DPRINT1("Setting physical address but not allowing access at address "
1572 "0x%.8X with attributes %x/%x.\n",
1573 Addr
, Attributes
, flProtect
);
1577 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1578 if (oldPdeOffset
!= PdeOffset
)
1580 Pt
= MmGetPageTableForProcess(NULL
, Addr
, TRUE
);
1590 oldPdeOffset
= PdeOffset
;
1597 InterlockedExchangeUL(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
1601 return(STATUS_SUCCESS
);
1605 MmCreatePageFileMapping(PEPROCESS Process
,
1607 SWAPENTRY SwapEntry
)
1609 if (Process
== NULL
&& Address
< (PVOID
)KERNEL_BASE
)
1611 DPRINT1("No process\n");
1614 if (Process
!= NULL
&& Address
>= (PVOID
)KERNEL_BASE
)
1616 DPRINT1("Setting kernel address with process context\n");
1619 if (SwapEntry
& (1 << 31))
1630 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, TRUE
);
1635 tmpPte
= SwapEntry
<< 1;
1636 Pte
= ExfpInterlockedExchange64UL(Pt
, &tmpPte
);
1637 if (PAE_PAGE_MASK((Pte
)) != 0)
1639 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte
)));
1644 MiFlushTlb((PULONG
)Pt
, Address
);
1648 MmUnmapPageTable((PULONG
)Pt
);
1656 Pt
= MmGetPageTableForProcess(Process
, Address
, TRUE
);
1662 if (PAGE_MASK((Pte
)) != 0)
1664 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1666 InterlockedExchangeUL(Pt
, SwapEntry
<< 1);
1669 MiFlushTlb(Pt
, Address
);
1673 MmUnmapPageTable(Pt
);
1676 if (Process
!= NULL
&&
1677 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1678 Address
< (PVOID
)KERNEL_BASE
)
1683 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1684 Idx
= Ke386Pae
? PAE_ADDR_TO_PAGE_TABLE(Address
) : ADDR_TO_PAGE_TABLE(Address
);
1687 return(STATUS_SUCCESS
);
1692 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
1701 ULONG oldPdeOffset
, PdeOffset
;
1702 BOOLEAN NoExecute
= FALSE
;
1704 DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
1705 Process
, Address
, flProtect
, Pages
, *Pages
, PageCount
);
1707 if (Process
== NULL
)
1709 if (Address
< (PVOID
)KERNEL_BASE
)
1711 DPRINT1("No process\n");
1714 if (PageCount
> 0x10000 ||
1715 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> 0x100000)
1717 DPRINT1("Page count to large\n");
1723 if (Address
>= (PVOID
)KERNEL_BASE
)
1725 DPRINT1("Setting kernel address with process context\n");
1728 if (PageCount
> KERNEL_BASE
/ PAGE_SIZE
||
1729 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> KERNEL_BASE
/ PAGE_SIZE
)
1731 DPRINT1("Page Count to large\n");
1736 Attributes
= ProtectToPTE(flProtect
);
1737 if (Attributes
& 0x80000000)
1741 Attributes
&= 0xfff;
1742 if (Address
>= (PVOID
)KERNEL_BASE
)
1744 Attributes
&= ~PA_USER
;
1745 if (Ke386GlobalPagesEnabled
)
1747 Attributes
|= PA_GLOBAL
;
1752 Attributes
|= PA_USER
;
1759 ULONGLONG Pte
, tmpPte
;
1760 PULONGLONG Pt
= NULL
;
1762 oldPdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
) + 1;
1763 for (i
= 0; i
< PageCount
; i
++, Addr
+= PAGE_SIZE
)
1765 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1767 DPRINT1("Setting physical address but not allowing access at address "
1768 "0x%.8X with attributes %x/%x.\n",
1769 Addr
, Attributes
, flProtect
);
1772 PdeOffset
= PAE_ADDR_TO_PDE_OFFSET(Addr
);
1773 if (oldPdeOffset
!= PdeOffset
)
1775 MmUnmapPageTable((PULONG
)Pt
);
1776 Pt
= MmGetPageTableForProcessForPAE(Process
, Addr
, TRUE
);
1786 oldPdeOffset
= PdeOffset
;
1788 MmMarkPageMapped(Pages
[i
]);
1789 tmpPte
= PAE_PFN_TO_PTE(Pages
[i
]) | Attributes
;
1792 tmpPte
|= 0x8000000000000000LL
;
1794 Pte
= ExfpInterlockedExchange64UL(Pt
, &tmpPte
);
1795 if (PAE_PAGE_MASK((Pte
)) != 0LL && !((Pte
) & PA_PRESENT
))
1799 if (PAE_PAGE_MASK((Pte
)) != 0LL)
1801 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte
)));
1803 if (Address
< (PVOID
)KERNEL_BASE
&&
1804 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1805 Attributes
& PA_PRESENT
)
1809 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1811 Ptrc
[PAE_ADDR_TO_PAGE_TABLE(Addr
)]++;
1815 if (Address
> (PVOID
)KERNEL_BASE
||
1816 (Pt
>= (PULONGLONG
)PAGETABLE_MAP
&& Pt
< (PULONGLONG
)PAGETABLE_MAP
+ 4*512*512))
1818 MiFlushTlb((PULONG
)Pt
, Address
);
1824 MmUnmapPageTable((PULONG
)Pt
);
1831 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
) + 1;
1832 for (i
= 0; i
< PageCount
; i
++, Addr
+= PAGE_SIZE
)
1834 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1836 DPRINT1("Setting physical address but not allowing access at address "
1837 "0x%.8X with attributes %x/%x.\n",
1838 Addr
, Attributes
, flProtect
);
1841 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1842 if (oldPdeOffset
!= PdeOffset
)
1844 MmUnmapPageTable(Pt
);
1845 Pt
= MmGetPageTableForProcess(Process
, Addr
, TRUE
);
1855 oldPdeOffset
= PdeOffset
;
1858 MmMarkPageMapped(Pages
[i
]);
1859 if (PAGE_MASK((Pte
)) != 0 && !((Pte
) & PA_PRESENT
))
1863 if (PAGE_MASK((Pte
)) != 0)
1865 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1867 InterlockedExchangeUL(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
1868 if (Address
< (PVOID
)KERNEL_BASE
&&
1869 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1870 Attributes
& PA_PRESENT
)
1874 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1876 Ptrc
[ADDR_TO_PAGE_TABLE(Addr
)]++;
1880 if (Address
> (PVOID
)KERNEL_BASE
||
1881 (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024))
1883 MiFlushTlb(Pt
, Address
);
1889 MmUnmapPageTable(Pt
);
1892 return(STATUS_SUCCESS
);
1896 MmCreateVirtualMapping(PEPROCESS Process
,
1904 for (i
= 0; i
< PageCount
; i
++)
1906 if (!MmIsUsablePage(Pages
[i
]))
1908 DPRINT1("Page at address %x not usable\n", PFN_TO_PTE(Pages
[i
]));
1913 return(MmCreateVirtualMappingUnsafe(Process
,
1921 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
1927 Entry
= MmGetPageEntryForProcessForPAE(Process
, Address
);
1931 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1934 if (!(Entry
& PA_PRESENT
))
1936 Protect
= PAGE_NOACCESS
;
1940 if (Entry
& PA_READWRITE
)
1942 Protect
= PAGE_READWRITE
;
1946 Protect
= PAGE_EXECUTE_READ
;
1950 Protect
|= PAGE_NOCACHE
;
1954 Protect
|= PAGE_WRITETHROUGH
;
1956 if (!(Entry
& PA_USER
))
1958 Protect
|= PAGE_SYSTEM
;
1966 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
1968 ULONG Attributes
= 0;
1969 BOOLEAN NoExecute
= FALSE
;
1971 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
1972 Process
, Address
, flProtect
);
1974 Attributes
= ProtectToPTE(flProtect
);
1975 if (Attributes
& 0x80000000)
1979 Attributes
&= 0xfff;
1980 if (Address
>= (PVOID
)KERNEL_BASE
)
1982 Attributes
&= ~PA_USER
;
1983 if (Ke386GlobalPagesEnabled
)
1985 Attributes
|= PA_GLOBAL
;
1990 Attributes
|= PA_USER
;
1995 ULONGLONG tmpPte
, Pte
;
1997 Pt
= MmGetPageTableForProcessForPAE(Process
, Address
, FALSE
);
2000 DPRINT1("Address %x\n", Address
);
2006 tmpPte
= PAE_PAGE_MASK(Pte
) | Attributes
| (Pte
& (PA_ACCESSED
|PA_DIRTY
));
2009 tmpPte
|= 0x8000000000000000LL
;
2013 tmpPte
&= ~0x8000000000000000LL
;
2015 } while (Pte
!= ExfInterlockedCompareExchange64UL(Pt
, &tmpPte
, &Pte
));
2017 MiFlushTlb((PULONG
)Pt
, Address
);
2023 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
2028 InterlockedExchange(Pt
, PAGE_MASK(*Pt
) | Attributes
| (*Pt
& (PA_ACCESSED
|PA_DIRTY
)));
2029 MiFlushTlb(Pt
, Address
);
2036 PHYSICAL_ADDRESS STDCALL
2037 MmGetPhysicalAddress(PVOID vaddr
)
2039 * FUNCTION: Returns the physical address corresponding to a virtual address
2044 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr
);
2048 Pte
= MmGetPageEntryForProcessForPAE(NULL
, vaddr
);
2049 if (Pte
!= 0 && Pte
& PA_PRESENT
)
2051 p
.QuadPart
= PAE_PAGE_MASK(Pte
);
2052 p
.u
.LowPart
|= (ULONG_PTR
)vaddr
& (PAGE_SIZE
- 1);
2062 Pte
= MmGetPageEntryForProcess(NULL
, vaddr
);
2063 if (Pte
!= 0 && Pte
& PA_PRESENT
)
2065 p
.QuadPart
= PAGE_MASK(Pte
);
2066 p
.u
.LowPart
|= (ULONG_PTR
)vaddr
& (PAGE_SIZE
- 1);
2077 MmCreateHyperspaceMapping(PFN_TYPE Page
)
2085 ULONGLONG ZeroEntry
= 0LL;
2088 Entry
= PFN_TO_PTE(Page
) | PA_PRESENT
| PA_READWRITE
;
2089 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
) + Page
% 1024;
2093 for (i
= Page
%1024; i
< 1024; i
++, Pte
++)
2095 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2102 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
);
2103 for (i
= 0; i
< Page
% 1024; i
++, Pte
++)
2105 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2110 if (i
>= Page
% 1024)
2118 for (i
= Page
%1024; i
>= 0; i
--, Pte
--)
2120 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2127 Pte
= PAE_ADDR_TO_PTE(HYPERSPACE
) + 1023;
2128 for (i
= 1023; i
> Page
% 1024; i
--, Pte
--)
2130 if (0LL == ExfInterlockedCompareExchange64UL(Pte
, &Entry
, &ZeroEntry
))
2135 if (i
<= Page
% 1024)
2146 Entry
= PFN_TO_PTE(Page
) | PA_PRESENT
| PA_READWRITE
;
2147 Pte
= ADDR_TO_PTE(HYPERSPACE
) + Page
% 1024;
2150 for (i
= Page
% 1024; i
< 1024; i
++, Pte
++)
2152 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2159 Pte
= ADDR_TO_PTE(HYPERSPACE
);
2160 for (i
= 0; i
< Page
% 1024; i
++, Pte
++)
2162 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2167 if (i
>= Page
% 1024)
2175 for (i
= Page
% 1024; i
>= 0; i
--, Pte
--)
2177 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2184 Pte
= ADDR_TO_PTE(HYPERSPACE
) + 1023;
2185 for (i
= 1023; i
> Page
% 1024; i
--, Pte
--)
2187 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
2192 if (i
<= Page
% 1024)
2199 Address
= (PVOID
)HYPERSPACE
+ i
* PAGE_SIZE
;
2200 FLUSH_TLB_ONE(Address
);
2205 MmChangeHyperspaceMapping(PVOID Address
, PFN_TYPE NewPage
)
2208 ASSERT (IS_HYPERSPACE(Address
));
2211 ULONGLONG Entry
= PAE_PFN_TO_PTE(NewPage
) | PA_PRESENT
| PA_READWRITE
;
2212 Entry
= (ULONG
)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PTE(Address
), &Entry
);
2213 Pfn
= PAE_PTE_TO_PFN(Entry
);
2218 Entry
= InterlockedExchange(ADDR_TO_PTE(Address
), PFN_TO_PTE(NewPage
) | PA_PRESENT
| PA_READWRITE
);
2219 Pfn
= PTE_TO_PFN(Entry
);
2221 FLUSH_TLB_ONE(Address
);
2226 MmDeleteHyperspaceMapping(PVOID Address
)
2229 ASSERT (IS_HYPERSPACE(Address
));
2232 ULONGLONG Entry
= 0LL;
2233 Entry
= (ULONG
)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PTE(Address
), &Entry
);
2234 Pfn
= PAE_PTE_TO_PFN(Entry
);
2239 Entry
= InterlockedExchange(ADDR_TO_PTE(Address
), 0);
2240 Pfn
= PTE_TO_PFN(Entry
);
2242 FLUSH_TLB_ONE(Address
);
2246 VOID
MmUpdatePageDir(PEPROCESS Process
, PVOID Address
, ULONG Size
)
2248 ULONG StartOffset
, EndOffset
, Offset
;
2250 if (Address
< (PVOID
)KERNEL_BASE
)
2256 PULONGLONG PageDirTable
;
2258 ULONGLONG ZeroPde
= 0LL;
2261 for (i
= PAE_ADDR_TO_PDTE_OFFSET(Address
); i
<= PAE_ADDR_TO_PDTE_OFFSET(Address
+ Size
); i
++)
2263 if (i
== PAE_ADDR_TO_PDTE_OFFSET(Address
))
2265 StartOffset
= PAE_ADDR_TO_PDE_PAGE_OFFSET(Address
);
2271 if (i
== PAE_ADDR_TO_PDTE_OFFSET(Address
+ Size
))
2273 EndOffset
= PAE_ADDR_TO_PDE_PAGE_OFFSET(Address
+ Size
);
2280 if (Process
!= NULL
&& Process
!= PsGetCurrentProcess())
2282 PageDirTable
= MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.QuadPart
));
2283 Pde
= (PULONGLONG
)MmCreateHyperspaceMapping(PTE_TO_PFN(PageDirTable
[i
]));
2284 MmDeleteHyperspaceMapping(PageDirTable
);
2288 Pde
= (PULONGLONG
)PAE_PAGEDIRECTORY_MAP
+ i
*512;
2291 for (Offset
= StartOffset
; Offset
<= EndOffset
; Offset
++)
2293 if (i
* 512 + Offset
< PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) || i
* 512 + Offset
>= PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
)+4)
2295 ExfInterlockedCompareExchange64UL(&Pde
[Offset
], &MmGlobalKernelPageDirectoryForPAE
[i
*512 + Offset
], &ZeroPde
);
2298 MmUnmapPageTable((PULONG
)Pde
);
2304 StartOffset
= ADDR_TO_PDE_OFFSET(Address
);
2305 EndOffset
= ADDR_TO_PDE_OFFSET(Address
+ Size
);
2307 if (Process
!= NULL
&& Process
!= PsGetCurrentProcess())
2309 Pde
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
.u
.LowPart
));
2313 Pde
= (PULONG
)PAGEDIRECTORY_MAP
;
2315 for (Offset
= StartOffset
; Offset
<= EndOffset
; Offset
++)
2317 if (Offset
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
))
2319 InterlockedCompareExchangeUL(&Pde
[Offset
], MmGlobalKernelPageDirectory
[Offset
], 0);
2322 if (Pde
!= (PULONG
)PAGEDIRECTORY_MAP
)
2324 MmDeleteHyperspaceMapping(Pde
);
2330 MmInitGlobalKernelPageDirectory(VOID
)
2334 DPRINT("MmInitGlobalKernelPageDirectory()\n");
2338 PULONGLONG CurrentPageDirectory
= (PULONGLONG
)PAE_PAGEDIRECTORY_MAP
;
2339 for (i
= PAE_ADDR_TO_PDE_OFFSET(KERNEL_BASE
); i
< 4 * 512; i
++)
2341 if (!(i
>= PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) && i
< PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) + 4) &&
2342 !(i
>= PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
) && i
< PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
) + 2) &&
2343 0LL == MmGlobalKernelPageDirectoryForPAE
[i
] && 0LL != CurrentPageDirectory
[i
])
2345 ExfpInterlockedExchange64UL(&MmGlobalKernelPageDirectoryForPAE
[i
], &CurrentPageDirectory
[i
]);
2346 if (Ke386GlobalPagesEnabled
)
2348 MmGlobalKernelPageDirectoryForPAE
[i
] |= PA_GLOBAL
;
2349 CurrentPageDirectory
[i
] |= PA_GLOBAL
;
2356 PULONG CurrentPageDirectory
= (PULONG
)PAGEDIRECTORY_MAP
;
2357 for (i
= ADDR_TO_PDE_OFFSET(KERNEL_BASE
); i
< 1024; i
++)
2359 if (i
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) &&
2360 i
!= ADDR_TO_PDE_OFFSET(HYPERSPACE
) &&
2361 0 == MmGlobalKernelPageDirectory
[i
] && 0 != CurrentPageDirectory
[i
])
2363 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];
2364 if (Ke386GlobalPagesEnabled
)
2366 MmGlobalKernelPageDirectory
[i
] |= PA_GLOBAL
;
2367 CurrentPageDirectory
[i
] |= PA_GLOBAL
;
2374 extern ULONGLONG pae_pagedirtable
;
2377 MiEnablePAE(PVOID
* LastKernelAddress
)
2379 PULONGLONG PageDirTable
;
2386 PageDirTable
= &pae_pagedirtable
;
2388 if (LastKernelAddress
)
2390 /* This is the boot processor */
2391 memcpy(PageDirTable
, (PVOID
)PAGEDIRECTORY_MAP
, PAGE_SIZE
);
2393 PageDir
= (PULONGLONG
)*LastKernelAddress
;
2394 (*LastKernelAddress
) += 6 * PAGE_SIZE
;
2395 PageDirTable
[0] = MmGetPhysicalAddress((PVOID
)PageDir
).QuadPart
| PA_PRESENT
;
2396 PageDirTable
[1] = PageDirTable
[0] + PAGE_SIZE
;
2397 PageDirTable
[2] = PageDirTable
[1] + PAGE_SIZE
;
2398 PageDirTable
[3] = PageDirTable
[2] + PAGE_SIZE
;
2400 memset(PageDir
, 0, 6 * PAGE_SIZE
);
2402 for (i
= 0; i
< 4; i
++)
2404 PageDir
[PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) + i
] = PageDirTable
[i
] | PA_READWRITE
;
2406 PageDir
[PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
)] = (PageDirTable
[0] + 4 * PAGE_SIZE
) | PA_READWRITE
;
2407 PageDir
[PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
)+1] = (PageDirTable
[0] + 5 * PAGE_SIZE
) | PA_READWRITE
;
2409 for (i
= 0; i
< 2048; i
++)
2411 if (!(i
>= PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) && i
< PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) + 4) &&
2412 !(i
>= PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
) && i
< PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE
)+2))
2415 PVOID Address
= (PVOID
)(i
* 512 * PAGE_SIZE
);
2416 PULONG Pde
= ADDR_TO_PDE(Address
);
2417 PULONGLONG PtePAE
=NULL
;
2421 if (PageDir
[i
] == 0LL)
2423 PtePAE
= (PULONGLONG
)(ULONG_PTR
)*LastKernelAddress
;
2424 (*LastKernelAddress
) += PAGE_SIZE
;
2425 PageDir
[i
] = MmGetPhysicalAddress((PVOID
)PtePAE
).QuadPart
| PA_PRESENT
| PA_READWRITE
;
2426 memset(PtePAE
, 0, PAGE_SIZE
);
2428 for (k
= 0; k
< 512; k
++)
2430 PULONG Pte
= ADDR_TO_PTE(Address
+ k
* PAGE_SIZE
);
2443 /* this is an application processor in a mp system */
2450 Ke386SaveFlags(Flags
);
2451 Ke386DisableInterrupts();
2453 Ke386SetPageTableDirectory(MmGetPhysicalAddress(PageDirTable
).u
.LowPart
)
2455 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PAE
);
2456 if (LastKernelAddress
)
2460 Ke386RestoreFlags(Flags
);
2464 MiGetUserPageDirectoryCount(VOID
)
2466 return Ke386Pae
? PAE_ADDR_TO_PDE_OFFSET(KERNEL_BASE
) : ADDR_TO_PDE_OFFSET(KERNEL_BASE
);
2470 MiInitPageDirectoryMap(VOID
)
2472 MEMORY_AREA
* kernel_map_desc
= NULL
;
2473 MEMORY_AREA
* hyperspace_desc
= NULL
;
2474 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
2477 DPRINT("MiInitPageDirectoryMap()\n");
2479 BoundaryAddressMultiple
.QuadPart
= 0;
2480 BaseAddress
= (PVOID
)PAGETABLE_MAP
;
2481 MmCreateMemoryArea(NULL
,
2482 MmGetKernelAddressSpace(),
2485 Ke386Pae
? 0x800000 : 0x400000,
2490 BoundaryAddressMultiple
);
2491 BaseAddress
= (PVOID
)HYPERSPACE
;
2492 MmCreateMemoryArea(NULL
,
2493 MmGetKernelAddressSpace(),
2501 BoundaryAddressMultiple
);