ReactOS 0.4.15-dev-6047-gb29e82d
pagfault.c File Reference
#include <ntoskrnl.h>
#include <debug.h>
#include <mm/ARM3/miarm.h>
Include dependency graph for pagfault.c:

Go to the source code of this file.

Macros

#define NDEBUG
 
#define MODULE_INVOLVED_IN_ARM3
 
#define HYDRA_PROCESS   (PEPROCESS)1
 
#define _BYTE_MASK(Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7)
 

Functions

static NTSTATUS NTAPI MiCheckForUserStackOverflow (IN PVOID Address, IN PVOID TrapInformation)
 
FORCEINLINE BOOLEAN MiIsAccessAllowed (_In_ ULONG ProtectionMask, _In_ BOOLEAN Write, _In_ BOOLEAN Execute)
 
static NTSTATUS NTAPI MiAccessCheck (IN PMMPTE PointerPte, IN BOOLEAN StoreInstruction, IN KPROCESSOR_MODE PreviousMode, IN ULONG_PTR ProtectionMask, IN PVOID TrapFrame, IN BOOLEAN LockHeld)
 
static PMMPTE NTAPI MiCheckVirtualAddress (IN PVOID VirtualAddress, OUT PULONG ProtectCode, OUT PMMVAD *ProtoVad)
 
NTSTATUS FASTCALL MiCheckPdeForPagedPool (IN PVOID Address)
 
VOID NTAPI MiZeroPfn (IN PFN_NUMBER PageFrameNumber)
 
VOID NTAPI MiCopyPfn (_In_ PFN_NUMBER DestPage, _In_ PFN_NUMBER SrcPage)
 
static NTSTATUS NTAPI MiResolveDemandZeroFault (IN PVOID Address, IN PMMPTE PointerPte, IN ULONG Protection, IN PEPROCESS Process, IN KIRQL OldIrql)
 
static NTSTATUS NTAPI MiCompleteProtoPteFault (IN BOOLEAN StoreInstruction, IN PVOID Address, IN PMMPTE PointerPte, IN PMMPTE PointerProtoPte, IN KIRQL OldIrql, IN PMMPFN *LockedProtoPfn)
 
static NTSTATUS NTAPI MiResolvePageFileFault (_In_ BOOLEAN StoreInstruction, _In_ PVOID FaultingAddress, _In_ PMMPTE PointerPte, _In_ PEPROCESS CurrentProcess, _Inout_ KIRQL *OldIrql)
 
static NTSTATUS NTAPI MiResolveTransitionFault (IN BOOLEAN StoreInstruction, IN PVOID FaultingAddress, IN PMMPTE PointerPte, IN PEPROCESS CurrentProcess, IN KIRQL OldIrql, OUT PKEVENT **InPageBlock)
 
static NTSTATUS NTAPI MiResolveProtoPteFault (IN BOOLEAN StoreInstruction, IN PVOID Address, IN PMMPTE PointerPte, IN PMMPTE PointerProtoPte, IN OUT PMMPFN *OutPfn, OUT PVOID *PageFileData, OUT PMMPTE PteValue, IN PEPROCESS Process, IN KIRQL OldIrql, IN PVOID TrapInformation)
 
NTSTATUS NTAPI MiDispatchFault (IN ULONG FaultCode, IN PVOID Address, IN PMMPTE PointerPte, IN PMMPTE PointerProtoPte, IN BOOLEAN Recursive, IN PEPROCESS Process, IN PVOID TrapInformation, IN PMMVAD Vad)
 
NTSTATUS NTAPI MmArmAccessFault (IN ULONG FaultCode, IN PVOID Address, IN KPROCESSOR_MODE Mode, IN PVOID TrapInformation)
 
NTSTATUS NTAPI MmGetExecuteOptions (IN PULONG ExecuteOptions)
 
NTSTATUS NTAPI MmSetExecuteOptions (IN ULONG ExecuteOptions)
 

Macro Definition Documentation

◆ _BYTE_MASK

#define _BYTE_MASK (   Bit0,
  Bit1,
  Bit2,
  Bit3,
  Bit4,
  Bit5,
  Bit6,
  Bit7 
)
Value:
(Bit0) | ((Bit1) << 1) | ((Bit2) << 2) | ((Bit3) << 3) | \
((Bit4) << 4) | ((Bit5) << 5) | ((Bit6) << 6) | ((Bit7) << 7)

◆ HYDRA_PROCESS

#define HYDRA_PROCESS   (PEPROCESS)1

Definition at line 20 of file pagfault.c.

◆ MODULE_INVOLVED_IN_ARM3

#define MODULE_INVOLVED_IN_ARM3

Definition at line 15 of file pagfault.c.

◆ NDEBUG

#define NDEBUG

Definition at line 12 of file pagfault.c.

Function Documentation

◆ MiAccessCheck()

static NTSTATUS NTAPI MiAccessCheck ( IN PMMPTE  PointerPte,
IN BOOLEAN  StoreInstruction,
IN KPROCESSOR_MODE  PreviousMode,
IN ULONG_PTR  ProtectionMask,
IN PVOID  TrapFrame,
IN BOOLEAN  LockHeld 
)
static

Definition at line 168 of file pagfault.c.

174{
176
177 /* Check for invalid user-mode access */
178 if ((PreviousMode == UserMode) && (PointerPte > MiHighestUserPte))
179 {
181 }
182
183 /* Capture the PTE -- is it valid? */
184 TempPte = *PointerPte;
185 if (TempPte.u.Hard.Valid)
186 {
187 /* Was someone trying to write to it? */
188 if (StoreInstruction)
189 {
190 /* Is it writable?*/
193 {
194 /* Then there's nothing to worry about */
195 return STATUS_SUCCESS;
196 }
197
198 /* Oops! This isn't allowed */
200 }
201
202 /* Someone was trying to read from a valid PTE, that's fine too */
203 return STATUS_SUCCESS;
204 }
205
206 /* Check if the protection on the page allows what is being attempted */
207 if (!MiIsAccessAllowed(ProtectionMask, StoreInstruction, FALSE))
208 {
210 }
211
212 /* Check if this is a guard page */
213 if ((ProtectionMask & MM_PROTECT_SPECIAL) == MM_GUARDPAGE)
214 {
215 ASSERT(ProtectionMask != MM_DECOMMIT);
216
217 /* Attached processes can't expand their stack */
219
220 /* No support for prototype PTEs yet */
221 ASSERT(TempPte.u.Soft.Prototype == 0);
222
223 /* Remove the guard page bit, and return a guard page violation */
224 TempPte.u.Soft.Protection = ProtectionMask & ~MM_GUARDPAGE;
225 ASSERT(TempPte.u.Long != 0);
226 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
228 }
229
230 /* Nothing to do */
231 return STATUS_SUCCESS;
232}
HARDWARE_PTE_ARMV6 TempPte
Definition: winldr.c:76
#define FALSE
Definition: types.h:117
PMMPTE MiHighestUserPte
Definition: mminit.c:233
#define MM_GUARDPAGE
Definition: miarm.h:57
#define MM_DECOMMIT
Definition: miarm.h:64
FORCEINLINE VOID MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte, IN MMPTE InvalidPte)
Definition: miarm.h:992
#define MM_PROTECT_SPECIAL
Definition: miarm.h:59
#define ASSERT(a)
Definition: mode.c:44
#define UserMode
Definition: asm.h:35
#define MI_IS_PAGE_COPY_ON_WRITE(x)
Definition: mm.h:110
#define MI_IS_PAGE_WRITEABLE(x)
Definition: mm.h:106
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:242
#define STATUS_GUARD_PAGE_VIOLATION
Definition: ntstatus.h:182
FORCEINLINE BOOLEAN MiIsAccessAllowed(_In_ ULONG ProtectionMask, _In_ BOOLEAN Write, _In_ BOOLEAN Execute)
Definition: pagfault.c:138
BOOLEAN NTAPI KeIsAttachedProcess(VOID)
Definition: procobj.c:693
#define STATUS_SUCCESS
Definition: shellext.h:65
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103

Referenced by MiResolveProtoPteFault(), and MmArmAccessFault().

◆ MiCheckForUserStackOverflow()

static NTSTATUS NTAPI MiCheckForUserStackOverflow ( IN PVOID  Address,
IN PVOID  TrapInformation 
)
static

Definition at line 30 of file pagfault.c.

32{
33 PETHREAD CurrentThread = PsGetCurrentThread();
34 PTEB Teb = CurrentThread->Tcb.Teb;
35 PVOID StackBase, DeallocationStack, NextStackAddress;
36 SIZE_T GuaranteedSize;
38
39 /* Do we own the address space lock? */
40 if (CurrentThread->AddressSpaceOwner == 1)
41 {
42 /* This isn't valid */
43 DPRINT1("Process owns address space lock\n");
46 }
47
48 /* Are we attached? */
50 {
51 /* This isn't valid */
52 DPRINT1("Process is attached\n");
54 }
55
56 /* Read the current settings */
57 StackBase = Teb->NtTib.StackBase;
58 DeallocationStack = Teb->DeallocationStack;
59 GuaranteedSize = Teb->GuaranteedStackBytes;
60 DPRINT("Handling guard page fault with Stacks Addresses 0x%p and 0x%p, guarantee: %lx\n",
61 StackBase, DeallocationStack, GuaranteedSize);
62
63 /* Guarantees make this code harder, for now, assume there aren't any */
64 ASSERT(GuaranteedSize == 0);
65
66 /* So allocate only the minimum guard page size */
67 GuaranteedSize = PAGE_SIZE;
68
69 /* Does this faulting stack address actually exist in the stack? */
70 if ((Address >= StackBase) || (Address < DeallocationStack))
71 {
72 /* That's odd... */
73 DPRINT1("Faulting address outside of stack bounds. Address=%p, StackBase=%p, DeallocationStack=%p\n",
74 Address, StackBase, DeallocationStack);
76 }
77
78 /* This is where the stack will start now */
79 NextStackAddress = (PVOID)((ULONG_PTR)PAGE_ALIGN(Address) - GuaranteedSize);
80
81 /* Do we have at least one page between here and the end of the stack? */
82 if (((ULONG_PTR)NextStackAddress - PAGE_SIZE) <= (ULONG_PTR)DeallocationStack)
83 {
84 /* We don't -- Trying to make this guard page valid now */
85 DPRINT1("Close to our death...\n");
86
87 /* Calculate the next memory address */
88 NextStackAddress = (PVOID)((ULONG_PTR)PAGE_ALIGN(DeallocationStack) + GuaranteedSize);
89
90 /* Allocate the memory */
91 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
92 &NextStackAddress,
93 0,
94 &GuaranteedSize,
97 if (NT_SUCCESS(Status))
98 {
99 /* Success! */
100 Teb->NtTib.StackLimit = NextStackAddress;
101 }
102 else
103 {
104 DPRINT1("Failed to allocate memory\n");
105 }
106
108 }
109
110 /* Don't handle this flag yet */
112
113 /* Update the stack limit */
114 Teb->NtTib.StackLimit = (PVOID)((ULONG_PTR)NextStackAddress + GuaranteedSize);
115
116 /* Now move the guard page to the next page */
117 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
118 &NextStackAddress,
119 0,
120 &GuaranteedSize,
124 {
125 /* We did it! */
126 DPRINT("Guard page handled successfully for %p\n", Address);
128 }
129
130 /* Fail, we couldn't move the guard page */
131 DPRINT1("Guard page failure: %lx\n", Status);
132 ASSERT(FALSE);
134}
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define TRUE
Definition: types.h:120
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
PPEB Peb
Definition: dllmain.c:27
#define ULONG_PTR
Definition: config.h:101
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define PAGE_SIZE
Definition: env_spec_w32.h:49
Status
Definition: gdiplustypes.h:25
#define FLG_DISABLE_STACK_EXTENSION
Definition: pstypes.h:71
#define PAGE_READWRITE
Definition: nt_native.h:1304
#define NtCurrentProcess()
Definition: nt_native.h:1657
#define MEM_COMMIT
Definition: nt_native.h:1313
#define PAGE_GUARD
Definition: nt_native.h:1310
BOOLEAN NTAPI KeAreAllApcsDisabled(VOID)
Definition: apc.c:985
#define STATUS_PAGE_FAULT_GUARD_PAGE
Definition: ntstatus.h:97
#define STATUS_ALREADY_COMMITTED
Definition: ntstatus.h:270
#define STATUS_STACK_OVERFLOW
Definition: ntstatus.h:489
static WCHAR Address[46]
Definition: ping.c:68
#define DPRINT
Definition: sndvol32.h:71
KTHREAD Tcb
Definition: pstypes.h:1103
PVOID Teb
Definition: ketypes.h:1747
PVOID StackLimit
Definition: compat.h:713
PVOID StackBase
Definition: compat.h:712
ULONG NtGlobalFlag
Definition: ntddk_ex.h:270
Definition: compat.h:836
NT_TIB NtTib
Definition: ntddk_ex.h:332
ULONG GuaranteedStackBytes
Definition: winternl.h:279
PVOID DeallocationStack
Definition: compat.h:878
void * PVOID
Definition: typedefs.h:50
ULONG_PTR SIZE_T
Definition: typedefs.h:80
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define PAGE_ALIGN(Va)
#define PsGetCurrentProcess
Definition: psfuncs.h:17

Referenced by MmArmAccessFault().

◆ MiCheckPdeForPagedPool()

NTSTATUS FASTCALL MiCheckPdeForPagedPool ( IN PVOID  Address)

Definition at line 475 of file pagfault.c.

476{
478}

Referenced by MiDeletePte(), MiInitializePfn(), MiInitializePfnAndMakePteValid(), and MmArmAccessFault().

◆ MiCheckVirtualAddress()

static PMMPTE NTAPI MiCheckVirtualAddress ( IN PVOID  VirtualAddress,
OUT PULONG  ProtectCode,
OUT PMMVAD ProtoVad 
)
static

Definition at line 237 of file pagfault.c.

