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 ***************************************************************/
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
);
66 MiFlushTlb(PULONG Pt
, PVOID Address
)
68 if ((Pt
&& MmUnmapPageTable(Pt
)) || Address
>= MmSystemRangeStart
)
75 MmGetPageDirectory(VOID
)
77 return (PULONG
)(ULONG_PTR
)__readcr3();
81 ProtectToPTE(ULONG flProtect
)
85 if (flProtect
& (PAGE_NOACCESS
|PAGE_GUARD
))
89 else if (flProtect
& PAGE_IS_WRITABLE
)
91 Attributes
= PA_PRESENT
| PA_READWRITE
;
93 else if (flProtect
& (PAGE_IS_READABLE
| PAGE_IS_EXECUTABLE
))
95 Attributes
= PA_PRESENT
;
99 DPRINT1("Unknown main protection type.\n");
100 KeBugCheck(MEMORY_MANAGEMENT
);
103 if (flProtect
& PAGE_SYSTEM
)
108 Attributes
= Attributes
| PA_USER
;
110 if (flProtect
& PAGE_NOCACHE
)
112 Attributes
= Attributes
| PA_CD
;
114 if (flProtect
& PAGE_WRITETHROUGH
)
116 Attributes
= Attributes
| PA_WT
;
123 Mmi386ReleaseMmInfo(PEPROCESS Process
)
125 PUSHORT LdtDescriptor
;
130 DPRINT("Mmi386ReleaseMmInfo(Process %x)\n",Process
);
132 LdtDescriptor
= (PUSHORT
) &Process
->Pcb
.LdtDescriptor
;
133 LdtBase
= LdtDescriptor
[1] |
134 ((LdtDescriptor
[2] & 0xff) << 16) |
135 ((LdtDescriptor
[3] & ~0xff) << 16);
137 DPRINT("LdtBase: %x\n", LdtBase
);
141 ExFreePool((PVOID
) LdtBase
);
144 PageDir
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
[0]));
145 for (i
= 0; i
< ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
++)
149 MiZeroPage(PTE_TO_PFN(PageDir
[i
]));
150 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(PageDir
[i
]));
153 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(PageDir
[ADDR_TO_PDE_OFFSET(HYPERSPACE
)]));
154 MmDeleteHyperspaceMapping(PageDir
);
155 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
[0]));
157 Process
->Pcb
.DirectoryTableBase
[0] = 0;
158 Process
->Pcb
.DirectoryTableBase
[1] = 0;
160 DPRINT("Finished Mmi386ReleaseMmInfo()\n");
161 return(STATUS_SUCCESS
);
166 MmInitializeHandBuiltProcess(IN PEPROCESS Process
,
167 IN PULONG_PTR DirectoryTableBase
)
169 /* Share the directory base with the idle process */
170 DirectoryTableBase
[0] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0];
171 DirectoryTableBase
[1] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[1];
173 /* Initialize the Addresss Space */
174 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
175 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= NULL
;
177 /* The process now has an address space */
178 Process
->HasAddressSpace
= TRUE
;
179 return STATUS_SUCCESS
;
184 MmCreateProcessAddressSpace(IN ULONG MinWs
,
185 IN PEPROCESS Process
,
186 IN PULONG DirectoryTableBase
)
191 PULONG_PTR PageDirectory
;
193 DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", MinWs
, Process
);
195 for (i
= 0; i
< 2; i
++)
197 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
[i
]);
198 if (!NT_SUCCESS(Status
))
200 for (j
= 0; j
< i
; j
++)
202 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
[j
]);
209 PageDirectory
= MmCreateHyperspaceMapping(Pfn
[0]);
211 memcpy(PageDirectory
+ ADDR_TO_PDE_OFFSET(MmSystemRangeStart
),
212 MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(MmSystemRangeStart
),
213 (1024 - ADDR_TO_PDE_OFFSET(MmSystemRangeStart
)) * sizeof(ULONG
));
215 DPRINT("Addr %x\n",ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
));
216 PageDirectory
[ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
)] = PFN_TO_PTE(Pfn
[0]) | PA_PRESENT
| PA_READWRITE
;
217 PageDirectory
[ADDR_TO_PDE_OFFSET(HYPERSPACE
)] = PFN_TO_PTE(Pfn
[1]) | PA_PRESENT
| PA_READWRITE
;
219 MmDeleteHyperspaceMapping(PageDirectory
);
221 DirectoryTableBase
[0] = PFN_TO_PTE(Pfn
[0]);
222 DirectoryTableBase
[1] = 0;
223 DPRINT("Finished MmCopyMmInfo(): 0x%x\n", DirectoryTableBase
[0]);
229 MmDeletePageTable(PEPROCESS Process
, PVOID Address
)
231 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
233 if (Process
!= NULL
&& Process
!= CurrentProcess
)
235 KeAttachProcess(&Process
->Pcb
);
238 MiAddressToPde(Address
)->u
.Long
= 0;
239 MiFlushTlb((PULONG
)MiAddressToPde(Address
),
240 MiAddressToPte(Address
));
242 if (Address
>= MmSystemRangeStart
)
244 KeBugCheck(MEMORY_MANAGEMENT
);
245 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
247 if (Process
!= NULL
&& Process
!= CurrentProcess
)
254 MmGetPageTableForProcess(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
256 ULONG PdeOffset
= ADDR_TO_PDE_OFFSET(Address
);
262 if (Address
< MmSystemRangeStart
&& Process
&& Process
!= PsGetCurrentProcess())
264 PageDir
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
[0]));
267 KeBugCheck(MEMORY_MANAGEMENT
);
269 if (0 == InterlockedCompareExchangePte(&PageDir
[PdeOffset
], 0, 0))
273 MmDeleteHyperspaceMapping(PageDir
);
276 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
277 if (!NT_SUCCESS(Status
) || Pfn
== 0)
279 KeBugCheck(MEMORY_MANAGEMENT
);
281 Entry
= InterlockedCompareExchangePte(&PageDir
[PdeOffset
], PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
284 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
285 Pfn
= PTE_TO_PFN(Entry
);
290 Pfn
= PTE_TO_PFN(PageDir
[PdeOffset
]);
292 MmDeleteHyperspaceMapping(PageDir
);
293 Pt
= MmCreateHyperspaceMapping(Pfn
);
296 KeBugCheck(MEMORY_MANAGEMENT
);
298 return Pt
+ ADDR_TO_PTE_OFFSET(Address
);
300 PageDir
= (PULONG
)MiAddressToPde(Address
);
301 if (0 == InterlockedCompareExchangePte(PageDir
, 0, 0))
303 if (Address
>= MmSystemRangeStart
)
305 if (0 == InterlockedCompareExchangePte(&MmGlobalKernelPageDirectory
[PdeOffset
], 0, 0))
311 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
312 if (!NT_SUCCESS(Status
) || Pfn
== 0)
314 KeBugCheck(MEMORY_MANAGEMENT
);
316 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
;
317 if (Ke386GlobalPagesEnabled
)
321 if(0 != InterlockedCompareExchangePte(&MmGlobalKernelPageDirectory
[PdeOffset
], Entry
, 0))
323 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
326 InterlockedExchangePte(PageDir
, MmGlobalKernelPageDirectory
[PdeOffset
]);
334 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
335 if (!NT_SUCCESS(Status
) || Pfn
== 0)
337 KeBugCheck(MEMORY_MANAGEMENT
);
339 Entry
= InterlockedCompareExchangePte(PageDir
, PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
342 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
346 return (PULONG
)MiAddressToPte(Address
);
349 BOOLEAN
MmUnmapPageTable(PULONG Pt
)
351 if (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024)
358 MmDeleteHyperspaceMapping((PVOID
)PAGE_ROUND_DOWN(Pt
));
363 static ULONG
MmGetPageEntryForProcess(PEPROCESS Process
, PVOID Address
)
368 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
372 MmUnmapPageTable(Pt
);
380 MmGetPfnForProcess(PEPROCESS Process
,
384 Entry
= MmGetPageEntryForProcess(Process
, Address
);
385 if (!(Entry
& PA_PRESENT
))
389 return(PTE_TO_PFN(Entry
));
394 MmDisableVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOLEAN
* WasDirty
, PPFN_TYPE Page
)
396 * FUNCTION: Delete a virtual mapping
403 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
406 KeBugCheck(MEMORY_MANAGEMENT
);
409 * Atomically disable the present bit and get the old value.
414 } while (Pte
!= InterlockedCompareExchangePte(Pt
, Pte
& ~PA_PRESENT
, Pte
));
416 MiFlushTlb(Pt
, Address
);
417 WasValid
= (PAGE_MASK(Pte
) != 0);
420 KeBugCheck(MEMORY_MANAGEMENT
);
424 * Return some information to the caller
426 if (WasDirty
!= NULL
)
428 *WasDirty
= Pte
& PA_DIRTY
;
432 *Page
= PTE_TO_PFN(Pte
);
438 MmRawDeleteVirtualMapping(PVOID Address
)
442 Pt
= MmGetPageTableForProcess(NULL
, Address
, FALSE
);
446 * Set the entry to zero
448 InterlockedExchangePte(Pt
, 0);
449 MiFlushTlb(Pt
, Address
);
455 MmDeleteVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOLEAN FreePage
,
456 BOOLEAN
* WasDirty
, PPFN_TYPE Page
)
458 * FUNCTION: Delete a virtual mapping
461 BOOLEAN WasValid
= FALSE
;
466 DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
467 Process
, Address
, FreePage
, WasDirty
, Page
);
469 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
473 if (WasDirty
!= NULL
)
485 * Atomically set the entry to zero and get the old value.
487 Pte
= InterlockedExchangePte(Pt
, 0);
489 MiFlushTlb(Pt
, Address
);
491 WasValid
= (PAGE_MASK(Pte
) != 0);
494 Pfn
= PTE_TO_PFN(Pte
);
495 MmMarkPageUnmapped(Pfn
);
502 if (FreePage
&& WasValid
)
504 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
508 * Return some information to the caller
510 if (WasDirty
!= NULL
)
512 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
522 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
523 SWAPENTRY
* SwapEntry
)
525 * FUNCTION: Delete a virtual mapping
531 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
540 * Atomically set the entry to zero and get the old value.
542 Pte
= InterlockedExchangePte(Pt
, 0);
544 MiFlushTlb(Pt
, Address
);
547 * Return some information to the caller
549 *SwapEntry
= Pte
>> 1;
553 Mmi386MakeKernelPageTableGlobal(PVOID PAddress
)
556 Pde
= (PULONG
)MiAddressToPde(PAddress
);
559 Pt
= MmGetPageTableForProcess(NULL
, PAddress
, FALSE
);
570 MmIsDirtyPage(PEPROCESS Process
, PVOID Address
)
572 return MmGetPageEntryForProcess(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
577 MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
582 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
584 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
585 KeBugCheck(MEMORY_MANAGEMENT
);
588 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
592 KeBugCheck(MEMORY_MANAGEMENT
);
598 } while (Pte
!= InterlockedCompareExchangePte(Pt
, Pte
& ~PA_DIRTY
, Pte
));
602 MiFlushTlb(Pt
, Address
);
606 MmUnmapPageTable(Pt
);
612 MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
617 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
619 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
620 KeBugCheck(MEMORY_MANAGEMENT
);
623 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
626 KeBugCheck(MEMORY_MANAGEMENT
);
632 } while (Pte
!= InterlockedCompareExchangePte(Pt
, Pte
| PA_DIRTY
, Pte
));
633 if (!(Pte
& PA_DIRTY
))
635 MiFlushTlb(Pt
, Address
);
639 MmUnmapPageTable(Pt
);
645 MmEnableVirtualMapping(PEPROCESS Process
, PVOID Address
)
650 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
653 KeBugCheck(MEMORY_MANAGEMENT
);
659 } while (Pte
!= InterlockedCompareExchangePte(Pt
, Pte
| PA_PRESENT
, Pte
));
660 if (!(Pte
& PA_PRESENT
))
662 MiFlushTlb(Pt
, Address
);
666 MmUnmapPageTable(Pt
);
672 MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
674 return MmGetPageEntryForProcess(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
679 MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
682 Entry
= MmGetPageEntryForProcess(Process
, Address
);
683 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
688 MmCreateVirtualMappingForKernel(PVOID Address
,
696 ULONG PdeOffset
, oldPdeOffset
;
699 BOOLEAN NoExecute
= FALSE
;
701 DPRINT("MmCreateVirtualMappingForKernel(%x, %x, %x, %d)\n",
702 Address
, flProtect
, Pages
, PageCount
);
704 if (Address
< MmSystemRangeStart
)
706 DPRINT1("MmCreateVirtualMappingForKernel is called for user space\n");
707 KeBugCheck(MEMORY_MANAGEMENT
);
710 Attributes
= ProtectToPTE(flProtect
);
711 if (Attributes
& 0x80000000)
716 if (Ke386GlobalPagesEnabled
)
718 Attributes
|= PA_GLOBAL
;
723 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
724 Pt
= MmGetPageTableForProcess(NULL
, Addr
, TRUE
);
727 KeBugCheck(MEMORY_MANAGEMENT
);
731 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
733 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
735 DPRINT1("Setting physical address but not allowing access at address "
736 "0x%.8X with attributes %x/%x.\n",
737 Addr
, Attributes
, flProtect
);
738 KeBugCheck(MEMORY_MANAGEMENT
);
741 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
742 if (oldPdeOffset
!= PdeOffset
)
744 Pt
= MmGetPageTableForProcess(NULL
, Addr
, TRUE
);
747 KeBugCheck(MEMORY_MANAGEMENT
);
754 oldPdeOffset
= PdeOffset
;
759 KeBugCheck(MEMORY_MANAGEMENT
);
761 InterlockedExchangePte(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
764 return(STATUS_SUCCESS
);
769 MmCreatePageFileMapping(PEPROCESS Process
,
776 if (Process
== NULL
&& Address
< MmSystemRangeStart
)
778 DPRINT1("No process\n");
779 KeBugCheck(MEMORY_MANAGEMENT
);
781 if (Process
!= NULL
&& Address
>= MmSystemRangeStart
)
783 DPRINT1("Setting kernel address with process context\n");
784 KeBugCheck(MEMORY_MANAGEMENT
);
786 if (SwapEntry
& (1 << 31))
788 KeBugCheck(MEMORY_MANAGEMENT
);
791 Pt
= MmGetPageTableForProcess(Process
, Address
, TRUE
);
794 KeBugCheck(MEMORY_MANAGEMENT
);
797 if (PAGE_MASK((Pte
)) != 0)
799 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
801 InterlockedExchangePte(Pt
, SwapEntry
<< 1);
804 MiFlushTlb(Pt
, Address
);
808 MmUnmapPageTable(Pt
);
811 return(STATUS_SUCCESS
);
817 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
826 ULONG oldPdeOffset
, PdeOffset
;
829 BOOLEAN NoExecute
= FALSE
;
831 DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
832 Process
, Address
, flProtect
, Pages
, *Pages
, PageCount
);
836 if (Address
< MmSystemRangeStart
)
838 DPRINT1("No process\n");
839 KeBugCheck(MEMORY_MANAGEMENT
);
841 if (PageCount
> 0x10000 ||
842 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> 0x100000)
844 DPRINT1("Page count to large\n");
845 KeBugCheck(MEMORY_MANAGEMENT
);
850 if (Address
>= MmSystemRangeStart
)
852 DPRINT1("Setting kernel address with process context\n");
853 KeBugCheck(MEMORY_MANAGEMENT
);
855 if (PageCount
> (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
||
856 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
>
857 (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
)
859 DPRINT1("Page Count to large\n");
860 KeBugCheck(MEMORY_MANAGEMENT
);
864 Attributes
= ProtectToPTE(flProtect
);
865 if (Attributes
& 0x80000000)
870 if (Address
>= MmSystemRangeStart
)
872 Attributes
&= ~PA_USER
;
873 if (Ke386GlobalPagesEnabled
)
875 Attributes
|= PA_GLOBAL
;
880 Attributes
|= PA_USER
;
884 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
) + 1;
885 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
887 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
889 DPRINT1("Setting physical address but not allowing access at address "
890 "0x%.8X with attributes %x/%x.\n",
891 Addr
, Attributes
, flProtect
);
892 KeBugCheck(MEMORY_MANAGEMENT
);
894 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
895 if (oldPdeOffset
!= PdeOffset
)
897 MmUnmapPageTable(Pt
);
898 Pt
= MmGetPageTableForProcess(Process
, Addr
, TRUE
);
901 KeBugCheck(MEMORY_MANAGEMENT
);
908 oldPdeOffset
= PdeOffset
;
911 MmMarkPageMapped(Pages
[i
]);
912 if (PAGE_MASK((Pte
)) != 0 && !((Pte
) & PA_PRESENT
))
914 KeBugCheck(MEMORY_MANAGEMENT
);
916 if (PAGE_MASK((Pte
)) != 0)
918 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
920 InterlockedExchangePte(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
923 if (Address
> MmSystemRangeStart
||
924 (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024))
926 MiFlushTlb(Pt
, Address
);
932 MmUnmapPageTable(Pt
);
935 return(STATUS_SUCCESS
);
940 MmCreateVirtualMapping(PEPROCESS Process
,
948 for (i
= 0; i
< PageCount
; i
++)
950 if (!MmIsPageInUse(Pages
[i
]))
952 DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages
[i
]));
953 KeBugCheck(MEMORY_MANAGEMENT
);
957 return(MmCreateVirtualMappingUnsafe(Process
,
966 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
971 Entry
= MmGetPageEntryForProcess(Process
, Address
);
974 if (!(Entry
& PA_PRESENT
))
976 Protect
= PAGE_NOACCESS
;
980 if (Entry
& PA_READWRITE
)
982 Protect
= PAGE_READWRITE
;
986 Protect
= PAGE_EXECUTE_READ
;
990 Protect
|= PAGE_NOCACHE
;
994 Protect
|= PAGE_WRITETHROUGH
;
996 if (!(Entry
& PA_USER
))
998 Protect
|= PAGE_SYSTEM
;
1007 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
1009 ULONG Attributes
= 0;
1010 BOOLEAN NoExecute
= FALSE
;
1013 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
1014 Process
, Address
, flProtect
);
1016 Attributes
= ProtectToPTE(flProtect
);
1017 if (Attributes
& 0x80000000)
1021 Attributes
&= 0xfff;
1022 if (Address
>= MmSystemRangeStart
)
1024 Attributes
&= ~PA_USER
;
1025 if (Ke386GlobalPagesEnabled
)
1027 Attributes
|= PA_GLOBAL
;
1032 Attributes
|= PA_USER
;
1035 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1038 KeBugCheck(MEMORY_MANAGEMENT
);
1040 InterlockedExchangePte(Pt
, PAGE_MASK(*Pt
) | Attributes
| (*Pt
& (PA_ACCESSED
|PA_DIRTY
)));
1041 MiFlushTlb(Pt
, Address
);
1047 PHYSICAL_ADDRESS NTAPI
1048 MmGetPhysicalAddress(PVOID vaddr
)
1050 * FUNCTION: Returns the physical address corresponding to a virtual address
1056 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr
);
1057 Pte
= MmGetPageEntryForProcess(NULL
, vaddr
);
1058 if (Pte
!= 0 && Pte
& PA_PRESENT
)
1060 p
.QuadPart
= PAGE_MASK(Pte
);
1061 p
.u
.LowPart
|= (ULONG_PTR
)vaddr
& (PAGE_SIZE
- 1);
1072 MmCreateHyperspaceMapping(PFN_TYPE Page
)
1079 Entry
= PFN_TO_PTE(Page
) | PA_PRESENT
| PA_READWRITE
;
1080 Pte
= (PULONG
)MiAddressToPte(HYPERSPACE
) + Page
% 1024;
1083 for (i
= Page
% 1024; i
< 1024; i
++, Pte
++)
1085 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1092 Pte
= (PULONG
)MiAddressToPte(HYPERSPACE
);
1093 for (i
= 0; i
< Page
% 1024; i
++, Pte
++)
1095 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1100 if (i
>= Page
% 1024)
1102 KeBugCheck(MEMORY_MANAGEMENT
);
1108 for (i
= Page
% 1024; (LONG
)i
>= 0; i
--, Pte
--)
1110 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1117 Pte
= (PULONG
)MiAddressToPte(HYPERSPACE
) + 1023;
1118 for (i
= 1023; i
> Page
% 1024; i
--, Pte
--)
1120 if (0 == InterlockedCompareExchange((PLONG
)Pte
, (LONG
)Entry
, 0))
1125 if (i
<= Page
% 1024)
1127 KeBugCheck(MEMORY_MANAGEMENT
);
1131 Address
= (PVOID
)((ULONG_PTR
)HYPERSPACE
+ i
* PAGE_SIZE
);
1138 MmDeleteHyperspaceMapping(PVOID Address
)
1143 ASSERT (IS_HYPERSPACE(Address
));
1145 Entry
= InterlockedExchangePte(MiAddressToPte(Address
), 0);
1146 Pfn
= PTE_TO_PFN(Entry
);
1154 MmUpdatePageDir(PEPROCESS Process
, PVOID Address
, ULONG Size
)
1156 ULONG StartOffset
, EndOffset
, Offset
;
1159 if (Address
< MmSystemRangeStart
)
1161 KeBugCheck(MEMORY_MANAGEMENT
);
1164 StartOffset
= ADDR_TO_PDE_OFFSET(Address
);
1165 EndOffset
= ADDR_TO_PDE_OFFSET((PVOID
)((ULONG_PTR
)Address
+ Size
));
1167 if (Process
!= NULL
&& Process
!= PsGetCurrentProcess())
1169 Pde
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
[0]));
1173 Pde
= (PULONG
)PAGEDIRECTORY_MAP
;
1175 for (Offset
= StartOffset
; Offset
<= EndOffset
; Offset
++)
1177 if (Offset
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
))
1179 InterlockedCompareExchangePte(&Pde
[Offset
], MmGlobalKernelPageDirectory
[Offset
], 0);
1182 if (Pde
!= (PULONG
)PAGEDIRECTORY_MAP
)
1184 MmDeleteHyperspaceMapping(Pde
);
1191 MmInitGlobalKernelPageDirectory(VOID
)
1194 PULONG CurrentPageDirectory
= (PULONG
)PAGEDIRECTORY_MAP
;
1196 DPRINT("MmInitGlobalKernelPageDirectory()\n");
1198 for (i
= ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
< 1024; i
++)
1200 if (i
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) &&
1201 i
!= ADDR_TO_PDE_OFFSET(HYPERSPACE
) &&
1202 0 == MmGlobalKernelPageDirectory
[i
] && 0 != CurrentPageDirectory
[i
])
1204 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];
1205 if (Ke386GlobalPagesEnabled
)
1207 MmGlobalKernelPageDirectory
[i
] |= PA_GLOBAL
;
1208 CurrentPageDirectory
[i
] |= PA_GLOBAL
;
1217 MiInitPageDirectoryMap(VOID
)
1219 MEMORY_AREA
* kernel_map_desc
= NULL
;
1220 MEMORY_AREA
* hyperspace_desc
= NULL
;
1221 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
1225 DPRINT("MiInitPageDirectoryMap()\n");
1227 BoundaryAddressMultiple
.QuadPart
= 0;
1228 BaseAddress
= (PVOID
)PAGETABLE_MAP
;
1229 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
1237 BoundaryAddressMultiple
);
1238 if (!NT_SUCCESS(Status
))
1240 KeBugCheck(MEMORY_MANAGEMENT
);
1242 BaseAddress
= (PVOID
)HYPERSPACE
;
1243 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
1251 BoundaryAddressMultiple
);
1252 if (!NT_SUCCESS(Status
))
1254 KeBugCheck(MEMORY_MANAGEMENT
);