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 ***************************************************************/
15 #include "../ARM3/miarm.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 HYPERSPACE (0xc0400000)
44 #define IS_HYPERSPACE(v) (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
46 ULONG MmGlobalKernelPageDirectory
[1024];
48 #define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT)
49 #define PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
52 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
54 __inline LARGE_INTEGER
PTE_TO_PAGE(ULONG npage
)
57 dummy
.QuadPart
= (LONGLONG
)(PAGE_MASK(npage
));
64 MmProtectToPteMask
[32] =
67 // These are the base MM_ protection flags
70 PTE_READONLY
| PTE_ENABLE_CACHE
,
71 PTE_EXECUTE
| PTE_ENABLE_CACHE
,
72 PTE_EXECUTE_READ
| PTE_ENABLE_CACHE
,
73 PTE_READWRITE
| PTE_ENABLE_CACHE
,
74 PTE_WRITECOPY
| PTE_ENABLE_CACHE
,
75 PTE_EXECUTE_READWRITE
| PTE_ENABLE_CACHE
,
76 PTE_EXECUTE_WRITECOPY
| PTE_ENABLE_CACHE
,
78 // These OR in the MM_NOCACHE flag
81 PTE_READONLY
| PTE_DISABLE_CACHE
,
82 PTE_EXECUTE
| PTE_DISABLE_CACHE
,
83 PTE_EXECUTE_READ
| PTE_DISABLE_CACHE
,
84 PTE_READWRITE
| PTE_DISABLE_CACHE
,
85 PTE_WRITECOPY
| PTE_DISABLE_CACHE
,
86 PTE_EXECUTE_READWRITE
| PTE_DISABLE_CACHE
,
87 PTE_EXECUTE_WRITECOPY
| PTE_DISABLE_CACHE
,
89 // These OR in the MM_DECOMMIT flag, which doesn't seem supported on x86/64/ARM
92 PTE_READONLY
| PTE_ENABLE_CACHE
,
93 PTE_EXECUTE
| PTE_ENABLE_CACHE
,
94 PTE_EXECUTE_READ
| PTE_ENABLE_CACHE
,
95 PTE_READWRITE
| PTE_ENABLE_CACHE
,
96 PTE_WRITECOPY
| PTE_ENABLE_CACHE
,
97 PTE_EXECUTE_READWRITE
| PTE_ENABLE_CACHE
,
98 PTE_EXECUTE_WRITECOPY
| PTE_ENABLE_CACHE
,
100 // These OR in the MM_NOACCESS flag, which seems to enable WriteCombining?
103 PTE_READONLY
| PTE_WRITECOMBINED_CACHE
,
104 PTE_EXECUTE
| PTE_WRITECOMBINED_CACHE
,
105 PTE_EXECUTE_READ
| PTE_WRITECOMBINED_CACHE
,
106 PTE_READWRITE
| PTE_WRITECOMBINED_CACHE
,
107 PTE_WRITECOPY
| PTE_WRITECOMBINED_CACHE
,
108 PTE_EXECUTE_READWRITE
| PTE_WRITECOMBINED_CACHE
,
109 PTE_EXECUTE_WRITECOPY
| PTE_WRITECOMBINED_CACHE
,
112 /* FUNCTIONS ***************************************************************/
114 BOOLEAN
MmUnmapPageTable(PULONG Pt
);
117 MiFlushTlb(PULONG Pt
, PVOID Address
)
119 if ((Pt
&& MmUnmapPageTable(Pt
)) || Address
>= MmSystemRangeStart
)
121 KeInvalidateTlbEntry(Address
);
126 ProtectToPTE(ULONG flProtect
)
128 ULONG Attributes
= 0;
130 if (flProtect
& (PAGE_NOACCESS
|PAGE_GUARD
))
134 else if (flProtect
& PAGE_IS_WRITABLE
)
136 Attributes
= PA_PRESENT
| PA_READWRITE
;
138 else if (flProtect
& (PAGE_IS_READABLE
| PAGE_IS_EXECUTABLE
))
140 Attributes
= PA_PRESENT
;
144 DPRINT1("Unknown main protection type.\n");
145 KeBugCheck(MEMORY_MANAGEMENT
);
148 if (flProtect
& PAGE_SYSTEM
)
153 Attributes
= Attributes
| PA_USER
;
155 if (flProtect
& PAGE_NOCACHE
)
157 Attributes
= Attributes
| PA_CD
;
159 if (flProtect
& PAGE_WRITETHROUGH
)
161 Attributes
= Attributes
| PA_WT
;
167 MmGetPageTableForProcess(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
169 ULONG PdeOffset
= ADDR_TO_PDE_OFFSET(Address
);
175 if (Address
< MmSystemRangeStart
&& Process
&& Process
!= PsGetCurrentProcess())
177 PageDir
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
[0]));
180 KeBugCheck(MEMORY_MANAGEMENT
);
182 if (0 == InterlockedCompareExchangePte(&PageDir
[PdeOffset
], 0, 0))
186 MmDeleteHyperspaceMapping(PageDir
);
189 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
190 if (!NT_SUCCESS(Status
) || Pfn
== 0)
192 KeBugCheck(MEMORY_MANAGEMENT
);
194 Entry
= InterlockedCompareExchangePte(&PageDir
[PdeOffset
], PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
197 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
198 Pfn
= PTE_TO_PFN(Entry
);
203 Pfn
= PTE_TO_PFN(PageDir
[PdeOffset
]);
205 MmDeleteHyperspaceMapping(PageDir
);
206 Pt
= MmCreateHyperspaceMapping(Pfn
);
209 KeBugCheck(MEMORY_MANAGEMENT
);
211 return Pt
+ ADDR_TO_PTE_OFFSET(Address
);
213 PageDir
= (PULONG
)MiAddressToPde(Address
);
214 if (0 == InterlockedCompareExchangePte(PageDir
, 0, 0))
216 if (Address
>= MmSystemRangeStart
)
218 if (0 == InterlockedCompareExchangePte(&MmGlobalKernelPageDirectory
[PdeOffset
], 0, 0))
224 Status
= MmRequestPageMemoryConsumer(MC_SYSTEM
, FALSE
, &Pfn
);
225 if (!NT_SUCCESS(Status
) || Pfn
== 0)
227 KeBugCheck(MEMORY_MANAGEMENT
);
229 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
;
230 if(0 != InterlockedCompareExchangePte(&MmGlobalKernelPageDirectory
[PdeOffset
], Entry
, 0))
232 MmReleasePageMemoryConsumer(MC_SYSTEM
, Pfn
);
234 InterlockedExchangePte(PageDir
, MmGlobalKernelPageDirectory
[PdeOffset
]);
235 RtlZeroMemory(MiPteToAddress(PageDir
), PAGE_SIZE
);
236 return (PULONG
)MiAddressToPte(Address
);
238 InterlockedExchangePte(PageDir
, MmGlobalKernelPageDirectory
[PdeOffset
]);
246 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
247 if (!NT_SUCCESS(Status
) || Pfn
== 0)
249 KeBugCheck(MEMORY_MANAGEMENT
);
251 Entry
= InterlockedCompareExchangePte(PageDir
, PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
254 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
258 return (PULONG
)MiAddressToPte(Address
);
261 BOOLEAN
MmUnmapPageTable(PULONG Pt
)
263 if (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024)
270 MmDeleteHyperspaceMapping((PVOID
)PAGE_ROUND_DOWN(Pt
));
275 static ULONG
MmGetPageEntryForProcess(PEPROCESS Process
, PVOID Address
)
280 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
284 MmUnmapPageTable(Pt
);
292 MmGetPfnForProcess(PEPROCESS Process
,
296 Entry
= MmGetPageEntryForProcess(Process
, Address
);
297 if (!(Entry
& PA_PRESENT
))
301 return(PTE_TO_PFN(Entry
));
306 MmDisableVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOLEAN
* WasDirty
, PPFN_NUMBER Page
)
308 * FUNCTION: Delete a virtual mapping
315 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
318 KeBugCheck(MEMORY_MANAGEMENT
);
321 * Atomically disable the present bit and get the old value.
326 } while (Pte
!= InterlockedCompareExchangePte(Pt
, Pte
& ~PA_PRESENT
, Pte
));
328 MiFlushTlb(Pt
, Address
);
329 WasValid
= (PAGE_MASK(Pte
) != 0);
332 KeBugCheck(MEMORY_MANAGEMENT
);
336 * Return some information to the caller
338 if (WasDirty
!= NULL
)
340 *WasDirty
= Pte
& PA_DIRTY
;
344 *Page
= PTE_TO_PFN(Pte
);
350 MmRawDeleteVirtualMapping(PVOID Address
)
354 Pt
= MmGetPageTableForProcess(NULL
, Address
, FALSE
);
358 * Set the entry to zero
360 InterlockedExchangePte(Pt
, 0);
361 MiFlushTlb(Pt
, Address
);
367 MmDeleteVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOLEAN FreePage
,
368 BOOLEAN
* WasDirty
, PPFN_NUMBER Page
)
370 * FUNCTION: Delete a virtual mapping
373 BOOLEAN WasValid
= FALSE
;
378 DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
379 Process
, Address
, FreePage
, WasDirty
, Page
);
381 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
385 if (WasDirty
!= NULL
)
397 * Atomically set the entry to zero and get the old value.
399 Pte
= InterlockedExchangePte(Pt
, 0);
401 MiFlushTlb(Pt
, Address
);
403 WasValid
= (PAGE_MASK(Pte
) != 0);
406 Pfn
= PTE_TO_PFN(Pte
);
413 if (FreePage
&& WasValid
)
415 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
419 * Return some information to the caller
421 if (WasDirty
!= NULL
)
423 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
433 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
434 SWAPENTRY
* SwapEntry
)
436 * FUNCTION: Delete a virtual mapping
442 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
451 * Atomically set the entry to zero and get the old value.
453 Pte
= InterlockedExchangePte(Pt
, 0);
455 MiFlushTlb(Pt
, Address
);
458 * Return some information to the caller
460 *SwapEntry
= Pte
>> 1;
464 Mmi386MakeKernelPageTableGlobal(PVOID PAddress
)
467 Pde
= (PULONG
)MiAddressToPde(PAddress
);
470 Pt
= MmGetPageTableForProcess(NULL
, PAddress
, FALSE
);
481 MmIsDirtyPage(PEPROCESS Process
, PVOID Address
)
483 return MmGetPageEntryForProcess(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
488 MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
493 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
495 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
496 KeBugCheck(MEMORY_MANAGEMENT
);
499 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
503 KeBugCheck(MEMORY_MANAGEMENT
);
509 } while (Pte
!= InterlockedCompareExchangePte(Pt
, Pte
& ~PA_DIRTY
, Pte
));
513 MiFlushTlb(Pt
, Address
);
517 MmUnmapPageTable(Pt
);
523 MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
528 if (Address
< MmSystemRangeStart
&& Process
== NULL
)
530 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
531 KeBugCheck(MEMORY_MANAGEMENT
);
534 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
537 KeBugCheck(MEMORY_MANAGEMENT
);
543 } while (Pte
!= InterlockedCompareExchangePte(Pt
, Pte
| PA_DIRTY
, Pte
));
544 if (!(Pte
& PA_DIRTY
))
546 MiFlushTlb(Pt
, Address
);
550 MmUnmapPageTable(Pt
);
556 MmEnableVirtualMapping(PEPROCESS Process
, PVOID Address
)
561 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
564 KeBugCheck(MEMORY_MANAGEMENT
);
570 } while (Pte
!= InterlockedCompareExchangePte(Pt
, Pte
| PA_PRESENT
, Pte
));
571 if (!(Pte
& PA_PRESENT
))
573 MiFlushTlb(Pt
, Address
);
577 MmUnmapPageTable(Pt
);
583 MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
585 return MmGetPageEntryForProcess(Process
, Address
) & PA_PRESENT
;
590 MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
593 Entry
= MmGetPageEntryForProcess(Process
, Address
);
594 return !(Entry
& PA_PRESENT
) && (Entry
& 0x800) && Entry
!= 0;
599 MmCreatePageFileMapping(PEPROCESS Process
,
606 if (Process
== NULL
&& Address
< MmSystemRangeStart
)
608 DPRINT1("No process\n");
609 KeBugCheck(MEMORY_MANAGEMENT
);
611 if (Process
!= NULL
&& Address
>= MmSystemRangeStart
)
613 DPRINT1("Setting kernel address with process context\n");
614 KeBugCheck(MEMORY_MANAGEMENT
);
617 if (SwapEntry
& (1 << 31))
619 KeBugCheck(MEMORY_MANAGEMENT
);
622 Pt
= MmGetPageTableForProcess(Process
, Address
, TRUE
);
625 KeBugCheck(MEMORY_MANAGEMENT
);
628 InterlockedExchangePte(Pt
, SwapEntry
<< 1);
631 MiFlushTlb(Pt
, Address
);
635 MmUnmapPageTable(Pt
);
638 return(STATUS_SUCCESS
);
644 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
653 ULONG oldPdeOffset
, PdeOffset
;
656 BOOLEAN NoExecute
= FALSE
;
658 DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
659 Process
, Address
, flProtect
, Pages
, *Pages
, PageCount
);
663 if (Address
< MmSystemRangeStart
)
665 DPRINT1("No process\n");
666 KeBugCheck(MEMORY_MANAGEMENT
);
668 if (PageCount
> 0x10000 ||
669 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> 0x100000)
671 DPRINT1("Page count too large\n");
672 KeBugCheck(MEMORY_MANAGEMENT
);
677 if (Address
>= MmSystemRangeStart
)
679 DPRINT1("Setting kernel address with process context\n");
680 KeBugCheck(MEMORY_MANAGEMENT
);
682 if (PageCount
> (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
||
683 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
>
684 (ULONG_PTR
)MmSystemRangeStart
/ PAGE_SIZE
)
686 DPRINT1("Page Count too large\n");
687 KeBugCheck(MEMORY_MANAGEMENT
);
691 Attributes
= ProtectToPTE(flProtect
);
692 if (Attributes
& 0x80000000)
697 if (Address
>= MmSystemRangeStart
)
699 Attributes
&= ~PA_USER
;
703 Attributes
|= PA_USER
;
707 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
) + 1;
708 for (i
= 0; i
< PageCount
; i
++, Addr
= (PVOID
)((ULONG_PTR
)Addr
+ PAGE_SIZE
))
710 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
712 DPRINT1("Setting physical address but not allowing access at address "
713 "0x%.8X with attributes %x/%x.\n",
714 Addr
, Attributes
, flProtect
);
715 KeBugCheck(MEMORY_MANAGEMENT
);
717 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
718 if (oldPdeOffset
!= PdeOffset
)
720 MmUnmapPageTable(Pt
);
721 Pt
= MmGetPageTableForProcess(Process
, Addr
, TRUE
);
724 KeBugCheck(MEMORY_MANAGEMENT
);
731 oldPdeOffset
= PdeOffset
;
734 if (PAGE_MASK(Pte
) != 0 && !(Pte
& PA_PRESENT
) && (Pte
& 0x800))
736 DPRINT1("Bad PTE %lx\n", Pte
);
737 KeBugCheck(MEMORY_MANAGEMENT
);
739 InterlockedExchangePte(Pt
, PFN_TO_PTE(Pages
[i
]) | Attributes
);
742 if (Address
> MmSystemRangeStart
||
743 (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024))
745 MiFlushTlb(Pt
, Address
);
751 MmUnmapPageTable(Pt
);
754 return(STATUS_SUCCESS
);
759 MmCreateVirtualMapping(PEPROCESS Process
,
767 for (i
= 0; i
< PageCount
; i
++)
769 if (!MmIsPageInUse(Pages
[i
]))
771 DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages
[i
]));
772 KeBugCheck(MEMORY_MANAGEMENT
);
776 return(MmCreateVirtualMappingUnsafe(Process
,
785 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
790 Entry
= MmGetPageEntryForProcess(Process
, Address
);
793 if (!(Entry
& PA_PRESENT
))
795 Protect
= PAGE_NOACCESS
;
799 if (Entry
& PA_READWRITE
)
801 Protect
= PAGE_READWRITE
;
805 Protect
= PAGE_EXECUTE_READ
;
809 Protect
|= PAGE_NOCACHE
;
813 Protect
|= PAGE_WRITETHROUGH
;
815 if (!(Entry
& PA_USER
))
817 Protect
|= PAGE_SYSTEM
;
826 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
828 ULONG Attributes
= 0;
829 BOOLEAN NoExecute
= FALSE
;
832 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
833 Process
, Address
, flProtect
);
835 Attributes
= ProtectToPTE(flProtect
);
837 if (Attributes
& 0x80000000)
842 if (Address
>= MmSystemRangeStart
)
844 Attributes
&= ~PA_USER
;
848 Attributes
|= PA_USER
;
851 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
854 KeBugCheck(MEMORY_MANAGEMENT
);
856 InterlockedExchangePte(Pt
, PAGE_MASK(*Pt
) | Attributes
| (*Pt
& (PA_ACCESSED
|PA_DIRTY
)));
857 MiFlushTlb(Pt
, Address
);
863 PHYSICAL_ADDRESS NTAPI
864 MmGetPhysicalAddress(PVOID vaddr
)
866 * FUNCTION: Returns the physical address corresponding to a virtual address
872 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr
);
873 Pte
= MmGetPageEntryForProcess(NULL
, vaddr
);
874 if (Pte
!= 0 && Pte
& PA_PRESENT
)
876 p
.QuadPart
= PAGE_MASK(Pte
);
877 p
.u
.LowPart
|= (ULONG_PTR
)vaddr
& (PAGE_SIZE
- 1);
888 MmUpdatePageDir(PEPROCESS Process
, PVOID Address
, ULONG Size
)
890 ULONG StartOffset
, EndOffset
, Offset
;
894 // Check if the process isn't there anymore
895 // This is probably a bad sign, since it means the caller is setting cr3 to
898 if ((PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
[0]) == 0) && (Process
!= PsGetCurrentProcess()))
900 DPRINT1("Process: %16s is dead: %p\n", Process
->ImageFileName
, Process
->Pcb
.DirectoryTableBase
[0]);
905 if (Address
< MmSystemRangeStart
)
907 KeBugCheck(MEMORY_MANAGEMENT
);
910 StartOffset
= ADDR_TO_PDE_OFFSET(Address
);
911 EndOffset
= ADDR_TO_PDE_OFFSET((PVOID
)((ULONG_PTR
)Address
+ Size
));
913 if (Process
!= NULL
&& Process
!= PsGetCurrentProcess())
915 Pde
= MmCreateHyperspaceMapping(PTE_TO_PFN(Process
->Pcb
.DirectoryTableBase
[0]));
919 Pde
= (PULONG
)PAGEDIRECTORY_MAP
;
921 for (Offset
= StartOffset
; Offset
<= EndOffset
; Offset
++)
923 if (Offset
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
))
925 InterlockedCompareExchangePte(&Pde
[Offset
], MmGlobalKernelPageDirectory
[Offset
], 0);
928 if (Pde
!= (PULONG
)PAGEDIRECTORY_MAP
)
930 MmDeleteHyperspaceMapping(Pde
);
937 MmInitGlobalKernelPageDirectory(VOID
)
940 PULONG CurrentPageDirectory
= (PULONG
)PAGEDIRECTORY_MAP
;
942 DPRINT("MmInitGlobalKernelPageDirectory()\n");
944 for (i
= ADDR_TO_PDE_OFFSET(MmSystemRangeStart
); i
< 1024; i
++)
946 if (i
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) &&
947 i
!= ADDR_TO_PDE_OFFSET(HYPERSPACE
) &&
948 0 == MmGlobalKernelPageDirectory
[i
] && 0 != CurrentPageDirectory
[i
])
950 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];