240{
241 PMMVAD Vad;
242 PMMPTE PointerPte;
243
244 /* No prototype/section support for now */
245 *ProtoVad = NULL;
246
247 /* User or kernel fault? */
249 {
250 /* Special case for shared data */
252 {
253 /* It's a read-only page */
254 *ProtectCode = MM_READONLY;
255 return MmSharedUserDataPte;
256 }
257
258 /* Find the VAD, it might not exist if the address is bogus */
260 if (!Vad)
261 {
262 /* Bogus virtual address */
263 *ProtectCode = MM_NOACCESS;
264 return NULL;
265 }
266
267 /* ReactOS does not handle physical memory VADs yet */
269
270 /* Check if it's a section, or just an allocation */
271 if (Vad->u.VadFlags.PrivateMemory)
272 {
273 /* ReactOS does not handle AWE VADs yet */
274 ASSERT(Vad->u.VadFlags.VadType != VadAwe);
275
276 /* This must be a TEB/PEB VAD */
277 if (Vad->u.VadFlags.MemCommit)
278 {
279 /* It's committed, so return the VAD protection */
280 *ProtectCode = (ULONG)Vad->u.VadFlags.Protection;
281 }
282 else
283 {
284 /* It has not yet been committed, so return no access */
285 *ProtectCode = MM_NOACCESS;
286 }
287
288 /* In both cases, return no PTE */
289 return NULL;
290 }
291 else
292 {
293 /* ReactOS does not supoprt these VADs yet */
296
297 /* Return the proto VAD */
298 *ProtoVad = Vad;
299
300 /* Get the prototype PTE for this page */
301 PointerPte = (((ULONG_PTR)VirtualAddress >> PAGE_SHIFT) - Vad->StartingVpn) + Vad->FirstPrototypePte;
302 ASSERT(PointerPte != NULL);
303 ASSERT(PointerPte <= Vad->LastContiguousPte);
304
305 /* Return the Prototype PTE and the protection for the page mapping */
306 *ProtectCode = (ULONG)Vad->u.VadFlags.Protection;
307 return PointerPte;
308 }
309 }
311 {
312 /* This should never happen, as these addresses are handled by the double-maping */
315 {
316 /* Fail such access */
317 *ProtectCode = MM_NOACCESS;
318 return NULL;
319 }
320
321 /* Return full access rights */
322 *ProtectCode = MM_EXECUTE_READWRITE;
323 return NULL;
324 }
326 {
327 /* ReactOS does not have an image list yet, so bail out to failure case */
329 }
330
331 /* Default case -- failure */
332 *ProtectCode = MM_NOACCESS;
333 return NULL;
334}
#define MM_HIGHEST_USER_ADDRESS
Definition: armddk.h:17
#define MM_READONLY
Definition: bootanim.c:18
#define NULL
Definition: types.h:112
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
PMMVAD NTAPI MiLocateAddress(IN PVOID VirtualAddress)
Definition: vadnode.c:48
PMMPTE MmSharedUserDataPte
Definition: mminit.c:26
PVOID MmPagedPoolStart
Definition: miarm.h:574
PMM_SESSION_SPACE MmSessionSpace
Definition: session.c:21
#define MI_IS_SESSION_ADDRESS(Address)
Definition: miarm.h:171
#define MM_EXECUTE_READWRITE
Definition: miarm.h:49
MM_PAGED_POOL_INFO MmPagedPoolInfo
Definition: pool.c:25
#define MI_IS_PAGE_TABLE_ADDRESS(Address)
Definition: miarm.h:177
#define MM_NOACCESS
Definition: miarm.h:65
#define MiAddressToPte(x)
Definition: mmx86.c:19
struct _MMPTE * PMMPTE
#define MM_SHARED_USER_DATA_VA
Definition: mmtypes.h:48
@ VadAwe
Definition: mmtypes.h:203
@ VadDevicePhysicalMemory
Definition: mmtypes.h:201
@ VadImageMap
Definition: mmtypes.h:202
ULONG ExtendableFile
Definition: mmtypes.h:709
ULONG_PTR MemCommit
Definition: mmtypes.h:692
ULONG_PTR Protection
Definition: mmtypes.h:693
ULONG_PTR VadType
Definition: mmtypes.h:691
ULONG_PTR PrivateMemory
Definition: mmtypes.h:695
union _MMVAD::@2589 u2
ULONG_PTR StartingVpn
Definition: mmtypes.h:726
MMVAD_FLAGS2 VadFlags2
Definition: mmtypes.h:739
union _MMVAD::@2588 u
MMVAD_FLAGS VadFlags
Definition: mmtypes.h:731
PMMPTE FirstPrototypePte
Definition: mmtypes.h:734
PMMPTE LastPteForPagedPool
Definition: mm.h:489
LIST_ENTRY ImageList
Definition: miarm.h:489
uint32_t ULONG
Definition: typedefs.h:59
_Must_inspect_result_ _In_ WDFDMATRANSACTION _In_ PFN_WDF_PROGRAM_DMA _In_ WDF_DMA_DIRECTION _In_ PMDL _In_ PVOID VirtualAddress

Referenced by MmArmAccessFault().

◆ MiCompleteProtoPteFault()

static NTSTATUS NTAPI MiCompleteProtoPteFault ( IN BOOLEAN  StoreInstruction,
IN PVOID  Address,
IN PMMPTE  PointerPte,
IN PMMPTE  PointerProtoPte,
IN KIRQL  OldIrql,
IN PMMPFN LockedProtoPfn 
)
static

Definition at line 765 of file pagfault.c.

771{
773 PMMPTE OriginalPte, PageTablePte;
774 ULONG_PTR Protection;
775 PFN_NUMBER PageFrameIndex;
776 PMMPFN Pfn1, Pfn2;
777 BOOLEAN OriginalProtection, DirtyPage;
778
779 /* Must be called with an valid prototype PTE, with the PFN lock held */
781 ASSERT(PointerProtoPte->u.Hard.Valid == 1);
782
783 /* Get the page */
784 PageFrameIndex = PFN_FROM_PTE(PointerProtoPte);
785
786 /* Get the PFN entry and set it as a prototype PTE */
787 Pfn1 = MiGetPfnEntry(PageFrameIndex);
788 Pfn1->u3.e1.PrototypePte = 1;
789
790 /* Increment the share count for the page table */
791 PageTablePte = MiAddressToPte(PointerPte);
792 Pfn2 = MiGetPfnEntry(PageTablePte->u.Hard.PageFrameNumber);
793 Pfn2->u2.ShareCount++;
794
795 /* Check where we should be getting the protection information from */
796 if (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
797 {
798 /* Get the protection from the PTE, there's no real Proto PTE data */
799 Protection = PointerPte->u.Soft.Protection;
800
801 /* Remember that we did not use the proto protection */
802 OriginalProtection = FALSE;
803 }
804 else
805 {
806 /* Get the protection from the original PTE link */
807 OriginalPte = &Pfn1->OriginalPte;
808 Protection = OriginalPte->u.Soft.Protection;
809
810 /* Remember that we used the original protection */
811 OriginalProtection = TRUE;
812
813 /* Check if this was a write on a read only proto */
814 if ((StoreInstruction) && !(Protection & MM_READWRITE))
815 {
816 /* Clear the flag */
817 StoreInstruction = 0;
818 }
819 }
820
821 /* Check if this was a write on a non-COW page */
822 DirtyPage = FALSE;
823 if ((StoreInstruction) && ((Protection & MM_WRITECOPY) != MM_WRITECOPY))
824 {
825 /* Then the page should be marked dirty */
826 DirtyPage = TRUE;
827
828 /* ReactOS check */
829 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype != 0);
830 }
831
832 /* Did we get a locked incoming PFN? */
833 if (*LockedProtoPfn)
834 {
835 /* Drop a reference */
836 ASSERT((*LockedProtoPfn)->u3.e2.ReferenceCount >= 1);
837 MiDereferencePfnAndDropLockCount(*LockedProtoPfn);
838 *LockedProtoPfn = NULL;
839 }
840
841 /* Release the PFN lock */
842 MiReleasePfnLock(OldIrql);
843
844 /* Remove special/caching bits */
845 Protection &= ~MM_PROTECT_SPECIAL;
846
847 /* Setup caching */
848 if (Pfn1->u3.e1.CacheAttribute == MiWriteCombined)
849 {
850 /* Write combining, no caching */
853 }
854 else if (Pfn1->u3.e1.CacheAttribute == MiNonCached)
855 {
856 /* Write through, no caching */
859 }
860
861 /* Check if this is a kernel or user address */
863 {
864 /* Build the user PTE */
865 MI_MAKE_HARDWARE_PTE_USER(&TempPte, PointerPte, Protection, PageFrameIndex);
866 }
867 else
868 {
869 /* Build the kernel PTE */
870 MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, Protection, PageFrameIndex);
871 }
872
873 /* Set the dirty flag if needed */
874 if (DirtyPage) MI_MAKE_DIRTY_PAGE(&TempPte);
875
876 /* Write the PTE */
877 MI_WRITE_VALID_PTE(PointerPte, TempPte);
878
879 /* Reset the protection if needed */
880 if (OriginalProtection) Protection = MM_ZERO_ACCESS;
881
882 /* Return success */
883 ASSERT(PointerPte == MiAddressToPte(Address));
884 return STATUS_SUCCESS;
885}
unsigned char BOOLEAN
#define MM_READWRITE
Definition: bootanim.c:19
FORCEINLINE VOID MI_MAKE_HARDWARE_PTE_USER(IN PMMPTE NewPte, IN PMMPTE MappingPte, IN ULONG_PTR ProtectionMask, IN PFN_NUMBER PageFrameNumber)
Definition: miarm.h:827
@ MiWriteCombined
Definition: miarm.h:412
@ MiNonCached
Definition: miarm.h:410
FORCEINLINE VOID MiDereferencePfnAndDropLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1615
#define MM_ZERO_ACCESS
Definition: miarm.h:43
FORCEINLINE VOID MI_MAKE_HARDWARE_PTE(IN PMMPTE NewPte, IN PMMPTE MappingPte, IN ULONG_PTR ProtectionMask, IN PFN_NUMBER PageFrameNumber)
Definition: miarm.h:807
#define MI_PTE_LOOKUP_NEEDED
Definition: miarm.h:241
FORCEINLINE VOID MI_WRITE_VALID_PTE(IN PMMPTE PointerPte, IN MMPTE TempPte)
Definition: miarm.h:959
#define MM_WRITECOPY
Definition: miarm.h:48
#define MI_PAGE_WRITE_COMBINED(x)
Definition: mm.h:103
#define MI_PAGE_DISABLE_CACHE(x)
Definition: mm.h:101
#define MmSystemRangeStart
Definition: mm.h:32
#define MI_PAGE_WRITE_THROUGH(x)
Definition: mm.h:102
#define MI_MAKE_DIRTY_PAGE(x)
Definition: mm.h:98
#define PFN_FROM_PTE(v)
Definition: mm.h:92
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:1047
#define MI_ASSERT_PFN_LOCK_HELD()
Definition: mm.h:1043
ULONG PFN_NUMBER
Definition: ke.h:9
USHORT CacheAttribute
Definition: mm.h:367
USHORT PrototypePte
Definition: mm.h:363
Definition: mm.h:374
union _MMPFN::@1772 u3
MMPTE OriginalPte
Definition: mm.h:407
MMPFNENTRY e1
Definition: mm.h:397
ULONG_PTR ShareCount
Definition: mm.h:390
union _MMPFN::@1771 u2
ULONG64 PageFrameNumber
Definition: mmtypes.h:171
ULONG64 Protection
Definition: mmtypes.h:88
ULONG64 Prototype
Definition: mmtypes.h:89
MMPTE_SOFTWARE Soft
Definition: mmtypes.h:219
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
union _MMPTE::@2307 u
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:792

Referenced by MiDispatchFault(), and MiResolveProtoPteFault().

◆ MiCopyPfn()

VOID NTAPI MiCopyPfn ( _In_ PFN_NUMBER  DestPage,
_In_ PFN_NUMBER  SrcPage 
)

Definition at line 529 of file pagfault.c.

532{
533 PMMPTE SysPtes;
535 PMMPFN DestPfn, SrcPfn;
536 PVOID DestAddress;
537 const VOID* SrcAddress;
538
539 /* Get the PFNs */
540 DestPfn = MiGetPfnEntry(DestPage);
541 ASSERT(DestPfn);
542 SrcPfn = MiGetPfnEntry(SrcPage);
543 ASSERT(SrcPfn);
544
545 /* Grab 2 system PTEs */
547 ASSERT(SysPtes);
548
549 /* Initialize the destination PTE */
551 TempPte.u.Hard.PageFrameNumber = DestPage;
552
553 /* Setup caching */
554 if (DestPfn->u3.e1.CacheAttribute == MiWriteCombined)
555 {
556 /* Write combining, no caching */
559 }
560 else if (DestPfn->u3.e1.CacheAttribute == MiNonCached)
561 {
562 /* Write through, no caching */
565 }
566
567 /* Make the system PTE valid with our PFN */
568 MI_WRITE_VALID_PTE(&SysPtes[0], TempPte);
569
570 /* Initialize the source PTE */
572 TempPte.u.Hard.PageFrameNumber = SrcPage;
573
574 /* Setup caching */
575 if (SrcPfn->u3.e1.CacheAttribute == MiNonCached)
576 {
578 }
579
580 /* Make the system PTE valid with our PFN */
581 MI_WRITE_VALID_PTE(&SysPtes[1], TempPte);
582
583 /* Get the addresses and perform the copy */
584 DestAddress = MiPteToAddress(&SysPtes[0]);
585 SrcAddress = MiPteToAddress(&SysPtes[1]);
586 RtlCopyMemory(DestAddress, SrcAddress, PAGE_SIZE);
587
588 /* Now get rid of it */
590}
@ SystemPteSpace
Definition: miarm.h:403
VOID NTAPI MiReleaseSystemPtes(IN PMMPTE StartingPte, IN ULONG NumberOfPtes, IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType)
Definition: syspte.c:264
PMMPTE NTAPI MiReserveSystemPtes(IN ULONG NumberOfPtes, IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType)
Definition: syspte.c:246
#define MiPteToAddress(_Pte)
Definition: mm.h:116
MMPTE ValidKernelPte
Definition: init.c:29
ULONG PageFrameNumber
Definition: mmtypes.h:109
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263

