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.54 2003/07/11 01:23:15 royce 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 DPRINT("Mmi386ReleaseMmInfo(Process %x)\n",Process
);
127 MmReleasePageMemoryConsumer(MC_NPPOOL
, Process
->Pcb
.DirectoryTableBase
);
128 Process
->Pcb
.DirectoryTableBase
.QuadPart
= 0LL;
130 DPRINT("Finished Mmi386ReleaseMmInfo()\n");
131 return(STATUS_SUCCESS
);
134 NTSTATUS
MmCopyMmInfo(PEPROCESS Src
, PEPROCESS Dest
)
136 PHYSICAL_ADDRESS PhysPageDirectory
;
137 PULONG PageDirectory
;
138 PKPROCESS KProcess
= &Dest
->Pcb
;
140 DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", Src
, Dest
);
142 PageDirectory
= ExAllocatePage();
143 if (PageDirectory
== NULL
)
145 return(STATUS_UNSUCCESSFUL
);
147 PhysPageDirectory
= MmGetPhysicalAddress(PageDirectory
);
148 KProcess
->DirectoryTableBase
= PhysPageDirectory
;
150 memset(PageDirectory
,0, ADDR_TO_PDE_OFFSET(KERNEL_BASE
) * sizeof(ULONG
));
151 memcpy(PageDirectory
+ ADDR_TO_PDE_OFFSET(KERNEL_BASE
),
152 MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(KERNEL_BASE
),
153 (1024 - ADDR_TO_PDE_OFFSET(KERNEL_BASE
)) * sizeof(ULONG
));
155 DPRINT("Addr %x\n",PAGETABLE_MAP
/ (4*1024*1024));
156 PageDirectory
[PAGETABLE_MAP
/ (4*1024*1024)] =
157 PhysPageDirectory
.u
.LowPart
| PA_PRESENT
| PA_READWRITE
;
159 ExUnmapPage(PageDirectory
);
161 DPRINT("Finished MmCopyMmInfo()\n");
162 return(STATUS_SUCCESS
);
165 VOID
MmDeletePageTable(PEPROCESS Process
, PVOID Address
)
167 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
169 if (Process
!= NULL
&& Process
!= CurrentProcess
)
171 KeAttachProcess(Process
);
173 *(ADDR_TO_PDE(Address
)) = 0;
174 if (Address
>= (PVOID
)KERNEL_BASE
)
177 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
180 if (Process
!= NULL
&& Process
!= CurrentProcess
)
186 VOID
MmFreePageTable(PEPROCESS Process
, PVOID Address
)
188 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
193 if (Process
!= NULL
&& Process
!= CurrentProcess
)
195 KeAttachProcess(Process
);
198 PageTable
= (PULONG
)PAGE_ROUND_DOWN((PVOID
)ADDR_TO_PTE(Address
));
199 for (i
= 0; i
< 1024; i
++)
201 if (PageTable
[i
] != 0)
203 DbgPrint("Page table entry not clear at %x/%x (is %x)\n",
204 ((ULONG
)Address
/ 4*1024*1024), i
, PageTable
[i
]);
208 npage
= *(ADDR_TO_PDE(Address
));
209 *(ADDR_TO_PDE(Address
)) = 0;
212 if (Address
>= (PVOID
)KERNEL_BASE
)
214 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
219 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PAGE(npage
));
221 if (Process
!= NULL
&& Process
!= CurrentProcess
)
227 NTSTATUS
MmGetPageEntry2(PVOID PAddress
, PULONG
* Pte
, BOOLEAN MayWait
)
229 * FUNCTION: Get a pointer to the page table entry for a virtual address
233 PHYSICAL_ADDRESS npage
;
234 BOOLEAN Free
= FALSE
;
238 DPRINT("MmGetPageEntry(Address %x)\n", PAddress
);
240 Pde
= ADDR_TO_PDE(PAddress
);
243 if (PAddress
>= (PVOID
)KERNEL_BASE
)
245 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(PAddress
);
246 oldIrql
= KeRaiseIrqlToSynchLevel();
254 KeLowerIrql(oldIrql
);
255 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, MayWait
, &npage
);
256 if (!NT_SUCCESS(Status
))
260 oldIrql
= KeRaiseIrqlToSynchLevel();
261 /* An other thread can set this pde entry, we must check again */
264 *kePde
= npage
.u
.LowPart
| PA_PRESENT
| PA_READWRITE
;
273 KeLowerIrql(oldIrql
);
277 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, MayWait
, &npage
);
278 if (!NT_SUCCESS(Status
))
282 *Pde
= npage
.u
.LowPart
| PA_PRESENT
| PA_READWRITE
| PA_USER
;
286 *Pte
= (PULONG
)ADDR_TO_PTE(PAddress
);
289 MmReleasePageMemoryConsumer(MC_NPPOOL
, npage
);
291 return STATUS_SUCCESS
;
294 ULONG
MmGetPageEntryForProcess(PEPROCESS Process
, PVOID Address
)
297 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
299 if (Process
!= NULL
&& Process
!= CurrentProcess
)
301 KeAttachProcess(Process
);
303 Entry
= *MmGetPageEntry(Address
);
304 if (Process
!= NULL
&& Process
!= CurrentProcess
)
311 ULONG
MmGetPageEntry1(PVOID PAddress
)
313 * FUNCTION: Get a pointer to the page table entry for a virtual address
319 DPRINT("MmGetPageEntry(Address %x)\n", PAddress
);
321 Pde
= ADDR_TO_PDE(PAddress
);
324 if (PAddress
>= (PVOID
)KERNEL_BASE
)
326 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(PAddress
);
331 Entry
= *(PULONG
)ADDR_TO_PTE(PAddress
);
337 Entry
= *(PULONG
)ADDR_TO_PTE(PAddress
);
342 ULONG
MmGetPageEntryForProcess1(PEPROCESS Process
, PVOID Address
)
345 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
347 if (Process
!= NULL
&& Process
!= CurrentProcess
)
349 KeAttachProcess(Process
);
351 Entry
= MmGetPageEntry1(Address
);
352 if (Process
!= NULL
&& Process
!= CurrentProcess
)
361 MmGetPhysicalAddressForProcess(PEPROCESS Process
,
366 PageEntry
= MmGetPageEntryForProcess(Process
, Address
);
368 if (!(PageEntry
& PA_PRESENT
))
370 return((LARGE_INTEGER
)0LL);
372 return(PTE_TO_PAGE(PageEntry
));
376 MmDisableVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOL
* WasDirty
, PHYSICAL_ADDRESS
* PhysicalAddr
)
378 * FUNCTION: Delete a virtual mapping
383 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
387 * If we are setting a page in another process we need to be in its
390 if (Process
!= NULL
&& Process
!= CurrentProcess
)
392 KeAttachProcess(Process
);
396 * Set the page directory entry, we may have to copy the entry from
397 * the global page directory.
399 Pde
= ADDR_TO_PDE(Address
);
401 MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)] != 0)
403 (*Pde
) = MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)];
412 * Atomically set the entry to zero and get the old value.
414 Pte
= *ADDR_TO_PTE(Address
);
415 *ADDR_TO_PTE(Address
) = Pte
& (~PA_PRESENT
);
417 WasValid
= (PAGE_MASK(Pte
) != 0);
424 * If necessary go back to the original context
426 if (Process
!= NULL
&& Process
!= CurrentProcess
)
432 * Return some information to the caller
434 if (WasDirty
!= NULL
)
436 *WasDirty
= Pte
& PA_DIRTY
;
438 if (PhysicalAddr
!= NULL
)
440 PhysicalAddr
->u
.HighPart
= 0;
441 PhysicalAddr
->u
.LowPart
= PAGE_MASK(Pte
);
446 MmDeleteVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOL FreePage
,
447 BOOL
* WasDirty
, PHYSICAL_ADDRESS
* PhysicalAddr
)
449 * FUNCTION: Delete a virtual mapping
454 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
458 * If we are setting a page in another process we need to be in its
461 if (Process
!= NULL
&& Process
!= CurrentProcess
)
463 KeAttachProcess(Process
);
467 * Set the page directory entry, we may have to copy the entry from
468 * the global page directory.
470 Pde
= ADDR_TO_PDE(Address
);
471 if (*Pde
== 0 && Address
>= (PVOID
)KERNEL_BASE
)
473 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(Address
);
483 if (Process
!= NULL
&& Process
!= CurrentProcess
)
487 if (WasDirty
!= NULL
)
491 if (PhysicalAddr
!= NULL
)
493 *PhysicalAddr
= (LARGE_INTEGER
)0LL;
499 * Atomically set the entry to zero and get the old value.
501 Pte
= (ULONG
)InterlockedExchange((PLONG
)ADDR_TO_PTE(Address
), 0);
503 WasValid
= (PAGE_MASK(Pte
) != 0);
506 MmMarkPageUnmapped(PTE_TO_PAGE(Pte
));
508 if (FreePage
&& WasValid
)
510 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PAGE(Pte
));
514 * Decrement the reference count for this page table.
516 if (Process
!= NULL
&& WasValid
&&
517 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
518 Address
< (PVOID
)KERNEL_BASE
)
522 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
524 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]--;
525 if (Ptrc
[ADDR_TO_PAGE_TABLE(Address
)] == 0)
527 MmFreePageTable(Process
, Address
);
532 * If necessary go back to the original context
534 if (Process
!= NULL
&& Process
!= CurrentProcess
)
540 * Return some information to the caller
542 if (WasDirty
!= NULL
)
553 if (PhysicalAddr
!= NULL
)
555 *PhysicalAddr
= PTE_TO_PAGE(Pte
);
560 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
561 SWAPENTRY
* SwapEntry
)
563 * FUNCTION: Delete a virtual mapping
568 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
569 BOOLEAN WasValid
= FALSE
;
572 * If we are setting a page in another process we need to be in its
575 if (Process
!= NULL
&& Process
!= CurrentProcess
)
577 KeAttachProcess(Process
);
581 * Set the page directory entry, we may have to copy the entry from
582 * the global page directory.
584 Pde
= ADDR_TO_PDE(Address
);
587 if (Address
>= (PVOID
)KERNEL_BASE
)
589 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(Address
);
599 if (Process
!= NULL
&& Process
!= CurrentProcess
)
608 * Atomically set the entry to zero and get the old value.
610 Pte
= (ULONG
)InterlockedExchange((PLONG
)ADDR_TO_PTE(Address
), 0);
613 WasValid
= PAGE_MASK(Pte
) == 0 ? FALSE
: TRUE
;
616 * Decrement the reference count for this page table.
618 if (Process
!= NULL
&& WasValid
&&
619 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
620 Address
< (PVOID
)KERNEL_BASE
)
624 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
626 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]--;
627 if (Ptrc
[ADDR_TO_PAGE_TABLE(Address
)] == 0)
629 MmFreePageTable(Process
, Address
);
634 * If necessary go back to the original context
636 if (Process
!= NULL
&& Process
!= CurrentProcess
)
642 * Return some information to the caller
644 *SwapEntry
= Pte
>> 1;
648 Mmi386MakeKernelPageTableGlobal(PVOID PAddress
)
652 Pde
= ADDR_TO_PDE(PAddress
);
655 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(PAddress
);
666 BOOLEAN
MmIsPageTablePresent(PVOID PAddress
)
670 Pde
= ADDR_TO_PDE(PAddress
);
673 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(PAddress
);
684 NTSTATUS
MmCreatePageTable(PVOID PAddress
)
687 PHYSICAL_ADDRESS npage
;
690 DPRINT("MmGetPageEntry(Address %x)\n", PAddress
);
692 Pde
= ADDR_TO_PDE(PAddress
);
693 DPRINT("page_dir %x *page_dir %x\n", Pde
, *Pde
);
694 if (*Pde
== 0 && PAddress
>= (PVOID
)KERNEL_BASE
)
696 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(PAddress
);
701 return STATUS_SUCCESS
;
703 /* Should we create a kernel page table? */
704 DPRINT1("!!!!!!!!!!!!!!!!!!\n");
705 return STATUS_UNSUCCESSFUL
;
710 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &npage
);
711 if (!NT_SUCCESS(Status
))
716 *Pde
= npage
.u
.LowPart
| PA_PRESENT
| PA_READWRITE
| PA_USER
;
719 return(STATUS_SUCCESS
);
722 PULONG
MmGetPageEntry(PVOID PAddress
)
724 * FUNCTION: Get a pointer to the page table entry for a virtual address
728 PHYSICAL_ADDRESS npage
;
730 BOOLEAN Free
= FALSE
;
733 DPRINT("MmGetPageEntry(Address %x)\n", PAddress
);
735 Pde
= ADDR_TO_PDE(PAddress
);
736 DPRINT("page_dir %x *page_dir %x\n",Pde
,*Pde
);
739 if (PAddress
>= (PVOID
)KERNEL_BASE
)
741 oldIrql
= KeRaiseIrqlToSynchLevel();
742 kePde
= MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(PAddress
);
750 KeLowerIrql(oldIrql
);
751 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &npage
);
752 if (!NT_SUCCESS(Status
))
757 oldIrql
= KeRaiseIrqlToSynchLevel();
766 *Pde
= *kePde
= npage
.u
.LowPart
| PA_PRESENT
| PA_READWRITE
;
770 KeLowerIrql(oldIrql
);
774 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &npage
);
775 if (!NT_SUCCESS(Status
))
780 *Pde
= npage
.u
.LowPart
| PA_PRESENT
| PA_READWRITE
| PA_USER
;
785 MmReleasePageMemoryConsumer(MC_NPPOOL
, npage
);
789 return ADDR_TO_PTE(PAddress
);
792 BOOLEAN
MmIsDirtyPage(PEPROCESS Process
, PVOID Address
)
794 return((MmGetPageEntryForProcess(Process
, Address
)) & PA_DIRTY
);
798 MmIsAccessedAndResetAccessPage(PEPROCESS Process
, PVOID Address
)
801 PEPROCESS CurrentProcess
;
806 CurrentProcess
= PsGetCurrentProcess();
807 if (Process
!= CurrentProcess
)
809 KeAttachProcess(Process
);
814 if (((ULONG
)Address
& ~0xFFF) < KERNEL_BASE
)
816 DPRINT1("MmIsAccessedAndResetAccessPage is called for user space without a process.\n");
819 CurrentProcess
= NULL
;
822 PageEntry
= MmGetPageEntry(Address
);
823 Accessed
= (*PageEntry
) & PA_ACCESSED
;
826 (*PageEntry
) = (*PageEntry
) & (~PA_ACCESSED
);
829 if (Process
!= CurrentProcess
)
837 VOID
MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
840 PEPROCESS CurrentProcess
;
844 CurrentProcess
= PsGetCurrentProcess();
845 if (Process
!= CurrentProcess
)
847 KeAttachProcess(Process
);
852 if (((ULONG
)Address
& ~0xFFF) < KERNEL_BASE
)
854 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
857 CurrentProcess
= NULL
;
859 PageEntry
= MmGetPageEntry(Address
);
860 (*PageEntry
) = (*PageEntry
) & (~PA_DIRTY
);
862 if (Process
!= CurrentProcess
)
868 VOID
MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
871 PEPROCESS CurrentProcess
= NULL
;
875 CurrentProcess
= PsGetCurrentProcess();
876 if (Process
!= CurrentProcess
)
878 KeAttachProcess(Process
);
883 if (((ULONG
)Address
& ~0xFFF) < KERNEL_BASE
)
885 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
888 CurrentProcess
= NULL
;
890 PageEntry
= MmGetPageEntry(Address
);
891 (*PageEntry
) = (*PageEntry
) | PA_DIRTY
;
893 if (Process
!= CurrentProcess
)
899 VOID
MmEnableVirtualMapping(PEPROCESS Process
, PVOID Address
)
902 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
904 if (Process
!= CurrentProcess
)
906 KeAttachProcess(Process
);
908 PageEntry
= MmGetPageEntry(Address
);
909 (*PageEntry
) = (*PageEntry
) | PA_PRESENT
;
911 if (Process
!= CurrentProcess
)
917 BOOLEAN
MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
919 return((MmGetPageEntryForProcess1(Process
, Address
)) & PA_PRESENT
);
922 BOOLEAN
MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
925 Pte
= MmGetPageEntryForProcess1(Process
, Address
);
926 return((!(Pte
& PA_PRESENT
)) && Pte
!= 0);
930 MmCreateVirtualMappingForKernel(PVOID Address
,
932 PHYSICAL_ADDRESS PhysicalAddress
)
934 PEPROCESS CurrentProcess
;
938 PEPROCESS Process
= NULL
;
942 CurrentProcess
= PsGetCurrentProcess();
946 CurrentProcess
= NULL
;
949 if (Process
== NULL
&& Address
< (PVOID
)KERNEL_BASE
)
951 DPRINT1("No process\n");
954 if (Process
!= NULL
&& Address
>= (PVOID
)KERNEL_BASE
)
956 DPRINT1("Setting kernel address with process context\n");
959 Attributes
= ProtectToPTE(flProtect
);
961 if (Process
!= NULL
&& Process
!= CurrentProcess
)
963 KeAttachProcess(Process
);
966 Status
= MmGetPageEntry2(Address
, &Pte
, FALSE
);
967 if (!NT_SUCCESS(Status
))
969 if (Process
!= NULL
&& Process
!= CurrentProcess
)
975 if (PAGE_MASK((*Pte
)) != 0 && !((*Pte
) & PA_PRESENT
))
979 if (PAGE_MASK((*Pte
)) != 0)
981 MmMarkPageUnmapped(PTE_TO_PAGE((*Pte
)));
983 *Pte
= PhysicalAddress
.QuadPart
| Attributes
;
984 if (Process
!= NULL
&&
985 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
986 Address
< (PVOID
)KERNEL_BASE
&&
987 Attributes
& PA_PRESENT
)
991 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
993 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]++;
996 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1000 return(STATUS_SUCCESS
);
1004 MmCreatePageFileMapping(PEPROCESS Process
,
1006 SWAPENTRY SwapEntry
)
1008 PEPROCESS CurrentProcess
;
1012 if (Process
!= NULL
)
1014 CurrentProcess
= PsGetCurrentProcess();
1018 CurrentProcess
= NULL
;
1021 if (Process
== NULL
&& Address
< (PVOID
)KERNEL_BASE
)
1023 DPRINT1("No process\n");
1026 if (Process
!= NULL
&& Address
>= (PVOID
)KERNEL_BASE
)
1028 DPRINT1("Setting kernel address with process context\n");
1031 if (SwapEntry
& (1 << 31))
1036 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1038 KeAttachProcess(Process
);
1041 Status
= MmGetPageEntry2(Address
, &Pte
, FALSE
);
1042 if (!NT_SUCCESS(Status
))
1044 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1050 if (PAGE_MASK((*Pte
)) != 0)
1052 MmMarkPageUnmapped(PTE_TO_PAGE((*Pte
)));
1054 *Pte
= SwapEntry
<< 1;
1055 if (Process
!= NULL
&&
1056 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1057 Address
< (PVOID
)KERNEL_BASE
)
1061 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1063 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]++;
1066 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1070 return(STATUS_SUCCESS
);
1074 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
1077 PHYSICAL_ADDRESS PhysicalAddress
,
1080 PEPROCESS CurrentProcess
;
1085 if (Process
!= NULL
)
1087 CurrentProcess
= PsGetCurrentProcess();
1091 CurrentProcess
= NULL
;
1094 if (Process
== NULL
&& Address
< (PVOID
)KERNEL_BASE
)
1096 DPRINT1("No process\n");
1099 if (Process
!= NULL
&& Address
>= (PVOID
)KERNEL_BASE
)
1101 DPRINT1("Setting kernel address with process context\n");
1104 MmMarkPageMapped(PhysicalAddress
);
1106 Attributes
= ProtectToPTE(flProtect
);
1107 if (!(Attributes
& PA_PRESENT
) && PhysicalAddress
.QuadPart
!= 0)
1109 DPRINT1("Setting physical address but not allowing access at address "
1110 "0x%.8X with attributes %x/%x.\n",
1111 Address
, Attributes
, flProtect
);
1115 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1117 KeAttachProcess(Process
);
1120 Status
= MmGetPageEntry2(Address
, &Pte
, MayWait
);
1121 if (!NT_SUCCESS(Status
))
1123 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1129 if (PAGE_MASK((*Pte
)) != 0 && !((*Pte
) & PA_PRESENT
))
1133 if (PAGE_MASK((*Pte
)) != 0)
1135 MmMarkPageUnmapped(PTE_TO_PAGE((*Pte
)));
1137 *Pte
= PhysicalAddress
.QuadPart
| Attributes
;
1138 if (Process
!= NULL
&&
1139 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1140 Address
< (PVOID
)KERNEL_BASE
&&
1141 Attributes
& PA_PRESENT
)
1145 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1147 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]++;
1150 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1154 return(STATUS_SUCCESS
);
1158 MmCreateVirtualMapping(PEPROCESS Process
,
1161 PHYSICAL_ADDRESS PhysicalAddress
,
1164 if (!MmIsUsablePage(PhysicalAddress
))
1166 DPRINT1("Page at address %x not usable\n", PhysicalAddress
);
1170 return(MmCreateVirtualMappingUnsafe(Process
,
1178 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
1183 Entry
= MmGetPageEntryForProcess1(Process
, Address
);
1185 if (!(Entry
& PA_PRESENT
))
1187 Protect
= PAGE_NOACCESS
;
1189 else if (Entry
& PA_READWRITE
)
1191 Protect
= PAGE_READWRITE
;
1195 Protect
= PAGE_EXECUTE_READ
;
1201 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
1203 ULONG Attributes
= 0;
1205 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
1207 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
1208 Process
, Address
, flProtect
);
1210 Attributes
= ProtectToPTE(flProtect
);
1211 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1213 KeAttachProcess(Process
);
1215 PageEntry
= MmGetPageEntry(Address
);
1216 (*PageEntry
) = PAGE_MASK(*PageEntry
) | Attributes
;
1218 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1227 PHYSICAL_ADDRESS STDCALL
1228 MmGetPhysicalAddress(PVOID vaddr
)
1230 * FUNCTION: Returns the physical address corresponding to a virtual address
1236 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr
);
1238 Pte
= *MmGetPageEntry(vaddr
);
1239 if (Pte
& PA_PRESENT
)
1241 p
.QuadPart
= PAGE_MASK(Pte
);
1253 MmUpdateStackPageDir(PULONG LocalPageDir
, PKTHREAD PThread
)
1255 unsigned EntryBase
= ADDR_TO_PDE_OFFSET(PThread
->StackLimit
);
1256 unsigned EntryTop
= ADDR_TO_PDE_OFFSET(PThread
->InitialStack
- PAGE_SIZE
);
1258 if (0 == LocalPageDir
[EntryBase
])
1260 LocalPageDir
[EntryBase
] = MmGlobalKernelPageDirectory
[EntryBase
];
1262 if (EntryBase
!= EntryTop
&& 0 == LocalPageDir
[EntryTop
])
1264 LocalPageDir
[EntryTop
] = MmGlobalKernelPageDirectory
[EntryTop
];
1269 MmInitGlobalKernelPageDirectory(VOID
)
1272 PULONG CurrentPageDirectory
= (PULONG
)PAGEDIRECTORY_MAP
;
1274 for (i
= ADDR_TO_PDE_OFFSET(KERNEL_BASE
); i
< 1024; i
++)
1276 if (i
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) &&
1277 0 == MmGlobalKernelPageDirectory
[i
] && 0 != CurrentPageDirectory
[i
])
1279 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];