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.
19 /* $Id: page.c,v 1.59 2003/08/27 21:28:08 dwelch Exp $
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 ***************************************************************/
31 #include <ddk/ntddk.h>
32 #include <internal/mm.h>
33 #include <internal/i386/mm.h>
34 #include <internal/ex.h>
35 #include <internal/ps.h>
38 #include <internal/debug.h>
40 /* GLOBALS *****************************************************************/
42 #define PA_BIT_PRESENT (0)
43 #define PA_BIT_READWRITE (1)
44 #define PA_BIT_USER (2)
47 #define PA_BIT_ACCESSED (5)
48 #define PA_BIT_DIRTY (6)
50 #define PA_PRESENT (1 << PA_BIT_PRESENT)
51 #define PA_READWRITE (1 << PA_BIT_READWRITE)
52 #define PA_USER (1 << PA_BIT_USER)
53 #define PA_DIRTY (1 << PA_BIT_DIRTY)
54 #define PA_WT (1 << PA_BIT_WT)
55 #define PA_CD (1 << PA_BIT_CD)
56 #define PA_ACCESSED (1 << PA_BIT_ACCESSED)
57 #define PA_DIRTY (1 << PA_BIT_DIRTY)
59 #define PAGETABLE_MAP (0xf0000000)
60 #define PAGEDIRECTORY_MAP (0xf0000000 + (PAGETABLE_MAP / (1024)))
62 ULONG MmGlobalKernelPageDirectory
[1024] = {0, };
64 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
66 /* FUNCTIONS ***************************************************************/
69 MmGetPageDirectory(VOID
)
71 unsigned int page_dir
=0;
72 __asm__("movl %%cr3,%0\n\t"
74 return((PULONG
)page_dir
);
78 ProtectToPTE(ULONG flProtect
)
82 if (flProtect
& PAGE_NOACCESS
|| flProtect
& PAGE_GUARD
)
86 else if (flProtect
& PAGE_READWRITE
|| flProtect
& PAGE_EXECUTE_READWRITE
)
88 Attributes
= PA_PRESENT
| PA_READWRITE
;
90 else if (flProtect
& PAGE_READONLY
|| flProtect
& PAGE_EXECUTE
||
91 flProtect
& PAGE_EXECUTE_READ
)
93 Attributes
= PA_PRESENT
;
97 DPRINT1("Unknown main protection type.\n");
100 if (!(flProtect
& PAGE_SYSTEM
))
102 Attributes
= Attributes
| PA_USER
;
104 if (flProtect
& PAGE_NOCACHE
)
106 Attributes
= Attributes
| PA_CD
;
108 if (flProtect
& PAGE_WRITETHROUGH
)
110 Attributes
= Attributes
| PA_WT
;
115 #define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (4 * 1024 * 1024))
117 #define ADDR_TO_PDE(v) (PULONG)(PAGEDIRECTORY_MAP + \
118 ((((ULONG)(v)) / (1024 * 1024))&(~0x3)))
119 #define ADDR_TO_PTE(v) (PULONG)(PAGETABLE_MAP + ((((ULONG)v / 1024))&(~0x3)))
121 #define ADDR_TO_PDE_OFFSET(v) ((((ULONG)(v)) / (4 * 1024 * 1024)))
123 NTSTATUS
Mmi386ReleaseMmInfo(PEPROCESS Process
)
125 PUSHORT LdtDescriptor
;
128 DPRINT("Mmi386ReleaseMmInfo(Process %x)\n",Process
);
130 LdtDescriptor
= (PUSHORT
) &Process
->Pcb
.LdtDescriptor
[0];
131 LdtBase
= LdtDescriptor
[1] |
132 ((LdtDescriptor
[2] & 0xff) << 16) |
133 ((LdtDescriptor
[3] & ~0xff) << 16);
135 DPRINT("LdtBase: %x\n", LdtBase
);
139 ExFreePool((PVOID
) LdtBase
);
142 MmReleasePageMemoryConsumer(MC_NPPOOL
, Process
->Pcb
.DirectoryTableBase
);
143 Process
->Pcb
.DirectoryTableBase
.QuadPart
= 0LL;
145 DPRINT("Finished Mmi386ReleaseMmInfo()\n");
146 return(STATUS_SUCCESS
);
149 NTSTATUS
MmCopyMmInfo(PEPROCESS Src
, PEPROCESS Dest
)
151 PHYSICAL_ADDRESS PhysPageDirectory
;
152 PULONG PageDirectory
;
153 PKPROCESS KProcess
= &Dest
->Pcb
;
155 DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", Src
, Dest
);
157 PageDirectory
= ExAllocatePage();
158 if (PageDirectory
== NULL
)
160 return(STATUS_UNSUCCESSFUL
);
162 PhysPageDirectory
= MmGetPhysicalAddress(PageDirectory
);
163 KProcess
->DirectoryTableBase
= PhysPageDirectory
;
165 memset(PageDirectory
,0, ADDR_TO_PDE_OFFSET(KERNEL_BASE
) * sizeof(ULONG
));
166 memcpy(PageDirectory
+ ADDR_TO_PDE_OFFSET(KERNEL_BASE
),
167 MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(KERNEL_BASE
),
168 (1024 - ADDR_TO_PDE_OFFSET(KERNEL_BASE
)) * sizeof(ULONG
));
170 DPRINT("Addr %x\n",PAGETABLE_MAP
/ (4*1024*1024));
171 PageDirectory
[PAGETABLE_MAP
/ (4*1024*1024)] =
172 PhysPageDirectory
.u
.LowPart
| PA_PRESENT
| PA_READWRITE
;
174 ExUnmapPage(PageDirectory
);
176 DPRINT("Finished MmCopyMmInfo()\n");
177 return(STATUS_SUCCESS
);
180 VOID
MmDeletePageTable(PEPROCESS Process
, PVOID Address
)
182 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
184 if (Process
!= NULL
&& Process
!= CurrentProcess
)
186 KeAttachProcess(Process
);
188 *(ADDR_TO_PDE(Address
)) = 0;
189 if (Address
>= (PVOID
)KERNEL_BASE
)
192 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
195 if (Process
!= NULL
&& Process
!= CurrentProcess
)
201 VOID
MmFreePageTable(PEPROCESS Process
, PVOID Address
)
203 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
208 if (Process
!= NULL
&& Process
!= CurrentProcess
)
210 KeAttachProcess(Process
);
213 PageTable
= (PULONG
)PAGE_ROUND_DOWN((PVOID
)ADDR_TO_PTE(Address
));
214 for (i
= 0; i
< 1024; i
++)
216 if (PageTable
[i
] != 0)
218 DbgPrint("Page table entry not clear at %x/%x (is %x)\n",
219 ((ULONG
)Address
/ 4*1024*1024), i
, PageTable
[i
]);
223 npage
= *(ADDR_TO_PDE(Address
));
224 *(ADDR_TO_PDE(Address
)) = 0;
227 if (Address
>= (PVOID
)KERNEL_BASE
)
229 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
234 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PAGE(npage
));
236 if (Process
!= NULL
&& Process
!= CurrentProcess
)
242 NTSTATUS
MmGetPageEntry2(PVOID PAddress
, PULONG
* Pte
, BOOLEAN MayWait
)
244 * FUNCTION: Get a pointer to the page table entry for a virtual address
248 PHYSICAL_ADDRESS npage
;
249 BOOLEAN Free
= FALSE
;
253 DPRINT("MmGetPageEntry(Address %x)\n", PAddress
);
255 Pde
= ADDR_TO_PDE(PAddress
);
258 if (PAddress
>= (PVOID
)KERNEL_BASE
)
260 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(PAddress
);
261 oldIrql
= KeRaiseIrqlToSynchLevel();
269 KeLowerIrql(oldIrql
);
270 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, MayWait
, &npage
);
271 if (!NT_SUCCESS(Status
))
275 oldIrql
= KeRaiseIrqlToSynchLevel();
276 /* An other thread can set this pde entry, we must check again */
279 *kePde
= npage
.u
.LowPart
| PA_PRESENT
| PA_READWRITE
;
288 KeLowerIrql(oldIrql
);
292 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, MayWait
, &npage
);
293 if (!NT_SUCCESS(Status
))
297 *Pde
= npage
.u
.LowPart
| PA_PRESENT
| PA_READWRITE
| PA_USER
;
301 *Pte
= (PULONG
)ADDR_TO_PTE(PAddress
);
304 MmReleasePageMemoryConsumer(MC_NPPOOL
, npage
);
306 return STATUS_SUCCESS
;
309 ULONG
MmGetPageEntryForProcess(PEPROCESS Process
, PVOID Address
)
312 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
314 if (Process
!= NULL
&& Process
!= CurrentProcess
)
316 KeAttachProcess(Process
);
318 Entry
= *MmGetPageEntry(Address
);
319 if (Process
!= NULL
&& Process
!= CurrentProcess
)
326 ULONG
MmGetPageEntry1(PVOID PAddress
)
328 * FUNCTION: Get a pointer to the page table entry for a virtual address
334 DPRINT("MmGetPageEntry(Address %x)\n", PAddress
);
336 Pde
= ADDR_TO_PDE(PAddress
);
339 if (PAddress
>= (PVOID
)KERNEL_BASE
)
341 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(PAddress
);
346 Entry
= *(PULONG
)ADDR_TO_PTE(PAddress
);
352 Entry
= *(PULONG
)ADDR_TO_PTE(PAddress
);
357 ULONG
MmGetPageEntryForProcess1(PEPROCESS Process
, PVOID Address
)
360 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
362 if (Process
!= NULL
&& Process
!= CurrentProcess
)
364 KeAttachProcess(Process
);
366 Entry
= MmGetPageEntry1(Address
);
367 if (Process
!= NULL
&& Process
!= CurrentProcess
)
376 MmGetPhysicalAddressForProcess(PEPROCESS Process
,
381 PageEntry
= MmGetPageEntryForProcess(Process
, Address
);
383 if (!(PageEntry
& PA_PRESENT
))
385 return((LARGE_INTEGER
)0LL);
387 return(PTE_TO_PAGE(PageEntry
));
391 MmDisableVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOL
* WasDirty
, PHYSICAL_ADDRESS
* PhysicalAddr
)
393 * FUNCTION: Delete a virtual mapping
398 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
402 * If we are setting a page in another process we need to be in its
405 if (Process
!= NULL
&& Process
!= CurrentProcess
)
407 KeAttachProcess(Process
);
411 * Set the page directory entry, we may have to copy the entry from
412 * the global page directory.
414 Pde
= ADDR_TO_PDE(Address
);
416 MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)] != 0)
418 (*Pde
) = MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)];
427 * Atomically set the entry to zero and get the old value.
429 Pte
= *ADDR_TO_PTE(Address
);
430 *ADDR_TO_PTE(Address
) = Pte
& (~PA_PRESENT
);
432 WasValid
= (PAGE_MASK(Pte
) != 0);
439 * If necessary go back to the original context
441 if (Process
!= NULL
&& Process
!= CurrentProcess
)
447 * Return some information to the caller
449 if (WasDirty
!= NULL
)
451 *WasDirty
= Pte
& PA_DIRTY
;
453 if (PhysicalAddr
!= NULL
)
455 PhysicalAddr
->u
.HighPart
= 0;
456 PhysicalAddr
->u
.LowPart
= PAGE_MASK(Pte
);
461 MmRawDeleteVirtualMapping(PVOID Address
)
466 * Set the page directory entry, we may have to copy the entry from
467 * the global page directory.
469 Pde
= ADDR_TO_PDE(Address
);
470 if (*Pde
== 0 && Address
>= (PVOID
)KERNEL_BASE
)
472 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(Address
);
486 * Set the entry to zero
488 *ADDR_TO_PTE(Address
) = 0;
493 MmDeleteVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOL FreePage
,
494 BOOL
* WasDirty
, PHYSICAL_ADDRESS
* PhysicalAddr
)
496 * FUNCTION: Delete a virtual mapping
501 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
505 * If we are setting a page in another process we need to be in its
508 if (Process
!= NULL
&& Process
!= CurrentProcess
)
510 KeAttachProcess(Process
);
514 * Set the page directory entry, we may have to copy the entry from
515 * the global page directory.
517 Pde
= ADDR_TO_PDE(Address
);
518 if (*Pde
== 0 && Address
>= (PVOID
)KERNEL_BASE
)
520 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(Address
);
530 if (Process
!= NULL
&& Process
!= CurrentProcess
)
534 if (WasDirty
!= NULL
)
538 if (PhysicalAddr
!= NULL
)
540 *PhysicalAddr
= (LARGE_INTEGER
)0LL;
546 * Atomically set the entry to zero and get the old value.
548 Pte
= (ULONG
)InterlockedExchange((PLONG
)ADDR_TO_PTE(Address
), 0);
550 WasValid
= (PAGE_MASK(Pte
) != 0);
553 MmMarkPageUnmapped(PTE_TO_PAGE(Pte
));
555 if (FreePage
&& WasValid
)
557 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PAGE(Pte
));
561 * Decrement the reference count for this page table.
563 if (Process
!= NULL
&& WasValid
&&
564 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
565 Address
< (PVOID
)KERNEL_BASE
)
569 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
571 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]--;
572 if (Ptrc
[ADDR_TO_PAGE_TABLE(Address
)] == 0)
574 MmFreePageTable(Process
, Address
);
579 * If necessary go back to the original context
581 if (Process
!= NULL
&& Process
!= CurrentProcess
)
587 * Return some information to the caller
589 if (WasDirty
!= NULL
)
600 if (PhysicalAddr
!= NULL
)
602 *PhysicalAddr
= PTE_TO_PAGE(Pte
);
607 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
608 SWAPENTRY
* SwapEntry
)
610 * FUNCTION: Delete a virtual mapping
615 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
616 BOOLEAN WasValid
= FALSE
;
619 * If we are setting a page in another process we need to be in its
622 if (Process
!= NULL
&& Process
!= CurrentProcess
)
624 KeAttachProcess(Process
);
628 * Set the page directory entry, we may have to copy the entry from
629 * the global page directory.
631 Pde
= ADDR_TO_PDE(Address
);
634 if (Address
>= (PVOID
)KERNEL_BASE
)
636 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(Address
);
646 if (Process
!= NULL
&& Process
!= CurrentProcess
)
655 * Atomically set the entry to zero and get the old value.
657 Pte
= (ULONG
)InterlockedExchange((PLONG
)ADDR_TO_PTE(Address
), 0);
660 WasValid
= PAGE_MASK(Pte
) == 0 ? FALSE
: TRUE
;
663 * Decrement the reference count for this page table.
665 if (Process
!= NULL
&& WasValid
&&
666 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
667 Address
< (PVOID
)KERNEL_BASE
)
671 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
673 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]--;
674 if (Ptrc
[ADDR_TO_PAGE_TABLE(Address
)] == 0)
676 MmFreePageTable(Process
, Address
);
681 * If necessary go back to the original context
683 if (Process
!= NULL
&& Process
!= CurrentProcess
)
689 * Return some information to the caller
691 *SwapEntry
= Pte
>> 1;
695 Mmi386MakeKernelPageTableGlobal(PVOID PAddress
)
699 Pde
= ADDR_TO_PDE(PAddress
);
702 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(PAddress
);
713 BOOLEAN
MmIsPageTablePresent(PVOID PAddress
)
717 Pde
= ADDR_TO_PDE(PAddress
);
720 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(PAddress
);
731 NTSTATUS
MmCreatePageTable(PVOID PAddress
)
734 PHYSICAL_ADDRESS npage
;
737 DPRINT("MmGetPageEntry(Address %x)\n", PAddress
);
739 Pde
= ADDR_TO_PDE(PAddress
);
740 DPRINT("page_dir %x *page_dir %x\n", Pde
, *Pde
);
741 if (*Pde
== 0 && PAddress
>= (PVOID
)KERNEL_BASE
)
743 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(PAddress
);
748 return STATUS_SUCCESS
;
750 /* Should we create a kernel page table? */
751 DPRINT1("!!!!!!!!!!!!!!!!!!\n");
752 return STATUS_UNSUCCESSFUL
;
757 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &npage
);
758 if (!NT_SUCCESS(Status
))
763 *Pde
= npage
.u
.LowPart
| PA_PRESENT
| PA_READWRITE
| PA_USER
;
766 return(STATUS_SUCCESS
);
769 PULONG
MmGetPageEntry(PVOID PAddress
)
771 * FUNCTION: Get a pointer to the page table entry for a virtual address
775 PHYSICAL_ADDRESS npage
;
777 BOOLEAN Free
= FALSE
;
780 DPRINT("MmGetPageEntry(Address %x)\n", PAddress
);
782 Pde
= ADDR_TO_PDE(PAddress
);
783 DPRINT("page_dir %x *page_dir %x\n",Pde
,*Pde
);
786 if (PAddress
>= (PVOID
)KERNEL_BASE
)
788 oldIrql
= KeRaiseIrqlToSynchLevel();
789 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(PAddress
);
797 KeLowerIrql(oldIrql
);
798 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &npage
);
799 if (!NT_SUCCESS(Status
))
804 oldIrql
= KeRaiseIrqlToSynchLevel();
813 *Pde
= *kePde
= npage
.u
.LowPart
| PA_PRESENT
| PA_READWRITE
;
817 KeLowerIrql(oldIrql
);
821 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &npage
);
822 if (!NT_SUCCESS(Status
))
827 *Pde
= npage
.u
.LowPart
| PA_PRESENT
| PA_READWRITE
| PA_USER
;
832 MmReleasePageMemoryConsumer(MC_NPPOOL
, npage
);
836 return ADDR_TO_PTE(PAddress
);
839 BOOLEAN
MmIsDirtyPage(PEPROCESS Process
, PVOID Address
)
841 return((MmGetPageEntryForProcess(Process
, Address
)) & PA_DIRTY
);
845 MmIsAccessedAndResetAccessPage(PEPROCESS Process
, PVOID Address
)
848 PEPROCESS CurrentProcess
;
853 CurrentProcess
= PsGetCurrentProcess();
854 if (Process
!= CurrentProcess
)
856 KeAttachProcess(Process
);
861 if (((ULONG
)Address
& ~0xFFF) < KERNEL_BASE
)
863 DPRINT1("MmIsAccessedAndResetAccessPage is called for user space without a process.\n");
866 CurrentProcess
= NULL
;
869 PageEntry
= MmGetPageEntry(Address
);
870 Accessed
= (*PageEntry
) & PA_ACCESSED
;
873 (*PageEntry
) = (*PageEntry
) & (~PA_ACCESSED
);
876 if (Process
!= CurrentProcess
)
884 VOID
MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
887 PEPROCESS CurrentProcess
;
891 CurrentProcess
= PsGetCurrentProcess();
892 if (Process
!= CurrentProcess
)
894 KeAttachProcess(Process
);
899 if (((ULONG
)Address
& ~0xFFF) < KERNEL_BASE
)
901 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
904 CurrentProcess
= NULL
;
906 PageEntry
= MmGetPageEntry(Address
);
907 (*PageEntry
) = (*PageEntry
) & (~PA_DIRTY
);
909 if (Process
!= CurrentProcess
)
915 VOID
MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
918 PEPROCESS CurrentProcess
= NULL
;
922 CurrentProcess
= PsGetCurrentProcess();
923 if (Process
!= CurrentProcess
)
925 KeAttachProcess(Process
);
930 if (((ULONG
)Address
& ~0xFFF) < KERNEL_BASE
)
932 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
935 CurrentProcess
= NULL
;
937 PageEntry
= MmGetPageEntry(Address
);
938 (*PageEntry
) = (*PageEntry
) | PA_DIRTY
;
940 if (Process
!= CurrentProcess
)
946 VOID
MmEnableVirtualMapping(PEPROCESS Process
, PVOID Address
)
949 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
951 if (Process
!= CurrentProcess
)
953 KeAttachProcess(Process
);
955 PageEntry
= MmGetPageEntry(Address
);
956 (*PageEntry
) = (*PageEntry
) | PA_PRESENT
;
958 if (Process
!= CurrentProcess
)
964 BOOLEAN
MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
966 return((MmGetPageEntryForProcess1(Process
, Address
)) & PA_PRESENT
);
969 BOOLEAN
MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
972 Pte
= MmGetPageEntryForProcess1(Process
, Address
);
973 return((!(Pte
& PA_PRESENT
)) && Pte
!= 0);
977 MmCreateVirtualMappingDump(PVOID Address
,
979 PHYSICAL_ADDRESS PhysicalAddress
)
985 if (Address
< (PVOID
)KERNEL_BASE
)
987 DPRINT1("No process\n");
991 Attributes
= ProtectToPTE(flProtect
);
992 if (!(Attributes
& PA_PRESENT
) && PhysicalAddress
.QuadPart
!= 0)
994 DPRINT1("Setting physical address but not allowing access at address "
995 "0x%.8X with attributes %x/%x.\n",
996 Address
, Attributes
, flProtect
);
1000 Status
= MmGetPageEntry2(Address
, &Pte
, FALSE
);
1001 if (!NT_SUCCESS(Status
))
1005 if (PAGE_MASK((*Pte
)) != 0 && !((*Pte
) & PA_PRESENT
))
1009 *Pte
= PhysicalAddress
.QuadPart
| Attributes
;
1011 return(STATUS_SUCCESS
);
1016 MmCreateVirtualMappingForKernel(PVOID Address
,
1018 PHYSICAL_ADDRESS PhysicalAddress
)
1020 PEPROCESS CurrentProcess
;
1024 PEPROCESS Process
= NULL
;
1026 if (Process
!= NULL
)
1028 CurrentProcess
= PsGetCurrentProcess();
1032 CurrentProcess
= NULL
;
1035 if (Process
== NULL
&& Address
< (PVOID
)KERNEL_BASE
)
1037 DPRINT1("No process\n");
1040 if (Process
!= NULL
&& Address
>= (PVOID
)KERNEL_BASE
)
1042 DPRINT1("Setting kernel address with process context\n");
1045 Attributes
= ProtectToPTE(flProtect
);
1047 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1049 KeAttachProcess(Process
);
1052 Status
= MmGetPageEntry2(Address
, &Pte
, FALSE
);
1053 if (!NT_SUCCESS(Status
))
1055 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1061 if (PAGE_MASK((*Pte
)) != 0 && !((*Pte
) & PA_PRESENT
))
1065 if (PAGE_MASK((*Pte
)) != 0)
1067 MmMarkPageUnmapped(PTE_TO_PAGE((*Pte
)));
1069 *Pte
= PhysicalAddress
.QuadPart
| Attributes
;
1070 if (Process
!= NULL
&&
1071 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1072 Address
< (PVOID
)KERNEL_BASE
&&
1073 Attributes
& PA_PRESENT
)
1077 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1079 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]++;
1082 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1086 return(STATUS_SUCCESS
);
1090 MmCreatePageFileMapping(PEPROCESS Process
,
1092 SWAPENTRY SwapEntry
)
1094 PEPROCESS CurrentProcess
;
1098 if (Process
!= NULL
)
1100 CurrentProcess
= PsGetCurrentProcess();
1104 CurrentProcess
= NULL
;
1107 if (Process
== NULL
&& Address
< (PVOID
)KERNEL_BASE
)
1109 DPRINT1("No process\n");
1112 if (Process
!= NULL
&& Address
>= (PVOID
)KERNEL_BASE
)
1114 DPRINT1("Setting kernel address with process context\n");
1117 if (SwapEntry
& (1 << 31))
1122 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1124 KeAttachProcess(Process
);
1127 Status
= MmGetPageEntry2(Address
, &Pte
, FALSE
);
1128 if (!NT_SUCCESS(Status
))
1130 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1136 if (PAGE_MASK((*Pte
)) != 0)
1138 MmMarkPageUnmapped(PTE_TO_PAGE((*Pte
)));
1140 *Pte
= SwapEntry
<< 1;
1141 if (Process
!= NULL
&&
1142 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1143 Address
< (PVOID
)KERNEL_BASE
)
1147 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1149 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]++;
1152 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1156 return(STATUS_SUCCESS
);
1162 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
1165 PHYSICAL_ADDRESS PhysicalAddress
,
1168 PEPROCESS CurrentProcess
;
1173 if (Process
!= NULL
)
1175 CurrentProcess
= PsGetCurrentProcess();
1179 CurrentProcess
= NULL
;
1182 if (Process
== NULL
&& Address
< (PVOID
)KERNEL_BASE
)
1184 DPRINT1("No process\n");
1187 if (Process
!= NULL
&& Address
>= (PVOID
)KERNEL_BASE
)
1189 DPRINT1("Setting kernel address with process context\n");
1192 MmMarkPageMapped(PhysicalAddress
);
1194 Attributes
= ProtectToPTE(flProtect
);
1195 if (!(Attributes
& PA_PRESENT
) && PhysicalAddress
.QuadPart
!= 0)
1197 DPRINT1("Setting physical address but not allowing access at address "
1198 "0x%.8X with attributes %x/%x.\n",
1199 Address
, Attributes
, flProtect
);
1203 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1205 KeAttachProcess(Process
);
1208 Status
= MmGetPageEntry2(Address
, &Pte
, MayWait
);
1209 if (!NT_SUCCESS(Status
))
1211 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1217 if (PAGE_MASK((*Pte
)) != 0 && !((*Pte
) & PA_PRESENT
))
1221 if (PAGE_MASK((*Pte
)) != 0)
1223 MmMarkPageUnmapped(PTE_TO_PAGE((*Pte
)));
1225 *Pte
= PhysicalAddress
.QuadPart
| Attributes
;
1226 if (Process
!= NULL
&&
1227 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1228 Address
< (PVOID
)KERNEL_BASE
&&
1229 Attributes
& PA_PRESENT
)
1233 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1235 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]++;
1238 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1242 return(STATUS_SUCCESS
);
1246 MmCreateVirtualMapping(PEPROCESS Process
,
1249 PHYSICAL_ADDRESS PhysicalAddress
,
1252 if (!MmIsUsablePage(PhysicalAddress
))
1254 DPRINT1("Page at address %x not usable\n", PhysicalAddress
);
1258 return(MmCreateVirtualMappingUnsafe(Process
,
1266 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
1271 Entry
= MmGetPageEntryForProcess1(Process
, Address
);
1273 if (!(Entry
& PA_PRESENT
))
1275 Protect
= PAGE_NOACCESS
;
1277 else if (Entry
& PA_READWRITE
)
1279 Protect
= PAGE_READWRITE
;
1283 Protect
= PAGE_EXECUTE_READ
;
1289 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
1291 ULONG Attributes
= 0;
1293 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
1295 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
1296 Process
, Address
, flProtect
);
1298 Attributes
= ProtectToPTE(flProtect
);
1299 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1301 KeAttachProcess(Process
);
1303 PageEntry
= MmGetPageEntry(Address
);
1304 (*PageEntry
) = PAGE_MASK(*PageEntry
) | Attributes
;
1306 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1315 PHYSICAL_ADDRESS STDCALL
1316 MmGetPhysicalAddress(PVOID vaddr
)
1318 * FUNCTION: Returns the physical address corresponding to a virtual address
1324 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr
);
1326 Pte
= *MmGetPageEntry(vaddr
);
1327 if (Pte
& PA_PRESENT
)
1329 p
.QuadPart
= PAGE_MASK(Pte
);
1341 MmUpdateStackPageDir(PULONG LocalPageDir
, PKTHREAD PThread
)
1343 unsigned EntryBase
= ADDR_TO_PDE_OFFSET(PThread
->StackLimit
);
1344 unsigned EntryTop
= ADDR_TO_PDE_OFFSET(PThread
->InitialStack
- PAGE_SIZE
);
1346 if (0 == LocalPageDir
[EntryBase
])
1348 LocalPageDir
[EntryBase
] = MmGlobalKernelPageDirectory
[EntryBase
];
1350 if (EntryBase
!= EntryTop
&& 0 == LocalPageDir
[EntryTop
])
1352 LocalPageDir
[EntryTop
] = MmGlobalKernelPageDirectory
[EntryTop
];
1357 MmInitGlobalKernelPageDirectory(VOID
)
1360 PULONG CurrentPageDirectory
= (PULONG
)PAGEDIRECTORY_MAP
;
1362 for (i
= ADDR_TO_PDE_OFFSET(KERNEL_BASE
); i
< 1024; i
++)
1364 if (i
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) &&
1365 0 == MmGlobalKernelPageDirectory
[i
] && 0 != CurrentPageDirectory
[i
])
1367 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];