Referenced by MiResolveProtoPteFault(), and MmArmAccessFault().

◆ MiDispatchFault()

NTSTATUS NTAPI MiDispatchFault ( IN ULONG  FaultCode,
IN PVOID  Address,
IN PMMPTE  PointerPte,
IN PMMPTE  PointerProtoPte,
IN BOOLEAN  Recursive,
IN PEPROCESS  Process,
IN PVOID  TrapInformation,
IN PMMVAD  Vad 
)

Definition at line 1319 of file pagfault.c.

1327{
1328 MMPTE TempPte;
1329 KIRQL OldIrql, LockIrql;
1331 PMMPTE SuperProtoPte;
1332 PMMPFN Pfn1, OutPfn = NULL;
1333 PFN_NUMBER PageFrameIndex;
1334 PFN_COUNT PteCount, ProcessedPtes;
1335 DPRINT("ARM3 Page Fault Dispatcher for address: %p in process: %p\n",
1336 Address,
1337 Process);
1338
1339 /* Make sure the addresses are ok */
1340 ASSERT(PointerPte == MiAddressToPte(Address));
1341
1342 //
1343 // Make sure APCs are off and we're not at dispatch
1344 //
1348
1349 //
1350 // Grab a copy of the PTE
1351 //
1352 TempPte = *PointerPte;
1353
1354 /* Do we have a prototype PTE? */
1355 if (PointerProtoPte)
1356 {
1357 /* This should never happen */
1358 ASSERT(!MI_IS_PHYSICAL_ADDRESS(PointerProtoPte));
1359
1360 /* Check if this is a kernel-mode address */
1361 SuperProtoPte = MiAddressToPte(PointerProtoPte);
1363 {
1364 /* Lock the PFN database */
1365 LockIrql = MiAcquirePfnLock();
1366
1367 /* Has the PTE been made valid yet? */
1368 if (!SuperProtoPte->u.Hard.Valid)
1369 {
1370 ASSERT(FALSE);
1371 }
1372 else if (PointerPte->u.Hard.Valid == 1)
1373 {
1374 ASSERT(FALSE);
1375 }
1376
1377 /* Resolve the fault -- this will release the PFN lock */
1379 Address,
1380 PointerPte,
1381 PointerProtoPte,
1382 &OutPfn,
1383 NULL,
1384 NULL,
1385 Process,
1386 LockIrql,
1387 TrapInformation);
1389
1390 /* Complete this as a transition fault */
1394 return Status;
1395 }
1396 else
1397 {
1398 /* We only handle the lookup path */
1399 ASSERT(PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED);
1400
1401 /* Is there a non-image VAD? */
1402 if ((Vad) &&
1403 (Vad->u.VadFlags.VadType != VadImageMap) &&
1404 !(Vad->u2.VadFlags2.ExtendableFile))
1405 {
1406 /* One day, ReactOS will cluster faults */
1408 DPRINT("Should cluster fault, but won't\n");
1409 }
1410
1411 /* Only one PTE to handle for now */
1412 PteCount = 1;
1413 ProcessedPtes = 0;
1414
1415 /* Lock the PFN database */
1416 LockIrql = MiAcquirePfnLock();
1417
1418 /* We only handle the valid path */
1419 ASSERT(SuperProtoPte->u.Hard.Valid == 1);
1420
1421 /* Capture the PTE */
1422 TempPte = *PointerProtoPte;
1423
1424 /* Loop to handle future case of clustered faults */
1425 while (TRUE)
1426 {
1427 /* For our current usage, this should be true */
1428 if (TempPte.u.Hard.Valid == 1)
1429 {
1430 /* Bump the share count on the PTE */
1431 PageFrameIndex = PFN_FROM_PTE(&TempPte);
1432 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1433 Pfn1->u2.ShareCount++;
1434 }
1435 else if ((TempPte.u.Soft.Prototype == 0) &&
1436 (TempPte.u.Soft.Transition == 1))
1437 {
1438 /* This is a standby page, bring it back from the cache */
1439 PageFrameIndex = TempPte.u.Trans.PageFrameNumber;
1440 DPRINT("oooh, shiny, a soft fault! 0x%lx\n", PageFrameIndex);
1441 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1443
1444 /* Should not yet happen in ReactOS */
1445 ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
1446 ASSERT(Pfn1->u4.InPageError == 0);
1447
1448 /* Get the page */
1450
1451 /* Bump its reference count */
1452 ASSERT(Pfn1->u2.ShareCount == 0);
1453 InterlockedIncrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1454 Pfn1->u2.ShareCount++;
1455
1456 /* Make it valid again */
1457 /* This looks like another macro.... */
1459 ASSERT(PointerProtoPte->u.Hard.Valid == 0);
1460 ASSERT(PointerProtoPte->u.Trans.Prototype == 0);
1461 ASSERT(PointerProtoPte->u.Trans.Transition == 1);
1462 TempPte.u.Long = (PointerProtoPte->u.Long & ~0xFFF) |
1463 MmProtectToPteMask[PointerProtoPte->u.Trans.Protection];
1464 TempPte.u.Hard.Valid = 1;
1466
1467 /* Is the PTE writeable? */
1468 if ((Pfn1->u3.e1.Modified) &&
1471 {
1472 /* Make it dirty */
1474 }
1475 else
1476 {
1477 /* Make it clean */
1479 }
1480
1481 /* Write the valid PTE */
1482 MI_WRITE_VALID_PTE(PointerProtoPte, TempPte);
1483 ASSERT(PointerPte->u.Hard.Valid == 0);
1484 }
1485 else
1486 {
1487 /* Page is invalid, get out of the loop */
1488 break;
1489 }
1490
1491 /* One more done, was it the last? */
1492 if (++ProcessedPtes == PteCount)
1493 {
1494 /* Complete the fault */
1496 Address,
1497 PointerPte,
1498 PointerProtoPte,
1499 LockIrql,
1500 &OutPfn);
1501
1502 /* THIS RELEASES THE PFN LOCK! */
1503 break;
1504 }
1505
1506 /* No clustered faults yet */
1507 ASSERT(FALSE);
1508 }
1509
1510 /* Did we resolve the fault? */
1511 if (ProcessedPtes)
1512 {
1513 /* Bump the transition count */
1514 InterlockedExchangeAddSizeT(&KeGetCurrentPrcb()->MmTransitionCount, ProcessedPtes);
1515 ProcessedPtes--;
1516
1517 /* Loop all the processing we did */
1518 ASSERT(ProcessedPtes == 0);
1519
1520 /* Complete this as a transition fault */
1525 }
1526
1527 /* We did not -- PFN lock is still held, prepare to resolve prototype PTE fault */
1528 OutPfn = MI_PFN_ELEMENT(SuperProtoPte->u.Hard.PageFrameNumber);
1530 ASSERT(OutPfn->u3.e2.ReferenceCount > 1);
1531 ASSERT(PointerPte->u.Hard.Valid == 0);
1532
1533 /* Resolve the fault -- this will release the PFN lock */
1535 Address,
1536 PointerPte,
1537 PointerProtoPte,
1538 &OutPfn,
1539 NULL,
1540 NULL,
1541 Process,
1542 LockIrql,
1543 TrapInformation);
1544 //ASSERT(Status != STATUS_ISSUE_PAGING_IO);
1545 //ASSERT(Status != STATUS_REFAULT);
1546 //ASSERT(Status != STATUS_PTE_CHANGED);
1547
1548 /* Did the routine clean out the PFN or should we? */
1549 if (OutPfn)
1550 {
1551 /* We had a locked PFN, so acquire the PFN lock to dereference it */
1552 ASSERT(PointerProtoPte != NULL);
1553 OldIrql = MiAcquirePfnLock();
1554
1555 /* Dereference the locked PFN */
1557 ASSERT(OutPfn->u3.e2.ReferenceCount >= 1);
1558
1559 /* And now release the lock */
1560 MiReleasePfnLock(OldIrql);
1561 }
1562
1563 /* Complete this as a transition fault */
1567 return Status;
1568 }
1569 }
1570
1571 /* Is this a transition PTE */
1572 if (TempPte.u.Soft.Transition)
1573 {
1574 PKEVENT* InPageBlock = NULL;
1575 PKEVENT PreviousPageEvent;
1576 KEVENT CurrentPageEvent;
1577
1578 /* Lock the PFN database */
1579 LockIrql = MiAcquirePfnLock();
1580
1581 /* Resolve */
1582 Status = MiResolveTransitionFault(!MI_IS_NOT_PRESENT_FAULT(FaultCode), Address, PointerPte, Process, LockIrql, &InPageBlock);
1583
1585
1586 if (InPageBlock != NULL)
1587 {
1588 /* Another thread is reading or writing this page. Put us into the waiting queue. */
1589 KeInitializeEvent(&CurrentPageEvent, NotificationEvent, FALSE);
1590 PreviousPageEvent = *InPageBlock;
1591 *InPageBlock = &CurrentPageEvent;
1592 }
1593
1594 /* And now release the lock and leave*/
1595 MiReleasePfnLock(LockIrql);
1596
1597 if (InPageBlock != NULL)
1598 {
1599 KeWaitForSingleObject(&CurrentPageEvent, WrPageIn, KernelMode, FALSE, NULL);
1600
1601 /* Let's the chain go on */
1602 if (PreviousPageEvent)
1603 {
1604 KeSetEvent(PreviousPageEvent, IO_NO_INCREMENT, FALSE);
1605 }
1606 }
1607
1611 return Status;
1612 }
1613
1614 /* Should we page the data back in ? */
1615 if (TempPte.u.Soft.PageFileHigh != 0)
1616 {
1617 /* Lock the PFN database */
1618 LockIrql = MiAcquirePfnLock();
1619
1620 /* Resolve */
1621 Status = MiResolvePageFileFault(!MI_IS_NOT_PRESENT_FAULT(FaultCode), Address, PointerPte, Process, &LockIrql);
1622
1623 /* And now release the lock and leave*/
1624 MiReleasePfnLock(LockIrql);
1625
1629 return Status;
1630 }
1631
1632 //
1633 // The PTE must be invalid but not completely empty. It must also not be a
1634 // prototype a transition or a paged-out PTE as those scenarii should've been handled above.
1635 // These are all Windows checks
1636 //
1637 ASSERT(TempPte.u.Hard.Valid == 0);
1638 ASSERT(TempPte.u.Soft.Prototype == 0);
1639 ASSERT(TempPte.u.Soft.Transition == 0);
1640 ASSERT(TempPte.u.Soft.PageFileHigh == 0);
1641 ASSERT(TempPte.u.Long != 0);
1642
1643 //
1644 // If we got this far, the PTE can only be a demand zero PTE, which is what
1645 // we want. Go handle it!
1646 //
1648 PointerPte,
1649 (ULONG)TempPte.u.Soft.Protection,
1650 Process,
1651 MM_NOIRQL);
1653 if (NT_SUCCESS(Status))
1654 {
1655#if MI_TRACE_PFNS
1656 /* Update debug info */
1657 if (TrapInformation)
1658 MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = (PVOID)((PKTRAP_FRAME)TrapInformation)->Eip;
1659 else
1660 MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = _ReturnAddress();
1661#endif
1662
1663 //
1664 // Make sure we're returning in a sane state and pass the status down
1665 //
1668 return Status;
1669 }
1670
1671 //
1672 // Generate an access fault
1673 //
1675}
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
#define InterlockedIncrement16
Definition: interlocked.h:206
#define InterlockedExchangeAddSizeT(a, b)
Definition: interlocked.h:196
#define _ReturnAddress()
Definition: intrin_arm.h:35
FORCEINLINE BOOLEAN MI_IS_PHYSICAL_ADDRESS(IN PVOID Address)
Definition: miarm.h:945
FORCEINLINE VOID MiReferenceUsedPageAndBumpLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1742
VOID NTAPI MiUnlinkPageFromList(IN PMMPFN Pfn)
Definition: pfnlist.c:265
FORCEINLINE PMMPFN MI_PFN_ELEMENT(IN PFN_NUMBER Pfn)
Definition: miarm.h:1574
#define KernelMode
Definition: asm.h:34
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1080
@ ActiveAndValid
Definition: mmtypes.h:155
@ NotificationEvent
#define MI_IS_NOT_PRESENT_FAULT(FaultCode)
Definition: mm.h:121
#define MI_MAKE_ACCESSED_PAGE(x)
Definition: mm.h:100
#define MI_MAKE_CLEAN_PAGE(x)
Definition: mm.h:99
#define MM_NOIRQL
Definition: mm.h:70
const ULONG MmProtectToPteMask[32]
Definition: page.c:22
#define STATUS_PAGE_FAULT_TRANSITION
Definition: ntstatus.h:94
static NTSTATUS NTAPI MiResolveDemandZeroFault(IN PVOID Address, IN PMMPTE PointerPte, IN ULONG Protection, IN PEPROCESS Process, IN KIRQL OldIrql)
Definition: pagfault.c:595
static NTSTATUS NTAPI MiCompleteProtoPteFault(IN BOOLEAN StoreInstruction, IN PVOID Address, IN PMMPTE PointerPte, IN PMMPTE PointerProtoPte, IN KIRQL OldIrql, IN PMMPFN *LockedProtoPfn)
Definition: pagfault.c:765
static NTSTATUS NTAPI MiResolveTransitionFault(IN BOOLEAN StoreInstruction, IN PVOID FaultingAddress, IN PMMPTE PointerPte, IN PEPROCESS CurrentProcess, IN KIRQL OldIrql, OUT PKEVENT **InPageBlock)
Definition: pagfault.c:978
static NTSTATUS NTAPI MiResolvePageFileFault(_In_ BOOLEAN StoreInstruction, _In_ PVOID FaultingAddress, _In_ PMMPTE PointerPte, _In_ PEPROCESS CurrentProcess, _Inout_ KIRQL *OldIrql)
Definition: pagfault.c:890
static NTSTATUS NTAPI MiResolveProtoPteFault(IN BOOLEAN StoreInstruction, IN PVOID Address, IN PMMPTE PointerPte, IN PMMPTE PointerProtoPte, IN OUT PMMPFN *OutPfn, OUT PVOID *PageFileData, OUT PMMPTE PteValue, IN PEPROCESS Process, IN KIRQL OldIrql, IN PVOID TrapInformation)
Definition: pagfault.c:1110
USHORT Modified
Definition: mm.h:360
USHORT ReadInProgress
Definition: mm.h:361
USHORT PageLocation
Definition: mm.h:365
union _MMPFN::@1775 u4
ULONG_PTR InPageError
Definition: mm.h:419
struct _MMPFN::@1772::@1778 e2
ULONG64 Valid
Definition: mmtypes.h:150
int16_t * PSHORT
Definition: typedefs.h:55
#define IO_NO_INCREMENT
Definition: iotypes.h:598
@ WrPageIn
Definition: ketypes.h:412
ULONG PFN_COUNT
Definition: mmtypes.h:102

