ReactOS 0.4.15-dev-7842-g558ab78
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

VOID NTAPI MmRebalanceMemoryConsumersAndWait (VOID)
 
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 24 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 172 of file pagfault.c.

178{
180
181 /* Check for invalid user-mode access */
182 if ((PreviousMode == UserMode) && (PointerPte > MiHighestUserPte))
183 {
185 }
186
187 /* Capture the PTE -- is it valid? */
188 TempPte = *PointerPte;
189 if (TempPte.u.Hard.Valid)
190 {
191 /* Was someone trying to write to it? */
192 if (StoreInstruction)
193 {
194 /* Is it writable?*/
197 {
198 /* Then there's nothing to worry about */
199 return STATUS_SUCCESS;
200 }
201
202 /* Oops! This isn't allowed */
204 }
205
206 /* Someone was trying to read from a valid PTE, that's fine too */
207 return STATUS_SUCCESS;
208 }
209
210 /* Check if the protection on the page allows what is being attempted */
211 if (!MiIsAccessAllowed(ProtectionMask, StoreInstruction, FALSE))
212 {
214 }
215
216 /* Check if this is a guard page */
217 if ((ProtectionMask & MM_PROTECT_SPECIAL) == MM_GUARDPAGE)
218 {
219 ASSERT(ProtectionMask != MM_DECOMMIT);
220
221 /* Attached processes can't expand their stack */
223
224 /* No support for prototype PTEs yet */
225 ASSERT(TempPte.u.Soft.Prototype == 0);
226
227 /* Remove the guard page bit, and return a guard page violation */
228 TempPte.u.Soft.Protection = ProtectionMask & ~MM_GUARDPAGE;
229 ASSERT(TempPte.u.Long != 0);
230 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
232 }
233
234 /* Nothing to do */
235 return STATUS_SUCCESS;
236}
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:142
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 34 of file pagfault.c.

36{
37 PETHREAD CurrentThread = PsGetCurrentThread();
38 PTEB Teb = CurrentThread->Tcb.Teb;
39 PVOID StackBase, DeallocationStack, NextStackAddress;
40 SIZE_T GuaranteedSize;
42
43 /* Do we own the address space lock? */
44 if (CurrentThread->AddressSpaceOwner == 1)
45 {
46 /* This isn't valid */
47 DPRINT1("Process owns address space lock\n");
50 }
51
52 /* Are we attached? */
54 {
55 /* This isn't valid */
56 DPRINT1("Process is attached\n");
58 }
59
60 /* Read the current settings */
61 StackBase = Teb->NtTib.StackBase;
62 DeallocationStack = Teb->DeallocationStack;
63 GuaranteedSize = Teb->GuaranteedStackBytes;
64 DPRINT("Handling guard page fault with Stacks Addresses 0x%p and 0x%p, guarantee: %lx\n",
65 StackBase, DeallocationStack, GuaranteedSize);
66
67 /* Guarantees make this code harder, for now, assume there aren't any */
68 ASSERT(GuaranteedSize == 0);
69
70 /* So allocate only the minimum guard page size */
71 GuaranteedSize = PAGE_SIZE;
72
73 /* Does this faulting stack address actually exist in the stack? */
74 if ((Address >= StackBase) || (Address < DeallocationStack))
75 {
76 /* That's odd... */
77 DPRINT1("Faulting address outside of stack bounds. Address=%p, StackBase=%p, DeallocationStack=%p\n",
78 Address, StackBase, DeallocationStack);
80 }
81
82 /* This is where the stack will start now */
83 NextStackAddress = (PVOID)((ULONG_PTR)PAGE_ALIGN(Address) - GuaranteedSize);
84
85 /* Do we have at least one page between here and the end of the stack? */
86 if (((ULONG_PTR)NextStackAddress - PAGE_SIZE) <= (ULONG_PTR)DeallocationStack)
87 {
88 /* We don't -- Trying to make this guard page valid now */
89 DPRINT1("Close to our death...\n");
90
91 /* Calculate the next memory address */
92 NextStackAddress = (PVOID)((ULONG_PTR)PAGE_ALIGN(DeallocationStack) + GuaranteedSize);
93
94 /* Allocate the memory */
95 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
96 &NextStackAddress,
97 0,
98 &GuaranteedSize,
101 if (NT_SUCCESS(Status))
102 {
103 /* Success! */
104 Teb->NtTib.StackLimit = NextStackAddress;
105 }
106 else
107 {
108 DPRINT1("Failed to allocate memory\n");
109 }
110
112 }
113
114 /* Don't handle this flag yet */
116
117 /* Update the stack limit */
118 Teb->NtTib.StackLimit = (PVOID)((ULONG_PTR)NextStackAddress + GuaranteedSize);
119
120 /* Now move the guard page to the next page */
121 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
122 &NextStackAddress,
123 0,
124 &GuaranteedSize,
128 {
129 /* We did it! */
130 DPRINT("Guard page handled successfully for %p\n", Address);
132 }
133
134 /* Fail, we couldn't move the guard page */
135 DPRINT1("Guard page failure: %lx\n", Status);
136 ASSERT(FALSE);
138}
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:1807
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 479 of file pagfault.c.

480{
482}

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 241 of file pagfault.c.

244{
245 PMMVAD Vad;
246 PMMPTE PointerPte;
247
248 /* No prototype/section support for now */
249 *ProtoVad = NULL;
250
251 /* User or kernel fault? */
253 {
254 /* Special case for shared data */
256 {
257 /* It's a read-only page */
258 *ProtectCode = MM_READONLY;
259 return MmSharedUserDataPte;
260 }
261
262 /* Find the VAD, it might not exist if the address is bogus */
264 if (!Vad)
265 {
266 /* Bogus virtual address */
267 *ProtectCode = MM_NOACCESS;
268 return NULL;
269 }
270
271 /* ReactOS does not handle physical memory VADs yet */
273
274 /* Check if it's a section, or just an allocation */
275 if (Vad->u.VadFlags.PrivateMemory)
276 {
277 /* ReactOS does not handle AWE VADs yet */
278 ASSERT(Vad->u.VadFlags.VadType != VadAwe);
279
280 /* This must be a TEB/PEB VAD */
281 if (Vad->u.VadFlags.MemCommit)
282 {
283 /* It's committed, so return the VAD protection */
284 *ProtectCode = (ULONG)Vad->u.VadFlags.Protection;
285 }
286 else
287 {
288 /* It has not yet been committed, so return no access */
289 *ProtectCode = MM_NOACCESS;
290 }
291
292 /* In both cases, return no PTE */
293 return NULL;
294 }
295 else
296 {
297 /* ReactOS does not supoprt these VADs yet */
300
301 /* Return the proto VAD */
302 *ProtoVad = Vad;
303
304 /* Get the prototype PTE for this page */
305 PointerPte = (((ULONG_PTR)VirtualAddress >> PAGE_SHIFT) - Vad->StartingVpn) + Vad->FirstPrototypePte;
306 ASSERT(PointerPte != NULL);
307 ASSERT(PointerPte <= Vad->LastContiguousPte);
308
309 /* Return the Prototype PTE and the protection for the page mapping */
310 *ProtectCode = (ULONG)Vad->u.VadFlags.Protection;
311 return PointerPte;
312 }
313 }
315 {
316 /* This should never happen, as these addresses are handled by the double-maping */
319 {
320 /* Fail such access */
321 *ProtectCode = MM_NOACCESS;
322 return NULL;
323 }
324
325 /* Return full access rights */
326 *ProtectCode = MM_EXECUTE_READWRITE;
327 return NULL;
328 }
330 {
331 /* ReactOS does not have an image list yet, so bail out to failure case */
333 }
334
335 /* Default case -- failure */
336 *ProtectCode = MM_NOACCESS;
337 return NULL;
338}
#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:116
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:207
@ VadDevicePhysicalMemory
Definition: mmtypes.h:205
@ VadImageMap
Definition: mmtypes.h:206
ULONG ExtendableFile
Definition: mmtypes.h:712
ULONG_PTR MemCommit
Definition: mmtypes.h:695
ULONG_PTR Protection
Definition: mmtypes.h:696
ULONG_PTR VadType
Definition: mmtypes.h:694
ULONG_PTR PrivateMemory
Definition: mmtypes.h:698
union _MMVAD::@2607 u2
ULONG_PTR StartingVpn
Definition: mmtypes.h:729
MMVAD_FLAGS2 VadFlags2
Definition: mmtypes.h:742
MMVAD_FLAGS VadFlags
Definition: mmtypes.h:734
union _MMVAD::@2606 u
PMMPTE FirstPrototypePte
Definition: mmtypes.h:737
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 775 of file pagfault.c.

