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.72 2004/09/07 11:08:16 hbirr 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 ***************************************************************/
33 #include <internal/debug.h>
35 /* GLOBALS *****************************************************************/
37 #define PA_BIT_PRESENT (0)
38 #define PA_BIT_READWRITE (1)
39 #define PA_BIT_USER (2)
42 #define PA_BIT_ACCESSED (5)
43 #define PA_BIT_DIRTY (6)
44 #define PA_BIT_GLOBAL (8)
46 #define PA_PRESENT (1 << PA_BIT_PRESENT)
47 #define PA_READWRITE (1 << PA_BIT_READWRITE)
48 #define PA_USER (1 << PA_BIT_USER)
49 #define PA_DIRTY (1 << PA_BIT_DIRTY)
50 #define PA_WT (1 << PA_BIT_WT)
51 #define PA_CD (1 << PA_BIT_CD)
52 #define PA_ACCESSED (1 << PA_BIT_ACCESSED)
53 #define PA_GLOBAL (1 << PA_BIT_GLOBAL)
55 #define PAGETABLE_MAP (0xf0000000)
56 #define PAGEDIRECTORY_MAP (0xf0000000 + (PAGETABLE_MAP / (1024)))
58 ULONG MmGlobalKernelPageDirectory
[1024] = {0, };
60 #define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT)
61 #define PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
64 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
66 __inline LARGE_INTEGER
PTE_TO_PAGE(ULONG npage
)
69 dummy
.QuadPart
= (LONGLONG
)(PAGE_MASK(npage
));
74 extern ULONG Ke386CpuidFlags
;
76 /* FUNCTIONS ***************************************************************/
79 MmGetPageDirectory(VOID
)
81 unsigned int page_dir
=0;
82 Ke386GetPageTableDirectory(page_dir
);
83 return((PULONG
)page_dir
);
87 ProtectToPTE(ULONG flProtect
)
91 if (flProtect
& (PAGE_NOACCESS
|PAGE_GUARD
))
95 else if (flProtect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
97 Attributes
= PA_PRESENT
| PA_READWRITE
;
99 else if (flProtect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
101 Attributes
= PA_PRESENT
;
105 DPRINT1("Unknown main protection type.\n");
108 if (!(flProtect
& PAGE_SYSTEM
))
110 Attributes
= Attributes
| PA_USER
;
112 if (flProtect
& PAGE_NOCACHE
)
114 Attributes
= Attributes
| PA_CD
;
116 if (flProtect
& PAGE_WRITETHROUGH
)
118 Attributes
= Attributes
| PA_WT
;
123 #define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (1024 * PAGE_SIZE))
125 #define ADDR_TO_PDE(v) (PULONG)(PAGEDIRECTORY_MAP + \
126 ((((ULONG)(v)) / (1024 * 1024))&(~0x3)))
127 #define ADDR_TO_PTE(v) (PULONG)(PAGETABLE_MAP + ((((ULONG)(v) / 1024))&(~0x3)))
129 #define ADDR_TO_PDE_OFFSET(v) ((((ULONG)(v)) / (1024 * PAGE_SIZE)))
131 #define ADDR_TO_PTE_OFFSET(v) ((((ULONG)(v)) % (1024 * PAGE_SIZE)) / PAGE_SIZE)
133 NTSTATUS
Mmi386ReleaseMmInfo(PEPROCESS Process
)
135 PUSHORT LdtDescriptor
;
140 DPRINT("Mmi386ReleaseMmInfo(Process %x)\n",Process
);
142 LdtDescriptor
= (PUSHORT
) &Process
->Pcb
.LdtDescriptor
[0];
143 LdtBase
= LdtDescriptor
[1] |
144 ((LdtDescriptor
[2] & 0xff) << 16) |
145 ((LdtDescriptor
[3] & ~0xff) << 16);
147 DPRINT("LdtBase: %x\n", LdtBase
);
151 ExFreePool((PVOID
) LdtBase
);
153 PageDir
= ExAllocatePageWithPhysPage(Process
->Pcb
.DirectoryTableBase
.QuadPart
>> PAGE_SHIFT
);
154 for (i
= 0; i
< ADDR_TO_PDE_OFFSET(KERNEL_BASE
); i
++)
158 DPRINT1("Pde for %08x - %08x is not freed, RefCount %d\n",
159 i
* 4 * 1024 * 1024, (i
+ 1) * 4 * 1024 * 1024 - 1,
160 Process
->AddressSpace
.PageTableRefCountTable
[i
]);
161 Pde
= ExAllocatePageWithPhysPage(PageDir
[i
] >> PAGE_SHIFT
);
162 for (j
= 0; j
< 1024; j
++)
166 if (Pde
[j
] & PA_PRESENT
)
168 DPRINT1("Page at %08x is not freed\n",
169 i
* 4 * 1024 * 1024 + j
* PAGE_SIZE
);
173 DPRINT1("Swapentry %x at %x is not freed\n",
174 Pde
[j
], i
* 4 * 1024 * 1024 + j
* PAGE_SIZE
);
180 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(PageDir
[i
]));
183 ExUnmapPage(PageDir
);
186 MmReleasePageMemoryConsumer(MC_NPPOOL
, Process
->Pcb
.DirectoryTableBase
.QuadPart
>> PAGE_SHIFT
);
187 #if defined(__GNUC__)
189 Process
->Pcb
.DirectoryTableBase
.QuadPart
= 0LL;
192 Process
->Pcb
.DirectoryTableBase
.QuadPart
= 0;
195 DPRINT("Finished Mmi386ReleaseMmInfo()\n");
196 return(STATUS_SUCCESS
);
199 NTSTATUS
MmCopyMmInfo(PEPROCESS Src
, PEPROCESS Dest
)
201 PHYSICAL_ADDRESS PhysPageDirectory
;
202 PULONG PageDirectory
;
203 PKPROCESS KProcess
= &Dest
->Pcb
;
205 DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", Src
, Dest
);
207 PageDirectory
= ExAllocatePage();
208 if (PageDirectory
== NULL
)
210 return(STATUS_UNSUCCESSFUL
);
212 PhysPageDirectory
= MmGetPhysicalAddress(PageDirectory
);
213 KProcess
->DirectoryTableBase
= PhysPageDirectory
;
215 memset(PageDirectory
,0, ADDR_TO_PDE_OFFSET(KERNEL_BASE
) * sizeof(ULONG
));
216 memcpy(PageDirectory
+ ADDR_TO_PDE_OFFSET(KERNEL_BASE
),
217 MmGlobalKernelPageDirectory
+ ADDR_TO_PDE_OFFSET(KERNEL_BASE
),
218 (1024 - ADDR_TO_PDE_OFFSET(KERNEL_BASE
)) * sizeof(ULONG
));
220 DPRINT("Addr %x\n",PAGETABLE_MAP
/ (4*1024*1024));
221 PageDirectory
[PAGETABLE_MAP
/ (4*1024*1024)] =
222 PhysPageDirectory
.u
.LowPart
| PA_PRESENT
| PA_READWRITE
;
224 ExUnmapPage(PageDirectory
);
226 DPRINT("Finished MmCopyMmInfo()\n");
227 return(STATUS_SUCCESS
);
230 VOID
MmDeletePageTable(PEPROCESS Process
, PVOID Address
)
232 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
234 if (Process
!= NULL
&& Process
!= CurrentProcess
)
236 KeAttachProcess(Process
);
238 *(ADDR_TO_PDE(Address
)) = 0;
239 if (Address
>= (PVOID
)KERNEL_BASE
)
242 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
245 if (Process
!= NULL
&& Process
!= CurrentProcess
)
251 VOID
MmFreePageTable(PEPROCESS Process
, PVOID Address
)
253 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
258 if (Process
!= NULL
&& Process
!= CurrentProcess
)
260 KeAttachProcess(Process
);
263 PageTable
= (PULONG
)PAGE_ROUND_DOWN((PVOID
)ADDR_TO_PTE(Address
));
264 for (i
= 0; i
< 1024; i
++)
266 if (PageTable
[i
] != 0)
268 DbgPrint("Page table entry not clear at %x/%x (is %x)\n",
269 ((ULONG
)Address
/ (4*1024*1024)), i
, PageTable
[i
]);
273 npage
= *(ADDR_TO_PDE(Address
));
274 *(ADDR_TO_PDE(Address
)) = 0;
277 if (Address
>= (PVOID
)KERNEL_BASE
)
279 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
284 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(npage
));
286 if (Process
!= NULL
&& Process
!= CurrentProcess
)
293 MmGetPageTableForProcess(PEPROCESS Process
, PVOID Address
, BOOLEAN Create
)
295 ULONG PdeOffset
= ADDR_TO_PDE_OFFSET(Address
);
301 if (Address
< (PVOID
)KERNEL_BASE
&& Process
&& Process
!= PsGetCurrentProcess())
303 PageDir
= ExAllocatePageWithPhysPage(Process
->Pcb
.DirectoryTableBase
.QuadPart
>> PAGE_SHIFT
);
308 if (PageDir
[PdeOffset
] == 0)
312 ExUnmapPage(PageDir
);
315 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
316 if (!NT_SUCCESS(Status
) || Pfn
== 0)
320 Entry
= InterlockedCompareExchange(&PageDir
[PdeOffset
], PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
323 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
324 Pfn
= PTE_TO_PFN(Entry
);
329 Pfn
= PTE_TO_PFN(PageDir
[PdeOffset
]);
331 ExUnmapPage(PageDir
);
333 Pt
= ExAllocatePageWithPhysPage(Pfn
);
338 return Pt
+ ADDR_TO_PTE_OFFSET(Address
);
340 PageDir
= ADDR_TO_PDE(Address
);
343 if (Address
>= (PVOID
)KERNEL_BASE
)
345 if (MmGlobalKernelPageDirectory
[PdeOffset
] == 0)
351 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
352 if (!NT_SUCCESS(Status
) || Pfn
== 0)
356 Entry
= PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
;
357 if (Ke386CpuidFlags
& X86_FEATURE_PGE
)
361 if(0 != InterlockedCompareExchange(&MmGlobalKernelPageDirectory
[PdeOffset
], Entry
, 0))
363 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
366 *PageDir
=MmGlobalKernelPageDirectory
[PdeOffset
];
374 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, FALSE
, &Pfn
);
375 if (!NT_SUCCESS(Status
) || Pfn
== 0)
379 Entry
= InterlockedCompareExchange(PageDir
, PFN_TO_PTE(Pfn
) | PA_PRESENT
| PA_READWRITE
| PA_USER
, 0);
382 MmReleasePageMemoryConsumer(MC_NPPOOL
, Pfn
);
386 return (PULONG
)ADDR_TO_PTE(Address
);
389 BOOLEAN
MmUnmapPageTable(PULONG Pt
)
391 if (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024)
397 ExUnmapPage((PVOID
)PAGE_ROUND_DOWN(Pt
));
403 static ULONG
MmGetPageEntryForProcess(PEPROCESS Process
, PVOID Address
)
408 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
413 MmUnmapPageTable(Pt
);
420 MmGetPfnForProcess(PEPROCESS Process
,
425 Entry
= MmGetPageEntryForProcess(Process
, Address
);
427 if (!(Entry
& PA_PRESENT
))
431 return(PTE_TO_PFN(Entry
));
435 MmDisableVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOL
* WasDirty
, PPFN_TYPE Page
)
437 * FUNCTION: Delete a virtual mapping
444 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
452 * Atomically set the entry to zero and get the old value.
457 } while (Pte
!= InterlockedCompareExchange(Pt
, Pte
& ~PA_PRESENT
, Pte
));
459 if (MmUnmapPageTable(Pt
) || Address
>= (PVOID
)KERNEL_BASE
)
461 FLUSH_TLB_ONE(Address
);
463 WasValid
= (PAGE_MASK(Pte
) != 0);
470 * Return some information to the caller
472 if (WasDirty
!= NULL
)
474 *WasDirty
= Pte
& PA_DIRTY
;
478 *Page
= PTE_TO_PFN(Pte
);
483 MmRawDeleteVirtualMapping(PVOID Address
)
487 Pt
= MmGetPageTableForProcess(NULL
, Address
, FALSE
);
491 * Set the entry to zero
494 FLUSH_TLB_ONE(Address
);
499 MmDeleteVirtualMapping(PEPROCESS Process
, PVOID Address
, BOOL FreePage
,
500 BOOL
* WasDirty
, PPFN_TYPE Page
)
502 * FUNCTION: Delete a virtual mapping
509 DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
510 Process
, Address
, FreePage
, WasDirty
, Page
);
512 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
516 if (WasDirty
!= NULL
)
528 * Atomically set the entry to zero and get the old value.
530 Pte
= InterlockedExchange(Pt
, 0);
532 if ((MmUnmapPageTable(Pt
) || Address
>=(PVOID
)KERNEL_BASE
) && Pte
)
534 FLUSH_TLB_ONE(Address
);
537 WasValid
= (PAGE_MASK(Pte
) != 0);
540 MmMarkPageUnmapped(PTE_TO_PFN(Pte
));
543 if (FreePage
&& WasValid
)
545 MmReleasePageMemoryConsumer(MC_NPPOOL
, PTE_TO_PFN(Pte
));
549 * Decrement the reference count for this page table.
551 if (Process
!= NULL
&& WasValid
&&
552 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
553 Address
< (PVOID
)KERNEL_BASE
)
557 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
559 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]--;
560 if (Ptrc
[ADDR_TO_PAGE_TABLE(Address
)] == 0)
562 MmFreePageTable(Process
, Address
);
567 * Return some information to the caller
569 if (WasDirty
!= NULL
)
571 *WasDirty
= Pte
& PA_DIRTY
? TRUE
: FALSE
;
575 *Page
= PTE_TO_PFN(Pte
);
580 MmDeletePageFileMapping(PEPROCESS Process
, PVOID Address
,
581 SWAPENTRY
* SwapEntry
)
583 * FUNCTION: Delete a virtual mapping
589 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
598 * Atomically set the entry to zero and get the old value.
600 Pte
= InterlockedExchange(Pt
, 0);
602 if (MmUnmapPageTable(Pt
) || Address
>= (PVOID
)KERNEL_BASE
)
604 FLUSH_TLB_ONE(Address
);
608 * Decrement the reference count for this page table.
610 if (Process
!= NULL
&& Pte
&&
611 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
612 Address
< (PVOID
)KERNEL_BASE
)
616 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
618 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]--;
619 if (Ptrc
[ADDR_TO_PAGE_TABLE(Address
)] == 0)
621 MmFreePageTable(Process
, Address
);
627 * Return some information to the caller
629 *SwapEntry
= Pte
>> 1;
633 Mmi386MakeKernelPageTableGlobal(PVOID PAddress
)
638 Pde
= ADDR_TO_PDE(PAddress
);
641 Pt
= MmGetPageTableForProcess(NULL
, PAddress
, FALSE
);
643 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
644 FLASH_TLB_ONE(PAddress
);
654 BOOLEAN
MmIsDirtyPage(PEPROCESS Process
, PVOID Address
)
656 return MmGetPageEntryForProcess(Process
, Address
) & PA_DIRTY
? TRUE
: FALSE
;
660 MmIsAccessedAndResetAccessPage(PEPROCESS Process
, PVOID Address
)
665 if (Address
< (PVOID
)KERNEL_BASE
&& Process
== NULL
)
667 DPRINT1("MmIsAccessedAndResetAccessPage is called for user space without a process.\n");
671 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
680 } while (Pte
!= InterlockedCompareExchange(Pt
, Pte
& ~PA_ACCESSED
, Pte
));
682 if (Pte
& PA_ACCESSED
)
684 if (MmUnmapPageTable(Pt
) || Address
>= (PVOID
)KERNEL_BASE
)
686 FLUSH_TLB_ONE(Address
);
692 MmUnmapPageTable(Pt
);
697 VOID
MmSetCleanPage(PEPROCESS Process
, PVOID Address
)
702 if (Address
< (PVOID
)KERNEL_BASE
&& Process
== NULL
)
704 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
708 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
718 } while (Pte
!= InterlockedCompareExchange(Pt
, Pte
& ~PA_DIRTY
, Pte
));
722 if (MmUnmapPageTable(Pt
) || Address
> (PVOID
)KERNEL_BASE
)
724 FLUSH_TLB_ONE(Address
);
729 MmUnmapPageTable(Pt
);
733 VOID
MmSetDirtyPage(PEPROCESS Process
, PVOID Address
)
738 if (Address
< (PVOID
)KERNEL_BASE
&& Process
== NULL
)
740 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
744 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
753 } while (Pte
!= InterlockedCompareExchange(Pt
, Pte
| PA_DIRTY
, Pte
));
754 if (!(Pte
& PA_DIRTY
))
756 if (MmUnmapPageTable(Pt
) || Address
> (PVOID
)KERNEL_BASE
)
758 FLUSH_TLB_ONE(Address
);
763 MmUnmapPageTable(Pt
);
767 VOID
MmEnableVirtualMapping(PEPROCESS Process
, PVOID Address
)
772 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
781 } while (Pte
!= InterlockedCompareExchange(Pt
, Pte
| PA_PRESENT
, Pte
));
782 if (!(Pte
& PA_PRESENT
))
784 if (MmUnmapPageTable(Pt
) || Address
> (PVOID
)KERNEL_BASE
)
786 FLUSH_TLB_ONE(Address
);
791 MmUnmapPageTable(Pt
);
795 BOOLEAN
MmIsPagePresent(PEPROCESS Process
, PVOID Address
)
797 return MmGetPageEntryForProcess(Process
, Address
) & PA_PRESENT
? TRUE
: FALSE
;
800 BOOLEAN
MmIsPageSwapEntry(PEPROCESS Process
, PVOID Address
)
803 Entry
= MmGetPageEntryForProcess(Process
, Address
);
804 return !(Entry
& PA_PRESENT
) && Entry
!= 0 ? TRUE
: FALSE
;
808 MmCreateVirtualMappingForKernel(PVOID Address
,
813 ULONG Attributes
, Pte
;
817 ULONG PdeOffset
, oldPdeOffset
;
819 DPRINT("MmCreateVirtualMappingForKernel(%x, %x, %x, %d)\n",
820 Address
, flProtect
, Pages
, PageCount
);
822 if (Address
< (PVOID
)KERNEL_BASE
)
824 DPRINT1("MmCreateVirtualMappingForKernel is called for user space\n");
828 Attributes
= ProtectToPTE(flProtect
);
829 if (Ke386CpuidFlags
& X86_FEATURE_PGE
)
831 Attributes
|= PA_GLOBAL
;
835 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
836 Pt
= MmGetPageTableForProcess(NULL
, Addr
, TRUE
);
843 for (i
= 0; i
< PageCount
; i
++, Addr
+= PAGE_SIZE
)
845 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
847 DPRINT1("Setting physical address but not allowing access at address "
848 "0x%.8X with attributes %x/%x.\n",
849 Addr
, Attributes
, flProtect
);
853 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
854 if (oldPdeOffset
!= PdeOffset
)
856 Pt
= MmGetPageTableForProcess(NULL
, Addr
, TRUE
);
866 oldPdeOffset
= PdeOffset
;
871 DPRINT1("%x %x %x\n", Address
, Pt
, Pte
<< PAGE_SHIFT
);
874 *Pt
= PFN_TO_PTE(Pages
[i
]) | Attributes
;
877 return(STATUS_SUCCESS
);
881 MmCreatePageFileMapping(PEPROCESS Process
,
889 if (Process
== NULL
&& Address
< (PVOID
)KERNEL_BASE
)
891 DPRINT1("No process\n");
894 if (Process
!= NULL
&& Address
>= (PVOID
)KERNEL_BASE
)
896 DPRINT1("Setting kernel address with process context\n");
899 if (SwapEntry
& (1 << 31))
904 Pt
= MmGetPageTableForProcess(Process
, Address
, TRUE
);
910 if (PAGE_MASK((Pte
)) != 0)
912 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
914 *Pt
= SwapEntry
<< 1;
917 if (MmUnmapPageTable(Pt
) || Address
> (PVOID
)KERNEL_BASE
)
919 FLUSH_TLB_ONE(Address
);
924 MmUnmapPageTable(Pt
);
927 if (Process
!= NULL
&&
928 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
929 Address
< (PVOID
)KERNEL_BASE
)
933 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
935 Ptrc
[ADDR_TO_PAGE_TABLE(Address
)]++;
937 return(STATUS_SUCCESS
);
942 MmCreateVirtualMappingUnsafe(PEPROCESS Process
,
953 ULONG oldPdeOffset
, PdeOffset
;
955 DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x, %d)\n",
956 Process
, Address
, flProtect
, Pages
, PageCount
);
960 if (Address
< (PVOID
)KERNEL_BASE
)
962 DPRINT1("No process\n");
965 if (PageCount
> 0x10000 ||
966 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> 0x100000)
968 DPRINT1("Page count to large\n");
974 if (Address
>= (PVOID
)KERNEL_BASE
)
976 DPRINT1("Setting kernel address with process context\n");
979 if (PageCount
> KERNEL_BASE
/ PAGE_SIZE
||
980 (ULONG_PTR
) Address
/ PAGE_SIZE
+ PageCount
> KERNEL_BASE
/ PAGE_SIZE
)
982 DPRINT1("Page Count to large\n");
987 Attributes
= ProtectToPTE(flProtect
);
988 if (Address
>= (PVOID
)KERNEL_BASE
)
990 Attributes
&= ~PA_USER
;
991 if (Ke386CpuidFlags
& X86_FEATURE_PGE
)
993 Attributes
|= PA_GLOBAL
;
998 Attributes
|= PA_USER
;
1002 oldPdeOffset
= ADDR_TO_PDE_OFFSET(Addr
) + 1;
1004 for (i
= 0; i
< PageCount
; i
++, Addr
+= PAGE_SIZE
)
1006 if (!(Attributes
& PA_PRESENT
) && Pages
[i
] != 0)
1008 DPRINT1("Setting physical address but not allowing access at address "
1009 "0x%.8X with attributes %x/%x.\n",
1010 Addr
, Attributes
, flProtect
);
1013 PdeOffset
= ADDR_TO_PDE_OFFSET(Addr
);
1014 if (oldPdeOffset
!= PdeOffset
)
1016 MmUnmapPageTable(Pt
);
1017 Pt
= MmGetPageTableForProcess(Process
, Addr
, TRUE
);
1027 oldPdeOffset
= PdeOffset
;
1030 MmMarkPageMapped(Pages
[i
]);
1031 if (PAGE_MASK((Pte
)) != 0 && !((Pte
) & PA_PRESENT
))
1035 if (PAGE_MASK((Pte
)) != 0)
1037 MmMarkPageUnmapped(PTE_TO_PFN((Pte
)));
1039 *Pt
= PFN_TO_PTE(Pages
[i
]) | Attributes
;
1040 if (Address
< (PVOID
)KERNEL_BASE
&&
1041 Process
->AddressSpace
.PageTableRefCountTable
!= NULL
&&
1042 Attributes
& PA_PRESENT
)
1046 Ptrc
= Process
->AddressSpace
.PageTableRefCountTable
;
1048 Ptrc
[ADDR_TO_PAGE_TABLE(Addr
)]++;
1052 if (Address
> (PVOID
)KERNEL_BASE
||
1053 (Pt
>= (PULONG
)PAGETABLE_MAP
&& Pt
< (PULONG
)PAGETABLE_MAP
+ 1024*1024))
1055 FLUSH_TLB_ONE(Address
);
1061 MmUnmapPageTable(Pt
);
1063 return(STATUS_SUCCESS
);
1067 MmCreateVirtualMapping(PEPROCESS Process
,
1075 for (i
= 0; i
< PageCount
; i
++)
1077 if (!MmIsUsablePage(Pages
[i
]))
1079 DPRINT1("Page at address %x not usable\n", Pages
[i
] << PAGE_SHIFT
);
1084 return(MmCreateVirtualMappingUnsafe(Process
,
1092 MmGetPageProtect(PEPROCESS Process
, PVOID Address
)
1097 Entry
= MmGetPageEntryForProcess(Process
, Address
);
1099 if (!(Entry
& PA_PRESENT
))
1101 Protect
= PAGE_NOACCESS
;
1105 if (Entry
& PA_READWRITE
)
1107 Protect
= PAGE_READWRITE
;
1111 Protect
= PAGE_EXECUTE_READ
;
1115 Protect
|= PAGE_NOCACHE
;
1119 Protect
|= PAGE_WRITETHROUGH
;
1121 if (!(Entry
& PA_USER
))
1123 Protect
|= PAGE_SYSTEM
;
1131 MmSetPageProtect(PEPROCESS Process
, PVOID Address
, ULONG flProtect
)
1133 ULONG Attributes
= 0;
1136 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
1137 Process
, Address
, flProtect
);
1139 Attributes
= ProtectToPTE(flProtect
);
1140 if (Address
>= (PVOID
)KERNEL_BASE
)
1142 Attributes
&= ~PA_USER
;
1143 if (Ke386CpuidFlags
& X86_FEATURE_PGE
)
1145 Attributes
|= PA_GLOBAL
;
1150 Attributes
|= PA_USER
;
1152 Pt
= MmGetPageTableForProcess(Process
, Address
, FALSE
);
1157 *Pt
= PAGE_MASK(*Pt
) | Attributes
| (*Pt
& (PA_ACCESSED
|PA_DIRTY
));
1158 if (MmUnmapPageTable(Pt
) || Address
> (PVOID
)KERNEL_BASE
)
1160 FLUSH_TLB_ONE(Address
);
1167 PHYSICAL_ADDRESS STDCALL
1168 MmGetPhysicalAddress(PVOID vaddr
)
1170 * FUNCTION: Returns the physical address corresponding to a virtual address
1176 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr
);
1178 Pte
= MmGetPageEntryForProcess(NULL
, vaddr
);
1179 if (Pte
!= 0 && Pte
& PA_PRESENT
)
1181 p
.QuadPart
= PAGE_MASK(Pte
);
1182 p
.u
.LowPart
|= (ULONG_PTR
)vaddr
& (PAGE_SIZE
- 1);
1192 VOID
MmUpdatePageDir(PEPROCESS Process
, PVOID Address
, ULONG Size
)
1195 ULONG StartOffset
, EndOffset
, Offset
;
1197 if (Address
< (PVOID
)KERNEL_BASE
)
1202 StartOffset
= ADDR_TO_PDE_OFFSET(Address
);
1203 EndOffset
= ADDR_TO_PDE_OFFSET(Address
+ Size
);
1205 if (Process
!= NULL
&& Process
!= PsGetCurrentProcess())
1207 Pde
= ExAllocatePageWithPhysPage(Process
->Pcb
.DirectoryTableBase
.u
.LowPart
>> PAGE_SHIFT
);
1211 Pde
= (PULONG
)PAGEDIRECTORY_MAP
;
1213 for (Offset
= StartOffset
; Offset
<= EndOffset
; Offset
++)
1215 if (Offset
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
))
1217 InterlockedCompareExchange(&Pde
[Offset
], MmGlobalKernelPageDirectory
[Offset
], 0);
1220 if (Pde
!= (PULONG
)PAGEDIRECTORY_MAP
)
1227 MmInitGlobalKernelPageDirectory(VOID
)
1230 PULONG CurrentPageDirectory
= (PULONG
)PAGEDIRECTORY_MAP
;
1232 for (i
= ADDR_TO_PDE_OFFSET(KERNEL_BASE
); i
< 1024; i
++)
1234 if (i
!= ADDR_TO_PDE_OFFSET(PAGETABLE_MAP
) &&
1235 0 == MmGlobalKernelPageDirectory
[i
] && 0 != CurrentPageDirectory
[i
])
1237 MmGlobalKernelPageDirectory
[i
] = CurrentPageDirectory
[i
];
1238 if (Ke386CpuidFlags
& X86_FEATURE_PGE
)
1240 MmGlobalKernelPageDirectory
[i
] |= PA_GLOBAL
;