Referenced by MmArmAccessFault().

◆ MiIsAccessAllowed()

FORCEINLINE BOOLEAN MiIsAccessAllowed ( _In_ ULONG  ProtectionMask,
_In_ BOOLEAN  Write,
_In_ BOOLEAN  Execute 
)

Definition at line 138 of file pagfault.c.

142{
143 #define _BYTE_MASK(Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7) \
144 (Bit0) | ((Bit1) << 1) | ((Bit2) << 2) | ((Bit3) << 3) | \
145 ((Bit4) << 4) | ((Bit5) << 5) | ((Bit6) << 6) | ((Bit7) << 7)
146 static const UCHAR AccessAllowedMask[2][2] =
147 {
148 { // Protect 0 1 2 3 4 5 6 7
149 _BYTE_MASK(0, 1, 1, 1, 1, 1, 1, 1), // READ
150 _BYTE_MASK(0, 0, 1, 1, 0, 0, 1, 1), // EXECUTE READ
151 },
152 {
153 _BYTE_MASK(0, 0, 0, 0, 1, 1, 1, 1), // WRITE
154 _BYTE_MASK(0, 0, 0, 0, 0, 0, 1, 1), // EXECUTE WRITE
155 }
156 };
157
158 /* We want only the lower access bits */
159 ProtectionMask &= MM_PROTECT_ACCESS;
160
161 /* Look it up in the table */
162 return (AccessAllowedMask[Write != 0][Execute != 0] >> ProtectionMask) & 1;
163}
static INT Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
Definition: cmd.c:347
#define MM_PROTECT_ACCESS
Definition: miarm.h:51
#define _BYTE_MASK(Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7)
static BOOL Write(PBYTE Address, PBYTE Data, SIZE_T Size)
Definition: vmhorizon.c:15
unsigned char UCHAR
Definition: xmlstorage.h:181

Referenced by MiAccessCheck().

◆ MiResolveDemandZeroFault()

static NTSTATUS NTAPI MiResolveDemandZeroFault ( IN PVOID  Address,
IN PMMPTE  PointerPte,
IN ULONG  Protection,
IN PEPROCESS  Process,
IN KIRQL  OldIrql 
)
static

Definition at line 595 of file pagfault.c.

600{
601 PFN_NUMBER PageFrameNumber = 0;
603 BOOLEAN NeedZero = FALSE, HaveLock = FALSE;
604 ULONG Color;
605 PMMPFN Pfn1;
606 DPRINT("ARM3 Demand Zero Page Fault Handler for address: %p in process: %p\n",
607 Address,
608 Process);
609
610 /* Must currently only be called by paging path */
611 if ((Process > HYDRA_PROCESS) && (OldIrql == MM_NOIRQL))
612 {
613 /* Sanity check */
614 ASSERT(MI_IS_PAGE_TABLE_ADDRESS(PointerPte));
615
616 /* No forking yet */
617 ASSERT(Process->ForkInProgress == NULL);
618
619 /* Get process color */
621 ASSERT(Color != 0xFFFFFFFF);
622
623 /* We'll need a zero page */
624 NeedZero = TRUE;
625 }
626 else
627 {
628 /* Check if we need a zero page */
629 NeedZero = (OldIrql != MM_NOIRQL);
630
631 /* Session-backed image views must be zeroed */
632 if ((Process == HYDRA_PROCESS) &&
635 {
636 NeedZero = TRUE;
637 }
638
639 /* Hardcode unknown color */
640 Color = 0xFFFFFFFF;
641 }
642
643 /* Check if the PFN database should be acquired */
644 if (OldIrql == MM_NOIRQL)
645 {
646 /* Acquire it and remember we should release it after */
647 OldIrql = MiAcquirePfnLock();
648 HaveLock = TRUE;
649 }
650
651 /* We either manually locked the PFN DB, or already came with it locked */
653 ASSERT(PointerPte->u.Hard.Valid == 0);
654
655 /* Assert we have enough pages */
657
658#if MI_TRACE_PFNS
659 if (UserPdeFault) MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
660 if (!UserPdeFault) MI_SET_USAGE(MI_USAGE_DEMAND_ZERO);
661#endif
662 if (Process == HYDRA_PROCESS) MI_SET_PROCESS2("Hydra");
663 else if (Process) MI_SET_PROCESS2(Process->ImageFileName);
664 else MI_SET_PROCESS2("Kernel Demand 0");
665
666 /* Do we need a zero page? */
667 if (Color != 0xFFFFFFFF)
668 {
669 /* Try to get one, if we couldn't grab a free page and zero it */
670 PageFrameNumber = MiRemoveZeroPageSafe(Color);
671 if (!PageFrameNumber)
672 {
673 /* We'll need a free page and zero it manually */
674 PageFrameNumber = MiRemoveAnyPage(Color);
675 NeedZero = TRUE;
676 }
677 else
678 {
679 /* Page guaranteed to be zero-filled */
680 NeedZero = FALSE;
681 }
682 }
683 else
684 {
685 /* Get a color, and see if we should grab a zero or non-zero page */
687 if (!NeedZero)
688 {
689 /* Process or system doesn't want a zero page, grab anything */
690 PageFrameNumber = MiRemoveAnyPage(Color);
691 }
692 else
693 {
694 /* System wants a zero page, obtain one */
695 PageFrameNumber = MiRemoveZeroPage(Color);
696 /* No need to zero-fill it */
697 NeedZero = FALSE;
698 }
699 }
700
701 /* Initialize it */
702 MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
703
704 /* Increment demand zero faults */
705 KeGetCurrentPrcb()->MmDemandZeroCount++;
706
707 /* Do we have the lock? */
708 if (HaveLock)
709 {
710 /* Release it */
711 MiReleasePfnLock(OldIrql);
712
713 /* Update performance counters */
714 if (Process > HYDRA_PROCESS) Process->NumberOfPrivatePages++;
715 }
716
717 /* Zero the page if need be */
718 if (NeedZero) MiZeroPfn(PageFrameNumber);
719
720 /* Fault on user PDE, or fault on user PTE? */
721 if (PointerPte <= MiHighestUserPte)
722 {
723 /* User fault, build a user PTE */
725 PointerPte,
726 Protection,
727 PageFrameNumber);
728 }
729 else
730 {
731 /* This is a user-mode PDE, create a kernel PTE for it */
733 PointerPte,
734 Protection,
735 PageFrameNumber);
736 }
737
738 /* Set it dirty if it's a writable page */
740
741 /* Write it */
742 MI_WRITE_VALID_PTE(PointerPte, TempPte);
743
744 /* Did we manually acquire the lock */
745 if (HaveLock)
746 {
747 /* Get the PFN entry */
748 Pfn1 = MI_PFN_ELEMENT(PageFrameNumber);
749
750 /* Windows does these sanity checks */
751 ASSERT(Pfn1->u1.Event == 0);
752 ASSERT(Pfn1->u3.e1.PrototypePte == 0);
753 }
754
755 //
756 // It's all good now
757 //
758 DPRINT("Demand zero page has now been paged in\n");
760}
PFN_NUMBER NTAPI MiRemoveZeroPage(IN ULONG Color)
Definition: pfnlist.c:533
#define MI_IS_SESSION_IMAGE_ADDRESS(Address)
Definition: miarm.h:168
#define MI_GET_NEXT_COLOR()
Definition: miarm.h:232
PFN_NUMBER NTAPI MiRemoveAnyPage(IN ULONG Color)
Definition: pfnlist.c:477
VOID NTAPI MiInitializePfn(IN PFN_NUMBER PageFrameIndex, IN PMMPTE PointerPte, IN BOOLEAN Modified)
Definition: pfnlist.c:962
#define MI_GET_NEXT_PROCESS_COLOR(x)
Definition: miarm.h:233
PVOID MiSessionSpaceWs
Definition: mminit.c:130
FORCEINLINE PFN_NUMBER MiRemoveZeroPageSafe(IN ULONG Color)
Definition: miarm.h:2415
#define MI_SET_PROCESS2(x)
Definition: mm.h:319
@ MI_USAGE_PAGE_TABLE
Definition: mm.h:334
@ MI_USAGE_DEMAND_ZERO
Definition: mm.h:340
#define MI_SET_USAGE(x)
Definition: mm.h:317
PFN_NUMBER MmAvailablePages
Definition: freelist.c:26
PVOID MiSessionViewStart
Definition: init.c:30
#define STATUS_PAGE_FAULT_DEMAND_ZERO
Definition: ntstatus.h:95
VOID NTAPI MiZeroPfn(IN PFN_NUMBER PageFrameNumber)
Definition: pagfault.c:483
#define HYDRA_PROCESS
Definition: pagfault.c:20
union _MMPFN::@1770 u1
PKEVENT Event
Definition: mm.h:379

Referenced by MiDispatchFault(), MiResolveProtoPteFault(), and MmArmAccessFault().

◆ MiResolvePageFileFault()

static NTSTATUS NTAPI MiResolvePageFileFault ( _In_ BOOLEAN  StoreInstruction,
_In_ PVOID  FaultingAddress,
_In_ PMMPTE  PointerPte,
_In_ PEPROCESS  CurrentProcess,
_Inout_ KIRQL OldIrql 
)
static

Definition at line 890 of file pagfault.c.

895{
896 ULONG Color;
899 MMPTE TempPte = *PointerPte;
900 PMMPFN Pfn1;
901 ULONG PageFileIndex = TempPte.u.Soft.PageFileLow;
902 ULONG_PTR PageFileOffset = TempPte.u.Soft.PageFileHigh;
903 ULONG Protection = TempPte.u.Soft.Protection;
904
905 /* Things we don't support yet */
906 ASSERT(CurrentProcess > HYDRA_PROCESS);
908
910 MI_SET_PROCESS(CurrentProcess);
911
912 /* We must hold the PFN lock */
914
915 /* Some sanity checks */
916 ASSERT(TempPte.u.Hard.Valid == 0);
917 ASSERT(TempPte.u.Soft.PageFileHigh != 0);
918 ASSERT(TempPte.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED);
919
920 /* Get any page, it will be overwritten */
921 Color = MI_GET_NEXT_PROCESS_COLOR(CurrentProcess);
923
924 /* Initialize this PFN */
925 MiInitializePfn(Page, PointerPte, StoreInstruction);
926
927 /* Sets the PFN as being in IO operation */
928 Pfn1 = MI_PFN_ELEMENT(Page);
929 ASSERT(Pfn1->u1.Event == NULL);
930 ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
931 ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
932 Pfn1->u3.e1.ReadInProgress = 1;
933
934 /* We must write the PTE now as the PFN lock will be released while performing the IO operation */
935 MI_MAKE_TRANSITION_PTE(&TempPte, Page, Protection);
936
937 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
938
939 /* Release the PFN lock while we proceed */
940 MiReleasePfnLock(*OldIrql);
941
942 /* Do the paging IO */
943 Status = MiReadPageFile(Page, PageFileIndex, PageFileOffset);
944
945 /* Lock the PFN database again */
946 *OldIrql = MiAcquirePfnLock();
947
948 /* Nobody should have changed that while we were not looking */
949 ASSERT(Pfn1->u3.e1.ReadInProgress == 1);
950 ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
951
952 if (!NT_SUCCESS(Status))
953 {
954 /* Malheur! */
955 ASSERT(FALSE);
956 Pfn1->u4.InPageError = 1;
957 Pfn1->u1.ReadStatus = Status;
958 }
959
960 /* And the PTE can finally be valid */
961 MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, Protection, Page);
962 MI_WRITE_VALID_PTE(PointerPte, TempPte);
963
964 Pfn1->u3.e1.ReadInProgress = 0;
965 /* Did someone start to wait on us while we proceeded ? */
966 if (Pfn1->u1.Event)
967 {
968 /* Tell them we're done */
970 }
971
972 return Status;
973}
FORCEINLINE VOID MI_MAKE_TRANSITION_PTE(_Out_ PMMPTE NewPte, _In_ PFN_NUMBER Page, _In_ ULONG Protection)
Definition: miarm.h:929
@ MI_USAGE_PAGE_FILE
Definition: mm.h:346
NTSTATUS NTAPI MiReadPageFile(_In_ PFN_NUMBER Page, _In_ ULONG PageFileIndex, _In_ ULONG_PTR PageFileOffset)
Definition: pagefile.c:211
_In_ PVOID _Out_opt_ BOOLEAN _Out_opt_ PPFN_NUMBER Page
Definition: mm.h:1298
#define MI_SET_PROCESS(x)
Definition: mm.h:318
USHORT WriteInProgress
Definition: mm.h:362
NTSTATUS ReadStatus
Definition: mm.h:380

Referenced by MiDispatchFault().

◆ MiResolveProtoPteFault()

static NTSTATUS NTAPI MiResolveProtoPteFault ( IN BOOLEAN  StoreInstruction,
IN PVOID  Address,
IN PMMPTE  PointerPte,
IN PMMPTE  PointerProtoPte,
IN OUT PMMPFN OutPfn,
OUT PVOID PageFileData,
OUT PMMPTE  PteValue,
IN PEPROCESS  Process,
IN KIRQL  OldIrql,
IN PVOID  TrapInformation 
)
static