781{
783 PMMPTE OriginalPte, PageTablePte;
784 ULONG_PTR Protection;
785 PFN_NUMBER PageFrameIndex;
786 PMMPFN Pfn1, Pfn2;
787 BOOLEAN OriginalProtection, DirtyPage;
788
789 /* Must be called with an valid prototype PTE, with the PFN lock held */
791 ASSERT(PointerProtoPte->u.Hard.Valid == 1);
792
793 /* Get the page */
794 PageFrameIndex = PFN_FROM_PTE(PointerProtoPte);
795
796 /* Get the PFN entry and set it as a prototype PTE */
797 Pfn1 = MiGetPfnEntry(PageFrameIndex);
798 Pfn1->u3.e1.PrototypePte = 1;
799
800 /* Increment the share count for the page table */
801 PageTablePte = MiAddressToPte(PointerPte);
802 Pfn2 = MiGetPfnEntry(PageTablePte->u.Hard.PageFrameNumber);
803 Pfn2->u2.ShareCount++;
804
805 /* Check where we should be getting the protection information from */
806 if (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
807 {
808 /* Get the protection from the PTE, there's no real Proto PTE data */
809 Protection = PointerPte->u.Soft.Protection;
810
811 /* Remember that we did not use the proto protection */
812 OriginalProtection = FALSE;
813 }
814 else
815 {
816 /* Get the protection from the original PTE link */
817 OriginalPte = &Pfn1->OriginalPte;
818 Protection = OriginalPte->u.Soft.Protection;
819
820 /* Remember that we used the original protection */
821 OriginalProtection = TRUE;
822
823 /* Check if this was a write on a read only proto */
824 if ((StoreInstruction) && !(Protection & MM_READWRITE))
825 {
826 /* Clear the flag */
827 StoreInstruction = 0;
828 }
829 }
830
831 /* Check if this was a write on a non-COW page */
832 DirtyPage = FALSE;
833 if ((StoreInstruction) && ((Protection & MM_WRITECOPY) != MM_WRITECOPY))
834 {
835 /* Then the page should be marked dirty */
836 DirtyPage = TRUE;
837
838 /* ReactOS check */
839 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype != 0);
840 }
841
842 /* Did we get a locked incoming PFN? */
843 if (*LockedProtoPfn)
844 {
845 /* Drop a reference */
846 ASSERT((*LockedProtoPfn)->u3.e2.ReferenceCount >= 1);
847 MiDereferencePfnAndDropLockCount(*LockedProtoPfn);
848 *LockedProtoPfn = NULL;
849 }
850
851 /* Release the PFN lock */
852 MiReleasePfnLock(OldIrql);
853
854 /* Remove special/caching bits */
855 Protection &= ~MM_PROTECT_SPECIAL;
856
857 /* Setup caching */
858 if (Pfn1->u3.e1.CacheAttribute == MiWriteCombined)
859 {
860 /* Write combining, no caching */
863 }
864 else if (Pfn1->u3.e1.CacheAttribute == MiNonCached)
865 {
866 /* Write through, no caching */
869 }
870
871 /* Check if this is a kernel or user address */
873 {
874 /* Build the user PTE */
875 MI_MAKE_HARDWARE_PTE_USER(&TempPte, PointerPte, Protection, PageFrameIndex);
876 }
877 else
878 {
879 /* Build the kernel PTE */
880 MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, Protection, PageFrameIndex);
881 }
882
883 /* Set the dirty flag if needed */
884 if (DirtyPage) MI_MAKE_DIRTY_PAGE(&TempPte);
885
886 /* Write the PTE */
887 MI_WRITE_VALID_PTE(PointerPte, TempPte);
888
889 /* Reset the protection if needed */
890 if (OriginalProtection) Protection = MM_ZERO_ACCESS;
891
892 /* Return success */
893 ASSERT(PointerPte == MiAddressToPte(Address));
894 return STATUS_SUCCESS;
895}
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::@1790 u3
MMPTE OriginalPte
Definition: mm.h:407
union _MMPFN::@1789 u2
MMPFNENTRY e1
Definition: mm.h:397
ULONG_PTR ShareCount
Definition: mm.h:390
ULONG64 PageFrameNumber
Definition: mmtypes.h:171
ULONG64 Protection
Definition: mmtypes.h:88
ULONG64 Prototype
Definition: mmtypes.h:89
union _MMPTE::@2325 u
MMPTE_SOFTWARE Soft
Definition: mmtypes.h:219
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778

Referenced by MiDispatchFault(), and MiResolveProtoPteFault().

◆ MiCopyPfn()

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

Definition at line 533 of file pagfault.c.

536{
537 PMMPTE SysPtes;
539 PMMPFN DestPfn, SrcPfn;
540 PVOID DestAddress;
541 const VOID* SrcAddress;
542
543 /* Get the PFNs */
544 DestPfn = MiGetPfnEntry(DestPage);
545 ASSERT(DestPfn);
546 SrcPfn = MiGetPfnEntry(SrcPage);
547 ASSERT(SrcPfn);
548
549 /* Grab 2 system PTEs */
551 ASSERT(SysPtes);
552
553 /* Initialize the destination PTE */
555 TempPte.u.Hard.PageFrameNumber = DestPage;
556
557 /* Setup caching */
558 if (DestPfn->u3.e1.CacheAttribute == MiWriteCombined)
559 {
560 /* Write combining, no caching */
563 }
564 else if (DestPfn->u3.e1.CacheAttribute == MiNonCached)
565 {
566 /* Write through, no caching */
569 }
570
571 /* Make the system PTE valid with our PFN */
572 MI_WRITE_VALID_PTE(&SysPtes[0], TempPte);
573
574 /* Initialize the source PTE */
576 TempPte.u.Hard.PageFrameNumber = SrcPage;
577
578 /* Setup caching */
579 if (SrcPfn->u3.e1.CacheAttribute == MiNonCached)
580 {
582 }
583
584 /* Make the system PTE valid with our PFN */
585 MI_WRITE_VALID_PTE(&SysPtes[1], TempPte);
586
587 /* Get the addresses and perform the copy */
588 DestAddress = MiPteToAddress(&SysPtes[0]);
589 SrcAddress = MiPteToAddress(&SysPtes[1]);
590 RtlCopyMemory(DestAddress, SrcAddress, PAGE_SIZE);
591
592 /* Now get rid of it */
594}
@ 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 1338 of file pagfault.c.

