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 ***************************************************************/
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];