Definition at line 1110 of file pagfault.c.

1120{
1121 MMPTE TempPte, PteContents;
1122 PMMPFN Pfn1;
1123 PFN_NUMBER PageFrameIndex;
1125 PKEVENT* InPageBlock = NULL;
1126 ULONG Protection;
1127
1128 /* Must be called with an invalid, prototype PTE, with the PFN lock held */
1130 ASSERT(PointerPte->u.Hard.Valid == 0);
1131 ASSERT(PointerPte->u.Soft.Prototype == 1);
1132
1133 /* Read the prototype PTE and check if it's valid */
1134 TempPte = *PointerProtoPte;
1135 if (TempPte.u.Hard.Valid == 1)
1136 {
1137 /* One more user of this mapped page */
1138 PageFrameIndex = PFN_FROM_PTE(&TempPte);
1139 Pfn1 = MiGetPfnEntry(PageFrameIndex);
1140 Pfn1->u2.ShareCount++;
1141
1142 /* Call it a transition */
1143 InterlockedIncrement(&KeGetCurrentPrcb()->MmTransitionCount);
1144
1145 /* Complete the prototype PTE fault -- this will release the PFN lock */
1146 return MiCompleteProtoPteFault(StoreInstruction,
1147 Address,
1148 PointerPte,
1149 PointerProtoPte,
1150 OldIrql,
1151 OutPfn);
1152 }
1153
1154 /* Make sure there's some protection mask */
1155 if (TempPte.u.Long == 0)
1156 {
1157 /* Release the lock */
1158 DPRINT1("Access on reserved section?\n");
1159 MiReleasePfnLock(OldIrql);
1161 }
1162
1163 /* There is no such thing as a decommitted prototype PTE */
1165
1166 /* Check for access rights on the PTE proper */
1167 PteContents = *PointerPte;
1168 if (PteContents.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED)
1169 {
1170 if (!PteContents.u.Proto.ReadOnly)
1171 {
1172 Protection = TempPte.u.Soft.Protection;
1173 }
1174 else
1175 {
1176 Protection = MM_READONLY;
1177 }
1178 /* Check for page acess in software */
1179 Status = MiAccessCheck(PointerProtoPte,
1180 StoreInstruction,
1181 KernelMode,
1182 TempPte.u.Soft.Protection,
1183 TrapInformation,
1184 TRUE);
1186 }
1187 else
1188 {
1189 Protection = PteContents.u.Soft.Protection;
1190 }
1191
1192 /* Check for writing copy on write page */
1193 if (((Protection & MM_WRITECOPY) == MM_WRITECOPY) && StoreInstruction)
1194 {
1195 PFN_NUMBER PageFrameIndex, ProtoPageFrameIndex;
1196 ULONG Color;
1197
1198 /* Resolve the proto fault as if it was a read operation */
1200 Address,
1201 PointerPte,
1202 PointerProtoPte,
1203 OutPfn,
1204 PageFileData,
1205 PteValue,
1206 Process,
1207 OldIrql,
1208 TrapInformation);
1209
1210 if (!NT_SUCCESS(Status))
1211 {
1212 return Status;
1213 }
1214
1215 /* Lock again the PFN lock, MiResolveProtoPteFault unlocked it */
1216 OldIrql = MiAcquirePfnLock();
1217
1218 /* And re-read the proto PTE */
1219 TempPte = *PointerProtoPte;
1220 ASSERT(TempPte.u.Hard.Valid == 1);
1221 ProtoPageFrameIndex = PFN_FROM_PTE(&TempPte);
1222
1225
1226 /* Get a new page for the private copy */
1227 if (Process > HYDRA_PROCESS)
1229 else
1231
1232 PageFrameIndex = MiRemoveAnyPage(Color);
1233
1234 /* Perform the copy */
1235 MiCopyPfn(PageFrameIndex, ProtoPageFrameIndex);
1236
1237 /* This will drop everything MiResolveProtoPteFault referenced */
1238 MiDeletePte(PointerPte, Address, Process, PointerProtoPte);
1239
1240 /* Because now we use this */
1241 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1242 MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
1243
1244 /* Fix the protection */
1245 Protection &= ~MM_WRITECOPY;
1246 Protection |= MM_READWRITE;
1248 {
1249 /* Build the user PTE */
1250 MI_MAKE_HARDWARE_PTE_USER(&PteContents, PointerPte, Protection, PageFrameIndex);
1251 }
1252 else
1253 {
1254 /* Build the kernel PTE */
1255 MI_MAKE_HARDWARE_PTE(&PteContents, PointerPte, Protection, PageFrameIndex);
1256 }
1257
1258 /* And finally, write the valid PTE */
1259 MI_WRITE_VALID_PTE(PointerPte, PteContents);
1260
1261 /* The caller expects us to release the PFN lock */
1262 MiReleasePfnLock(OldIrql);
1263 return Status;
1264 }
1265
1266 /* Check for clone PTEs */
1267 if (PointerPte <= MiHighestUserPte) ASSERT(Process->CloneRoot == NULL);
1268
1269 /* We don't support mapped files yet */
1270 ASSERT(TempPte.u.Soft.Prototype == 0);
1271
1272 /* We might however have transition PTEs */
1273 if (TempPte.u.Soft.Transition == 1)
1274 {
1275 /* Resolve the transition fault */
1277 Status = MiResolveTransitionFault(StoreInstruction,
1278 Address,
1279 PointerProtoPte,
1280 Process,
1281 OldIrql,
1282 &InPageBlock);
1284 }
1285 else
1286 {
1287 /* We also don't support paged out pages */
1288 ASSERT(TempPte.u.Soft.PageFileHigh == 0);
1289
1290 /* Resolve the demand zero fault */
1292 PointerProtoPte,
1293 (ULONG)TempPte.u.Soft.Protection,
1294 Process,
1295 OldIrql);
1296#if MI_TRACE_PFNS
1297 /* Update debug info */
1298 if (TrapInformation)
1299 MiGetPfnEntry(PointerProtoPte->u.Hard.PageFrameNumber)->CallSite = (PVOID)((PKTRAP_FRAME)TrapInformation)->Eip;
1300 else
1301 MiGetPfnEntry(PointerProtoPte->u.Hard.PageFrameNumber)->CallSite = _ReturnAddress();
1302#endif
1303
1305 }
1306
1307 /* Complete the prototype PTE fault -- this will release the PFN lock */
1308 ASSERT(PointerPte->u.Hard.Valid == 0);
1309 return MiCompleteProtoPteFault(StoreInstruction,
1310 Address,
1311 PointerPte,
1312 PointerProtoPte,
1313 OldIrql,
1314 OutPfn);
1315}
#define InterlockedIncrement
Definition: armddk.h:53
VOID NTAPI MiDeletePte(IN PMMPTE PointerPte, IN PVOID VirtualAddress, IN PEPROCESS CurrentProcess, IN PMMPTE PrototypePte)
Definition: virtual.c:369
@ MI_USAGE_COW
Definition: mm.h:347
MMPTE MmDecommittedPte
Definition: init.c:44
VOID NTAPI MiCopyPfn(_In_ PFN_NUMBER DestPage, _In_ PFN_NUMBER SrcPage)
Definition: pagfault.c:529
static NTSTATUS NTAPI MiAccessCheck(IN PMMPTE PointerPte, IN BOOLEAN StoreInstruction, IN KPROCESSOR_MODE PreviousMode, IN ULONG_PTR ProtectionMask, IN PVOID TrapFrame, IN BOOLEAN LockHeld)
Definition: pagfault.c:168
ULONG64 ReadOnly
Definition: mmtypes.h:119
ULONG64 PageFileHigh
Definition: mmtypes.h:93
MMPTE_PROTOTYPE Proto
Definition: mmtypes.h:218
ULONG_PTR Long
Definition: mmtypes.h:215

Referenced by MiDispatchFault(), and MiResolveProtoPteFault().

◆ MiResolveTransitionFault()

static NTSTATUS NTAPI MiResolveTransitionFault ( IN BOOLEAN  StoreInstruction,
IN PVOID  FaultingAddress,
IN PMMPTE  PointerPte,
IN PEPROCESS  CurrentProcess,
IN KIRQL  OldIrql,
OUT PKEVENT **  InPageBlock 
)
static

Definition at line 978 of file pagfault.c.

