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.34 2002/01/08 00:49:01 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 /* FUNCTIONS ***************************************************************/
67 MmGetPageDirectory(VOID
)
69 unsigned int page_dir
=0;
70 __asm__("movl %%cr3,%0\n\t"
72 return((PULONG
)page_dir
);
76 ProtectToPTE(ULONG flProtect
)
80 if (flProtect
& PAGE_NOACCESS
|| flProtect
& PAGE_GUARD
)
84 else if (flProtect
& PAGE_READWRITE
|| flProtect
& PAGE_EXECUTE_READWRITE
)
86 Attributes
= PA_PRESENT
| PA_READWRITE
;
88 else if (flProtect
& PAGE_READONLY
|| flProtect
& PAGE_EXECUTE
||
89 flProtect
& PAGE_EXECUTE_READ
)
91 Attributes
= PA_PRESENT
;
95 DPRINT1("Unknown main protection type.\n");
98 if (!(flProtect
& PAGE_SYSTEM
))
100 Attributes
= Attributes
| PA_USER
;
102 if (flProtect
& PAGE_NOCACHE
)
104 Attributes
= Attributes
| PA_CD
;
106 if (flProtect
& PAGE_WRITETHROUGH
)
108 Attributes
= Attributes
| PA_WT
;
113 #define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (4 * 1024 * 1024))
115 #define ADDR_TO_PDE(v) (PULONG)(PAGEDIRECTORY_MAP + \
116 (((ULONG)v / (1024 * 1024))&(~0x3)))
117 #define ADDR_TO_PTE(v) (PULONG)(PAGETABLE_MAP + ((((ULONG)v / 1024))&(~0x3)))
119 #define ADDR_TO_PDE_OFFSET(v) (((ULONG)v / (4 * 1024 * 1024)))
121 NTSTATUS
Mmi386ReleaseMmInfo(PEPROCESS Process
)
123 DPRINT("Mmi386ReleaseMmInfo(Process %x)\n",Process
);
125 MmDereferencePage(Process
->Pcb
.DirectoryTableBase
[0]);
126 Process
->Pcb
.DirectoryTableBase
[0] = NULL
;
128 DPRINT("Finished Mmi386ReleaseMmInfo()\n");
129 return(STATUS_SUCCESS
);
132 NTSTATUS
MmCopyMmInfo(PEPROCESS Src
, PEPROCESS Dest
)
134 PULONG PhysPageDirectory
;
135 PULONG PageDirectory
;
136 PULONG CurrentPageDirectory
;
137 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
= (PULONG
)(MmGetPhysicalAddress(PageDirectory
)).u
.LowPart
;
148 KProcess
->DirectoryTableBase
[0] = PhysPageDirectory
;
149 CurrentPageDirectory
= (PULONG
)PAGEDIRECTORY_MAP
;
151 memset(PageDirectory
,0,PAGESIZE
);
152 for (i
=768; i
<896; i
++)
154 PageDirectory
[i
] = CurrentPageDirectory
[i
];
156 for (i
=961; i
<1024; i
++)
158 PageDirectory
[i
] = CurrentPageDirectory
[i
];
160 DPRINT("Addr %x\n",PAGETABLE_MAP
/ (4*1024*1024));
161 PageDirectory
[PAGETABLE_MAP
/ (4*1024*1024)] =
162 (ULONG
)PhysPageDirectory
| 0x7;
164 ExUnmapPage(PageDirectory
);
166 DPRINT("Finished MmCopyMmInfo()\n");
167 return(STATUS_SUCCESS
);
170 VOID
MmDeletePageTable(PEPROCESS Process
, PVOID Address
)
172 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
174 if (Process
!= NULL
&& Process
!= CurrentProcess
)
176 KeAttachProcess(Process
);
178 *(ADDR_TO_PDE(Address
)) = 0;
179 if (Address
>= (PVOID
)KERNEL_BASE
)
181 MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)] = 0;
184 if (Process
!= NULL
&& Process
!= CurrentProcess
)
190 VOID
MmFreePageTable(PEPROCESS Process
, PVOID Address
)
192 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
197 if (Process
!= NULL
&& Process
!= CurrentProcess
)
199 KeAttachProcess(Process
);
201 PageTable
= (PULONG
)PAGE_ROUND_DOWN((PVOID
)ADDR_TO_PTE(Address
));
202 for (i
= 0; i
< 1024; i
++)
204 if (PageTable
[i
] != 0)
206 DbgPrint("Page table entry not clear at %x/%x (is %x)\n",
207 ((ULONG
)Address
/ 4*1024*1024), i
, PageTable
[i
]);
211 npage
= *(ADDR_TO_PDE(Address
));
212 *(ADDR_TO_PDE(Address
)) = 0;
213 if (Address
>= (PVOID
)KERNEL_BASE
)
215 MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)] = 0;
217 MmDereferencePage((PVOID
)PAGE_MASK(npage
));
219 if (Process
!= NULL
&& Process
!= CurrentProcess
)
225 NTSTATUS
MmGetPageEntry2(PVOID PAddress
, PULONG
* Pte
, BOOLEAN MayWait
)
227 * FUNCTION: Get a pointer to the page table entry for a virtual address
231 ULONG Address
= (ULONG
)PAddress
;
234 DPRINT("MmGetPageEntry(Address %x)\n", Address
);
236 Pde
= ADDR_TO_PDE(Address
);
239 if (Address
>= KERNEL_BASE
&&
240 MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)] != 0)
242 (*Pde
) = MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)];
248 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, MayWait
, (PVOID
*)&npage
);
249 if (!NT_SUCCESS(Status
))
253 (*Pde
) = npage
| 0x7;
254 if (Address
>= KERNEL_BASE
)
256 MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)] =
259 memset((PVOID
)PAGE_ROUND_DOWN(ADDR_TO_PTE(Address
)), 0, PAGESIZE
);
263 *Pte
= ADDR_TO_PTE(Address
);
264 return(STATUS_SUCCESS
);
267 ULONG
MmGetPageEntryForProcess(PEPROCESS Process
, PVOID Address
)
270 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
272 if (Process
!= NULL
&& Process
!= CurrentProcess
)
274 KeAttachProcess(Process
);
276 Entry
= *MmGetPageEntry(Address
);
277 if (Process
!= NULL
&& Process
!= CurrentProcess
)
284 ULONG
MmGetPageEntry1(PVOID PAddress
)
286 * FUNCTION: Get a pointer to the page table entry for a virtual address
291 ULONG Address
= (ULONG
)PAddress
;
293 DPRINT("MmGetPageEntry(Address %x)\n", Address
);
295 page_dir
= ADDR_TO_PDE(Address
);
296 if ((*page_dir
) == 0 &&
297 MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)] != 0)
299 (*page_dir
) = MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)];
302 DPRINT("page_dir %x *page_dir %x\n",page_dir
,*page_dir
);
303 if ((*page_dir
) == 0)
307 page_tlb
= ADDR_TO_PTE(Address
);
308 DPRINT("page_tlb %x\n",page_tlb
);
312 ULONG
MmGetPageEntryForProcess1(PEPROCESS Process
, PVOID Address
)
315 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
317 if (Process
!= NULL
&& Process
!= CurrentProcess
)
319 KeAttachProcess(Process
);
321 Entry
= MmGetPageEntry1(Address
);
322 if (Process
!= NULL
&& Process
!= CurrentProcess
)
330 ULONG
MmGetPhysicalAddressForProcess(PEPROCESS Process
,
335 PageEntry
= MmGetPageEntryForProcess(Process
, Address
);
337 if (!(PageEntry
& PA_PRESENT
))
341 return(PAGE_MASK(PageEntry
));
345 MmDisableVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOL
* WasDirty
, ULONG
* PhysicalAddr
)
347 * FUNCTION: Delete a virtual mapping
352 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
356 * If we are setting a page in another process we need to be in its
359 if (Process
!= NULL
&& Process
!= CurrentProcess
)
361 KeAttachProcess(Process
);
365 * Set the page directory entry, we may have to copy the entry from
366 * the global page directory.
368 Pde
= ADDR_TO_PDE(Address
);
370 MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)] != 0)
372 (*Pde
) = MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)];
381 * Atomically set the entry to zero and get the old value.
383 Pte
= *ADDR_TO_PTE(Address
);
384 *ADDR_TO_PTE(Address
) = Pte
& (~PA_PRESENT
);
386 WasValid
= (PAGE_MASK(Pte
) != 0);
393 * If necessary go back to the original context
395 if (Process
!= NULL
&& Process
!= CurrentProcess
)
401 * Return some information to the caller
403 if (WasDirty
!= NULL
)
405 *WasDirty
= Pte
& PA_DIRTY
;
407 if (PhysicalAddr
!= NULL
)
409 *PhysicalAddr
= PAGE_MASK(Pte
);
414 MmDeleteVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOL FreePage
,
415 BOOL
* WasDirty
, ULONG
* PhysicalAddr
)
417 * FUNCTION: Delete a virtual mapping
422 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
426 * If we are setting a page in another process we need to be in its
429 if (Process
!= NULL
&& Process
!= CurrentProcess
)
431 KeAttachProcess(Process
);
435 * Set the page directory entry, we may have to copy the entry from
436 * the global page directory.
438 Pde
= ADDR_TO_PDE(Address
);
440 MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)] != 0)
442 (*Pde
) = MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)];
447 if (Process
!= NULL
&& Process
!= CurrentProcess
)
451 if (WasDirty
!= NULL
)
455 if (PhysicalAddr
!= NULL
)
463 * Atomically set the entry to zero and get the old value.
465 Pte
= (ULONG
)InterlockedExchange((PLONG
)ADDR_TO_PTE(Address
), 0);
467 WasValid
= (PAGE_MASK(Pte
) != 0);
470 MmMarkPageUnmapped((PVOID
)PAGE_MASK(Pte
));
472 if (FreePage
&& WasValid
)
474 MmDereferencePage((PVOID
)PAGE_MASK(Pte
));
478 * Decrement the reference count for this page table.
480 if (Process
!= NULL
&& WasValid
&&
481 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
482 ADDR_TO_PAGE_TABLE(Address
) < 768)
486 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
488 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]--;
489 if (Ptrc
[ADDR_TO_PAGE_TABLE(Address
)] == 0)
491 MmFreePageTable(Process
, Address
);
496 * If necessary go back to the original context
498 if (Process
!= NULL
&& Process
!= CurrentProcess
)
504 * Return some information to the caller
506 if (WasDirty
!= NULL
)
517 if (PhysicalAddr
!= NULL
)
519 *PhysicalAddr
= PAGE_MASK(Pte
);
524 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
525 SWAPENTRY
* SwapEntry
)
527 * FUNCTION: Delete a virtual mapping
532 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
536 * If we are setting a page in another process we need to be in its
539 if (Process
!= NULL
&& Process
!= CurrentProcess
)
541 KeAttachProcess(Process
);
545 * Set the page directory entry, we may have to copy the entry from
546 * the global page directory.
548 Pde
= ADDR_TO_PDE(Address
);
550 MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)] != 0)
552 (*Pde
) = MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)];
557 if (Process
!= NULL
&& Process
!= CurrentProcess
)
566 * Atomically set the entry to zero and get the old value.
568 Pte
= (ULONG
)InterlockedExchange((PLONG
)ADDR_TO_PTE(Address
), 0);
572 * Decrement the reference count for this page table.
574 if (Process
!= NULL
&& WasValid
&&
575 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
576 ADDR_TO_PAGE_TABLE(Address
) < 768)
580 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
582 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]--;
583 if (Ptrc
[ADDR_TO_PAGE_TABLE(Address
)] == 0)
585 MmFreePageTable(Process
, Address
);
590 * If necessary go back to the original context
592 if (Process
!= NULL
&& Process
!= CurrentProcess
)
598 * Return some information to the caller
600 *SwapEntry
= Pte
>> 1;
604 Mmi386MakeKernelPageTableGlobal(PVOID PAddress
)
607 ULONG Address
= (ULONG
)PAddress
;
609 page_dir
= ADDR_TO_PDE(Address
);
610 if ((*page_dir
) == 0 &&
611 MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)] != 0)
613 (*page_dir
) = MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)];
620 BOOLEAN
MmIsPageTablePresent(PVOID PAddress
)
623 ULONG Address
= (ULONG
)PAddress
;
625 page_dir
= ADDR_TO_PDE(Address
);
626 if ((*page_dir
) == 0 &&
627 MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)] != 0)
629 (*page_dir
) = MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)];
632 return((*page_dir
) == 0);
635 NTSTATUS
MmCreatePageTable(PVOID PAddress
)
638 ULONG Address
= (ULONG
)PAddress
;
641 DPRINT("MmGetPageEntry(Address %x)\n", Address
);
643 page_dir
= ADDR_TO_PDE(Address
);
644 DPRINT("page_dir %x *page_dir %x\n",page_dir
,*page_dir
);
645 if ((*page_dir
) == 0 &&
646 MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)] != 0)
648 (*page_dir
) = MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)];
651 if ((*page_dir
) == 0)
654 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, (PVOID
*)&npage
);
655 if (!NT_SUCCESS(Status
))
659 (*page_dir
) = npage
| 0x7;
660 memset((PVOID
)PAGE_ROUND_DOWN(ADDR_TO_PTE(Address
)), 0, PAGESIZE
);
663 return(STATUS_SUCCESS
);
666 PULONG
MmGetPageEntry(PVOID PAddress
)
668 * FUNCTION: Get a pointer to the page table entry for a virtual address
673 ULONG Address
= (ULONG
)PAddress
;
676 DPRINT("MmGetPageEntry(Address %x)\n", Address
);
678 page_dir
= ADDR_TO_PDE(Address
);
679 DPRINT("page_dir %x *page_dir %x\n",page_dir
,*page_dir
);
680 if ((*page_dir
) == 0 &&
681 MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)] != 0)
683 (*page_dir
) = MmGlobalKernelPageDirectory
[ADDR_TO_PDE_OFFSET(Address
)];
686 if ((*page_dir
) == 0)
689 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, (PVOID
*)&npage
);
690 if (!NT_SUCCESS(Status
))
694 (*page_dir
) = npage
| 0x7;
695 memset((PVOID
)PAGE_ROUND_DOWN(ADDR_TO_PTE(Address
)), 0, PAGESIZE
);
698 page_tlb
= ADDR_TO_PTE(Address
);
699 DPRINT("page_tlb %x\n",page_tlb
);
703 BOOLEAN
MmIsPageDirty(PEPROCESS Process
, PVOID Address
)
705 return((MmGetPageEntryForProcess(Process
, Address
)) & PA_DIRTY
);
709 MmIsAccessedAndResetAccessPage(PEPROCESS Process
, PVOID Address
)
712 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
715 if (Process
!= CurrentProcess
)
717 KeAttachProcess(Process
);
719 PageEntry
= MmGetPageEntry(Address
);
720 Accessed
= (*PageEntry
) & PA_ACCESSED
;
723 (*PageEntry
) = (*PageEntry
) & (~PA_ACCESSED
);
726 if (Process
!= CurrentProcess
)
734 VOID
MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
737 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
739 if (Process
!= CurrentProcess
)
741 KeAttachProcess(Process
);
743 PageEntry
= MmGetPageEntry(Address
);
744 (*PageEntry
) = (*PageEntry
) & (~PA_DIRTY
);
746 if (Process
!= CurrentProcess
)
752 VOID
MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
755 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
757 if (Process
!= CurrentProcess
)
759 KeAttachProcess(Process
);
761 PageEntry
= MmGetPageEntry(Address
);
762 (*PageEntry
) = (*PageEntry
) | PA_DIRTY
;
764 if (Process
!= CurrentProcess
)
770 VOID
MmEnableVirtualMapping(PEPROCESS Process
, PVOID Address
)
773 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
775 if (Process
!= CurrentProcess
)
777 KeAttachProcess(Process
);
779 PageEntry
= MmGetPageEntry(Address
);
780 (*PageEntry
) = (*PageEntry
) | PA_PRESENT
;
782 if (Process
!= CurrentProcess
)
788 BOOLEAN
MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
790 return((MmGetPageEntryForProcess1(Process
, Address
)) & PA_PRESENT
);
793 BOOLEAN
MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
796 Pte
= MmGetPageEntryForProcess1(Process
, Address
);
797 return((!(Pte
& PA_PRESENT
)) && Pte
!= 0);
801 MmCreateVirtualMappingForKernel(PVOID Address
,
803 ULONG PhysicalAddress
)
805 PEPROCESS CurrentProcess
;
809 PEPROCESS Process
= NULL
;
813 CurrentProcess
= PsGetCurrentProcess();
817 CurrentProcess
= NULL
;
820 if (Process
== NULL
&& Address
< (PVOID
)KERNEL_BASE
)
822 DPRINT1("No process\n");
825 if (Process
!= NULL
&& Address
>= (PVOID
)KERNEL_BASE
)
827 DPRINT1("Setting kernel address with process context\n");
830 Attributes
= ProtectToPTE(flProtect
);
832 if (Process
!= NULL
&& Process
!= CurrentProcess
)
834 KeAttachProcess(Process
);
837 Status
= MmGetPageEntry2(Address
, &Pte
, FALSE
);
838 if (!NT_SUCCESS(Status
))
840 if (Process
!= NULL
&& Process
!= CurrentProcess
)
846 if (PAGE_MASK((*Pte
)) != 0 && !((*Pte
) & PA_PRESENT
))
850 if (PAGE_MASK((*Pte
)) != 0)
852 MmMarkPageUnmapped((PVOID
)PAGE_MASK((*Pte
)));
854 *Pte
= PhysicalAddress
| Attributes
;
855 if (Process
!= NULL
&&
856 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
857 ADDR_TO_PAGE_TABLE(Address
) < 768 &&
858 Attributes
& PA_PRESENT
)
862 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
864 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]++;
867 if (Process
!= NULL
&& Process
!= CurrentProcess
)
871 return(STATUS_SUCCESS
);
875 MmCreatePageFileMapping(PEPROCESS Process
,
879 PEPROCESS CurrentProcess
;
885 CurrentProcess
= PsGetCurrentProcess();
889 CurrentProcess
= NULL
;
892 if (Process
== NULL
&& Address
< (PVOID
)KERNEL_BASE
)
894 DPRINT1("No process\n");
897 if (Process
!= NULL
&& Address
>= (PVOID
)KERNEL_BASE
)
899 DPRINT1("Setting kernel address with process context\n");
902 if (SwapEntry
& (1 << 31))
907 if (Process
!= NULL
&& Process
!= CurrentProcess
)
909 KeAttachProcess(Process
);
912 Status
= MmGetPageEntry2(Address
, &Pte
, FALSE
);
913 if (!NT_SUCCESS(Status
))
915 if (Process
!= NULL
&& Process
!= CurrentProcess
)
921 if (PAGE_MASK((*Pte
)) != 0)
923 MmMarkPageUnmapped((PVOID
)PAGE_MASK((*Pte
)));
925 *Pte
= SwapEntry
<< 1;
926 if (Process
!= NULL
&&
927 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
928 ADDR_TO_PAGE_TABLE(Address
) < 768)
932 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
934 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]++;
937 if (Process
!= NULL
&& Process
!= CurrentProcess
)
941 return(STATUS_SUCCESS
);
945 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
948 ULONG PhysicalAddress
,
951 PEPROCESS CurrentProcess
;
958 CurrentProcess
= PsGetCurrentProcess();
962 CurrentProcess
= NULL
;
965 if (Process
== NULL
&& Address
< (PVOID
)KERNEL_BASE
)
967 DPRINT1("No process\n");
970 if (Process
!= NULL
&& Address
>= (PVOID
)KERNEL_BASE
)
972 DPRINT1("Setting kernel address with process context\n");
975 MmMarkPageMapped((PVOID
)PhysicalAddress
);
977 Attributes
= ProtectToPTE(flProtect
);
978 if (!(Attributes
& PA_PRESENT
) && PhysicalAddress
!= 0)
980 DPRINT1("Setting physical address but not allowing access at address "
981 "0x%.8X with attributes %x/%x.\n",
982 Address
, Attributes
, flProtect
);
986 if (Process
!= NULL
&& Process
!= CurrentProcess
)
988 KeAttachProcess(Process
);
991 Status
= MmGetPageEntry2(Address
, &Pte
, MayWait
);
992 if (!NT_SUCCESS(Status
))
994 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1000 if (PAGE_MASK((*Pte
)) != 0 && !((*Pte
) & PA_PRESENT
))
1004 if (PAGE_MASK((*Pte
)) != 0)
1006 MmMarkPageUnmapped((PVOID
)PAGE_MASK((*Pte
)));
1008 *Pte
= PhysicalAddress
| Attributes
;
1009 if (Process
!= NULL
&&
1010 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1011 ADDR_TO_PAGE_TABLE(Address
) < 768 &&
1012 Attributes
& PA_PRESENT
)
1016 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1018 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]++;
1021 if (Process
!= NULL
&& Process
!= CurrentProcess
)
1025 return(STATUS_SUCCESS
);
1029 MmCreateVirtualMapping(PEPROCESS Process
,
1032 ULONG PhysicalAddress
,
1035 if (!MmIsUsablePage((PVOID
)PhysicalAddress
))
1037 DPRINT1("Page at address %x not usable\n", PhysicalAddress
);
1041 return(MmCreateVirtualMappingUnsafe(Process
,
1049 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
1054 Entry
= MmGetPageEntryForProcess1(Process
, Address
);
1056 if (!(Entry
& PA_PRESENT
))
1058 Protect
= PAGE_NOACCESS
;
1060 else if (Entry
& PA_READWRITE
)
1062 Protect
= PAGE_READWRITE
;
1066 Protect
= PAGE_EXECUTE_READ
;
1072 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
1074 ULONG Attributes
= 0;
1076 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
1078 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
1079 Process
, Address
, flProtect
);
1081 Attributes
= ProtectToPTE(flProtect
);
1082 if (Process
!= CurrentProcess
)
1084 KeAttachProcess(Process
);
1086 PageEntry
= MmGetPageEntry(Address
);
1087 (*PageEntry
) = PAGE_MASK(*PageEntry
) | Attributes
;
1089 if (Process
!= CurrentProcess
)
1095 PHYSICAL_ADDRESS STDCALL
1096 MmGetPhysicalAddress(PVOID vaddr
)
1098 * FUNCTION: Returns the physical address corresponding to a virtual address
1104 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr
);
1106 Pte
= *MmGetPageEntry(vaddr
);
1107 if (Pte
& PA_PRESENT
)
1109 p
.QuadPart
= PAGE_MASK(Pte
);