1346{
1347 MMPTE TempPte;
1348 KIRQL OldIrql, LockIrql;
1350 PMMPTE SuperProtoPte;
1351 PMMPFN Pfn1, OutPfn = NULL;
1352 PFN_NUMBER PageFrameIndex;
1353 PFN_COUNT PteCount, ProcessedPtes;
1354 DPRINT("ARM3 Page Fault Dispatcher for address: %p in process: %p\n",
1355 Address,
1356 Process);
1357
1358 /* Make sure the addresses are ok */
1359 ASSERT(PointerPte == MiAddressToPte(Address));
1360
1361 //
1362 // Make sure APCs are off and we're not at dispatch
1363 //
1367
1368 //
1369 // Grab a copy of the PTE
1370 //
1371 TempPte = *PointerPte;
1372
1373 /* Do we have a prototype PTE? */
1374 if (PointerProtoPte)
1375 {
1376 /* This should never happen */
1377 ASSERT(!MI_IS_PHYSICAL_ADDRESS(PointerProtoPte));
1378
1379 /* Check if this is a kernel-mode address */
1380 SuperProtoPte = MiAddressToPte(PointerProtoPte);
1382 {
1383 /* Lock the PFN database */
1384 LockIrql = MiAcquirePfnLock();
1385
1386 /* Has the PTE been made valid yet? */
1387 if (!SuperProtoPte->u.Hard.Valid)
1388 {
1389 ASSERT(FALSE);
1390 }
1391 else if (PointerPte->u.Hard.Valid == 1)
1392 {
1393 ASSERT(FALSE);
1394 }
1395
1396 /* Resolve the fault -- this will release the PFN lock */
1398 Address,
1399 PointerPte,
1400 PointerProtoPte,
1401 &OutPfn,
1402 NULL,
1403 NULL,
1404 Process,
1405 LockIrql,
1406 TrapInformation);
1408
1409 /* Complete this as a transition fault */
1413 return Status;
1414 }
1415 else
1416 {
1417 /* We only handle the lookup path */
1418 ASSERT(PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED);
1419
1420 /* Is there a non-image VAD? */
1421 if ((Vad) &&
1422 (Vad->u.VadFlags.VadType != VadImageMap) &&
1423 !(Vad->u2.VadFlags2.ExtendableFile))
1424 {
1425 /* One day, ReactOS will cluster faults */
1427 DPRINT("Should cluster fault, but won't\n");
1428 }
1429
1430 /* Only one PTE to handle for now */
1431 PteCount = 1;
1432 ProcessedPtes = 0;
1433
1434 /* Lock the PFN database */
1435 LockIrql = MiAcquirePfnLock();
1436
1437 /* We only handle the valid path */
1438 ASSERT(SuperProtoPte->u.Hard.Valid == 1);
1439
1440 /* Capture the PTE */
1441 TempPte = *PointerProtoPte;
1442
1443 /* Loop to handle future case of clustered faults */
1444 while (TRUE)
1445 {
1446 /* For our current usage, this should be true */
1447 if (TempPte.u.Hard.Valid == 1)
1448 {
1449 /* Bump the share count on the PTE */
1450 PageFrameIndex = PFN_FROM_PTE(&TempPte);
1451 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1452 Pfn1->u2.ShareCount++;
1453 }
1454 else if ((TempPte.u.Soft.Prototype == 0) &&
1455 (TempPte.u.Soft.Transition == 1))
1456 {
1457 /* This is a standby page, bring it back from the cache */
1458 PageFrameIndex = TempPte.u.Trans.PageFrameNumber;
1459 DPRINT("oooh, shiny, a soft fault! 0x%lx\n", PageFrameIndex);
1460 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1462
1463 /* Should not yet happen in ReactOS */
1464 ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
1465 ASSERT(Pfn1->u4.InPageError == 0);
1466
1467 /* Get the page */
1469
1470 /* Bump its reference count */
1471 ASSERT(Pfn1->u2.ShareCount == 0);
1472 InterlockedIncrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1473 Pfn1->u2.ShareCount++;
1474
1475 /* Make it valid again */
1476 /* This looks like another macro.... */
1478 ASSERT(PointerProtoPte->u.Hard.Valid == 0);
1479 ASSERT(PointerProtoPte->u.Trans.Prototype == 0);
1480 ASSERT(PointerProtoPte->u.Trans.Transition == 1);
1481 TempPte.u.Long = (PointerProtoPte->u.Long & ~0xFFF) |
1482 MmProtectToPteMask[PointerProtoPte->u.Trans.Protection];
1483 TempPte.u.Hard.Valid = 1;
1485
1486 /* Is the PTE writeable? */
1487 if ((Pfn1->u3.e1.Modified) &&
1490 {
1491 /* Make it dirty */
1493 }
1494 else
1495 {
1496 /* Make it clean */
1498 }
1499
1500 /* Write the valid PTE */
1501 MI_WRITE_VALID_PTE(PointerProtoPte, TempPte);
1502 ASSERT(PointerPte->u.Hard.Valid == 0);
1503 }
1504 else
1505 {
1506 /* Page is invalid, get out of the loop */
1507 break;
1508 }
1509
1510 /* One more done, was it the last? */
1511 if (++ProcessedPtes == PteCount)
1512 {
1513 /* Complete the fault */
1515 Address,
1516 PointerPte,
1517 PointerProtoPte,
1518 LockIrql,
1519 &OutPfn);
1520
1521 /* THIS RELEASES THE PFN LOCK! */
1522 break;
1523 }
1524
1525 /* No clustered faults yet */
1526 ASSERT(FALSE);
1527 }
1528
1529 /* Did we resolve the fault? */
1530 if (ProcessedPtes)
1531 {
1532 /* Bump the transition count */
1533 InterlockedExchangeAddSizeT(&KeGetCurrentPrcb()->MmTransitionCount, ProcessedPtes);
1534 ProcessedPtes--;
1535
1536 /* Loop all the processing we did */
1537 ASSERT(ProcessedPtes == 0);
1538
1539 /* Complete this as a transition fault */
1544 }
1545
1546 /* We did not -- PFN lock is still held, prepare to resolve prototype PTE fault */
1547 OutPfn = MI_PFN_ELEMENT(SuperProtoPte->u.Hard.PageFrameNumber);
1549 ASSERT(OutPfn->u3.e2.ReferenceCount > 1);
1550 ASSERT(PointerPte->u.Hard.Valid == 0);
1551
1552 /* Resolve the fault -- this will release the PFN lock */
1554 Address,
1555 PointerPte,
1556 PointerProtoPte,
1557 &OutPfn,
1558 NULL,
1559 NULL,
1560 Process,
1561 LockIrql,
1562 TrapInformation);
1563 //ASSERT(Status != STATUS_ISSUE_PAGING_IO);
1564 //ASSERT(Status != STATUS_REFAULT);
1565 //ASSERT(Status != STATUS_PTE_CHANGED);
1566
1567 /* Did the routine clean out the PFN or should we? */
1568 if (OutPfn)
1569 {
1570 /* We had a locked PFN, so acquire the PFN lock to dereference it */
1571 ASSERT(PointerProtoPte != NULL);
1572 OldIrql = MiAcquirePfnLock();
1573
1574 /* Dereference the locked PFN */
1576 ASSERT(OutPfn->u3.e2.ReferenceCount >= 1);
1577
1578 /* And now release the lock */
1579 MiReleasePfnLock(OldIrql);
1580 }
1581
1582 /* Complete this as a transition fault */
1586 return Status;
1587 }
1588 }
1589
1590 /* Is this a transition PTE */
1591 if (TempPte.u.Soft.Transition)
1592 {
1593 PKEVENT* InPageBlock = NULL;
1594 PKEVENT PreviousPageEvent;
1595 KEVENT CurrentPageEvent;
1596
1597 /* Lock the PFN database */
1598 LockIrql = MiAcquirePfnLock();
1599
1600 /* Resolve */
1601 Status = MiResolveTransitionFault(!MI_IS_NOT_PRESENT_FAULT(FaultCode), Address, PointerPte, Process, LockIrql, &InPageBlock);
1602
1604
1605 if (InPageBlock != NULL)
1606 {
1607 /* Another thread is reading or writing this page. Put us into the waiting queue. */
1608 KeInitializeEvent(&CurrentPageEvent, NotificationEvent, FALSE);
1609 PreviousPageEvent = *InPageBlock;
1610 *InPageBlock = &CurrentPageEvent;
1611 }
1612
1613 /* And now release the lock and leave*/
1614 MiReleasePfnLock(LockIrql);
1615
1616 if (InPageBlock != NULL)
1617 {
1618 KeWaitForSingleObject(&CurrentPageEvent, WrPageIn, KernelMode, FALSE, NULL);
1619
1620 /* Let's the chain go on */
1621 if (PreviousPageEvent)
1622 {
1623 KeSetEvent(PreviousPageEvent, IO_NO_INCREMENT, FALSE);
1624 }
1625 }
1626
1630 return Status;
1631 }
1632
1633 /* Should we page the data back in ? */
1634 if (TempPte.u.Soft.PageFileHigh != 0)
1635 {
1636 /* Lock the PFN database */
1637 LockIrql = MiAcquirePfnLock();
1638
1639 /* Resolve */
1640 Status = MiResolvePageFileFault(!MI_IS_NOT_PRESENT_FAULT(FaultCode), Address, PointerPte, Process, &LockIrql);
1641
1642 /* And now release the lock and leave*/
1643 MiReleasePfnLock(LockIrql);
1644
1648 return Status;
1649 }
1650
1651 //
1652 // The PTE must be invalid but not completely empty. It must also not be a
1653 // prototype a transition or a paged-out PTE as those scenarii should've been handled above.
1654 // These are all Windows checks
1655 //
1656 ASSERT(TempPte.u.Hard.Valid == 0);
1657 ASSERT(TempPte.u.Soft.Prototype == 0);
1658 ASSERT(TempPte.u.Soft.Transition == 0);
1659 ASSERT(TempPte.u.Soft.PageFileHigh == 0);
1660 ASSERT(TempPte.u.Long != 0);
1661
1662 //
1663 // If we got this far, the PTE can only be a demand zero PTE, which is what
1664 // we want. Go handle it!
1665 //
1667 PointerPte,
1668 (ULONG)TempPte.u.Soft.Protection,
1669 Process,
1670 MM_NOIRQL);
1672 if (NT_SUCCESS(Status))
1673 {
1674#if MI_TRACE_PFNS
1675 /* Update debug info */
1676 if (TrapInformation)
1677 MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = (PVOID)((PKTRAP_FRAME)TrapInformation)->Eip;
1678 else
1679 MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = _ReturnAddress();
1680#endif
1681
1682 //
1683 // Make sure we're returning in a sane state and pass the status down
1684 //
1687 return Status;
1688 }
1689
1690 //
1691 // Return status
1692 //
1693 return Status;
1694}
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:1148
@ ActiveAndValid
Definition: mmtypes.h:159
@ 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:599
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:775
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:992
static NTSTATUS NTAPI MiResolvePageFileFault(_In_ BOOLEAN StoreInstruction, _In_ PVOID FaultingAddress, _In_ PMMPTE PointerPte, _In_ PEPROCESS CurrentProcess, _Inout_ KIRQL *OldIrql)
Definition: pagfault.c:900
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:1124
USHORT Modified
Definition: mm.h:360
USHORT ReadInProgress
Definition: mm.h:361
USHORT PageLocation
Definition: mm.h:365
union _MMPFN::@1793 u4
struct _MMPFN::@1790::@1796 e2
ULONG_PTR InPageError
Definition: mm.h:419
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:424
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 142 of file pagfault.c.

