2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/i386/page.c
5 * PURPOSE: Low level memory managment manipulation
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
10 /* INCLUDES ***************************************************************/
14 #include <internal/debug.h>
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, MmInitGlobalKernelPageDirectory)
18 #pragma alloc_text(INIT, MiInitPageDirectoryMap)
22 /* GLOBALS *****************************************************************/
24 #define PA_BIT_PRESENT (0)
25 #define PA_BIT_READWRITE (1)
26 #define PA_BIT_USER (2)
29 #define PA_BIT_ACCESSED (5)
30 #define PA_BIT_DIRTY (6)
31 #define PA_BIT_GLOBAL (8)
33 #define PA_PRESENT (1 << PA_BIT_PRESENT)
34 #define PA_READWRITE (1 << PA_BIT_READWRITE)
35 #define PA_USER (1 << PA_BIT_USER)
36 #define PA_DIRTY (1 << PA_BIT_DIRTY)
37 #define PA_WT (1 << PA_BIT_WT)
38 #define PA_CD (1 << PA_BIT_CD)
39 #define PA_ACCESSED (1 << PA_BIT_ACCESSED)
40 #define PA_GLOBAL (1 << PA_BIT_GLOBAL)
42 #define HYPERSPACE (0xc0400000)
43 #define IS_HYPERSPACE(v) (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
45 ULONG MmGlobalKernelPageDirectory
[1024];
47 #define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT)
48 #define PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
51 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
53 __inline LARGE_INTEGER
PTE_TO_PAGE(ULONG npage
)
56 dummy
.QuadPart
= (LONGLONG
)(PAGE_MASK(npage
));
61 /* FUNCTIONS ***************************************************************/
63 BOOLEAN
MmUnmapPageTable(PULONG Pt
);
67 MiFlushTlbIpiRoutine(ULONG_PTR Address
)
69 if (Address
== (ULONG_PTR
)-1)
73 else if (Address
== (ULONG_PTR
)-2)
79 __invlpg((PVOID
)Address
);
85 MiFlushTlb(PULONG Pt
, PVOID Address
)
87 if ((Pt
&& MmUnmapPageTable(Pt
)) || Address
>= MmSystemRangeStart
)
96 MmGetPageDirectory(VOID
)
98 return (PULONG
)__readcr3();
102 ProtectToPTE(ULONG flProtect
)
104 ULONG Attributes
= 0;
106 if (flProtect
& (PAGE_NOACCESS
|PAGE_GUARD
))
110 else if (flProtect
& PAGE_IS_WRITABLE
)
112 Attributes
= PA_PRESENT
| PA_READWRITE
;
114 else if (flProtect
& (PAGE_IS_READABLE
| PAGE_IS_EXECUTABLE
))
116 Attributes
= PA_PRESENT
;
120 DPRINT1("Unknown main protection type.\n");
124 if (flProtect
& PAGE_SYSTEM
)
129 Attributes
= Attributes
| PA_USER
;
131 if (flProtect
& PAGE_NOCACHE
)
133 Attributes
= Attributes
| PA_CD
;
135 if (flProtect
& PAGE_WRITETHROUGH
)
137 Attributes
= Attributes
| PA_WT
;
144 Mmi386ReleaseMmInfo(PEPROCESS Process
)
146 PUSHORT LdtDescriptor
;
151 DPRINT("Mmi386ReleaseMmInfo(Process %x)\n",Process
);
153 LdtDescriptor
= (PUSHORT
) &Process
->Pcb
.LdtDescriptor
;
154 LdtBase
= LdtDescriptor
[1] |
155 ((LdtDescriptor
[2] & 0xff) << 16) |
156 ((LdtDescriptor
[3] & ~0xff) << 16);
158 DPRINT("LdtBase: %x\n", LdtBase
);
162 ExFreePool((PVOID
) LdtBase
);
165 PageDir
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
[0]));
166 for (i
= 0; i
< ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
++)
170 MiZeroPage(PTE_TO_PFN(PageDir
[i
]));
171 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(PageDir
[i
]));
174 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(PageDir
[ADDR_TO_PDE_OFFSET(HYPERSPACE
)]));
175 MmDeleteHyperspaceMapping(PageDir
);
176 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
[0]));
178 Process
->Pcb
.DirectoryTableBase
[0] = 0;
179 Process
->Pcb
.DirectoryTableBase
[1] = 0;
181 DPRINT("Finished Mmi386ReleaseMmInfo()\n");
182 return(STATUS_SUCCESS
);
187 MmInitializeHandBuiltProcess(IN PEPROCESS Process
,
188 IN PULONG DirectoryTableBase
)
190 /* Share the directory base with the idle process */
191 DirectoryTableBase
[0] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0];
192 DirectoryTableBase
[1] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[1];
194 /* Initialize the Addresss Space */
195 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
196 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= NULL
;
198 /* The process now has an address space */
199 Process
->HasAddressSpace
= TRUE
;
200 return STATUS_SUCCESS
;
205 MmCreateProcessAddressSpace(IN ULONG MinWs
,
206 IN PEPROCESS Process
,
207 IN PULONG DirectoryTableBase
)
212 PULONG PageDirectory
;
214 DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", MinWs
, Process
);
216 for (i
= 0; i
< 2; i
++)
218 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
[i
]);
219 if (!NT_SUCCESS(Status
))
221 for (j
= 0; j
< i
; j
++)
223 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
[j
]);
230 PageDirectory
= MmCreateHyperspaceMapping(Pfn
[0]);
232 memcpy(PageDirectory
+ ADDR_TO_PDE_OFFSET(MmSystemRangeStart
),
233 MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(MmSystemRangeStart
),
234 (1024 - ADDR_TO_PDE_OFFSET(MmSystemRangeStart
)) * sizeof(ULONG
));
236 DPRINT("Addr %x\n",ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
));
237 PageDirectory
[ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
)] = PFN_TO_PTE(Pfn
[0]) | PA_PRESENT
| PA_READWRITE
;
238 PageDirectory
[ADDR_TO_PDE_OFFSET(HYPERSPACE
)] = PFN_TO_PTE(Pfn
[1]) | PA_PRESENT
| PA_READWRITE
;
240 MmDeleteHyperspaceMapping(PageDirectory
);
242 DirectoryTableBase
[0] = PFN_TO_PTE(Pfn
[0]);
243 DirectoryTableBase
[1] = 0;
244 DPRINT("Finished MmCopyMmInfo(): 0x%x\n", DirectoryTableBase
[0]);
250 MmDeletePageTable(PEPROCESS Process
, PVOID Address
)
252 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
254 if (Process
!= NULL
&& Process
!= CurrentProcess
)
256 KeAttachProcess(&Process
->Pcb
);
259 MiAddressToPde(Address
)->u
.Long
= 0;
260 MiFlushTlb((PULONG
)MiAddressToPde(Address
),
261 MiAddressToPte(Address
));
263 if (Address
>= MmSystemRangeStart
)
266 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
268 if (Process
!= NULL
&& Process
!= CurrentProcess
)
276 MmFreePageTable(PEPROCESS Process
, PVOID Address
)
278 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
283 DPRINT("ProcessId %d, Address %x\n", Process
->UniqueProcessId
, Address
);
284 if (Process
!= NULL
&& Process
!= CurrentProcess
)
286 KeAttachProcess(&Process
->Pcb
);
289 PageTable
= (PULONG
)PAGE_ROUND_DOWN((PVOID
)MiAddressToPte(Address
));
290 for (i
= 0; i
< 1024; i
++)
292 if (PageTable
[i
] != 0)
294 DbgPrint("Page table entry not clear at %x/%x (is %x)\n",
295 ((ULONG
)Address
/ (4*1024*1024)), i
, PageTable
[i
]);
299 Pfn
= MiAddressToPde(Address
)->u
.Hard
.PageFrameNumber
;
300 MiAddressToPde(Address
)->u
.Long
= 0;
301 MiFlushTlb((PULONG
)MiAddressToPde(Address
), MiAddressToPte(Address
));
303 if (Address
>= MmSystemRangeStart
)
305 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
310 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
312 if (Process
!= NULL
&& Process
!= CurrentProcess
)
319 MmGetPageTableForProcess(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
321 ULONG PdeOffset
= ADDR_TO_PDE_OFFSET(Address
);
327 if (Address
< MmSystemRangeStart
&& Process
&& Process
!= PsGetCurrentProcess())
329 PageDir
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
[0]));
334 if (0 == InterlockedCompareExchangeUL(&PageDir
[PdeOffset
], 0, 0))
338 MmDeleteHyperspaceMapping(PageDir
);
341 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
342 if (!NT_SUCCESS(Status
) || Pfn
== 0)
346 Entry
= InterlockedCompareExchangeUL(&PageDir
[PdeOffset
], PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
349 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
350 Pfn
= PTE_TO_PFN(Entry
);
355 Pfn
= PTE_TO_PFN(PageDir
[PdeOffset
]);
357 MmDeleteHyperspaceMapping(PageDir
);
358 Pt
= MmCreateHyperspaceMapping(Pfn
);
363 return Pt
+ ADDR_TO_PTE_OFFSET(Address
);
365 PageDir
= (PULONG
)MiAddressToPde(Address
);
366 if (0 == InterlockedCompareExchangeUL(PageDir
, 0, 0))
368 if (Address
>= MmSystemRangeStart
)
370 if (0 == InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory
[PdeOffset
], 0, 0))
376 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
377 if (!NT_SUCCESS(Status
) || Pfn
== 0)
381 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
;
382 if (Ke386GlobalPagesEnabled
)
386 if(0 != InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory
[PdeOffset
], Entry
, 0))
388 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
391 (void)InterlockedExchangeUL(PageDir
, MmGlobalKernelPageDirectory
[PdeOffset
]);
399 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
400 if (!NT_SUCCESS(Status
) || Pfn
== 0)
404 Entry
= InterlockedCompareExchangeUL(PageDir
, PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
407 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
411 return (PULONG
)MiAddressToPte(Address
);
414 BOOLEAN
MmUnmapPageTable(PULONG Pt
)
416 if (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024)
423 MmDeleteHyperspaceMapping((PVOID
)PAGE_ROUND_DOWN(Pt
));
428 static ULONG
MmGetPageEntryForProcess(PEPROCESS Process
, PVOID Address
)
433 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
437 MmUnmapPageTable(Pt
);
445 MmGetPfnForProcess(PEPROCESS Process
,
449 Entry
= MmGetPageEntryForProcess(Process
, Address
);
450 if (!(Entry
& PA_PRESENT
))
454 return(PTE_TO_PFN(Entry
));
459 MmDisableVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOLEAN
* WasDirty
, PPFN_TYPE Page
)
461 * FUNCTION: Delete a virtual mapping
468 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
474 * Atomically disable the present bit and get the old value.
479 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_PRESENT
, Pte
));
481 MiFlushTlb(Pt
, Address
);
482 WasValid
= (PAGE_MASK(Pte
) != 0);
489 * Return some information to the caller
491 if (WasDirty
!= NULL
)
493 *WasDirty
= Pte
& PA_DIRTY
;
497 *Page
= PTE_TO_PFN(Pte
);
503 MmRawDeleteVirtualMapping(PVOID Address
)
507 Pt
= MmGetPageTableForProcess(NULL
, Address
, FALSE
);
511 * Set the entry to zero
513 (void)InterlockedExchangeUL(Pt
, 0);
514 MiFlushTlb(Pt
, Address
);
520 MmDeleteVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOLEAN FreePage
,
521 BOOLEAN
* WasDirty
, PPFN_TYPE Page
)
523 * FUNCTION: Delete a virtual mapping
526 BOOLEAN WasValid
= FALSE
;
531 DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
532 Process
, Address
, FreePage
, WasDirty
, Page
);
534 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
538 if (WasDirty
!= NULL
)
550 * Atomically set the entry to zero and get the old value.
552 Pte
= InterlockedExchangeUL(Pt
, 0);
554 MiFlushTlb(Pt
, Address
);
556 WasValid
= (PAGE_MASK(Pte
) != 0);
559 Pfn
= PTE_TO_PFN(Pte
);
560 MmMarkPageUnmapped(Pfn
);
567 if (FreePage
&& WasValid
)
569 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
573 * Return some information to the caller
575 if (WasDirty
!= NULL
)
577 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
587 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
588 SWAPENTRY
* SwapEntry
)
590 * FUNCTION: Delete a virtual mapping
596 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
605 * Atomically set the entry to zero and get the old value.
607 Pte
= InterlockedExchangeUL(Pt
, 0);
609 MiFlushTlb(Pt
, Address
);
612 * Return some information to the caller
614 *SwapEntry
= Pte
>> 1;
618 Mmi386MakeKernelPageTableGlobal(PVOID PAddress
)
621 Pde
= (PULONG
)MiAddressToPde(PAddress
);
624 Pt
= MmGetPageTableForProcess(NULL
, PAddress
, FALSE
);
635 MmIsDirtyPage(PEPROCESS Process
, PVOID Address
)
637 return MmGetPageEntryForProcess(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
642 MmIsAccessedAndResetAccessPage(PEPROCESS Process
, PVOID Address
)
647 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
649 DPRINT1("MmIsAccessedAndResetAccessPage is called for user space without a process.\n");
653 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
662 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_ACCESSED
, Pte
));
664 if (Pte
& PA_ACCESSED
)
666 MiFlushTlb(Pt
, Address
);
671 MmUnmapPageTable(Pt
);
678 MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
683 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
685 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
689 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
699 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
& ~PA_DIRTY
, Pte
));
703 MiFlushTlb(Pt
, Address
);
707 MmUnmapPageTable(Pt
);
713 MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
718 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
720 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
724 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
733 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
| PA_DIRTY
, Pte
));
734 if (!(Pte
& PA_DIRTY
))
736 MiFlushTlb(Pt
, Address
);
740 MmUnmapPageTable(Pt
);
746 MmEnableVirtualMapping(PEPROCESS Process
, PVOID Address
)
751 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
760 } while (Pte
!= InterlockedCompareExchangeUL(Pt
, Pte
| PA_PRESENT
, Pte
));
761 if (!(Pte
& PA_PRESENT
))
763 MiFlushTlb(Pt
, Address
);
767 MmUnmapPageTable(Pt
);
773 MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
775 return MmGetPageEntryForProcess(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
780 MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
783 Entry
= MmGetPageEntryForProcess(Process
, Address
);
784 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
789 MmCreateVirtualMappingForKernel(PVOID Address
,
797 ULONG PdeOffset
, oldPdeOffset
;
800 BOOLEAN NoExecute
= FALSE
;
802 DPRINT("MmCreateVirtualMappingForKernel(%x, %x, %x, %d)\n",
803 Address
, flProtect
, Pages
, PageCount
);
805 if (Address
< MmSystemRangeStart
)
807 DPRINT1("MmCreateVirtualMappingForKernel is called for user space\n");
811 Attributes
= ProtectToPTE(flProtect
);
812 if (Attributes
& 0x80000000)
817 if (Ke386GlobalPagesEnabled
)
819 Attributes
|= PA_GLOBAL
;
824 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
825 Pt
= MmGetPageTableForProcess(NULL
, Addr
, TRUE
);
832 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
834 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
836 DPRINT1("Setting physical address but not allowing access at address "
837 "0x%.8X with attributes %x/%x.\n",
838 Addr
, Attributes
, flProtect
);
842 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
843 if (oldPdeOffset
!= PdeOffset
)
845 Pt
= MmGetPageTableForProcess(NULL
, Addr
, TRUE
);
855 oldPdeOffset
= PdeOffset
;
862 (void)InterlockedExchangeUL(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
865 return(STATUS_SUCCESS
);
870 MmCreatePageFileMapping(PEPROCESS Process
,
877 if (Process
== NULL
&& Address
< MmSystemRangeStart
)
879 DPRINT1("No process\n");
882 if (Process
!= NULL
&& Address
>= MmSystemRangeStart
)
884 DPRINT1("Setting kernel address with process context\n");
887 if (SwapEntry
& (1 << 31))
892 Pt
= MmGetPageTableForProcess(Process
, Address
, TRUE
);
898 if (PAGE_MASK((Pte
)) != 0)
900 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
902 (void)InterlockedExchangeUL(Pt
, SwapEntry
<< 1);
905 MiFlushTlb(Pt
, Address
);
909 MmUnmapPageTable(Pt
);
912 return(STATUS_SUCCESS
);
918 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
927 ULONG oldPdeOffset
, PdeOffset
;
930 BOOLEAN NoExecute
= FALSE
;
932 DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
933 Process
, Address
, flProtect
, Pages
, *Pages
, PageCount
);
937 if (Address
< MmSystemRangeStart
)
939 DPRINT1("No process\n");
942 if (PageCount
> 0x10000 ||
943 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> 0x100000)
945 DPRINT1("Page count to large\n");
951 if (Address
>= MmSystemRangeStart
)
953 DPRINT1("Setting kernel address with process context\n");
956 if (PageCount
> (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
||
957 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
>
958 (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
)
960 DPRINT1("Page Count to large\n");
965 Attributes
= ProtectToPTE(flProtect
);
966 if (Attributes
& 0x80000000)
971 if (Address
>= MmSystemRangeStart
)
973 Attributes
&= ~PA_USER
;
974 if (Ke386GlobalPagesEnabled
)
976 Attributes
|= PA_GLOBAL
;
981 Attributes
|= PA_USER
;
985 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
) + 1;
986 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
988 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
990 DPRINT1("Setting physical address but not allowing access at address "
991 "0x%.8X with attributes %x/%x.\n",
992 Addr
, Attributes
, flProtect
);
995 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
996 if (oldPdeOffset
!= PdeOffset
)
998 MmUnmapPageTable(Pt
);
999 Pt
= MmGetPageTableForProcess(Process
, Addr
, TRUE
);
1009 oldPdeOffset
= PdeOffset
;
1012 MmMarkPageMapped(Pages
[i
]);
1013 if (PAGE_MASK((Pte
)) != 0 && !((Pte
) & PA_PRESENT
))
1017 if (PAGE_MASK((Pte
)) != 0)
1019 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1021 (void)InterlockedExchangeUL(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
1024 if (Address
> MmSystemRangeStart
||
1025 (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024))
1027 MiFlushTlb(Pt
, Address
);
1033 MmUnmapPageTable(Pt
);
1036 return(STATUS_SUCCESS
);
1041 MmCreateVirtualMapping(PEPROCESS Process
,
1049 for (i
= 0; i
< PageCount
; i
++)
1051 if (!MmIsPageInUse(Pages
[i
]))
1053 DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages
[i
]));
1058 return(MmCreateVirtualMappingUnsafe(Process
,
1067 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
1072 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1075 if (!(Entry
& PA_PRESENT
))
1077 Protect
= PAGE_NOACCESS
;
1081 if (Entry
& PA_READWRITE
)
1083 Protect
= PAGE_READWRITE
;
1087 Protect
= PAGE_EXECUTE_READ
;
1091 Protect
|= PAGE_NOCACHE
;
1095 Protect
|= PAGE_WRITETHROUGH
;
1097 if (!(Entry
& PA_USER
))
1099 Protect
|= PAGE_SYSTEM
;
1108 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
1110 ULONG Attributes
= 0;
1111 BOOLEAN NoExecute
= FALSE
;
1114 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
1115 Process
, Address
, flProtect
);
1117 Attributes
= ProtectToPTE(flProtect
);
1118 if (Attributes
& 0x80000000)
1122 Attributes
&= 0xfff;
1123 if (Address
>= MmSystemRangeStart
)
1125 Attributes
&= ~PA_USER
;
1126 if (Ke386GlobalPagesEnabled
)
1128 Attributes
|= PA_GLOBAL
;
1133 Attributes
|= PA_USER
;
1136 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1141 InterlockedExchange((PLONG
)Pt
, PAGE_MASK(*Pt
) | Attributes
| (*Pt
& (PA_ACCESSED
|PA_DIRTY
)));
1142 MiFlushTlb(Pt
, Address
);
1148 PHYSICAL_ADDRESS STDCALL
1149 MmGetPhysicalAddress(PVOID vaddr
)
1151 * FUNCTION: Returns the physical address corresponding to a virtual address
1157 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr
);
1158 Pte
= MmGetPageEntryForProcess(NULL
, vaddr
);
1159 if (Pte
!= 0 && Pte
& PA_PRESENT
)
1161 p
.QuadPart
= PAGE_MASK(Pte
);
1162 p
.u
.LowPart
|= (ULONG_PTR
)vaddr
& (PAGE_SIZE
- 1);
1173 MmCreateHyperspaceMapping(PFN_TYPE Page
)
1180 Entry
= PFN_TO_PTE(Page
) | PA_PRESENT
| PA_READWRITE
;
1181 Pte
= (PULONG
)MiAddressToPte(HYPERSPACE
) + Page
% 1024;
1184 for (i
= Page
% 1024; i
< 1024; i
++, Pte
++)
1186 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1193 Pte
= (PULONG
)MiAddressToPte(HYPERSPACE
);
1194 for (i
= 0; i
< Page
% 1024; i
++, Pte
++)
1196 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1201 if (i
>= Page
% 1024)
1209 for (i
= Page
% 1024; (LONG
)i
>= 0; i
--, Pte
--)
1211 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1218 Pte
= (PULONG
)MiAddressToPte(HYPERSPACE
) + 1023;
1219 for (i
= 1023; i
> Page
% 1024; i
--, Pte
--)
1221 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1226 if (i
<= Page
% 1024)
1232 Address
= (PVOID
)((ULONG_PTR
)HYPERSPACE
+ i
* PAGE_SIZE
);
1239 MmChangeHyperspaceMapping(PVOID Address
, PFN_TYPE NewPage
)
1244 ASSERT (IS_HYPERSPACE(Address
));
1246 Entry
= InterlockedExchange((PLONG
)MiAddressToPte(Address
), PFN_TO_PTE(NewPage
) | PA_PRESENT
| PA_READWRITE
);
1247 Pfn
= PTE_TO_PFN(Entry
);
1255 MmDeleteHyperspaceMapping(PVOID Address
)
1260 ASSERT (IS_HYPERSPACE(Address
));
1262 Entry
= InterlockedExchange((PLONG
)MiAddressToPte(Address
), 0);
1263 Pfn
= PTE_TO_PFN(Entry
);
1271 MmUpdatePageDir(PEPROCESS Process
, PVOID Address
, ULONG Size
)
1273 ULONG StartOffset
, EndOffset
, Offset
;
1276 if (Address
< MmSystemRangeStart
)
1281 StartOffset
= ADDR_TO_PDE_OFFSET(Address
);
1282 EndOffset
= ADDR_TO_PDE_OFFSET((PVOID
)((ULONG_PTR
)Address
+ Size
));
1284 if (Process
!= NULL
&& Process
!= PsGetCurrentProcess())
1286 Pde
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
[0]));
1290 Pde
= (PULONG
)PAGEDIRECTORY_MAP
;
1292 for (Offset
= StartOffset
; Offset
<= EndOffset
; Offset
++)
1294 if (Offset
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
))
1296 (void)InterlockedCompareExchangeUL(&Pde
[Offset
], MmGlobalKernelPageDirectory
[Offset
], 0);
1299 if (Pde
!= (PULONG
)PAGEDIRECTORY_MAP
)
1301 MmDeleteHyperspaceMapping(Pde
);
1308 MmInitGlobalKernelPageDirectory(VOID
)
1311 PULONG CurrentPageDirectory
= (PULONG
)PAGEDIRECTORY_MAP
;
1313 DPRINT("MmInitGlobalKernelPageDirectory()\n");
1315 for (i
= ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
< 1024; i
++)
1317 if (i
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) &&
1318 i
!= ADDR_TO_PDE_OFFSET(HYPERSPACE
) &&
1319 0 == MmGlobalKernelPageDirectory
[i
] && 0 != CurrentPageDirectory
[i
])
1321 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];
1322 if (Ke386GlobalPagesEnabled
)
1324 MmGlobalKernelPageDirectory
[i
] |= PA_GLOBAL
;
1325 CurrentPageDirectory
[i
] |= PA_GLOBAL
;
1334 MiInitPageDirectoryMap(VOID
)
1336 MEMORY_AREA
* kernel_map_desc
= NULL
;
1337 MEMORY_AREA
* hyperspace_desc
= NULL
;
1338 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
1342 DPRINT("MiInitPageDirectoryMap()\n");
1344 BoundaryAddressMultiple
.QuadPart
= 0;
1345 BaseAddress
= (PVOID
)PAGETABLE_MAP
;
1346 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
1354 BoundaryAddressMultiple
);
1355 if (!NT_SUCCESS(Status
))
1359 BaseAddress
= (PVOID
)HYPERSPACE
;
1360 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
1368 BoundaryAddressMultiple
);
1369 if (!NT_SUCCESS(Status
))