984{
985 PFN_NUMBER PageFrameIndex;
986 PMMPFN Pfn1;
988 PMMPTE PointerToPteForProtoPage;
989 DPRINT("Transition fault on 0x%p with PTE 0x%p in process %s\n",
990 FaultingAddress, PointerPte, CurrentProcess->ImageFileName);
991
992 /* Windowss does this check */
993 ASSERT(*InPageBlock == NULL);
994
995 /* ARM3 doesn't support this path */
997
998 /* Capture the PTE and make sure it's in transition format */
999 TempPte = *PointerPte;
1000 ASSERT((TempPte.u.Soft.Valid == 0) &&
1001 (TempPte.u.Soft.Prototype == 0) &&
1002 (TempPte.u.Soft.Transition == 1));
1003
1004 /* Get the PFN and the PFN entry */
1005 PageFrameIndex = TempPte.u.Trans.PageFrameNumber;
1006 DPRINT("Transition PFN: %lx\n", PageFrameIndex);
1007 Pfn1 = MiGetPfnEntry(PageFrameIndex);
1008
1009 /* One more transition fault! */
1010 InterlockedIncrement(&KeGetCurrentPrcb()->MmTransitionCount);
1011
1012 /* This is from ARM3 -- Windows normally handles this here */
1013 ASSERT(Pfn1->u4.InPageError == 0);
1014
1015 /* See if we should wait before terminating the fault */
1016 if ((Pfn1->u3.e1.ReadInProgress == 1)
1017 || ((Pfn1->u3.e1.WriteInProgress == 1) && StoreInstruction))
1018 {
1019 DPRINT1("The page is currently in a page transition !\n");
1020 *InPageBlock = &Pfn1->u1.Event;
1021 if (PointerPte == Pfn1->PteAddress)
1022 {
1023 DPRINT1("And this if for this particular PTE.\n");
1024 /* The PTE will be made valid by the thread serving the fault */
1025 return STATUS_SUCCESS; // FIXME: Maybe something more descriptive
1026 }
1027 }
1028
1029 /* Windows checks there's some free pages and this isn't an in-page error */
1031 ASSERT(Pfn1->u4.InPageError == 0);
1032
1033 /* ReactOS checks for this */
1035
1036 /* Was this a transition page in the valid list, or free/zero list? */
1037 if (Pfn1->u3.e1.PageLocation == ActiveAndValid)
1038 {
1039 /* All Windows does here is a bunch of sanity checks */
1040 DPRINT("Transition in active list\n");
1043 ASSERT(Pfn1->u2.ShareCount != 0);
1044 ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
1045 }
1046 else
1047 {
1048 /* Otherwise, the page is removed from its list */
1049 DPRINT("Transition page in free/zero list\n");
1052 }
1053
1054 /* At this point, there should no longer be any in-page errors */
1055 ASSERT(Pfn1->u4.InPageError == 0);
1056
1057 /* Check if this was a PFN with no more share references */
1058 if (Pfn1->u2.ShareCount == 0) MiDropLockCount(Pfn1);
1059
1060 /* Bump the share count and make the page valid */
1061 Pfn1->u2.ShareCount++;
1063
1064 /* Prototype PTEs are in paged pool, which itself might be in transition */
1065 if (FaultingAddress >= MmSystemRangeStart)
1066 {
1067 /* Check if this is a paged pool PTE in transition state */
1068 PointerToPteForProtoPage = MiAddressToPte(PointerPte);
1069 TempPte = *PointerToPteForProtoPage;
1070 if ((TempPte.u.Hard.Valid == 0) && (TempPte.u.Soft.Transition == 1))
1071 {
1072 /* This isn't yet supported */
1073 DPRINT1("Double transition fault not yet supported\n");
1074 ASSERT(FALSE);
1075 }
1076 }
1077
1078 /* Build the final PTE */
1079 ASSERT(PointerPte->u.Hard.Valid == 0);
1080 ASSERT(PointerPte->u.Trans.Prototype == 0);
1081 ASSERT(PointerPte->u.Trans.Transition == 1);
1082 TempPte.u.Long = (PointerPte->u.Long & ~0xFFF) |
1083 (MmProtectToPteMask[PointerPte->u.Trans.Protection]) |
1084 MiDetermineUserGlobalPteMask(PointerPte);
1085
1086 /* Is the PTE writeable? */
1087 if ((Pfn1->u3.e1.Modified) &&
1090 {
1091 /* Make it dirty */
1093 }
1094 else
1095 {
1096 /* Make it clean */
1098 }
1099
1100 /* Write the valid PTE */
1101 MI_WRITE_VALID_PTE(PointerPte, TempPte);
1102
1103 /* Return success */
1105}
FORCEINLINE VOID MiReferenceUnusedPageAndBumpLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1787
FORCEINLINE VOID MiDropLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1585
FORCEINLINE ULONG_PTR MiDetermineUserGlobalPteMask(IN PVOID PointerPte)
Definition: miarm.h:736
PVOID MmPagedPoolEnd
Definition: init.c:26
PMMPTE PteAddress
Definition: mm.h:386

Referenced by MiDispatchFault(), and MiResolveProtoPteFault().

◆ MiZeroPfn()

VOID NTAPI MiZeroPfn ( IN PFN_NUMBER  PageFrameNumber)

Definition at line 483 of file pagfault.c.

484{
485 PMMPTE ZeroPte;
487 PMMPFN Pfn1;
488 PVOID ZeroAddress;
489
490 /* Get the PFN for this page */
491 Pfn1 = MiGetPfnEntry(PageFrameNumber);
492 ASSERT(Pfn1);
493
494 /* Grab a system PTE we can use to zero the page */
496 ASSERT(ZeroPte);
497
498 /* Initialize the PTE for it */
500 TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
501
502 /* Setup caching */
503 if (Pfn1->u3.e1.CacheAttribute == MiWriteCombined)
504 {
505 /* Write combining, no caching */
508 }
509 else if (Pfn1->u3.e1.CacheAttribute == MiNonCached)
510 {
511 /* Write through, no caching */
514 }
515
516 /* Make the system PTE valid with our PFN */
517 MI_WRITE_VALID_PTE(ZeroPte, TempPte);
518
519 /* Get the address it maps to, and zero it out */
520 ZeroAddress = MiPteToAddress(ZeroPte);
521 KeZeroPages(ZeroAddress, PAGE_SIZE);
522
523 /* Now get rid of it */
525}
VOID FASTCALL KeZeroPages(IN PVOID Address, IN ULONG Size)
Definition: cpu.c:56

Referenced by MiResolveDemandZeroFault(), and MmArmAccessFault().

◆ MmArmAccessFault()

NTSTATUS NTAPI MmArmAccessFault ( IN ULONG  FaultCode,
IN PVOID  Address,
IN KPROCESSOR_MODE  Mode,
IN PVOID  TrapInformation 
)

Definition at line 1679 of file pagfault.c.

1683{
1684 KIRQL OldIrql = KeGetCurrentIrql(), LockIrql;
1685 PMMPTE ProtoPte = NULL;
1686 PMMPTE PointerPte = MiAddressToPte(Address);
1687 PMMPDE PointerPde = MiAddressToPde(Address);
1688#if (_MI_PAGING_LEVELS >= 3)
1689 PMMPDE PointerPpe = MiAddressToPpe(Address);
1690#if (_MI_PAGING_LEVELS == 4)
1691 PMMPDE PointerPxe = MiAddressToPxe(Address);
1692#endif
1693#endif
1694 MMPTE TempPte;
1695 PETHREAD CurrentThread;
1696 PEPROCESS CurrentProcess;
1698 PMMSUPPORT WorkingSet;
1699 ULONG ProtectionCode;
1700 PMMVAD Vad = NULL;
1701 PFN_NUMBER PageFrameIndex;
1702 ULONG Color;
1703 BOOLEAN IsSessionAddress;
1704 PMMPFN Pfn1;
1705 DPRINT("ARM3 FAULT AT: %p\n", Address);
1706
1707 /* Check for page fault on high IRQL */
1708 if (OldIrql > APC_LEVEL)
1709 {
1710#if (_MI_PAGING_LEVELS < 3)
1711 /* Could be a page table for paged pool, which we'll allow */
1712 if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)) MiSynchronizeSystemPde((PMMPDE)PointerPte);
1714#endif
1715 /* Check if any of the top-level pages are invalid */
1716 if (
1717#if (_MI_PAGING_LEVELS == 4)
1718 (PointerPxe->u.Hard.Valid == 0) ||
1719#endif
1720#if (_MI_PAGING_LEVELS >= 3)
1721 (PointerPpe->u.Hard.Valid == 0) ||
1722#endif
1723 (PointerPde->u.Hard.Valid == 0) ||
1724 (PointerPte->u.Hard.Valid == 0))
1725 {
1726 /* This fault is not valid, print out some debugging help */
1727 DbgPrint("MM:***PAGE FAULT AT IRQL > 1 Va %p, IRQL %lx\n",
1728 Address,
1729 OldIrql);
1730 if (TrapInformation)
1731 {
1732 PKTRAP_FRAME TrapFrame = TrapInformation;
1733#ifdef _M_IX86
1734 DbgPrint("MM:***EIP %p, EFL %p\n", TrapFrame->Eip, TrapFrame->EFlags);
1735 DbgPrint("MM:***EAX %p, ECX %p EDX %p\n", TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
1736 DbgPrint("MM:***EBX %p, ESI %p EDI %p\n", TrapFrame->Ebx, TrapFrame->Esi, TrapFrame->Edi);
1737#elif defined(_M_AMD64)
1738 DbgPrint("MM:***RIP %p, EFL %p\n", TrapFrame->Rip, TrapFrame->EFlags);
1739 DbgPrint("MM:***RAX %p, RCX %p RDX %p\n", TrapFrame->Rax, TrapFrame->Rcx, TrapFrame->Rdx);
1740 DbgPrint("MM:***RBX %p, RSI %p RDI %p\n", TrapFrame->Rbx, TrapFrame->Rsi, TrapFrame->Rdi);
1741#elif defined(_M_ARM)
1742 DbgPrint("MM:***PC %p\n", TrapFrame->Pc);
1743 DbgPrint("MM:***R0 %p, R1 %p R2 %p, R3 %p\n", TrapFrame->R0, TrapFrame->R1, TrapFrame->R2, TrapFrame->R3);
1744 DbgPrint("MM:***R11 %p, R12 %p SP %p, LR %p\n", TrapFrame->R11, TrapFrame->R12, TrapFrame->Sp, TrapFrame->Lr);
1745#endif
1746 }
1747
1748 /* Tell the trap handler to fail */
1749 return STATUS_IN_PAGE_ERROR | 0x10000000;
1750 }
1751
1752 /* Not yet implemented in ReactOS */
1753 ASSERT(MI_IS_PAGE_LARGE(PointerPde) == FALSE);
1754 ASSERT((!MI_IS_NOT_PRESENT_FAULT(FaultCode) && MI_IS_PAGE_COPY_ON_WRITE(PointerPte)) == FALSE);
1755
1756 /* Check if this was a write */
1757 if (MI_IS_WRITE_ACCESS(FaultCode))
1758 {
1759 /* Was it to a read-only page? */
1760 Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1761 if (!(PointerPte->u.Long & PTE_READWRITE) &&
1763 {
1764 /* Crash with distinguished bugcheck code */
1765 KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1767 PointerPte->u.Long,
1768 (ULONG_PTR)TrapInformation,
1769 10);
1770 }
1771 }
1772
1773 /* Nothing is actually wrong */
1774 DPRINT1("Fault at IRQL %u is ok (%p)\n", OldIrql, Address);
1775 return STATUS_SUCCESS;
1776 }
1777
1778 /* Check for kernel fault address */
1780 {
1781 /* Bail out, if the fault came from user mode */
1782 if (Mode == UserMode) return STATUS_ACCESS_VIOLATION;
1783
1784#if (_MI_PAGING_LEVELS == 2)
1785 if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)) MiSynchronizeSystemPde((PMMPDE)PointerPte);
1787#endif
1788
1789 /* Check if the higher page table entries are invalid */
1790 if (
1791#if (_MI_PAGING_LEVELS == 4)
1792 /* AMD64 system, check if PXE is invalid */
1793 (PointerPxe->u.Hard.Valid == 0) ||
1794#endif
1795#if (_MI_PAGING_LEVELS >= 3)
1796 /* PAE/AMD64 system, check if PPE is invalid */
1797 (PointerPpe->u.Hard.Valid == 0) ||
1798#endif
1799 /* Always check if the PDE is valid */
1800 (PointerPde->u.Hard.Valid == 0))
1801 {
1802 /* PXE/PPE/PDE (still) not valid, kill the system */
1803 KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
1805 FaultCode,
1806 (ULONG_PTR)TrapInformation,
1807 2);
1808 }
1809
1810 /* Not handling session faults yet */
1811 IsSessionAddress = MI_IS_SESSION_ADDRESS(Address);
1812
1813 /* The PDE is valid, so read the PTE */
1814 TempPte = *PointerPte;
1815 if (TempPte.u.Hard.Valid == 1)
1816 {
1817 /* Check if this was system space or session space */
1818 if (!IsSessionAddress)
1819 {
1820 /* Check if the PTE is still valid under PFN lock */
1821 OldIrql = MiAcquirePfnLock();
1822 TempPte = *PointerPte;
1823 if (TempPte.u.Hard.Valid)
1824 {
1825 /* Check if this was a write */
1826 if (MI_IS_WRITE_ACCESS(FaultCode))
1827 {
1828 /* Was it to a read-only page? */
1829 Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1830 if (!(PointerPte->u.Long & PTE_READWRITE) &&
1832 {
1833 /* Crash with distinguished bugcheck code */
1834 KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1836 PointerPte->u.Long,
1837 (ULONG_PTR)TrapInformation,
1838 11);
1839 }
1840 }
1841
1842 /* Check for execution of non-executable memory */
1843 if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
1845 {
1846 KeBugCheckEx(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY,
1848 (ULONG_PTR)TempPte.u.Long,
1849 (ULONG_PTR)TrapInformation,
1850 1);
1851 }
1852 }
1853
1854 /* Release PFN lock and return all good */
1855 MiReleasePfnLock(OldIrql);
1856 return STATUS_SUCCESS;
1857 }
1858 }
1859#if (_MI_PAGING_LEVELS == 2)
1860 /* Check if this was a session PTE that needs to remap the session PDE */
1862 {
1863 /* Do the remapping */
1864 Status = MiCheckPdeForSessionSpace(Address);
1865 if (!NT_SUCCESS(Status))
1866 {
1867 /* It failed, this address is invalid */
1868 KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
1870 FaultCode,
1871 (ULONG_PTR)TrapInformation,
1872 6);
1873 }
1874 }
1875#else
1876
1877_WARN("Session space stuff is not implemented yet!")
1878
1879#endif
1880
1881 /* Check for a fault on the page table or hyperspace */
1883 {
1884#if (_MI_PAGING_LEVELS < 3)
1885 /* Windows does this check but I don't understand why -- it's done above! */
1887#endif
1888 /* Handle this as a user mode fault */
1889 goto UserFault;
1890 }
1891
1892 /* Get the current thread */
1893 CurrentThread = PsGetCurrentThread();
1894
1895 /* What kind of address is this */
1896 if (!IsSessionAddress)
1897 {
1898 /* Use the system working set */
1899 WorkingSet = &MmSystemCacheWs;
1900 CurrentProcess = NULL;
1901
1902 /* Make sure we don't have a recursive working set lock */
1903 if ((CurrentThread->OwnsProcessWorkingSetExclusive) ||
1904 (CurrentThread->OwnsProcessWorkingSetShared) ||
1905 (CurrentThread->OwnsSystemWorkingSetExclusive) ||
1906 (CurrentThread->OwnsSystemWorkingSetShared) ||
1907 (CurrentThread->OwnsSessionWorkingSetExclusive) ||
1908 (CurrentThread->OwnsSessionWorkingSetShared))
1909 {
1910 /* Fail */
1911 return STATUS_IN_PAGE_ERROR | 0x10000000;
1912 }
1913 }
1914 else
1915 {
1916 /* Use the session process and working set */
1917 CurrentProcess = HYDRA_PROCESS;
1918 WorkingSet = &MmSessionSpace->GlobalVirtualAddress->Vm;
1919
1920 /* Make sure we don't have a recursive working set lock */
1921 if ((CurrentThread->OwnsSessionWorkingSetExclusive) ||
1922 (CurrentThread->OwnsSessionWorkingSetShared))
1923 {
1924 /* Fail */
1925 return STATUS_IN_PAGE_ERROR | 0x10000000;
1926 }
1927 }
1928
1929 /* Acquire the working set lock */
1930 KeRaiseIrql(APC_LEVEL, &LockIrql);
1931 MiLockWorkingSet(CurrentThread, WorkingSet);
1932
1933 /* Re-read PTE now that we own the lock */
1934 TempPte = *PointerPte;
1935 if (TempPte.u.Hard.Valid == 1)
1936 {
1937 /* Check if this was a write */
1938 if (MI_IS_WRITE_ACCESS(FaultCode))
1939 {
1940 /* Was it to a read-only page that is not copy on write? */
1941 Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1942 if (!(TempPte.u.Long & PTE_READWRITE) &&
1945 {
1946 /* Case not yet handled */
1947 ASSERT(!IsSessionAddress);
1948
1949 /* Crash with distinguished bugcheck code */
1950 KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1952 TempPte.u.Long,
1953 (ULONG_PTR)TrapInformation,
1954 12);
1955 }
1956 }
1957
1958 /* Check for execution of non-executable memory */
1959 if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
1961 {
1962 KeBugCheckEx(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY,
1964 (ULONG_PTR)TempPte.u.Long,
1965 (ULONG_PTR)TrapInformation,
1966 2);
1967 }
1968
1969 /* Check for read-only write in session space */
1970 if ((IsSessionAddress) &&
1971 MI_IS_WRITE_ACCESS(FaultCode) &&
1973 {
1974 /* Sanity check */
1976
1977 /* Was this COW? */
1979 {
1980 /* Then this is not allowed */
1981 KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1983 (ULONG_PTR)TempPte.u.Long,
1984 (ULONG_PTR)TrapInformation,
1985 13);
1986 }
1987
1988 /* Otherwise, handle COW */
1989 ASSERT(FALSE);
1990 }
1991
1992 /* Release the working set */
1993 MiUnlockWorkingSet(CurrentThread, WorkingSet);
1994 KeLowerIrql(LockIrql);
1995
1996 /* Otherwise, the PDE was probably invalid, and all is good now */
1997 return STATUS_SUCCESS;
1998 }
1999
2000 /* Check one kind of prototype PTE */
2001 if (TempPte.u.Soft.Prototype)
2002 {
2003 /* Make sure protected pool is on, and that this is a pool address */
2010 {
2011 /* Bad boy, bad boy, whatcha gonna do, whatcha gonna do when ARM3 comes for you! */
2012 KeBugCheckEx(DRIVER_CAUGHT_MODIFYING_FREED_POOL,
2014 FaultCode,
2015 Mode,
2016 4);
2017 }
2018
2019 /* Get the prototype PTE! */
2020 ProtoPte = MiProtoPteToPte(&TempPte);
2021
2022 /* Do we need to locate the prototype PTE in session space? */
2023 if ((IsSessionAddress) &&
2024 (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED))
2025 {
2026 /* Yep, go find it as well as the VAD for it */
2027 ProtoPte = MiCheckVirtualAddress(Address,
2028 &ProtectionCode,
2029 &Vad);
2030 ASSERT(ProtoPte != NULL);
2031 }
2032 }
2033 else
2034 {
2035 /* We don't implement transition PTEs */
2036 ASSERT(TempPte.u.Soft.Transition == 0);
2037
2038 /* Check for no-access PTE */
2039 if (TempPte.u.Soft.Protection == MM_NOACCESS)
2040 {
2041 /* Bugcheck the system! */
2042 KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
2044 FaultCode,
2045 (ULONG_PTR)TrapInformation,
2046 1);
2047 }
2048
2049 /* Check for no protecton at all */
2050 if (TempPte.u.Soft.Protection == MM_ZERO_ACCESS)
2051 {
2052 /* Bugcheck the system! */
2053 KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
2055 FaultCode,
2056 (ULONG_PTR)TrapInformation,
2057 0);
2058 }
2059 }
2060
2061 /* Check for demand page */
2062 if (MI_IS_WRITE_ACCESS(FaultCode) &&
2063 !(ProtoPte) &&
2064 !(IsSessionAddress) &&
2065 !(TempPte.u.Hard.Valid))
2066 {
2067 /* Get the protection code */
2068 ASSERT(TempPte.u.Soft.Transition == 0);
2069 if (!(TempPte.u.Soft.Protection & MM_READWRITE))
2070 {
2071 /* Bugcheck the system! */
2072 KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
2074 TempPte.u.Long,
2075 (ULONG_PTR)TrapInformation,
2076 14);
2077 }
2078 }
2079
2080 /* Now do the real fault handling */
2081 Status = MiDispatchFault(FaultCode,
2082 Address,
2083 PointerPte,
2084 ProtoPte,
2085 FALSE,
2086 CurrentProcess,
2087 TrapInformation,
2088 NULL);
2089
2090 /* Release the working set */
2092 MiUnlockWorkingSet(CurrentThread, WorkingSet);
2093 KeLowerIrql(LockIrql);
2094
2095 /* We are done! */
2096 DPRINT("Fault resolved with status: %lx\n", Status);
2097 return Status;
2098 }
2099
2100 /* This is a user fault */
2101UserFault:
2102 CurrentThread = PsGetCurrentThread();
2103 CurrentProcess = (PEPROCESS)CurrentThread->Tcb.ApcState.Process;
2104
2105 /* Lock the working set */
2106 MiLockProcessWorkingSet(CurrentProcess, CurrentThread);
2107
2108 ProtectionCode = MM_INVALID_PROTECTION;
2109
2110#if (_MI_PAGING_LEVELS == 4)
2111 /* Check if the PXE is valid */
2112 if (PointerPxe->u.Hard.Valid == 0)
2113 {
2114 /* Right now, we only handle scenarios where the PXE is totally empty */
2115 ASSERT(PointerPxe->u.Long == 0);
2116
2117 /* This is only possible for user mode addresses! */
2118 ASSERT(PointerPte <= MiHighestUserPte);
2119
2120 /* Check if we have a VAD */
2121 MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2122 if (ProtectionCode == MM_NOACCESS)
2123 {
2124 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2126 }
2127
2128 /* Resolve a demand zero fault */
2129 MiResolveDemandZeroFault(PointerPpe,
2130 PointerPxe,
2132 CurrentProcess,
2133 MM_NOIRQL);
2134
2135 /* We should come back with a valid PXE */
2136 ASSERT(PointerPxe->u.Hard.Valid == 1);
2137 }
2138#endif
2139
2140#if (_MI_PAGING_LEVELS >= 3)
2141 /* Check if the PPE is valid */
2142 if (PointerPpe->u.Hard.Valid == 0)
2143 {
2144 /* Right now, we only handle scenarios where the PPE is totally empty */
2145 ASSERT(PointerPpe->u.Long == 0);
2146
2147 /* This is only possible for user mode addresses! */
2148 ASSERT(PointerPte <= MiHighestUserPte);
2149
2150 /* Check if we have a VAD, unless we did this already */
2151 if (ProtectionCode == MM_INVALID_PROTECTION)
2152 {
2153 MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2154 }
2155
2156 if (ProtectionCode == MM_NOACCESS)
2157 {
2158 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2160 }
2161
2162 /* Resolve a demand zero fault */
2163 MiResolveDemandZeroFault(PointerPde,
2164 PointerPpe,
2166 CurrentProcess,
2167 MM_NOIRQL);
2168
2169 /* We should come back with a valid PPE */
2170 ASSERT(PointerPpe->u.Hard.Valid == 1);
2172 }
2173#endif
2174
2175 /* Check if the PDE is invalid */
2176 if (PointerPde->u.Hard.Valid == 0)
2177 {
2178 /* Right now, we only handle scenarios where the PDE is totally empty */
2179 ASSERT(PointerPde->u.Long == 0);
2180
2181 /* And go dispatch the fault on the PDE. This should handle the demand-zero */
2182#if MI_TRACE_PFNS
2183 UserPdeFault = TRUE;
2184#endif
2185 /* Check if we have a VAD, unless we did this already */
2186 if (ProtectionCode == MM_INVALID_PROTECTION)
2187 {
2188 MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2189 }
2190
2191 if (ProtectionCode == MM_NOACCESS)
2192 {
2193#if (_MI_PAGING_LEVELS == 2)
2194 /* Could be a page table for paged pool */
2196#endif
2197 /* Has the code above changed anything -- is this now a valid PTE? */
2198 Status = (PointerPde->u.Hard.Valid == 1) ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
2199
2200 /* Either this was a bogus VA or we've fixed up a paged pool PDE */
2201 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2202 return Status;
2203 }
2204
2205 /* Resolve a demand zero fault */
2206 MiResolveDemandZeroFault(PointerPte,
2207 PointerPde,
2209 CurrentProcess,
2210 MM_NOIRQL);
2211#if _MI_PAGING_LEVELS >= 3
2213#endif
2214
2215#if MI_TRACE_PFNS
2216 UserPdeFault = FALSE;
2217 /* Update debug info */
2218 if (TrapInformation)
2219 MiGetPfnEntry(PointerPde->u.Hard.PageFrameNumber)->CallSite = (PVOID)((PKTRAP_FRAME)TrapInformation)->Eip;
2220 else
2221 MiGetPfnEntry(PointerPde->u.Hard.PageFrameNumber)->CallSite = _ReturnAddress();
2222#endif
2223 /* We should come back with APCs enabled, and with a valid PDE */
2225 ASSERT(PointerPde->u.Hard.Valid == 1);
2226 }
2227 else
2228 {
2229 /* Not yet implemented in ReactOS */
2230 ASSERT(MI_IS_PAGE_LARGE(PointerPde) == FALSE);
2231 }
2232
2233 /* Now capture the PTE. */
2234 TempPte = *PointerPte;
2235
2236 /* Check if the PTE is valid */
2237 if (TempPte.u.Hard.Valid)
2238 {
2239 /* Check if this is a write on a readonly PTE */
2240 if (MI_IS_WRITE_ACCESS(FaultCode))
2241 {
2242 /* Is this a copy on write PTE? */
2244 {
2245 PFN_NUMBER PageFrameIndex, OldPageFrameIndex;
2246 PMMPFN Pfn1;
2247
2248 LockIrql = MiAcquirePfnLock();
2249
2251
2253 MI_SET_PROCESS(CurrentProcess);
2254
2255 /* Allocate a new page and copy it */
2256 PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(CurrentProcess));
2257 OldPageFrameIndex = PFN_FROM_PTE(&TempPte);
2258
2259 MiCopyPfn(PageFrameIndex, OldPageFrameIndex);
2260
2261 /* Dereference whatever this PTE is referencing */
2262 Pfn1 = MI_PFN_ELEMENT(OldPageFrameIndex);
2263 ASSERT(Pfn1->u3.e1.PrototypePte == 1);
2264 ASSERT(!MI_IS_PFN_DELETED(Pfn1));
2265 ProtoPte = Pfn1->PteAddress;
2266 MiDeletePte(PointerPte, Address, CurrentProcess, ProtoPte);
2267
2268 /* And make a new shiny one with our page */
2269 MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
2270 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
2271 TempPte.u.Hard.Write = 1;
2272 TempPte.u.Hard.CopyOnWrite = 0;
2273
2274 MI_WRITE_VALID_PTE(PointerPte, TempPte);
2275
2276 MiReleasePfnLock(LockIrql);
2277
2278 /* Return the status */
2279 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2281 }
2282
2283 /* Is this a read-only PTE? */
2285 {
2286 /* Return the status */
2287 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2289 }
2290 }
2291
2292 /* Check for execution of non-executable memory */
2293 if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
2295 {
2296 /* Return the status */
2297 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2299 }
2300
2301 /* The fault has already been resolved by a different thread */
2302 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2303 return STATUS_SUCCESS;
2304 }
2305
2306 /* Quick check for demand-zero */
2309 {
2310 /* Resolve the fault */
2312 PointerPte,
2313 TempPte.u.Soft.Protection,
2314 CurrentProcess,
2315 MM_NOIRQL);
2316
2317#if MI_TRACE_PFNS
2318 /* Update debug info */
2319 if (TrapInformation)
2320 MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = (PVOID)((PKTRAP_FRAME)TrapInformation)->Eip;
2321 else
2322 MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = _ReturnAddress();
2323#endif
2324
2325 /* Return the status */
2326 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2328 }
2329
2330 /* Check for zero PTE */
2331 if (TempPte.u.Long == 0)
2332 {
2333 /* Check if this address range belongs to a valid allocation (VAD) */
2334 ProtoPte = MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2335 if (ProtectionCode == MM_NOACCESS)
2336 {
2337#if (_MI_PAGING_LEVELS == 2)
2338 /* Could be a page table for paged pool */
2340#endif
2341 /* Has the code above changed anything -- is this now a valid PTE? */
2342 Status = (PointerPte->u.Hard.Valid == 1) ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
2343
2344 /* Either this was a bogus VA or we've fixed up a paged pool PDE */
2345 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2346 return Status;
2347 }
2348
2349 /*
2350 * Check if this is a real user-mode address or actually a kernel-mode
2351 * page table for a user mode address
2352 */
2354#if _MI_PAGING_LEVELS >= 3
2356#if _MI_PAGING_LEVELS == 4
2358#endif
2359#endif
2360 )
2361 {
2362 /* Add an additional page table reference */
2364 }
2365
2366 /* Is this a guard page? */
2367 if ((ProtectionCode & MM_PROTECT_SPECIAL) == MM_GUARDPAGE)
2368 {
2369 /* The VAD protection cannot be MM_DECOMMIT! */
2370 ASSERT(ProtectionCode != MM_DECOMMIT);
2371
2372 /* Remove the bit */
2373 TempPte.u.Soft.Protection = ProtectionCode & ~MM_GUARDPAGE;
2374 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2375
2376 /* Not supported */
2377 ASSERT(ProtoPte == NULL);
2378 ASSERT(CurrentThread->ApcNeeded == 0);
2379
2380 /* Drop the working set lock */
2381 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2383
2384 /* Handle stack expansion */
2385 return MiCheckForUserStackOverflow(Address, TrapInformation);
2386 }
2387
2388 /* Did we get a prototype PTE back? */
2389 if (!ProtoPte)
2390 {
2391 /* Is this PTE actually part of the PDE-PTE self-mapping directory? */
2392 if (PointerPde == MiAddressToPde(PTE_BASE))
2393 {
2394 /* Then it's really a demand-zero PDE (on behalf of user-mode) */
2395#ifdef _M_ARM
2396 _WARN("This is probably completely broken!");
2398#else
2400#endif
2401 }
2402 else
2403 {
2404 /* No, create a new PTE. First, write the protection */
2405 TempPte.u.Soft.Protection = ProtectionCode;
2406 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2407 }
2408
2409 /* Lock the PFN database since we're going to grab a page */
2410 OldIrql = MiAcquirePfnLock();
2411
2412 /* Make sure we have enough pages */
2413 ASSERT(MmAvailablePages >= 32);
2414
2415 /* Try to get a zero page */
2417 MI_SET_PROCESS2(CurrentProcess->ImageFileName);
2418 Color = MI_GET_NEXT_PROCESS_COLOR(CurrentProcess);
2419 PageFrameIndex = MiRemoveZeroPageSafe(Color);
2420 if (!PageFrameIndex)
2421 {
2422 /* Grab a page out of there. Later we should grab a colored zero page */
2423 PageFrameIndex = MiRemoveAnyPage(Color);
2424 ASSERT(PageFrameIndex);
2425
2426 /* Release the lock since we need to do some zeroing */
2427 MiReleasePfnLock(OldIrql);
2428
2429 /* Zero out the page, since it's for user-mode */
2430 MiZeroPfn(PageFrameIndex);
2431
2432 /* Grab the lock again so we can initialize the PFN entry */
2433 OldIrql = MiAcquirePfnLock();
2434 }
2435
2436 /* Initialize the PFN entry now */
2437 MiInitializePfn(PageFrameIndex, PointerPte, 1);
2438
2439 /* Increment the count of pages in the process */
2440 CurrentProcess->NumberOfPrivatePages++;
2441
2442 /* One more demand-zero fault */
2443 KeGetCurrentPrcb()->MmDemandZeroCount++;
2444
2445 /* And we're done with the lock */
2446 MiReleasePfnLock(OldIrql);
2447
2448 /* Fault on user PDE, or fault on user PTE? */
2449 if (PointerPte <= MiHighestUserPte)
2450 {
2451 /* User fault, build a user PTE */
2453 PointerPte,
2454 PointerPte->u.Soft.Protection,
2455 PageFrameIndex);
2456 }
2457 else
2458 {
2459 /* This is a user-mode PDE, create a kernel PTE for it */
2461 PointerPte,
2462 PointerPte->u.Soft.Protection,
2463 PageFrameIndex);
2464 }
2465
2466 /* Write the dirty bit for writeable pages */
2468
2469 /* And now write down the PTE, making the address valid */
2470 MI_WRITE_VALID_PTE(PointerPte, TempPte);
2471 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
2472 ASSERT(Pfn1->u1.Event == NULL);
2473
2474 /* Demand zero */
2476 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2478 }
2479
2480 /* We should have a valid protection here */
2481 ASSERT(ProtectionCode != 0x100);
2482
2483 /* Write the prototype PTE */
2485 TempPte.u.Soft.Protection = ProtectionCode;
2486 ASSERT(TempPte.u.Long != 0);
2487 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2488 }
2489 else
2490 {
2491 /* Get the protection code and check if this is a proto PTE */
2492 ProtectionCode = (ULONG)TempPte.u.Soft.Protection;
2493 if (TempPte.u.Soft.Prototype)
2494 {
2495 /* Do we need to go find the real PTE? */
2496 if (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
2497 {
2498 /* Get the prototype pte and VAD for it */
2499 ProtoPte = MiCheckVirtualAddress(Address,
2500 &ProtectionCode,
2501 &Vad);
2502 if (!ProtoPte)
2503 {
2505 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2507 }
2508 }
2509 else
2510 {
2511 /* Get the prototype PTE! */
2512 ProtoPte = MiProtoPteToPte(&TempPte);
2513
2514 /* Is it read-only */
2515 if (TempPte.u.Proto.ReadOnly)
2516 {
2517 /* Set read-only code */
2518 ProtectionCode = MM_READONLY;
2519 }
2520 else
2521 {
2522 /* Set unknown protection */
2523 ProtectionCode = 0x100;
2524 ASSERT(CurrentProcess->CloneRoot != NULL);
2525 }
2526 }
2527 }
2528 }
2529
2530 /* Do we have a valid protection code? */
2531 if (ProtectionCode != 0x100)
2532 {
2533 /* Run a software access check first, including to detect guard pages */
2534 Status = MiAccessCheck(PointerPte,
2535 !MI_IS_NOT_PRESENT_FAULT(FaultCode),
2536 Mode,
2537 ProtectionCode,
2538 TrapInformation,
2539 FALSE);
2540 if (Status != STATUS_SUCCESS)
2541 {
2542 /* Not supported */
2543 ASSERT(CurrentThread->ApcNeeded == 0);
2544
2545 /* Drop the working set lock */
2546 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2548
2549 /* Did we hit a guard page? */
2551 {
2552 /* Handle stack expansion */
2553 return MiCheckForUserStackOverflow(Address, TrapInformation);
2554 }
2555
2556 /* Otherwise, fail back to the caller directly */
2557 return Status;
2558 }
2559 }
2560
2561 /* Dispatch the fault */
2562 Status = MiDispatchFault(FaultCode,
2563 Address,
2564 PointerPte,
2565 ProtoPte,
2566 FALSE,
2567 CurrentProcess,
2568 TrapInformation,
2569 Vad);
2570
2571 /* Return the status */
2573 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2574 return Status;
2575}
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define DbgPrint
Definition: hal.h:12
_In_ ULONG Mode
Definition: hubbusif.h:303
if(dx< 0)
Definition: linetemp.h:194
#define MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)
Definition: miarm.h:180
FORCEINLINE VOID MiLockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1265
PVOID MmNonPagedPoolEnd
Definition: mminit.c:99
BOOLEAN MmProtectFreedNonPagedPool
Definition: pool.c:31
FORCEINLINE BOOLEAN MiIsUserPte(PVOID Address)
Definition: miarm.h:725
#define MI_IS_SESSION_PTE(Pte)
Definition: miarm.h:174
#define MM_INVALID_PROTECTION
Definition: miarm.h:67
FORCEINLINE VOID MiUnlockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1194
FORCEINLINE VOID MiUnlockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1351
FORCEINLINE VOID MI_WRITE_INVALID_PDE(IN PMMPDE PointerPde, IN MMPDE InvalidPde)
Definition: miarm.h:1035
FORCEINLINE BOOLEAN MiIsUserPde(PVOID Address)
Definition: miarm.h:717
#define MI_IS_PFN_DELETED(x)
Definition: miarm.h:195
#define MI_IS_PAGE_TABLE_OR_HYPER_ADDRESS(Address)
Definition: miarm.h:183
FORCEINLINE USHORT MiIncrementPageTableReferences(IN PVOID Address)
Definition: miarm.h:2481
FORCEINLINE VOID MiLockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1124
#define PTE_BASE
Definition: mmx86.c:14
#define MiAddressToPde(x)
Definition: mmx86.c:20
struct _EPROCESS * PEPROCESS
Definition: nt_native.h:30
#define MI_IS_PAGE_EXECUTABLE(x)
Definition: mm.h:111
#define MI_IS_WRITE_ACCESS(FaultCode)
Definition: mm.h:122
#define MM_PTE_SOFTWARE_PROTECTION_BITS
Definition: mm.h:75
#define MI_IS_INSTRUCTION_FETCH(FaultCode)
Definition: mm.h:125
#define _MI_PAGING_LEVELS
Definition: mm.h:6
FORCEINLINE PMMPTE MiAddressToPpe(PVOID Address)
Definition: mm.h:161
#define MiProtoPteToPte(x)
Definition: mm.h:316
FORCEINLINE PMMPTE MiAddressToPxe(PVOID Address)
Definition: mm.h:171
#define MI_IS_PAGE_LARGE(x)
Definition: mm.h:104
@ MI_USAGE_PEB_TEB
Definition: mm.h:332
ULONG MmSizeOfNonPagedPoolInBytes
Definition: init.c:21
PVOID MmNonPagedPoolExpansionStart
Definition: init.c:25
MMSUPPORT MmSystemCacheWs
Definition: init.c:55
PVOID MmNonPagedPoolStart
Definition: init.c:24
MMPDE DemandZeroPde
Definition: init.c:36
MMPTE PrototypePte
Definition: init.c:40
#define STATUS_WAIT_1
Definition: ntstatus.h:71
#define STATUS_PAGE_FAULT_COPY_ON_WRITE
Definition: ntstatus.h:96
#define STATUS_IN_PAGE_ERROR
Definition: ntstatus.h:243
static PMMPTE NTAPI MiCheckVirtualAddress(IN PVOID VirtualAddress, OUT PULONG ProtectCode, OUT PMMVAD *ProtoVad)
Definition: pagfault.c:237
NTSTATUS FASTCALL MiCheckPdeForPagedPool(IN PVOID Address)
Definition: pagfault.c:475
static NTSTATUS NTAPI MiCheckForUserStackOverflow(IN PVOID Address, IN PVOID TrapInformation)
Definition: pagfault.c:30
NTSTATUS NTAPI MiDispatchFault(IN ULONG FaultCode, IN PVOID Address, IN PMMPTE PointerPte, IN PMMPTE PointerProtoPte, IN BOOLEAN Recursive, IN PEPROCESS Process, IN PVOID TrapInformation, IN PMMVAD Vad)
Definition: pagfault.c:1319
VOID NTAPI KeBugCheckEx(_In_ ULONG BugCheckCode, _In_ ULONG_PTR BugCheckParameter1, _In_ ULONG_PTR BugCheckParameter2, _In_ ULONG_PTR BugCheckParameter3, _In_ ULONG_PTR BugCheckParameter4)
Definition: rtlcompat.c:108
#define _WARN(msg)
Definition: debug.h:263
PFN_NUMBER NumberOfPrivatePages
Definition: pstypes.h:1300
PVOID CloneRoot
Definition: pstypes.h:1299
CHAR ImageFileName[16]
Definition: pstypes.h:1326
ULONG OwnsSessionWorkingSetExclusive
Definition: pstypes.h:1225
ULONG OwnsSessionWorkingSetShared
Definition: pstypes.h:1226
ULONG OwnsSystemWorkingSetShared
Definition: pstypes.h:1224
ULONG OwnsProcessWorkingSetShared
Definition: pstypes.h:1222
ULONG OwnsProcessWorkingSetExclusive
Definition: pstypes.h:1221
ULONG OwnsSystemWorkingSetExclusive
Definition: pstypes.h:1223
KAPC_STATE ApcState
Definition: ketypes.h:1718
ULONG R3
Definition: ketypes.h:363
UINT64 Rdi
Definition: ketypes.h:375
ULONG Sp
Definition: ketypes.h:365
ULONG Pc
Definition: ketypes.h:368
ULONG Edi
Definition: ketypes.h:263
UINT64 Rsi
Definition: ketypes.h:376
UINT64 Rdx
Definition: ketypes.h:325
ULONG Lr
Definition: ketypes.h:366
ULONG EFlags
Definition: ketypes.h:389
ULONG R0
Definition: ketypes.h:360
ULONG Ebx
Definition: ketypes.h:265
ULONG Ecx
Definition: ketypes.h:258
UINT64 Rbx
Definition: ketypes.h:374
ULONG Eip
Definition: ketypes.h:268
UINT64 Rax
Definition: ketypes.h:323
UINT64 Rip
Definition: ketypes.h:384
ULONG R2
Definition: ketypes.h:362
ULONG R1
Definition: ketypes.h:361
ULONG Eax
Definition: ketypes.h:259
UINT64 Rcx
Definition: ketypes.h:324
ULONG Esi
Definition: ketypes.h:264
ULONG Edx
Definition: ketypes.h:257
UINT64 R11
Definition: ketypes.h:329
ULONG R12
Definition: ketypes.h:364
struct _MM_SESSION_SPACE * GlobalVirtualAddress
Definition: miarm.h:470