146{
147 #define _BYTE_MASK(Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7) \
148 (Bit0) | ((Bit1) << 1) | ((Bit2) << 2) | ((Bit3) << 3) | \
149 ((Bit4) << 4) | ((Bit5) << 5) | ((Bit6) << 6) | ((Bit7) << 7)
150 static const UCHAR AccessAllowedMask[2][2] =
151 {
152 { // Protect 0 1 2 3 4 5 6 7
153 _BYTE_MASK(0, 1, 1, 1, 1, 1, 1, 1), // READ
154 _BYTE_MASK(0, 0, 1, 1, 0, 0, 1, 1), // EXECUTE READ
155 },
156 {
157 _BYTE_MASK(0, 0, 0, 0, 1, 1, 1, 1), // WRITE
158 _BYTE_MASK(0, 0, 0, 0, 0, 0, 1, 1), // EXECUTE WRITE
159 }
160 };
161
162 /* We want only the lower access bits */
163 ProtectionMask &= MM_PROTECT_ACCESS;
164
165 /* Look it up in the table */
166 return (AccessAllowedMask[Write != 0][Execute != 0] >> ProtectionMask) & 1;
167}
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 599 of file pagfault.c.

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

905{
906 ULONG Color;
909 MMPTE TempPte = *PointerPte;
910 PMMPFN Pfn1;
911 ULONG PageFileIndex = TempPte.u.Soft.PageFileLow;
912 ULONG_PTR PageFileOffset = TempPte.u.Soft.PageFileHigh;
913 ULONG Protection = TempPte.u.Soft.Protection;
914
915 /* Things we don't support yet */
916 ASSERT(CurrentProcess > HYDRA_PROCESS);
918
920 MI_SET_PROCESS(CurrentProcess);
921
922 /* We must hold the PFN lock */
924
925 /* Some sanity checks */
926 ASSERT(TempPte.u.Hard.Valid == 0);
927 ASSERT(TempPte.u.Soft.PageFileHigh != 0);
928 ASSERT(TempPte.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED);
929
930 /* Get any page, it will be overwritten */
931 Color = MI_GET_NEXT_PROCESS_COLOR(CurrentProcess);
933 if (Page == 0)
934 {
935 return STATUS_NO_MEMORY;
936 }
937
938 /* Initialize this PFN */
939 MiInitializePfn(Page, PointerPte, StoreInstruction);
940
941 /* Sets the PFN as being in IO operation */
942 Pfn1 = MI_PFN_ELEMENT(Page);
943 ASSERT(Pfn1->u1.Event == NULL);
944 ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
945 ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
946 Pfn1->u3.e1.ReadInProgress = 1;
947
948 /* We must write the PTE now as the PFN lock will be released while performing the IO operation */
949 MI_MAKE_TRANSITION_PTE(&TempPte, Page, Protection);
950
951 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
952
953 /* Release the PFN lock while we proceed */
954 MiReleasePfnLock(*OldIrql);
955
956 /* Do the paging IO */
957 Status = MiReadPageFile(Page, PageFileIndex, PageFileOffset);
958
959 /* Lock the PFN database again */
960 *OldIrql = MiAcquirePfnLock();
961
962 /* Nobody should have changed that while we were not looking */
963 ASSERT(Pfn1->u3.e1.ReadInProgress == 1);
964 ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
965
966 if (!NT_SUCCESS(Status))
967 {
968 /* Malheur! */
969 ASSERT(FALSE);
970 Pfn1->u4.InPageError = 1;
971 Pfn1->u1.ReadStatus = Status;
972 }
973
974 /* And the PTE can finally be valid */
975 MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, Protection, Page);
976 MI_WRITE_VALID_PTE(PointerPte, TempPte);
977
978 Pfn1->u3.e1.ReadInProgress = 0;
979 /* Did someone start to wait on us while we proceeded ? */
980 if (Pfn1->u1.Event)
981 {
982 /* Tell them we're done */
984 }
985
986 return Status;
987}
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:1306
#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 1124 of file pagfault.c.

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

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

488{
489 PMMPTE ZeroPte;
491 PMMPFN Pfn1;
492 PVOID ZeroAddress;
493
494 /* Get the PFN for this page */
495 Pfn1 = MiGetPfnEntry(PageFrameNumber);
496 ASSERT(Pfn1);
497
498 /* Grab a system PTE we can use to zero the page */
500 ASSERT(ZeroPte);
501
502 /* Initialize the PTE for it */
504 TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
505
506 /* Setup caching */
507 if (Pfn1->u3.e1.CacheAttribute == MiWriteCombined)
508 {
509 /* Write combining, no caching */
512 }
513 else if (Pfn1->u3.e1.CacheAttribute == MiNonCached)
514 {
515 /* Write through, no caching */
518 }
519
520 /* Make the system PTE valid with our PFN */
521 MI_WRITE_VALID_PTE(ZeroPte, TempPte);
522
523 /* Get the address it maps to, and zero it out */
524 ZeroAddress = MiPteToAddress(ZeroPte);
525 KeZeroPages(ZeroAddress, PAGE_SIZE);
526
527 /* Now get rid of it */
529}
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 1698 of file pagfault.c.