Referenced by MmAccessFault().

◆ MmGetExecuteOptions()

NTSTATUS NTAPI MmGetExecuteOptions ( IN PULONG  ExecuteOptions)

Definition at line 2579 of file pagfault.c.

2580{
2581 PKPROCESS CurrentProcess = &PsGetCurrentProcess()->Pcb;
2583
2584 *ExecuteOptions = 0;
2585
2586 if (CurrentProcess->Flags.ExecuteDisable)
2587 {
2588 *ExecuteOptions |= MEM_EXECUTE_OPTION_DISABLE;
2589 }
2590
2591 if (CurrentProcess->Flags.ExecuteEnable)
2592 {
2593 *ExecuteOptions |= MEM_EXECUTE_OPTION_ENABLE;
2594 }
2595
2596 if (CurrentProcess->Flags.DisableThunkEmulation)
2597 {
2599 }
2600
2601 if (CurrentProcess->Flags.Permanent)
2602 {
2603 *ExecuteOptions |= MEM_EXECUTE_OPTION_PERMANENT;
2604 }
2605
2606 if (CurrentProcess->Flags.ExecuteDispatchEnable)
2607 {
2609 }
2610
2611 if (CurrentProcess->Flags.ImageDispatchEnable)
2612 {
2614 }
2615
2616 return STATUS_SUCCESS;
2617}
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
#define MEM_EXECUTE_OPTION_DISABLE
Definition: mmtypes.h:73
#define MEM_EXECUTE_OPTION_PERMANENT
Definition: mmtypes.h:76
#define MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE
Definition: mmtypes.h:77
#define MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE
Definition: mmtypes.h:78
#define MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION
Definition: mmtypes.h:75
#define MEM_EXECUTE_OPTION_ENABLE
Definition: mmtypes.h:74
UCHAR DisableThunkEmulation
Definition: ketypes.h:929
UCHAR ExecuteDisable
Definition: ketypes.h:927
UCHAR ExecuteEnable
Definition: ketypes.h:928
UCHAR ExecuteDispatchEnable
Definition: ketypes.h:931
UCHAR ImageDispatchEnable
Definition: ketypes.h:932
KEXECUTE_OPTIONS Flags
Definition: ketypes.h:2070