1702{
1703 KIRQL OldIrql = KeGetCurrentIrql(), LockIrql;
1704 PMMPTE ProtoPte = NULL;
1705 PMMPTE PointerPte = MiAddressToPte(Address);
1706 PMMPDE PointerPde = MiAddressToPde(Address);
1707#if (_MI_PAGING_LEVELS >= 3)
1708 PMMPDE PointerPpe = MiAddressToPpe(Address);
1709#if (_MI_PAGING_LEVELS == 4)
1710 PMMPDE PointerPxe = MiAddressToPxe(Address);
1711#endif
1712#endif
1713 MMPTE TempPte;
1714 PETHREAD CurrentThread;
1715 PEPROCESS CurrentProcess;
1717 PMMSUPPORT WorkingSet;
1718 ULONG ProtectionCode;
1719 PMMVAD Vad = NULL;
1720 PFN_NUMBER PageFrameIndex;
1721 ULONG Color;
1722 BOOLEAN IsSessionAddress;
1723 PMMPFN Pfn1;
1724 DPRINT("ARM3 FAULT AT: %p\n", Address);
1725
1726 /* Check for page fault on high IRQL */
1727 if (OldIrql > APC_LEVEL)
1728 {
1729#if (_MI_PAGING_LEVELS < 3)
1730 /* Could be a page table for paged pool, which we'll allow */
1731 if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)) MiSynchronizeSystemPde((PMMPDE)PointerPte);
1733#endif
1734 /* Check if any of the top-level pages are invalid */
1735 if (
1736#if (_MI_PAGING_LEVELS == 4)
1737 (PointerPxe->u.Hard.Valid == 0) ||
1738#endif
1739#if (_MI_PAGING_LEVELS >= 3)
1740 (PointerPpe->u.Hard.Valid == 0) ||
1741#endif
1742 (PointerPde->u.Hard.Valid == 0) ||
1743 (PointerPte->u.Hard.Valid == 0))
1744 {
1745 /* This fault is not valid, print out some debugging help */
1746 DbgPrint("MM:***PAGE FAULT AT IRQL > 1 Va %p, IRQL %lx\n",
1747 Address,
1748 OldIrql);
1749 if (TrapInformation)
1750 {
1751 PKTRAP_FRAME TrapFrame = TrapInformation;
1752#ifdef _M_IX86
1753 DbgPrint("MM:***EIP %p, EFL %p\n", TrapFrame->Eip, TrapFrame->EFlags);
1754 DbgPrint("MM:***EAX %p, ECX %p EDX %p\n", TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
1755 DbgPrint("MM:***EBX %p, ESI %p EDI %p\n", TrapFrame->Ebx, TrapFrame->Esi, TrapFrame->Edi);
1756#elif defined(_M_AMD64)
1757 DbgPrint("MM:***RIP %p, EFL %p\n", TrapFrame->Rip, TrapFrame->EFlags);
1758 DbgPrint("MM:***RAX %p, RCX %p RDX %p\n", TrapFrame->Rax, TrapFrame->Rcx, TrapFrame->Rdx);
1759 DbgPrint("MM:***RBX %p, RSI %p RDI %p\n", TrapFrame->Rbx, TrapFrame->Rsi, TrapFrame->Rdi);
1760#elif defined(_M_ARM)
1761 DbgPrint("MM:***PC %p\n", TrapFrame->Pc);
1762 DbgPrint("MM:***R0 %p, R1 %p R2 %p, R3 %p\n", TrapFrame->R0, TrapFrame->R1, TrapFrame->R2, TrapFrame->R3);
1763 DbgPrint("MM:***R11 %p, R12 %p SP %p, LR %p\n", TrapFrame->R11, TrapFrame->R12, TrapFrame->Sp, TrapFrame->Lr);
1764#endif
1765 }
1766
1767 /* Tell the trap handler to fail */
1768 return STATUS_IN_PAGE_ERROR | 0x10000000;
1769 }
1770
1771 /* Not yet implemented in ReactOS */
1772 ASSERT(MI_IS_PAGE_LARGE(PointerPde) == FALSE);
1773 ASSERT((!MI_IS_NOT_PRESENT_FAULT(FaultCode) && MI_IS_PAGE_COPY_ON_WRITE(PointerPte)) == FALSE);
1774
1775 /* Check if this was a write */
1776 if (MI_IS_WRITE_ACCESS(FaultCode))
1777 {
1778 /* Was it to a read-only page? */
1779 Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1780 if (!(PointerPte->u.Long & PTE_READWRITE) &&
1782 {
1783 /* Crash with distinguished bugcheck code */
1784 KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1786 PointerPte->u.Long,
1787 (ULONG_PTR)TrapInformation,
1788 10);
1789 }
1790 }
1791
1792 /* Nothing is actually wrong */
1793 DPRINT1("Fault at IRQL %u is ok (%p)\n", OldIrql, Address);
1794 return STATUS_SUCCESS;
1795 }
1796
1797 /* Check for kernel fault address */
1799 {
1800 /* Bail out, if the fault came from user mode */
1801 if (Mode == UserMode) return STATUS_ACCESS_VIOLATION;
1802
1803#if (_MI_PAGING_LEVELS == 2)
1804 if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)) MiSynchronizeSystemPde((PMMPDE)PointerPte);
1806#endif
1807
1808 /* Check if the higher page table entries are invalid */
1809 if (
1810#if (_MI_PAGING_LEVELS == 4)
1811 /* AMD64 system, check if PXE is invalid */
1812 (PointerPxe->u.Hard.Valid == 0) ||
1813#endif
1814#if (_MI_PAGING_LEVELS >= 3)
1815 /* PAE/AMD64 system, check if PPE is invalid */
1816 (PointerPpe->u.Hard.Valid == 0) ||
1817#endif
1818 /* Always check if the PDE is valid */
1819 (PointerPde->u.Hard.Valid == 0))
1820 {
1821 /* PXE/PPE/PDE (still) not valid, kill the system */
1822 KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
1824 FaultCode,
1825 (ULONG_PTR)TrapInformation,
1826 2);
1827 }
1828
1829 /* Not handling session faults yet */
1830 IsSessionAddress = MI_IS_SESSION_ADDRESS(Address);
1831
1832 /* The PDE is valid, so read the PTE */
1833 TempPte = *PointerPte;
1834 if (TempPte.u.Hard.Valid == 1)
1835 {
1836 /* Check if this was system space or session space */
1837 if (!IsSessionAddress)
1838 {
1839 /* Check if the PTE is still valid under PFN lock */
1840 OldIrql = MiAcquirePfnLock();
1841 TempPte = *PointerPte;
1842 if (TempPte.u.Hard.Valid)
1843 {
1844 /* Check if this was a write */
1845 if (MI_IS_WRITE_ACCESS(FaultCode))
1846 {
1847 /* Was it to a read-only page? */
1848 Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1849 if (!(PointerPte->u.Long & PTE_READWRITE) &&
1851 {
1852 /* Crash with distinguished bugcheck code */
1853 KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1855 PointerPte->u.Long,
1856 (ULONG_PTR)TrapInformation,
1857 11);
1858 }
1859 }
1860
1861 /* Check for execution of non-executable memory */
1862 if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
1864 {
1865 KeBugCheckEx(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY,
1867 (ULONG_PTR)TempPte.u.Long,
1868 (ULONG_PTR)TrapInformation,
1869 1);
1870 }
1871 }
1872
1873 /* Release PFN lock and return all good */
1874 MiReleasePfnLock(OldIrql);
1875 return STATUS_SUCCESS;
1876 }
1877 }
1878#if (_MI_PAGING_LEVELS == 2)
1879 /* Check if this was a session PTE that needs to remap the session PDE */
1881 {
1882 /* Do the remapping */
1883 Status = MiCheckPdeForSessionSpace(Address);
1884 if (!NT_SUCCESS(Status))
1885 {
1886 /* It failed, this address is invalid */
1887 KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
1889 FaultCode,
1890 (ULONG_PTR)TrapInformation,
1891 6);
1892 }
1893 }
1894#else
1895
1896_WARN("Session space stuff is not implemented yet!")
1897
1898#endif
1899
1900 /* Check for a fault on the page table or hyperspace */
1902 {
1903#if (_MI_PAGING_LEVELS < 3)
1904 /* Windows does this check but I don't understand why -- it's done above! */
1906#endif
1907 /* Handle this as a user mode fault */
1908 goto UserFault;
1909 }
1910
1911 /* Get the current thread */
1912 CurrentThread = PsGetCurrentThread();
1913
1914 /* What kind of address is this */
1915 if (!IsSessionAddress)
1916 {
1917 /* Use the system working set */
1918 WorkingSet = &MmSystemCacheWs;
1919 CurrentProcess = NULL;
1920
1921 /* Make sure we don't have a recursive working set lock */
1922 if ((CurrentThread->OwnsProcessWorkingSetExclusive) ||
1923 (CurrentThread->OwnsProcessWorkingSetShared) ||
1924 (CurrentThread->OwnsSystemWorkingSetExclusive) ||
1925 (CurrentThread->OwnsSystemWorkingSetShared) ||
1926 (CurrentThread->OwnsSessionWorkingSetExclusive) ||
1927 (CurrentThread->OwnsSessionWorkingSetShared))
1928 {
1929 /* Fail */
1930 return STATUS_IN_PAGE_ERROR | 0x10000000;
1931 }
1932 }
1933 else
1934 {
1935 /* Use the session process and working set */
1936 CurrentProcess = HYDRA_PROCESS;
1937 WorkingSet = &MmSessionSpace->GlobalVirtualAddress->Vm;
1938
1939 /* Make sure we don't have a recursive working set lock */
1940 if ((CurrentThread->OwnsSessionWorkingSetExclusive) ||
1941 (CurrentThread->OwnsSessionWorkingSetShared))
1942 {
1943 /* Fail */
1944 return STATUS_IN_PAGE_ERROR | 0x10000000;
1945 }
1946 }
1947RetryKernel:
1948 /* Acquire the working set lock */
1949 KeRaiseIrql(APC_LEVEL, &LockIrql);
1950 MiLockWorkingSet(CurrentThread, WorkingSet);
1951
1952 /* Re-read PTE now that we own the lock */
1953 TempPte = *PointerPte;
1954 if (TempPte.u.Hard.Valid == 1)
1955 {
1956 /* Check if this was a write */
1957 if (MI_IS_WRITE_ACCESS(FaultCode))
1958 {
1959 /* Was it to a read-only page that is not copy on write? */
1960 Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1961 if (!(TempPte.u.Long & PTE_READWRITE) &&
1964 {
1965 /* Case not yet handled */
1966 ASSERT(!IsSessionAddress);
1967
1968 /* Crash with distinguished bugcheck code */
1969 KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1971 TempPte.u.Long,
1972 (ULONG_PTR)TrapInformation,
1973 12);
1974 }
1975 }
1976
1977 /* Check for execution of non-executable memory */
1978 if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
1980 {
1981 KeBugCheckEx(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY,
1983 (ULONG_PTR)TempPte.u.Long,
1984 (ULONG_PTR)TrapInformation,
1985 2);
1986 }
1987
1988 /* Check for read-only write in session space */
1989 if ((IsSessionAddress) &&
1990 MI_IS_WRITE_ACCESS(FaultCode) &&
1992 {
1993 /* Sanity check */
1995
1996 /* Was this COW? */
1998 {
1999 /* Then this is not allowed */
2000 KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
2002 (ULONG_PTR)TempPte.u.Long,
2003 (ULONG_PTR)TrapInformation,
2004 13);
2005 }
2006
2007 /* Otherwise, handle COW */
2008 ASSERT(FALSE);
2009 }
2010
2011 /* Release the working set */
2012 MiUnlockWorkingSet(CurrentThread, WorkingSet);
2013 KeLowerIrql(LockIrql);
2014
2015 /* Otherwise, the PDE was probably invalid, and all is good now */
2016 return STATUS_SUCCESS;
2017 }
2018
2019 /* Check one kind of prototype PTE */
2020 if (TempPte.u.Soft.Prototype)
2021 {
2022 /* Make sure protected pool is on, and that this is a pool address */
2029 {
2030 /* Bad boy, bad boy, whatcha gonna do, whatcha gonna do when ARM3 comes for you! */
2031 KeBugCheckEx(DRIVER_CAUGHT_MODIFYING_FREED_POOL,
2033 FaultCode,
2034 Mode,
2035 4);
2036 }
2037
2038 /* Get the prototype PTE! */
2039 ProtoPte = MiProtoPteToPte(&TempPte);
2040
2041 /* Do we need to locate the prototype PTE in session space? */
2042 if ((IsSessionAddress) &&
2043 (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED))
2044 {
2045 /* Yep, go find it as well as the VAD for it */
2046 ProtoPte = MiCheckVirtualAddress(Address,
2047 &ProtectionCode,
2048 &Vad);
2049 ASSERT(ProtoPte != NULL);
2050 }
2051 }
2052 else
2053 {
2054 /* We don't implement transition PTEs */
2055 ASSERT(TempPte.u.Soft.Transition == 0);
2056
2057 /* Check for no-access PTE */
2058 if (TempPte.u.Soft.Protection == MM_NOACCESS)
2059 {
2060 /* Bugcheck the system! */
2061 KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
2063 FaultCode,
2064 (ULONG_PTR)TrapInformation,
2065 1);
2066 }
2067
2068 /* Check for no protecton at all */
2069 if (TempPte.u.Soft.Protection == MM_ZERO_ACCESS)
2070 {
2071 /* Bugcheck the system! */
2072 KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
2074 FaultCode,
2075 (ULONG_PTR)TrapInformation,
2076 0);
2077 }
2078 }
2079
2080 /* Check for demand page */
2081 if (MI_IS_WRITE_ACCESS(FaultCode) &&
2082 !(ProtoPte) &&
2083 !(IsSessionAddress) &&
2084 !(TempPte.u.Hard.Valid))
2085 {
2086 /* Get the protection code */
2087 ASSERT(TempPte.u.Soft.Transition == 0);
2088 if (!(TempPte.u.Soft.Protection & MM_READWRITE))
2089 {
2090 /* Bugcheck the system! */
2091 KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
2093 TempPte.u.Long,
2094 (ULONG_PTR)TrapInformation,
2095 14);
2096 }
2097 }
2098
2099 /* Now do the real fault handling */
2100 Status = MiDispatchFault(FaultCode,
2101 Address,
2102 PointerPte,
2103 ProtoPte,
2104 FALSE,
2105 CurrentProcess,
2106 TrapInformation,
2107 NULL);
2108
2109 /* Release the working set */
2111 MiUnlockWorkingSet(CurrentThread, WorkingSet);
2112 KeLowerIrql(LockIrql);
2113
2114 if (Status == STATUS_NO_MEMORY)
2115 {
2117 goto RetryKernel;
2118 }
2119
2120 /* We are done! */
2121 DPRINT("Fault resolved with status: %lx\n", Status);
2122 return Status;
2123 }
2124
2125 /* This is a user fault */
2126UserFault:
2127 CurrentThread = PsGetCurrentThread();
2128 CurrentProcess = (PEPROCESS)CurrentThread->Tcb.ApcState.Process;
2129
2130 /* Lock the working set */
2131 MiLockProcessWorkingSet(CurrentProcess, CurrentThread);
2132
2133 ProtectionCode = MM_INVALID_PROTECTION;
2134
2135#if (_MI_PAGING_LEVELS == 4)
2136 /* Check if the PXE is valid */
2137 if (PointerPxe->u.Hard.Valid == 0)
2138 {
2139 /* Right now, we only handle scenarios where the PXE is totally empty */
2140 ASSERT(PointerPxe->u.Long == 0);
2141
2142 /* This is only possible for user mode addresses! */
2143 ASSERT(PointerPte <= MiHighestUserPte);
2144
2145 /* Check if we have a VAD */
2146 MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2147 if (ProtectionCode == MM_NOACCESS)
2148 {
2149 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2151 }
2152
2153 /* Resolve a demand zero fault */
2154 Status = MiResolveDemandZeroFault(PointerPpe,
2155 PointerPxe,
2157 CurrentProcess,
2158 MM_NOIRQL);
2159 if (!NT_SUCCESS(Status))
2160 {
2161 goto ExitUser;
2162 }
2163
2164 /* We should come back with a valid PXE */
2165 ASSERT(PointerPxe->u.Hard.Valid == 1);
2166 }
2167#endif
2168
2169#if (_MI_PAGING_LEVELS >= 3)
2170 /* Check if the PPE is valid */
2171 if (PointerPpe->u.Hard.Valid == 0)
2172 {
2173 /* Right now, we only handle scenarios where the PPE is totally empty */
2174 ASSERT(PointerPpe->u.Long == 0);
2175
2176 /* This is only possible for user mode addresses! */
2177 ASSERT(PointerPte <= MiHighestUserPte);
2178
2179 /* Check if we have a VAD, unless we did this already */
2180 if (ProtectionCode == MM_INVALID_PROTECTION)
2181 {
2182 MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2183 }
2184
2185 if (ProtectionCode == MM_NOACCESS)
2186 {
2187 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2189 }
2190
2191 /* Resolve a demand zero fault */
2192 Status = MiResolveDemandZeroFault(PointerPde,
2193 PointerPpe,
2195 CurrentProcess,
2196 MM_NOIRQL);
2197 if (!NT_SUCCESS(Status))
2198 {
2199 goto ExitUser;
2200 }
2201
2202 /* We should come back with a valid PPE */
2203 ASSERT(PointerPpe->u.Hard.Valid == 1);
2205 }
2206#endif
2207
2208 /* Check if the PDE is invalid */
2209 if (PointerPde->u.Hard.Valid == 0)
2210 {
2211 /* Right now, we only handle scenarios where the PDE is totally empty */
2212 ASSERT(PointerPde->u.Long == 0);
2213
2214 /* And go dispatch the fault on the PDE. This should handle the demand-zero */
2215#if MI_TRACE_PFNS
2216 UserPdeFault = TRUE;
2217#endif
2218 /* Check if we have a VAD, unless we did this already */
2219 if (ProtectionCode == MM_INVALID_PROTECTION)
2220 {
2221 MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2222 }
2223
2224 if (ProtectionCode == MM_NOACCESS)
2225 {
2226#if (_MI_PAGING_LEVELS == 2)
2227 /* Could be a page table for paged pool */
2229#endif
2230 /* Has the code above changed anything -- is this now a valid PTE? */
2231 Status = (PointerPde->u.Hard.Valid == 1) ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
2232
2233 /* Either this was a bogus VA or we've fixed up a paged pool PDE */
2234 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2235 return Status;
2236 }
2237
2238 /* Resolve a demand zero fault */
2239 Status = MiResolveDemandZeroFault(PointerPte,
2240 PointerPde,
2242 CurrentProcess,
2243 MM_NOIRQL);
2244 if (!NT_SUCCESS(Status))
2245 {
2246 goto ExitUser;
2247 }
2248
2249#if _MI_PAGING_LEVELS >= 3
2251#endif
2252
2253#if MI_TRACE_PFNS
2254 UserPdeFault = FALSE;
2255 /* Update debug info */
2256 if (TrapInformation)
2257 MiGetPfnEntry(PointerPde->u.Hard.PageFrameNumber)->CallSite = (PVOID)((PKTRAP_FRAME)TrapInformation)->Eip;
2258 else
2259 MiGetPfnEntry(PointerPde->u.Hard.PageFrameNumber)->CallSite = _ReturnAddress();
2260#endif
2261 /* We should come back with APCs enabled, and with a valid PDE */
2263 ASSERT(PointerPde->u.Hard.Valid == 1);
2264 }
2265 else
2266 {
2267 /* Not yet implemented in ReactOS */
2268 ASSERT(MI_IS_PAGE_LARGE(PointerPde) == FALSE);
2269 }
2270
2271 /* Now capture the PTE. */
2272 TempPte = *PointerPte;
2273
2274 /* Check if the PTE is valid */
2275 if (TempPte.u.Hard.Valid)
2276 {
2277 /* Check if this is a write on a readonly PTE */
2278 if (MI_IS_WRITE_ACCESS(FaultCode))
2279 {
2280 /* Is this a copy on write PTE? */
2282 {
2283 PFN_NUMBER PageFrameIndex, OldPageFrameIndex;
2284 PMMPFN Pfn1;
2285
2286 LockIrql = MiAcquirePfnLock();
2287
2289
2291 MI_SET_PROCESS(CurrentProcess);
2292
2293 /* Allocate a new page and copy it */
2294 PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(CurrentProcess));
2295 if (PageFrameIndex == 0)
2296 {
2297 MiReleasePfnLock(LockIrql);
2299 goto ExitUser;
2300 }
2301 OldPageFrameIndex = PFN_FROM_PTE(&TempPte);
2302
2303 MiCopyPfn(PageFrameIndex, OldPageFrameIndex);
2304
2305 /* Dereference whatever this PTE is referencing */
2306 Pfn1 = MI_PFN_ELEMENT(OldPageFrameIndex);
2307 ASSERT(Pfn1->u3.e1.PrototypePte == 1);
2308 ASSERT(!MI_IS_PFN_DELETED(Pfn1));
2309 ProtoPte = Pfn1->PteAddress;
2310 MiDeletePte(PointerPte, Address, CurrentProcess, ProtoPte);
2311
2312 /* And make a new shiny one with our page */
2313 MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
2314 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
2315 TempPte.u.Hard.Write = 1;
2316 TempPte.u.Hard.CopyOnWrite = 0;
2317
2318 MI_WRITE_VALID_PTE(PointerPte, TempPte);
2319
2320 MiReleasePfnLock(LockIrql);
2321
2322 /* Return the status */
2323 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2325 }
2326
2327 /* Is this a read-only PTE? */
2329 {
2330 /* Return the status */
2331 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2333 }
2334 }
2335
2336#if _MI_HAS_NO_EXECUTE
2337 /* Check for execution of non-executable memory */
2338 if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
2340 {
2341 /* Check if execute enable was set */
2342 if (CurrentProcess->Pcb.Flags.ExecuteEnable)
2343 {
2344 /* Fix up the PTE to be executable */
2345 TempPte.u.Hard.NoExecute = 0;
2346 MI_UPDATE_VALID_PTE(PointerPte, TempPte);
2347 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2348 return STATUS_SUCCESS;
2349 }
2350
2351 /* Return the status */
2352 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2354 }
2355#endif
2356
2357 /* The fault has already been resolved by a different thread */
2358 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2359 return STATUS_SUCCESS;
2360 }
2361
2362 /* Quick check for demand-zero */
2365 {
2366 /* Resolve the fault */
2368 PointerPte,
2369 TempPte.u.Soft.Protection,
2370 CurrentProcess,
2371 MM_NOIRQL);
2372 if (!NT_SUCCESS(Status))
2373 {
2374 goto ExitUser;
2375 }
2376
2377#if MI_TRACE_PFNS
2378 /* Update debug info */
2379 if (TrapInformation)
2380 MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = (PVOID)((PKTRAP_FRAME)TrapInformation)->Eip;
2381 else
2382 MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = _ReturnAddress();
2383#endif
2384
2385 /* Return the status */
2386 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2388 }
2389
2390 /* Check for zero PTE */
2391 if (TempPte.u.Long == 0)
2392 {
2393 /* Check if this address range belongs to a valid allocation (VAD) */
2394 ProtoPte = MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2395 if (ProtectionCode == MM_NOACCESS)
2396 {
2397#if (_MI_PAGING_LEVELS == 2)
2398 /* Could be a page table for paged pool */
2400#endif
2401 /* Has the code above changed anything -- is this now a valid PTE? */
2402 Status = (PointerPte->u.Hard.Valid == 1) ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
2403
2404 /* Either this was a bogus VA or we've fixed up a paged pool PDE */
2405 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2406 return Status;
2407 }
2408
2409 /*
2410 * Check if this is a real user-mode address or actually a kernel-mode
2411 * page table for a user mode address
2412 */
2414#if _MI_PAGING_LEVELS >= 3
2416#if _MI_PAGING_LEVELS == 4
2418#endif
2419#endif
2420 )
2421 {
2422 /* Add an additional page table reference */
2424 }
2425
2426 /* Is this a guard page? */
2427 if ((ProtectionCode & MM_PROTECT_SPECIAL) == MM_GUARDPAGE)
2428 {
2429 /* The VAD protection cannot be MM_DECOMMIT! */
2430 ASSERT(ProtectionCode != MM_DECOMMIT);
2431
2432 /* Remove the bit */
2433 TempPte.u.Soft.Protection = ProtectionCode & ~MM_GUARDPAGE;
2434 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2435
2436 /* Not supported */
2437 ASSERT(ProtoPte == NULL);
2438 ASSERT(CurrentThread->ApcNeeded == 0);
2439
2440 /* Drop the working set lock */
2441 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2443
2444 /* Handle stack expansion */
2445 return MiCheckForUserStackOverflow(Address, TrapInformation);
2446 }
2447
2448 /* Did we get a prototype PTE back? */
2449 if (!ProtoPte)
2450 {
2451 /* Is this PTE actually part of the PDE-PTE self-mapping directory? */
2452 if (PointerPde == MiAddressToPde(PTE_BASE))
2453 {
2454 /* Then it's really a demand-zero PDE (on behalf of user-mode) */
2455#ifdef _M_ARM
2456 _WARN("This is probably completely broken!");
2458#else
2460#endif
2461 }
2462 else
2463 {
2464 /* No, create a new PTE. First, write the protection */
2465 TempPte.u.Soft.Protection = ProtectionCode;
2466 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2467 }
2468
2469 /* Lock the PFN database since we're going to grab a page */
2470 OldIrql = MiAcquirePfnLock();
2471
2472 /* Make sure we have enough pages */
2473 //ASSERT(MmAvailablePages >= 32);
2474
2475 /* Try to get a zero page */
2477 MI_SET_PROCESS2(CurrentProcess->ImageFileName);
2478 Color = MI_GET_NEXT_PROCESS_COLOR(CurrentProcess);
2479 PageFrameIndex = MiRemoveZeroPageSafe(Color);
2480 if (!PageFrameIndex)
2481 {
2482 /* Grab a page out of there. Later we should grab a colored zero page */
2483 PageFrameIndex = MiRemoveAnyPage(Color);
2484
2485 /* Release the lock since we need to do some zeroing */
2486 MiReleasePfnLock(OldIrql);
2487
2488 if (PageFrameIndex == 0)
2489 {
2491 goto ExitUser;
2492 }
2493
2494 /* Zero out the page, since it's for user-mode */
2495 MiZeroPfn(PageFrameIndex);
2496
2497 /* Grab the lock again so we can initialize the PFN entry */
2498 OldIrql = MiAcquirePfnLock();
2499 }
2500
2501 /* Initialize the PFN entry now */
2502 MiInitializePfn(PageFrameIndex, PointerPte, 1);
2503
2504 /* Increment the count of pages in the process */
2505 CurrentProcess->NumberOfPrivatePages++;
2506
2507 /* One more demand-zero fault */
2508 KeGetCurrentPrcb()->MmDemandZeroCount++;
2509
2510 /* And we're done with the lock */
2511 MiReleasePfnLock(OldIrql);
2512
2513 /* Fault on user PDE, or fault on user PTE? */
2514 if (PointerPte <= MiHighestUserPte)
2515 {
2516 /* User fault, build a user PTE */
2518 PointerPte,
2519 PointerPte->u.Soft.Protection,
2520 PageFrameIndex);
2521 }
2522 else
2523 {
2524 /* This is a user-mode PDE, create a kernel PTE for it */
2526 PointerPte,
2527 PointerPte->u.Soft.Protection,
2528 PageFrameIndex);
2529 }
2530
2531 /* Write the dirty bit for writeable pages */
2533
2534 /* And now write down the PTE, making the address valid */
2535 MI_WRITE_VALID_PTE(PointerPte, TempPte);
2536 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
2537 ASSERT(Pfn1->u1.Event == NULL);
2538
2539 /* Demand zero */
2541 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2543 }
2544
2545 /* We should have a valid protection here */
2546 ASSERT(ProtectionCode != 0x100);
2547
2548 /* Write the prototype PTE */
2550 TempPte.u.Soft.Protection = ProtectionCode;
2551 ASSERT(TempPte.u.Long != 0);
2552 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2553 }
2554 else
2555 {
2556 /* Get the protection code and check if this is a proto PTE */
2557 ProtectionCode = (ULONG)TempPte.u.Soft.Protection;
2558 if (TempPte.u.Soft.Prototype)
2559 {
2560 /* Do we need to go find the real PTE? */
2561 if (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
2562 {
2563 /* Get the prototype pte and VAD for it */
2564 ProtoPte = MiCheckVirtualAddress(Address,
2565 &ProtectionCode,
2566 &Vad);
2567 if (!ProtoPte)
2568 {
2570 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2572 }
2573 }
2574 else
2575 {
2576 /* Get the prototype PTE! */
2577 ProtoPte = MiProtoPteToPte(&TempPte);
2578
2579 /* Is it read-only */
2580 if (TempPte.u.Proto.ReadOnly)
2581 {
2582 /* Set read-only code */
2583 ProtectionCode = MM_READONLY;
2584 }
2585 else
2586 {
2587 /* Set unknown protection */
2588 ProtectionCode = 0x100;
2589 ASSERT(CurrentProcess->CloneRoot != NULL);
2590 }
2591 }
2592 }
2593 }
2594
2595 /* Do we have a valid protection code? */
2596 if (ProtectionCode != 0x100)
2597 {
2598 /* Run a software access check first, including to detect guard pages */
2599 Status = MiAccessCheck(PointerPte,
2600 !MI_IS_NOT_PRESENT_FAULT(FaultCode),
2601 Mode,
2602 ProtectionCode,
2603 TrapInformation,
2604 FALSE);
2605 if (Status != STATUS_SUCCESS)
2606 {
2607 /* Not supported */
2608 ASSERT(CurrentThread->ApcNeeded == 0);
2609
2610 /* Drop the working set lock */
2611 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2613
2614 /* Did we hit a guard page? */
2616 {
2617 /* Handle stack expansion */
2618 return MiCheckForUserStackOverflow(Address, TrapInformation);
2619 }
2620
2621 /* Otherwise, fail back to the caller directly */
2622 return Status;
2623 }
2624 }
2625
2626 /* Dispatch the fault */
2627 Status = MiDispatchFault(FaultCode,
2628 Address,
2629 PointerPte,
2630 ProtoPte,
2631 FALSE,
2632 CurrentProcess,
2633 TrapInformation,
2634 Vad);
2635
2636ExitUser:
2637
2638 /* Return the status */
2640 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2641
2642 if (Status == STATUS_NO_MEMORY)
2643 {
2645 goto UserFault;
2646 }
2647
2648 return Status;
2649}
#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
FORCEINLINE VOID MI_UPDATE_VALID_PTE(IN PMMPTE PointerPte, IN MMPTE TempPte)
Definition: miarm.h:977
#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:241
VOID NTAPI MmRebalanceMemoryConsumersAndWait(VOID)
Definition: balance.c:300
NTSTATUS FASTCALL MiCheckPdeForPagedPool(IN PVOID Address)
Definition: pagfault.c:479
static NTSTATUS NTAPI MiCheckForUserStackOverflow(IN PVOID Address, IN PVOID TrapInformation)
Definition: pagfault.c:34
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:1338
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
KPROCESS Pcb
Definition: pstypes.h:1262
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
UCHAR ExecuteEnable
Definition: ketypes.h:988
KEXECUTE_OPTIONS Flags
Definition: ketypes.h:2130
KAPC_STATE ApcState
Definition: ketypes.h:1778
ULONG R3
Definition: ketypes.h:370
UINT64 Rdi
Definition: ketypes.h:440
ULONG Sp
Definition: ketypes.h:372
ULONG Pc
Definition: ketypes.h:375
ULONG Edi
Definition: ketypes.h:316
UINT64 Rsi
Definition: ketypes.h:441
UINT64 Rdx
Definition: ketypes.h:390
ULONG Lr
Definition: ketypes.h:373
ULONG EFlags
Definition: ketypes.h:454
ULONG R0
Definition: ketypes.h:367
ULONG Ebx
Definition: ketypes.h:318
ULONG Ecx
Definition: ketypes.h:311
UINT64 Rbx
Definition: ketypes.h:439
ULONG Eip
Definition: ketypes.h:321
UINT64 Rax
Definition: ketypes.h:388
UINT64 Rip
Definition: ketypes.h:449
ULONG R2
Definition: ketypes.h:369
ULONG R1
Definition: ketypes.h:368
ULONG Eax
Definition: ketypes.h:312
UINT64 Rcx
Definition: ketypes.h:389
ULONG Esi
Definition: ketypes.h:317
ULONG Edx
Definition: ketypes.h:310
UINT64 R11
Definition: ketypes.h:394
ULONG R12
Definition: ketypes.h:371
struct _MM_SESSION_SPACE * GlobalVirtualAddress
Definition: miarm.h:470

Referenced by MmAccessFault().

◆ MmGetExecuteOptions()

NTSTATUS NTAPI MmGetExecuteOptions ( IN PULONG  ExecuteOptions)

Definition at line 2653 of file pagfault.c.

2654{
2655 PKPROCESS CurrentProcess = &PsGetCurrentProcess()->Pcb;
2657
2658 *ExecuteOptions = 0;
2659
2660 if (CurrentProcess->Flags.ExecuteDisable)
2661 {
2662 *ExecuteOptions |= MEM_EXECUTE_OPTION_DISABLE;
2663 }
2664
2665 if (CurrentProcess->Flags.ExecuteEnable)
2666 {
2667 *ExecuteOptions |= MEM_EXECUTE_OPTION_ENABLE;
2668 }
2669
2670 if (CurrentProcess->Flags.DisableThunkEmulation)
2671 {
2673 }
2674
2675 if (CurrentProcess->Flags.Permanent)
2676 {
2677 *ExecuteOptions |= MEM_EXECUTE_OPTION_PERMANENT;
2678 }
2679
2680 if (CurrentProcess->Flags.ExecuteDispatchEnable)
2681 {
2683 }
2684
2685 if (CurrentProcess->Flags.ImageDispatchEnable)
2686 {
2688 }
2689
2690 return STATUS_SUCCESS;
2691}
#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:989
UCHAR ExecuteDisable
Definition: ketypes.h:987
UCHAR ExecuteDispatchEnable
Definition: ketypes.h:991
UCHAR ImageDispatchEnable
Definition: ketypes.h:992