Referenced by NtQueryInformationProcess().

◆ MmSetExecuteOptions()

NTSTATUS NTAPI MmSetExecuteOptions ( IN ULONG  ExecuteOptions)

Definition at line 2621 of file pagfault.c.

2622{
2623 PKPROCESS CurrentProcess = &PsGetCurrentProcess()->Pcb;
2624 KLOCK_QUEUE_HANDLE ProcessLock;
2627
2628 /* Only accept valid flags */
2629 if (ExecuteOptions & ~MEM_EXECUTE_OPTION_VALID_FLAGS)
2630 {
2631 /* Fail */
2632 DPRINT1("Invalid no-execute options\n");
2634 }
2635
2636 /* Change the NX state in the process lock */
2637 KiAcquireProcessLockRaiseToSynch(CurrentProcess, &ProcessLock);
2638
2639 /* Don't change anything if the permanent flag was set */
2640 if (!CurrentProcess->Flags.Permanent)
2641 {
2642 /* Start by assuming it's not disabled */
2643 CurrentProcess->Flags.ExecuteDisable = FALSE;
2644
2645 /* Now process each flag and turn the equivalent bit on */
2646 if (ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE)
2647 {
2648 CurrentProcess->Flags.ExecuteDisable = TRUE;
2649 }
2650 if (ExecuteOptions & MEM_EXECUTE_OPTION_ENABLE)
2651 {
2652 CurrentProcess->Flags.ExecuteEnable = TRUE;
2653 }
2654 if (ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)
2655 {
2656 CurrentProcess->Flags.DisableThunkEmulation = TRUE;
2657 }
2658 if (ExecuteOptions & MEM_EXECUTE_OPTION_PERMANENT)
2659 {
2660 CurrentProcess->Flags.Permanent = TRUE;
2661 }
2662 if (ExecuteOptions & MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE)
2663 {
2664 CurrentProcess->Flags.ExecuteDispatchEnable = TRUE;
2665 }
2666 if (ExecuteOptions & MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE)
2667 {
2668 CurrentProcess->Flags.ImageDispatchEnable = TRUE;
2669 }
2670
2671 /* These are turned on by default if no-execution is also eanbled */
2672 if (CurrentProcess->Flags.ExecuteEnable)
2673 {
2674 CurrentProcess->Flags.ExecuteDispatchEnable = TRUE;
2675 CurrentProcess->Flags.ImageDispatchEnable = TRUE;
2676 }
2677
2678 /* All good */
2680 }
2681
2682 /* Release the lock and return status */
2683 KiReleaseProcessLock(&ProcessLock);
2684 return Status;
2685}
FORCEINLINE VOID KiReleaseProcessLock(IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:660
FORCEINLINE VOID KiAcquireProcessLockRaiseToSynch(IN PKPROCESS Process, IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:651
#define MEM_EXECUTE_OPTION_VALID_FLAGS
Definition: mmtypes.h:79
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135

Referenced by NtSetInformationProcess().