Referenced by NtQueryInformationProcess().

◆ MmRebalanceMemoryConsumersAndWait()

VOID NTAPI MmRebalanceMemoryConsumersAndWait ( VOID  )

Definition at line 300 of file balance.c.

301{
302 ASSERT(PsGetCurrentProcess()->AddressCreationLock.Owner != KeGetCurrentThread());
305
309}
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
LONG NTAPI KeResetEvent(IN PKEVENT Event)
Definition: eventobj.c:133
#define KeGetCurrentThread
Definition: hal.h:55
FORCEINLINE BOOLEAN MM_ANY_WS_LOCK_HELD(IN PETHREAD Thread)
Definition: miarm.h:1052
static KEVENT MiBalancerDoneEvent
Definition: balance.c:34
VOID NTAPI MmRebalanceMemoryConsumers(VOID)
Definition: balance.c:290
@ Executive
Definition: ketypes.h:415

Referenced by MmArmAccessFault().

◆ MmSetExecuteOptions()

NTSTATUS NTAPI MmSetExecuteOptions ( IN ULONG  ExecuteOptions)

Definition at line 2695 of file pagfault.c.

2696{
2697 PKPROCESS CurrentProcess = &PsGetCurrentProcess()->Pcb;
2698 KLOCK_QUEUE_HANDLE ProcessLock;
2701
2702 /* Only accept valid flags */
2703 if (ExecuteOptions & ~MEM_EXECUTE_OPTION_VALID_FLAGS)
2704 {
2705 /* Fail */
2706 DPRINT1("Invalid no-execute options\n");
2708 }
2709
2710 /* Change the NX state in the process lock */
2711 KiAcquireProcessLockRaiseToSynch(CurrentProcess, &ProcessLock);
2712
2713 /* Don't change anything if the permanent flag was set */
2714 if (!CurrentProcess->Flags.Permanent)
2715 {
2716 /* Start by assuming it's not disabled */
2717 CurrentProcess->Flags.ExecuteDisable = FALSE;
2718
2719 /* Now process each flag and turn the equivalent bit on */
2720 if (ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE)
2721 {
2722 CurrentProcess->Flags.ExecuteDisable = TRUE;
2723 }
2724 if (ExecuteOptions & MEM_EXECUTE_OPTION_ENABLE)
2725 {
2726 CurrentProcess->Flags.ExecuteEnable = TRUE;
2727 }
2728 if (ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)
2729 {
2730 CurrentProcess->Flags.DisableThunkEmulation = TRUE;
2731 }
2732 if (ExecuteOptions & MEM_EXECUTE_OPTION_PERMANENT)
2733 {
2734 CurrentProcess->Flags.Permanent = TRUE;
2735 }
2736 if (ExecuteOptions & MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE)
2737 {
2738 CurrentProcess->Flags.ExecuteDispatchEnable = TRUE;
2739 }
2740 if (ExecuteOptions & MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE)
2741 {
2742 CurrentProcess->Flags.ImageDispatchEnable = TRUE;
2743 }
2744
2745 /* These are turned on by default if no-execution is also enabled */
2746 if (CurrentProcess->Flags.ExecuteEnable)
2747 {
2748 CurrentProcess->Flags.ExecuteDispatchEnable = TRUE;
2749 CurrentProcess->Flags.ImageDispatchEnable = TRUE;
2750 }
2751
2752 /* All good */
2754 }
2755
2756 /* Release the lock and return status */
2757 KiReleaseProcessLock(&ProcessLock);
2758 return Status;
2759}
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().