ReactOS  0.4.10-dev-234-g15c29d0
pagfault.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: BSD - See COPYING.ARM in the top level directory
4  * FILE: ntoskrnl/mm/ARM3/pagfault.c
5  * PURPOSE: ARM Memory Manager Page Fault Handling
6  * PROGRAMMERS: ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 #define MODULE_INVOLVED_IN_ARM3
16 #include <mm/ARM3/miarm.h>
17 
18 /* GLOBALS ********************************************************************/
19 
20 #define HYDRA_PROCESS (PEPROCESS)1
21 #if MI_TRACE_PFNS
22 BOOLEAN UserPdeFault = FALSE;
23 #endif
24 
25 /* PRIVATE FUNCTIONS **********************************************************/
26 
27 static
29 NTAPI
31  IN PVOID TrapInformation)
32 {
33  PETHREAD CurrentThread = PsGetCurrentThread();
34  PTEB Teb = CurrentThread->Tcb.Teb;
35  PVOID StackBase, DeallocationStack, NextStackAddress;
36  SIZE_T GuranteedSize;
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? */
49  if (KeIsAttachedProcess())
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  GuranteedSize = Teb->GuaranteedStackBytes;
60  DPRINT("Handling guard page fault with Stacks Addresses 0x%p and 0x%p, guarantee: %lx\n",
61  StackBase, DeallocationStack, GuranteedSize);
62 
63  /* Guarantees make this code harder, for now, assume there aren't any */
64  ASSERT(GuranteedSize == 0);
65 
66  /* So allocate only the minimum guard page size */
67  GuranteedSize = 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) - GuranteedSize);
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 -- Windows would try to make this guard page valid now */
85  DPRINT1("Close to our death...\n");
86  return STATUS_STACK_OVERFLOW;
87  }
88 
89  /* Don't handle this flag yet */
91 
92  /* Update the stack limit */
93  Teb->NtTib.StackLimit = (PVOID)((ULONG_PTR)NextStackAddress + GuranteedSize);
94 
95  /* Now move the guard page to the next page */
96  Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
97  &NextStackAddress,
98  0,
99  &GuranteedSize,
100  MEM_COMMIT,
102  if ((NT_SUCCESS(Status) || (Status == STATUS_ALREADY_COMMITTED)))
103  {
104  /* We did it! */
105  DPRINT("Guard page handled successfully for %p\n", Address);
107  }
108 
109  /* Fail, we couldn't move the guard page */
110  DPRINT1("Guard page failure: %lx\n", Status);
111  ASSERT(FALSE);
112  return STATUS_STACK_OVERFLOW;
113 }
114 
116 BOOLEAN
118  _In_ ULONG ProtectionMask,
121 {
122  #define _BYTE_MASK(Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7) \
123  (Bit0) | ((Bit1) << 1) | ((Bit2) << 2) | ((Bit3) << 3) | \
124  ((Bit4) << 4) | ((Bit5) << 5) | ((Bit6) << 6) | ((Bit7) << 7)
125  static const UCHAR AccessAllowedMask[2][2] =
126  {
127  { // Protect 0 1 2 3 4 5 6 7
128  _BYTE_MASK(0, 1, 1, 1, 1, 1, 1, 1), // READ
129  _BYTE_MASK(0, 0, 1, 1, 0, 0, 1, 1), // EXECUTE READ
130  },
131  {
132  _BYTE_MASK(0, 0, 0, 0, 1, 1, 1, 1), // WRITE
133  _BYTE_MASK(0, 0, 0, 0, 0, 0, 1, 1), // EXECUTE WRITE
134  }
135  };
136 
137  /* We want only the lower access bits */
138  ProtectionMask &= MM_PROTECT_ACCESS;
139 
140  /* Look it up in the table */
141  return (AccessAllowedMask[Write != 0][Execute != 0] >> ProtectionMask) & 1;
142 }
143 
144 static
145 NTSTATUS
146 NTAPI
148  IN BOOLEAN StoreInstruction,
150  IN ULONG_PTR ProtectionMask,
151  IN PVOID TrapFrame,
152  IN BOOLEAN LockHeld)
153 {
154  MMPTE TempPte;
155 
156  /* Check for invalid user-mode access */
157  if ((PreviousMode == UserMode) && (PointerPte > MiHighestUserPte))
158  {
160  }
161 
162  /* Capture the PTE -- is it valid? */
163  TempPte = *PointerPte;
164  if (TempPte.u.Hard.Valid)
165  {
166  /* Was someone trying to write to it? */
167  if (StoreInstruction)
168  {
169  /* Is it writable?*/
170  if (MI_IS_PAGE_WRITEABLE(&TempPte) ||
171  MI_IS_PAGE_COPY_ON_WRITE(&TempPte))
172  {
173  /* Then there's nothing to worry about */
174  return STATUS_SUCCESS;
175  }
176 
177  /* Oops! This isn't allowed */
179  }
180 
181  /* Someone was trying to read from a valid PTE, that's fine too */
182  return STATUS_SUCCESS;
183  }
184 
185  /* Check if the protection on the page allows what is being attempted */
186  if (!MiIsAccessAllowed(ProtectionMask, StoreInstruction, FALSE))
187  {
189  }
190 
191  /* Check if this is a guard page */
192  if ((ProtectionMask & MM_PROTECT_SPECIAL) == MM_GUARDPAGE)
193  {
194  ASSERT(ProtectionMask != MM_DECOMMIT);
195 
196  /* Attached processes can't expand their stack */
198 
199  /* No support for prototype PTEs yet */
200  ASSERT(TempPte.u.Soft.Prototype == 0);
201 
202  /* Remove the guard page bit, and return a guard page violation */
203  TempPte.u.Soft.Protection = ProtectionMask & ~MM_GUARDPAGE;
204  ASSERT(TempPte.u.Long != 0);
205  MI_WRITE_INVALID_PTE(PointerPte, TempPte);
207  }
208 
209  /* Nothing to do */
210  return STATUS_SUCCESS;
211 }
212 
213 static
214 PMMPTE
215 NTAPI
217  OUT PULONG ProtectCode,
218  OUT PMMVAD *ProtoVad)
219 {
220  PMMVAD Vad;
221  PMMPTE PointerPte;
222 
223  /* No prototype/section support for now */
224  *ProtoVad = NULL;
225 
226  /* User or kernel fault? */
227  if (VirtualAddress <= MM_HIGHEST_USER_ADDRESS)
228  {
229  /* Special case for shared data */
230  if (PAGE_ALIGN(VirtualAddress) == (PVOID)MM_SHARED_USER_DATA_VA)
231  {
232  /* It's a read-only page */
233  *ProtectCode = MM_READONLY;
234  return MmSharedUserDataPte;
235  }
236 
237  /* Find the VAD, it might not exist if the address is bogus */
238  Vad = MiLocateAddress(VirtualAddress);
239  if (!Vad)
240  {
241  /* Bogus virtual address */
242  *ProtectCode = MM_NOACCESS;
243  return NULL;
244  }
245 
246  /* ReactOS does not handle physical memory VADs yet */
248 
249  /* Check if it's a section, or just an allocation */
250  if (Vad->u.VadFlags.PrivateMemory)
251  {
252  /* ReactOS does not handle AWE VADs yet */
253  ASSERT(Vad->u.VadFlags.VadType != VadAwe);
254 
255  /* This must be a TEB/PEB VAD */
256  if (Vad->u.VadFlags.MemCommit)
257  {
258  /* It's committed, so return the VAD protection */
259  *ProtectCode = (ULONG)Vad->u.VadFlags.Protection;
260  }
261  else
262  {
263  /* It has not yet been committed, so return no access */
264  *ProtectCode = MM_NOACCESS;
265  }
266 
267  /* In both cases, return no PTE */
268  return NULL;
269  }
270  else
271  {
272  /* ReactOS does not supoprt these VADs yet */
274  ASSERT(Vad->u2.VadFlags2.ExtendableFile == 0);
275 
276  /* Return the proto VAD */
277  *ProtoVad = Vad;
278 
279  /* Get the prototype PTE for this page */
280  PointerPte = (((ULONG_PTR)VirtualAddress >> PAGE_SHIFT) - Vad->StartingVpn) + Vad->FirstPrototypePte;
281  ASSERT(PointerPte != NULL);
282  ASSERT(PointerPte <= Vad->LastContiguousPte);
283 
284  /* Return the Prototype PTE and the protection for the page mapping */
285  *ProtectCode = (ULONG)Vad->u.VadFlags.Protection;
286  return PointerPte;
287  }
288  }
289  else if (MI_IS_PAGE_TABLE_ADDRESS(VirtualAddress))
290  {
291  /* This should never happen, as these addresses are handled by the double-maping */
292  if (((PMMPTE)VirtualAddress >= MiAddressToPte(MmPagedPoolStart)) &&
293  ((PMMPTE)VirtualAddress <= MmPagedPoolInfo.LastPteForPagedPool))
294  {
295  /* Fail such access */
296  *ProtectCode = MM_NOACCESS;
297  return NULL;
298  }
299 
300  /* Return full access rights */
301  *ProtectCode = MM_READWRITE;
302  return NULL;
303  }
304  else if (MI_IS_SESSION_ADDRESS(VirtualAddress))
305  {
306  /* ReactOS does not have an image list yet, so bail out to failure case */
308  }
309 
310  /* Default case -- failure */
311  *ProtectCode = MM_NOACCESS;
312  return NULL;
313 }
314 
315 #if (_MI_PAGING_LEVELS == 2)
316 static
317 NTSTATUS
318 FASTCALL
319 MiCheckPdeForSessionSpace(IN PVOID Address)
320 {
321  MMPTE TempPde;
322  PMMPDE PointerPde;
323  PVOID SessionAddress;
324  ULONG Index;
325 
326  /* Is this a session PTE? */
327  if (MI_IS_SESSION_PTE(Address))
328  {
329  /* Make sure the PDE for session space is valid */
330  PointerPde = MiAddressToPde(MmSessionSpace);
331  if (!PointerPde->u.Hard.Valid)
332  {
333  /* This means there's no valid session, bail out */
334  DbgPrint("MiCheckPdeForSessionSpace: No current session for PTE %p\n",
335  Address);
336  DbgBreakPoint();
338  }
339 
340  /* Now get the session-specific page table for this address */
341  SessionAddress = MiPteToAddress(Address);
342  PointerPde = MiAddressToPte(Address);
343  if (PointerPde->u.Hard.Valid) return STATUS_WAIT_1;
344 
345  /* It's not valid, so find it in the page table array */
346  Index = ((ULONG_PTR)SessionAddress - (ULONG_PTR)MmSessionBase) >> 22;
347  TempPde.u.Long = MmSessionSpace->PageTables[Index].u.Long;
348  if (TempPde.u.Hard.Valid)
349  {
350  /* The copy is valid, so swap it in */
351  InterlockedExchange((PLONG)PointerPde, TempPde.u.Long);
352  return STATUS_WAIT_1;
353  }
354 
355  /* We don't seem to have allocated a page table for this address yet? */
356  DbgPrint("MiCheckPdeForSessionSpace: No Session PDE for PTE %p, %p\n",
357  PointerPde->u.Long, SessionAddress);
358  DbgBreakPoint();
360  }
361 
362  /* Is the address also a session address? If not, we're done */
363  if (!MI_IS_SESSION_ADDRESS(Address)) return STATUS_SUCCESS;
364 
365  /* It is, so again get the PDE for session space */
366  PointerPde = MiAddressToPde(MmSessionSpace);
367  if (!PointerPde->u.Hard.Valid)
368  {
369  /* This means there's no valid session, bail out */
370  DbgPrint("MiCheckPdeForSessionSpace: No current session for VA %p\n",
371  Address);
372  DbgBreakPoint();
374  }
375 
376  /* Now get the PDE for the address itself */
377  PointerPde = MiAddressToPde(Address);
378  if (!PointerPde->u.Hard.Valid)
379  {
380  /* Do the swap, we should be good to go */
381  Index = ((ULONG_PTR)Address - (ULONG_PTR)MmSessionBase) >> 22;
382  PointerPde->u.Long = MmSessionSpace->PageTables[Index].u.Long;
383  if (PointerPde->u.Hard.Valid) return STATUS_WAIT_1;
384 
385  /* We had not allocated a page table for this session address yet, fail! */
386  DbgPrint("MiCheckPdeForSessionSpace: No Session PDE for VA %p, %p\n",
387  PointerPde->u.Long, Address);
388  DbgBreakPoint();
390  }
391 
392  /* It's valid, so there's nothing to do */
393  return STATUS_SUCCESS;
394 }
395 
396 NTSTATUS
397 FASTCALL
399 {
400  PMMPDE PointerPde;
402 
403  /* Check session PDE */
404  if (MI_IS_SESSION_ADDRESS(Address)) return MiCheckPdeForSessionSpace(Address);
405  if (MI_IS_SESSION_PTE(Address)) return MiCheckPdeForSessionSpace(Address);
406 
407  //
408  // Check if this is a fault while trying to access the page table itself
409  //
410  if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address))
411  {
412  //
413  // Send a hint to the page fault handler that this is only a valid fault
414  // if we already detected this was access within the page table range
415  //
416  PointerPde = (PMMPDE)MiAddressToPte(Address);
417  Status = STATUS_WAIT_1;
418  }
419  else if (Address < MmSystemRangeStart)
420  {
421  //
422  // This is totally illegal
423  //
425  }
426  else
427  {
428  //
429  // Get the PDE for the address
430  //
431  PointerPde = MiAddressToPde(Address);
432  }
433 
434  //
435  // Check if it's not valid
436  //
437  if (PointerPde->u.Hard.Valid == 0)
438  {
439  //
440  // Copy it from our double-mapped system page directory
441  //
442  InterlockedExchangePte(PointerPde,
443  MmSystemPagePtes[((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE)].u.Long);
444  }
445 
446  //
447  // Return status
448  //
449  return Status;
450 }
451 #else
452 NTSTATUS
453 FASTCALL
455 {
457 }
458 #endif
459 
460 VOID
461 NTAPI
462 MiZeroPfn(IN PFN_NUMBER PageFrameNumber)
463 {
464  PMMPTE ZeroPte;
465  MMPTE TempPte;
466  PMMPFN Pfn1;
467  PVOID ZeroAddress;
468 
469  /* Get the PFN for this page */
470  Pfn1 = MiGetPfnEntry(PageFrameNumber);
471  ASSERT(Pfn1);
472 
473  /* Grab a system PTE we can use to zero the page */
474  ZeroPte = MiReserveSystemPtes(1, SystemPteSpace);
475  ASSERT(ZeroPte);
476 
477  /* Initialize the PTE for it */
478  TempPte = ValidKernelPte;
479  TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
480 
481  /* Setup caching */
482  if (Pfn1->u3.e1.CacheAttribute == MiWriteCombined)
483  {
484  /* Write combining, no caching */
485  MI_PAGE_DISABLE_CACHE(&TempPte);
486  MI_PAGE_WRITE_COMBINED(&TempPte);
487  }
488  else if (Pfn1->u3.e1.CacheAttribute == MiNonCached)
489  {
490  /* Write through, no caching */
491  MI_PAGE_DISABLE_CACHE(&TempPte);
492  MI_PAGE_WRITE_THROUGH(&TempPte);
493  }
494 
495  /* Make the system PTE valid with our PFN */
496  MI_WRITE_VALID_PTE(ZeroPte, TempPte);
497 
498  /* Get the address it maps to, and zero it out */
499  ZeroAddress = MiPteToAddress(ZeroPte);
500  KeZeroPages(ZeroAddress, PAGE_SIZE);
501 
502  /* Now get rid of it */
503  MiReleaseSystemPtes(ZeroPte, 1, SystemPteSpace);
504 }
505 
506 VOID
507 NTAPI
509  _In_ PFN_NUMBER DestPage,
510  _In_ PFN_NUMBER SrcPage)
511 {
512  PMMPTE SysPtes;
513  MMPTE TempPte;
514  PMMPFN DestPfn, SrcPfn;
515  PVOID DestAddress;
516  const VOID* SrcAddress;
517 
518  /* Get the PFNs */
519  DestPfn = MiGetPfnEntry(DestPage);
520  ASSERT(DestPfn);
521  SrcPfn = MiGetPfnEntry(SrcPage);
522  ASSERT(SrcPfn);
523 
524  /* Grab 2 system PTEs */
525  SysPtes = MiReserveSystemPtes(2, SystemPteSpace);
526  ASSERT(SysPtes);
527 
528  /* Initialize the destination PTE */
529  TempPte = ValidKernelPte;
530  TempPte.u.Hard.PageFrameNumber = DestPage;
531 
532  /* Setup caching */
533  if (DestPfn->u3.e1.CacheAttribute == MiWriteCombined)
534  {
535  /* Write combining, no caching */
536  MI_PAGE_DISABLE_CACHE(&TempPte);
537  MI_PAGE_WRITE_COMBINED(&TempPte);
538  }
539  else if (DestPfn->u3.e1.CacheAttribute == MiNonCached)
540  {
541  /* Write through, no caching */
542  MI_PAGE_DISABLE_CACHE(&TempPte);
543  MI_PAGE_WRITE_THROUGH(&TempPte);
544  }
545 
546  /* Make the system PTE valid with our PFN */
547  MI_WRITE_VALID_PTE(&SysPtes[0], TempPte);
548 
549  /* Initialize the source PTE */
550  TempPte = ValidKernelPte;
551  TempPte.u.Hard.PageFrameNumber = SrcPage;
552 
553  /* Setup caching */
554  if (SrcPfn->u3.e1.CacheAttribute == MiNonCached)
555  {
556  MI_PAGE_DISABLE_CACHE(&TempPte);
557  }
558 
559  /* Make the system PTE valid with our PFN */
560  MI_WRITE_VALID_PTE(&SysPtes[1], TempPte);
561 
562  /* Get the addresses and perform the copy */
563  DestAddress = MiPteToAddress(&SysPtes[0]);
564  SrcAddress = MiPteToAddress(&SysPtes[1]);
565  RtlCopyMemory(DestAddress, SrcAddress, PAGE_SIZE);
566 
567  /* Now get rid of it */
568  MiReleaseSystemPtes(SysPtes, 2, SystemPteSpace);
569 }
570 
571 static
572 NTSTATUS
573 NTAPI
575  IN PMMPTE PointerPte,
576  IN ULONG Protection,
578  IN KIRQL OldIrql)
579 {
580  PFN_NUMBER PageFrameNumber = 0;
581  MMPTE TempPte;
582  BOOLEAN NeedZero = FALSE, HaveLock = FALSE;
583  ULONG Color;
584  PMMPFN Pfn1;
585  DPRINT("ARM3 Demand Zero Page Fault Handler for address: %p in process: %p\n",
586  Address,
587  Process);
588 
589  /* Must currently only be called by paging path */
590  if ((Process > HYDRA_PROCESS) && (OldIrql == MM_NOIRQL))
591  {
592  /* Sanity check */
593  ASSERT(MI_IS_PAGE_TABLE_ADDRESS(PointerPte));
594 
595  /* No forking yet */
596  ASSERT(Process->ForkInProgress == NULL);
597 
598  /* Get process color */
599  Color = MI_GET_NEXT_PROCESS_COLOR(Process);
600  ASSERT(Color != 0xFFFFFFFF);
601 
602  /* We'll need a zero page */
603  NeedZero = TRUE;
604  }
605  else
606  {
607  /* Check if we need a zero page */
608  NeedZero = (OldIrql != MM_NOIRQL);
609 
610  /* Session-backed image views must be zeroed */
611  if ((Process == HYDRA_PROCESS) &&
612  ((MI_IS_SESSION_IMAGE_ADDRESS(Address)) ||
613  ((Address >= MiSessionViewStart) && (Address < MiSessionSpaceWs))))
614  {
615  NeedZero = TRUE;
616  }
617 
618  /* Hardcode unknown color */
619  Color = 0xFFFFFFFF;
620  }
621 
622  /* Check if the PFN database should be acquired */
623  if (OldIrql == MM_NOIRQL)
624  {
625  /* Acquire it and remember we should release it after */
626  OldIrql = MiAcquirePfnLock();
627  HaveLock = TRUE;
628  }
629 
630  /* We either manually locked the PFN DB, or already came with it locked */
632  ASSERT(PointerPte->u.Hard.Valid == 0);
633 
634  /* Assert we have enough pages */
635  ASSERT(MmAvailablePages >= 32);
636 
637 #if MI_TRACE_PFNS
638  if (UserPdeFault) MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
639  if (!UserPdeFault) MI_SET_USAGE(MI_USAGE_DEMAND_ZERO);
640 #endif
641  if (Process == HYDRA_PROCESS) MI_SET_PROCESS2("Hydra");
642  else if (Process) MI_SET_PROCESS2(Process->ImageFileName);
643  else MI_SET_PROCESS2("Kernel Demand 0");
644 
645  /* Do we need a zero page? */
646  if (Color != 0xFFFFFFFF)
647  {
648  /* Try to get one, if we couldn't grab a free page and zero it */
649  PageFrameNumber = MiRemoveZeroPageSafe(Color);
650  if (!PageFrameNumber)
651  {
652  /* We'll need a free page and zero it manually */
653  PageFrameNumber = MiRemoveAnyPage(Color);
654  NeedZero = TRUE;
655  }
656  }
657  else
658  {
659  /* Get a color, and see if we should grab a zero or non-zero page */
660  Color = MI_GET_NEXT_COLOR();
661  if (!NeedZero)
662  {
663  /* Process or system doesn't want a zero page, grab anything */
664  PageFrameNumber = MiRemoveAnyPage(Color);
665  }
666  else
667  {
668  /* System wants a zero page, obtain one */
669  PageFrameNumber = MiRemoveZeroPage(Color);
670  }
671  }
672 
673  /* Initialize it */
674  MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
675 
676  /* Increment demand zero faults */
677  KeGetCurrentPrcb()->MmDemandZeroCount++;
678 
679  /* Do we have the lock? */
680  if (HaveLock)
681  {
682  /* Release it */
683  MiReleasePfnLock(OldIrql);
684 
685  /* Update performance counters */
686  if (Process > HYDRA_PROCESS) Process->NumberOfPrivatePages++;
687  }
688 
689  /* Zero the page if need be */
690  if (NeedZero) MiZeroPfn(PageFrameNumber);
691 
692  /* Fault on user PDE, or fault on user PTE? */
693  if (PointerPte <= MiHighestUserPte)
694  {
695  /* User fault, build a user PTE */
696  MI_MAKE_HARDWARE_PTE_USER(&TempPte,
697  PointerPte,
698  Protection,
699  PageFrameNumber);
700  }
701  else
702  {
703  /* This is a user-mode PDE, create a kernel PTE for it */
704  MI_MAKE_HARDWARE_PTE(&TempPte,
705  PointerPte,
706  Protection,
707  PageFrameNumber);
708  }
709 
710  /* Set it dirty if it's a writable page */
711  if (MI_IS_PAGE_WRITEABLE(&TempPte)) MI_MAKE_DIRTY_PAGE(&TempPte);
712 
713  /* Write it */
714  MI_WRITE_VALID_PTE(PointerPte, TempPte);
715 
716  /* Did we manually acquire the lock */
717  if (HaveLock)
718  {
719  /* Get the PFN entry */
720  Pfn1 = MI_PFN_ELEMENT(PageFrameNumber);
721 
722  /* Windows does these sanity checks */
723  ASSERT(Pfn1->u1.Event == 0);
724  ASSERT(Pfn1->u3.e1.PrototypePte == 0);
725  }
726 
727  //
728  // It's all good now
729  //
730  DPRINT("Demand zero page has now been paged in\n");
732 }
733 
734 static
735 NTSTATUS
736 NTAPI
738  IN PVOID Address,
739  IN PMMPTE PointerPte,
740  IN PMMPTE PointerProtoPte,
741  IN KIRQL OldIrql,
742  IN PMMPFN* LockedProtoPfn)
743 {
744  MMPTE TempPte;
745  PMMPTE OriginalPte, PageTablePte;
746  ULONG_PTR Protection;
747  PFN_NUMBER PageFrameIndex;
748  PMMPFN Pfn1, Pfn2;
749  BOOLEAN OriginalProtection, DirtyPage;
750 
751  /* Must be called with an valid prototype PTE, with the PFN lock held */
753  ASSERT(PointerProtoPte->u.Hard.Valid == 1);
754 
755  /* Get the page */
756  PageFrameIndex = PFN_FROM_PTE(PointerProtoPte);
757 
758  /* Get the PFN entry and set it as a prototype PTE */
759  Pfn1 = MiGetPfnEntry(PageFrameIndex);
760  Pfn1->u3.e1.PrototypePte = 1;
761 
762  /* Increment the share count for the page table */
763  PageTablePte = MiAddressToPte(PointerPte);
764  Pfn2 = MiGetPfnEntry(PageTablePte->u.Hard.PageFrameNumber);
765  Pfn2->u2.ShareCount++;
766 
767  /* Check where we should be getting the protection information from */
768  if (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
769  {
770  /* Get the protection from the PTE, there's no real Proto PTE data */
771  Protection = PointerPte->u.Soft.Protection;
772 
773  /* Remember that we did not use the proto protection */
774  OriginalProtection = FALSE;
775  }
776  else
777  {
778  /* Get the protection from the original PTE link */
779  OriginalPte = &Pfn1->OriginalPte;
780  Protection = OriginalPte->u.Soft.Protection;
781 
782  /* Remember that we used the original protection */
783  OriginalProtection = TRUE;
784 
785  /* Check if this was a write on a read only proto */
786  if ((StoreInstruction) && !(Protection & MM_READWRITE))
787  {
788  /* Clear the flag */
789  StoreInstruction = 0;
790  }
791  }
792 
793  /* Check if this was a write on a non-COW page */
794  DirtyPage = FALSE;
795  if ((StoreInstruction) && ((Protection & MM_WRITECOPY) != MM_WRITECOPY))
796  {
797  /* Then the page should be marked dirty */
798  DirtyPage = TRUE;
799 
800  /* ReactOS check */
801  ASSERT(Pfn1->OriginalPte.u.Soft.Prototype != 0);
802  }
803 
804  /* Did we get a locked incoming PFN? */
805  if (*LockedProtoPfn)
806  {
807  /* Drop a reference */
808  ASSERT((*LockedProtoPfn)->u3.e2.ReferenceCount >= 1);
809  MiDereferencePfnAndDropLockCount(*LockedProtoPfn);
810  *LockedProtoPfn = NULL;
811  }
812 
813  /* Release the PFN lock */
814  MiReleasePfnLock(OldIrql);
815 
816  /* Remove special/caching bits */
817  Protection &= ~MM_PROTECT_SPECIAL;
818 
819  /* Setup caching */
820  if (Pfn1->u3.e1.CacheAttribute == MiWriteCombined)
821  {
822  /* Write combining, no caching */
823  MI_PAGE_DISABLE_CACHE(&TempPte);
824  MI_PAGE_WRITE_COMBINED(&TempPte);
825  }
826  else if (Pfn1->u3.e1.CacheAttribute == MiNonCached)
827  {
828  /* Write through, no caching */
829  MI_PAGE_DISABLE_CACHE(&TempPte);
830  MI_PAGE_WRITE_THROUGH(&TempPte);
831  }
832 
833  /* Check if this is a kernel or user address */
834  if (Address < MmSystemRangeStart)
835  {
836  /* Build the user PTE */
837  MI_MAKE_HARDWARE_PTE_USER(&TempPte, PointerPte, Protection, PageFrameIndex);
838  }
839  else
840  {
841  /* Build the kernel PTE */
842  MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, Protection, PageFrameIndex);
843  }
844 
845  /* Set the dirty flag if needed */
846  if (DirtyPage) MI_MAKE_DIRTY_PAGE(&TempPte);
847 
848  /* Write the PTE */
849  MI_WRITE_VALID_PTE(PointerPte, TempPte);
850 
851  /* Reset the protection if needed */
852  if (OriginalProtection) Protection = MM_ZERO_ACCESS;
853 
854  /* Return success */
855  ASSERT(PointerPte == MiAddressToPte(Address));
856  return STATUS_SUCCESS;
857 }
858 
859 static
860 NTSTATUS
861 NTAPI
863  _In_ PVOID FaultingAddress,
864  _In_ PMMPTE PointerPte,
867 {
868  ULONG Color;
869  PFN_NUMBER Page;
871  MMPTE TempPte = *PointerPte;
872  PMMPFN Pfn1;
873  ULONG PageFileIndex = TempPte.u.Soft.PageFileLow;
874  ULONG_PTR PageFileOffset = TempPte.u.Soft.PageFileHigh;
875  ULONG Protection = TempPte.u.Soft.Protection;
876 
877  /* Things we don't support yet */
878  ASSERT(CurrentProcess > HYDRA_PROCESS);
879  ASSERT(*OldIrql != MM_NOIRQL);
880 
881  /* We must hold the PFN lock */
883 
884  /* Some sanity checks */
885  ASSERT(TempPte.u.Hard.Valid == 0);
886  ASSERT(TempPte.u.Soft.PageFileHigh != 0);
888 
889  /* Get any page, it will be overwritten */
890  Color = MI_GET_NEXT_PROCESS_COLOR(CurrentProcess);
891  Page = MiRemoveAnyPage(Color);
892 
893  /* Initialize this PFN */
894  MiInitializePfn(Page, PointerPte, StoreInstruction);
895 
896  /* Sets the PFN as being in IO operation */
897  Pfn1 = MI_PFN_ELEMENT(Page);
898  ASSERT(Pfn1->u1.Event == NULL);
899  ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
900  ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
901  Pfn1->u3.e1.ReadInProgress = 1;
902 
903  /* We must write the PTE now as the PFN lock will be released while performing the IO operation */
904  MI_MAKE_TRANSITION_PTE(&TempPte, Page, Protection);
905 
906  MI_WRITE_INVALID_PTE(PointerPte, TempPte);
907 
908  /* Release the PFN lock while we proceed */
909  MiReleasePfnLock(*OldIrql);
910 
911  /* Do the paging IO */
912  Status = MiReadPageFile(Page, PageFileIndex, PageFileOffset);
913 
914  /* Lock the PFN database again */
915  *OldIrql = MiAcquirePfnLock();
916 
917  /* Nobody should have changed that while we were not looking */
918  ASSERT(Pfn1->u3.e1.ReadInProgress == 1);
919  ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
920 
921  if (!NT_SUCCESS(Status))
922  {
923  /* Malheur! */
924  ASSERT(FALSE);
925  Pfn1->u4.InPageError = 1;
926  Pfn1->u1.ReadStatus = Status;
927  }
928 
929  /* And the PTE can finally be valid */
930  MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, Protection, Page);
931  MI_WRITE_VALID_PTE(PointerPte, TempPte);
932 
933  Pfn1->u3.e1.ReadInProgress = 0;
934  /* Did someone start to wait on us while we proceeded ? */
935  if (Pfn1->u1.Event)
936  {
937  /* Tell them we're done */
939  }
940 
941  return Status;
942 }
943 
944 static
945 NTSTATUS
946 NTAPI
948  IN PVOID FaultingAddress,
949  IN PMMPTE PointerPte,
951  IN KIRQL OldIrql,
952  OUT PKEVENT **InPageBlock)
953 {
954  PFN_NUMBER PageFrameIndex;
955  PMMPFN Pfn1;
956  MMPTE TempPte;
957  PMMPTE PointerToPteForProtoPage;
958  DPRINT("Transition fault on 0x%p with PTE 0x%p in process %s\n",
959  FaultingAddress, PointerPte, CurrentProcess->ImageFileName);
960 
961  /* Windowss does this check */
962  ASSERT(*InPageBlock == NULL);
963 
964  /* ARM3 doesn't support this path */
965  ASSERT(OldIrql != MM_NOIRQL);
966 
967  /* Capture the PTE and make sure it's in transition format */
968  TempPte = *PointerPte;
969  ASSERT((TempPte.u.Soft.Valid == 0) &&
970  (TempPte.u.Soft.Prototype == 0) &&
971  (TempPte.u.Soft.Transition == 1));
972 
973  /* Get the PFN and the PFN entry */
974  PageFrameIndex = TempPte.u.Trans.PageFrameNumber;
975  DPRINT("Transition PFN: %lx\n", PageFrameIndex);
976  Pfn1 = MiGetPfnEntry(PageFrameIndex);
977 
978  /* One more transition fault! */
979  InterlockedIncrement(&KeGetCurrentPrcb()->MmTransitionCount);
980 
981  /* This is from ARM3 -- Windows normally handles this here */
982  ASSERT(Pfn1->u4.InPageError == 0);
983 
984  /* See if we should wait before terminating the fault */
985  if ((Pfn1->u3.e1.ReadInProgress == 1)
986  || ((Pfn1->u3.e1.WriteInProgress == 1) && StoreInstruction))
987  {
988  DPRINT1("The page is currently in a page transition !\n");
989  *InPageBlock = &Pfn1->u1.Event;
990  if (PointerPte == Pfn1->PteAddress)
991  {
992  DPRINT1("And this if for this particular PTE.\n");
993  /* The PTE will be made valid by the thread serving the fault */
994  return STATUS_SUCCESS; // FIXME: Maybe something more descriptive
995  }
996  }
997 
998  /* Windows checks there's some free pages and this isn't an in-page error */
1000  ASSERT(Pfn1->u4.InPageError == 0);
1001 
1002  /* ReactOS checks for this */
1003  ASSERT(MmAvailablePages > 32);
1004 
1005  /* Was this a transition page in the valid list, or free/zero list? */
1006  if (Pfn1->u3.e1.PageLocation == ActiveAndValid)
1007  {
1008  /* All Windows does here is a bunch of sanity checks */
1009  DPRINT("Transition in active list\n");
1012  ASSERT(Pfn1->u2.ShareCount != 0);
1013  ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
1014  }
1015  else
1016  {
1017  /* Otherwise, the page is removed from its list */
1018  DPRINT("Transition page in free/zero list\n");
1019  MiUnlinkPageFromList(Pfn1);
1021  }
1022 
1023  /* At this point, there should no longer be any in-page errors */
1024  ASSERT(Pfn1->u4.InPageError == 0);
1025 
1026  /* Check if this was a PFN with no more share references */
1027  if (Pfn1->u2.ShareCount == 0) MiDropLockCount(Pfn1);
1028 
1029  /* Bump the share count and make the page valid */
1030  Pfn1->u2.ShareCount++;
1031  Pfn1->u3.e1.PageLocation = ActiveAndValid;
1032 
1033  /* Prototype PTEs are in paged pool, which itself might be in transition */
1034  if (FaultingAddress >= MmSystemRangeStart)
1035  {
1036  /* Check if this is a paged pool PTE in transition state */
1037  PointerToPteForProtoPage = MiAddressToPte(PointerPte);
1038  TempPte = *PointerToPteForProtoPage;
1039  if ((TempPte.u.Hard.Valid == 0) && (TempPte.u.Soft.Transition == 1))
1040  {
1041  /* This isn't yet supported */
1042  DPRINT1("Double transition fault not yet supported\n");
1043  ASSERT(FALSE);
1044  }
1045  }
1046 
1047  /* Build the final PTE */
1048  ASSERT(PointerPte->u.Hard.Valid == 0);
1049  ASSERT(PointerPte->u.Trans.Prototype == 0);
1050  ASSERT(PointerPte->u.Trans.Transition == 1);
1051  TempPte.u.Long = (PointerPte->u.Long & ~0xFFF) |
1052  (MmProtectToPteMask[PointerPte->u.Trans.Protection]) |
1053  MiDetermineUserGlobalPteMask(PointerPte);
1054 
1055  /* Is the PTE writeable? */
1056  if ((Pfn1->u3.e1.Modified) &&
1057  MI_IS_PAGE_WRITEABLE(&TempPte) &&
1058  !MI_IS_PAGE_COPY_ON_WRITE(&TempPte))
1059  {
1060  /* Make it dirty */
1061  MI_MAKE_DIRTY_PAGE(&TempPte);
1062  }
1063  else
1064  {
1065  /* Make it clean */
1066  MI_MAKE_CLEAN_PAGE(&TempPte);
1067  }
1068 
1069  /* Write the valid PTE */
1070  MI_WRITE_VALID_PTE(PointerPte, TempPte);
1071 
1072  /* Return success */
1074 }
1075 
1076 static
1077 NTSTATUS
1078 NTAPI
1080  IN PVOID Address,
1081  IN PMMPTE PointerPte,
1082  IN PMMPTE PointerProtoPte,
1083  IN OUT PMMPFN *OutPfn,
1084  OUT PVOID *PageFileData,
1085  OUT PMMPTE PteValue,
1087  IN KIRQL OldIrql,
1088  IN PVOID TrapInformation)
1089 {
1090  MMPTE TempPte, PteContents;
1091  PMMPFN Pfn1;
1092  PFN_NUMBER PageFrameIndex;
1093  NTSTATUS Status;
1094  PKEVENT* InPageBlock = NULL;
1095  ULONG Protection;
1096 
1097  /* Must be called with an invalid, prototype PTE, with the PFN lock held */
1099  ASSERT(PointerPte->u.Hard.Valid == 0);
1100  ASSERT(PointerPte->u.Soft.Prototype == 1);
1101 
1102  /* Read the prototype PTE and check if it's valid */
1103  TempPte = *PointerProtoPte;
1104  if (TempPte.u.Hard.Valid == 1)
1105  {
1106  /* One more user of this mapped page */
1107  PageFrameIndex = PFN_FROM_PTE(&TempPte);
1108  Pfn1 = MiGetPfnEntry(PageFrameIndex);
1109  Pfn1->u2.ShareCount++;
1110 
1111  /* Call it a transition */
1112  InterlockedIncrement(&KeGetCurrentPrcb()->MmTransitionCount);
1113 
1114  /* Complete the prototype PTE fault -- this will release the PFN lock */
1115  return MiCompleteProtoPteFault(StoreInstruction,
1116  Address,
1117  PointerPte,
1118  PointerProtoPte,
1119  OldIrql,
1120  OutPfn);
1121  }
1122 
1123  /* Make sure there's some protection mask */
1124  if (TempPte.u.Long == 0)
1125  {
1126  /* Release the lock */
1127  DPRINT1("Access on reserved section?\n");
1128  MiReleasePfnLock(OldIrql);
1129  return STATUS_ACCESS_VIOLATION;
1130  }
1131 
1132  /* There is no such thing as a decommitted prototype PTE */
1133  ASSERT(TempPte.u.Long != MmDecommittedPte.u.Long);
1134 
1135  /* Check for access rights on the PTE proper */
1136  PteContents = *PointerPte;
1137  if (PteContents.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED)
1138  {
1139  if (!PteContents.u.Proto.ReadOnly)
1140  {
1141  Protection = TempPte.u.Soft.Protection;
1142  }
1143  else
1144  {
1145  Protection = MM_READONLY;
1146  }
1147  /* Check for page acess in software */
1148  Status = MiAccessCheck(PointerProtoPte,
1149  StoreInstruction,
1150  KernelMode,
1151  TempPte.u.Soft.Protection,
1152  TrapInformation,
1153  TRUE);
1154  ASSERT(Status == STATUS_SUCCESS);
1155  }
1156  else
1157  {
1158  Protection = PteContents.u.Soft.Protection;
1159  }
1160 
1161  /* Check for writing copy on write page */
1162  if (((Protection & MM_WRITECOPY) == MM_WRITECOPY) && StoreInstruction)
1163  {
1164  PFN_NUMBER PageFrameIndex, ProtoPageFrameIndex;
1165  ULONG Color;
1166 
1167  /* Resolve the proto fault as if it was a read operation */
1168  Status = MiResolveProtoPteFault(FALSE,
1169  Address,
1170  PointerPte,
1171  PointerProtoPte,
1172  OutPfn,
1173  PageFileData,
1174  PteValue,
1175  Process,
1176  OldIrql,
1177  TrapInformation);
1178 
1179  if (!NT_SUCCESS(Status))
1180  {
1181  return Status;
1182  }
1183 
1184  /* Lock again the PFN lock, MiResolveProtoPteFault unlocked it */
1185  OldIrql = MiAcquirePfnLock();
1186 
1187  /* And re-read the proto PTE */
1188  TempPte = *PointerProtoPte;
1189  ASSERT(TempPte.u.Hard.Valid == 1);
1190  ProtoPageFrameIndex = PFN_FROM_PTE(&TempPte);
1191 
1192  /* Get a new page for the private copy */
1193  if (Process > HYDRA_PROCESS)
1194  Color = MI_GET_NEXT_PROCESS_COLOR(Process);
1195  else
1196  Color = MI_GET_NEXT_COLOR();
1197 
1198  PageFrameIndex = MiRemoveAnyPage(Color);
1199 
1200  /* Perform the copy */
1201  MiCopyPfn(PageFrameIndex, ProtoPageFrameIndex);
1202 
1203  /* This will drop everything MiResolveProtoPteFault referenced */
1204  MiDeletePte(PointerPte, Address, Process, PointerProtoPte);
1205 
1206  /* Because now we use this */
1207  Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1208  MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
1209 
1210  /* Fix the protection */
1211  Protection &= ~MM_WRITECOPY;
1212  Protection |= MM_READWRITE;
1213  if (Address < MmSystemRangeStart)
1214  {
1215  /* Build the user PTE */
1216  MI_MAKE_HARDWARE_PTE_USER(&PteContents, PointerPte, Protection, PageFrameIndex);
1217  }
1218  else
1219  {
1220  /* Build the kernel PTE */
1221  MI_MAKE_HARDWARE_PTE(&PteContents, PointerPte, Protection, PageFrameIndex);
1222  }
1223 
1224  /* And finally, write the valid PTE */
1225  MI_WRITE_VALID_PTE(PointerPte, PteContents);
1226 
1227  /* The caller expects us to release the PFN lock */
1228  MiReleasePfnLock(OldIrql);
1229  return Status;
1230  }
1231 
1232  /* Check for clone PTEs */
1233  if (PointerPte <= MiHighestUserPte) ASSERT(Process->CloneRoot == NULL);
1234 
1235  /* We don't support mapped files yet */
1236  ASSERT(TempPte.u.Soft.Prototype == 0);
1237 
1238  /* We might however have transition PTEs */
1239  if (TempPte.u.Soft.Transition == 1)
1240  {
1241  /* Resolve the transition fault */
1242  ASSERT(OldIrql != MM_NOIRQL);
1243  Status = MiResolveTransitionFault(StoreInstruction,
1244  Address,
1245  PointerProtoPte,
1246  Process,
1247  OldIrql,
1248  &InPageBlock);
1249  ASSERT(NT_SUCCESS(Status));
1250  }
1251  else
1252  {
1253  /* We also don't support paged out pages */
1254  ASSERT(TempPte.u.Soft.PageFileHigh == 0);
1255 
1256  /* Resolve the demand zero fault */
1257  Status = MiResolveDemandZeroFault(Address,
1258  PointerProtoPte,
1259  (ULONG)TempPte.u.Soft.Protection,
1260  Process,
1261  OldIrql);
1262  ASSERT(NT_SUCCESS(Status));
1263  }
1264 
1265  /* Complete the prototype PTE fault -- this will release the PFN lock */
1266  ASSERT(PointerPte->u.Hard.Valid == 0);
1267  return MiCompleteProtoPteFault(StoreInstruction,
1268  Address,
1269  PointerPte,
1270  PointerProtoPte,
1271  OldIrql,
1272  OutPfn);
1273 }
1274 
1275 NTSTATUS
1276 NTAPI
1278  IN PVOID Address,
1279  IN PMMPTE PointerPte,
1280  IN PMMPTE PointerProtoPte,
1281  IN BOOLEAN Recursive,
1283  IN PVOID TrapInformation,
1284  IN PMMVAD Vad)
1285 {
1286  MMPTE TempPte;
1287  KIRQL OldIrql, LockIrql;
1288  NTSTATUS Status;
1289  PMMPTE SuperProtoPte;
1290  PMMPFN Pfn1, OutPfn = NULL;
1291  PFN_NUMBER PageFrameIndex;
1292  PFN_COUNT PteCount, ProcessedPtes;
1293  DPRINT("ARM3 Page Fault Dispatcher for address: %p in process: %p\n",
1294  Address,
1295  Process);
1296 
1297  /* Make sure the addresses are ok */
1298  ASSERT(PointerPte == MiAddressToPte(Address));
1299 
1300  //
1301  // Make sure APCs are off and we're not at dispatch
1302  //
1303  OldIrql = KeGetCurrentIrql();
1304  ASSERT(OldIrql <= APC_LEVEL);
1306 
1307  //
1308  // Grab a copy of the PTE
1309  //
1310  TempPte = *PointerPte;
1311 
1312  /* Do we have a prototype PTE? */
1313  if (PointerProtoPte)
1314  {
1315  /* This should never happen */
1316  ASSERT(!MI_IS_PHYSICAL_ADDRESS(PointerProtoPte));
1317 
1318  /* Check if this is a kernel-mode address */
1319  SuperProtoPte = MiAddressToPte(PointerProtoPte);
1320  if (Address >= MmSystemRangeStart)
1321  {
1322  /* Lock the PFN database */
1323  LockIrql = MiAcquirePfnLock();
1324 
1325  /* Has the PTE been made valid yet? */
1326  if (!SuperProtoPte->u.Hard.Valid)
1327  {
1328  ASSERT(FALSE);
1329  }
1330  else if (PointerPte->u.Hard.Valid == 1)
1331  {
1332  ASSERT(FALSE);
1333  }
1334 
1335  /* Resolve the fault -- this will release the PFN lock */
1336  Status = MiResolveProtoPteFault(!MI_IS_NOT_PRESENT_FAULT(FaultCode),
1337  Address,
1338  PointerPte,
1339  PointerProtoPte,
1340  &OutPfn,
1341  NULL,
1342  NULL,
1343  Process,
1344  LockIrql,
1345  TrapInformation);
1346  ASSERT(Status == STATUS_SUCCESS);
1347 
1348  /* Complete this as a transition fault */
1349  ASSERT(OldIrql == KeGetCurrentIrql());
1350  ASSERT(OldIrql <= APC_LEVEL);
1352  return Status;
1353  }
1354  else
1355  {
1356  /* We only handle the lookup path */
1357  ASSERT(PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED);
1358 
1359  /* Is there a non-image VAD? */
1360  if ((Vad) &&
1361  (Vad->u.VadFlags.VadType != VadImageMap) &&
1362  !(Vad->u2.VadFlags2.ExtendableFile))
1363  {
1364  /* One day, ReactOS will cluster faults */
1365  ASSERT(Address <= MM_HIGHEST_USER_ADDRESS);
1366  DPRINT("Should cluster fault, but won't\n");
1367  }
1368 
1369  /* Only one PTE to handle for now */
1370  PteCount = 1;
1371  ProcessedPtes = 0;
1372 
1373  /* Lock the PFN database */
1374  LockIrql = MiAcquirePfnLock();
1375 
1376  /* We only handle the valid path */
1377  ASSERT(SuperProtoPte->u.Hard.Valid == 1);
1378 
1379  /* Capture the PTE */
1380  TempPte = *PointerProtoPte;
1381 
1382  /* Loop to handle future case of clustered faults */
1383  while (TRUE)
1384  {
1385  /* For our current usage, this should be true */
1386  if (TempPte.u.Hard.Valid == 1)
1387  {
1388  /* Bump the share count on the PTE */
1389  PageFrameIndex = PFN_FROM_PTE(&TempPte);
1390  Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1391  Pfn1->u2.ShareCount++;
1392  }
1393  else if ((TempPte.u.Soft.Prototype == 0) &&
1394  (TempPte.u.Soft.Transition == 1))
1395  {
1396  /* This is a standby page, bring it back from the cache */
1397  PageFrameIndex = TempPte.u.Trans.PageFrameNumber;
1398  DPRINT("oooh, shiny, a soft fault! 0x%lx\n", PageFrameIndex);
1399  Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1401 
1402  /* Should not yet happen in ReactOS */
1403  ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
1404  ASSERT(Pfn1->u4.InPageError == 0);
1405 
1406  /* Get the page */
1407  MiUnlinkPageFromList(Pfn1);
1408 
1409  /* Bump its reference count */
1410  ASSERT(Pfn1->u2.ShareCount == 0);
1411  InterlockedIncrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1412  Pfn1->u2.ShareCount++;
1413 
1414  /* Make it valid again */
1415  /* This looks like another macro.... */
1416  Pfn1->u3.e1.PageLocation = ActiveAndValid;
1417  ASSERT(PointerProtoPte->u.Hard.Valid == 0);
1418  ASSERT(PointerProtoPte->u.Trans.Prototype == 0);
1419  ASSERT(PointerProtoPte->u.Trans.Transition == 1);
1420  TempPte.u.Long = (PointerProtoPte->u.Long & ~0xFFF) |
1421  MmProtectToPteMask[PointerProtoPte->u.Trans.Protection];
1422  TempPte.u.Hard.Valid = 1;
1423  MI_MAKE_ACCESSED_PAGE(&TempPte);
1424 
1425  /* Is the PTE writeable? */
1426  if ((Pfn1->u3.e1.Modified) &&
1427  MI_IS_PAGE_WRITEABLE(&TempPte) &&
1428  !MI_IS_PAGE_COPY_ON_WRITE(&TempPte))
1429  {
1430  /* Make it dirty */
1431  MI_MAKE_DIRTY_PAGE(&TempPte);
1432  }
1433  else
1434  {
1435  /* Make it clean */
1436  MI_MAKE_CLEAN_PAGE(&TempPte);
1437  }
1438 
1439  /* Write the valid PTE */
1440  MI_WRITE_VALID_PTE(PointerProtoPte, TempPte);
1441  ASSERT(PointerPte->u.Hard.Valid == 0);
1442  }
1443  else
1444  {
1445  /* Page is invalid, get out of the loop */
1446  break;
1447  }
1448 
1449  /* One more done, was it the last? */
1450  if (++ProcessedPtes == PteCount)
1451  {
1452  /* Complete the fault */
1454  Address,
1455  PointerPte,
1456  PointerProtoPte,
1457  LockIrql,
1458  &OutPfn);
1459 
1460  /* THIS RELEASES THE PFN LOCK! */
1461  break;
1462  }
1463 
1464  /* No clustered faults yet */
1465  ASSERT(FALSE);
1466  }
1467 
1468  /* Did we resolve the fault? */
1469  if (ProcessedPtes)
1470  {
1471  /* Bump the transition count */
1472  InterlockedExchangeAddSizeT(&KeGetCurrentPrcb()->MmTransitionCount, ProcessedPtes);
1473  ProcessedPtes--;
1474 
1475  /* Loop all the processing we did */
1476  ASSERT(ProcessedPtes == 0);
1477 
1478  /* Complete this as a transition fault */
1479  ASSERT(OldIrql == KeGetCurrentIrql());
1480  ASSERT(OldIrql <= APC_LEVEL);
1483  }
1484 
1485  /* We did not -- PFN lock is still held, prepare to resolve prototype PTE fault */
1486  OutPfn = MI_PFN_ELEMENT(SuperProtoPte->u.Hard.PageFrameNumber);
1488  ASSERT(OutPfn->u3.e2.ReferenceCount > 1);
1489  ASSERT(PointerPte->u.Hard.Valid == 0);
1490 
1491  /* Resolve the fault -- this will release the PFN lock */
1492  Status = MiResolveProtoPteFault(!MI_IS_NOT_PRESENT_FAULT(FaultCode),
1493  Address,
1494  PointerPte,
1495  PointerProtoPte,
1496  &OutPfn,
1497  NULL,
1498  NULL,
1499  Process,
1500  LockIrql,
1501  TrapInformation);
1502  //ASSERT(Status != STATUS_ISSUE_PAGING_IO);
1503  //ASSERT(Status != STATUS_REFAULT);
1504  //ASSERT(Status != STATUS_PTE_CHANGED);
1505 
1506  /* Did the routine clean out the PFN or should we? */
1507  if (OutPfn)
1508  {
1509  /* We had a locked PFN, so acquire the PFN lock to dereference it */
1510  ASSERT(PointerProtoPte != NULL);
1511  OldIrql = MiAcquirePfnLock();
1512 
1513  /* Dereference the locked PFN */
1515  ASSERT(OutPfn->u3.e2.ReferenceCount >= 1);
1516 
1517  /* And now release the lock */
1518  MiReleasePfnLock(OldIrql);
1519  }
1520 
1521  /* Complete this as a transition fault */
1522  ASSERT(OldIrql == KeGetCurrentIrql());
1523  ASSERT(OldIrql <= APC_LEVEL);
1525  return Status;
1526  }
1527  }
1528 
1529  /* Is this a transition PTE */
1530  if (TempPte.u.Soft.Transition)
1531  {
1532  PKEVENT* InPageBlock = NULL;
1533  PKEVENT PreviousPageEvent;
1534  KEVENT CurrentPageEvent;
1535 
1536  /* Lock the PFN database */
1537  LockIrql = MiAcquirePfnLock();
1538 
1539  /* Resolve */
1540  Status = MiResolveTransitionFault(!MI_IS_NOT_PRESENT_FAULT(FaultCode), Address, PointerPte, Process, LockIrql, &InPageBlock);
1541 
1542  ASSERT(NT_SUCCESS(Status));
1543 
1544  if (InPageBlock != NULL)
1545  {
1546  /* Another thread is reading or writing this page. Put us into the waiting queue. */
1547  KeInitializeEvent(&CurrentPageEvent, NotificationEvent, FALSE);
1548  PreviousPageEvent = *InPageBlock;
1549  *InPageBlock = &CurrentPageEvent;
1550  }
1551 
1552  /* And now release the lock and leave*/
1553  MiReleasePfnLock(LockIrql);
1554 
1555  if (InPageBlock != NULL)
1556  {
1557  KeWaitForSingleObject(&CurrentPageEvent, WrPageIn, KernelMode, FALSE, NULL);
1558 
1559  /* Let's the chain go on */
1560  if (PreviousPageEvent)
1561  {
1562  KeSetEvent(PreviousPageEvent, IO_NO_INCREMENT, FALSE);
1563  }
1564  }
1565 
1566  ASSERT(OldIrql == KeGetCurrentIrql());
1567  ASSERT(OldIrql <= APC_LEVEL);
1569  return Status;
1570  }
1571 
1572  /* Should we page the data back in ? */
1573  if (TempPte.u.Soft.PageFileHigh != 0)
1574  {
1575  /* Lock the PFN database */
1576  LockIrql = MiAcquirePfnLock();
1577 
1578  /* Resolve */
1579  Status = MiResolvePageFileFault(!MI_IS_NOT_PRESENT_FAULT(FaultCode), Address, PointerPte, Process, &LockIrql);
1580 
1581  /* And now release the lock and leave*/
1582  MiReleasePfnLock(LockIrql);
1583 
1584  ASSERT(OldIrql == KeGetCurrentIrql());
1585  ASSERT(OldIrql <= APC_LEVEL);
1587  return Status;
1588  }
1589 
1590  //
1591  // The PTE must be invalid but not completely empty. It must also not be a
1592  // prototype a transition or a paged-out PTE as those scenarii should've been handled above.
1593  // These are all Windows checks
1594  //
1595  ASSERT(TempPte.u.Hard.Valid == 0);
1596  ASSERT(TempPte.u.Soft.Prototype == 0);
1597  ASSERT(TempPte.u.Soft.Transition == 0);
1598  ASSERT(TempPte.u.Soft.PageFileHigh == 0);
1599  ASSERT(TempPte.u.Long != 0);
1600 
1601  //
1602  // If we got this far, the PTE can only be a demand zero PTE, which is what
1603  // we want. Go handle it!
1604  //
1605  Status = MiResolveDemandZeroFault(Address,
1606  PointerPte,
1607  (ULONG)TempPte.u.Soft.Protection,
1608  Process,
1609  MM_NOIRQL);
1611  if (NT_SUCCESS(Status))
1612  {
1613  //
1614  // Make sure we're returning in a sane state and pass the status down
1615  //
1616  ASSERT(OldIrql == KeGetCurrentIrql());
1618  return Status;
1619  }
1620 
1621  //
1622  // Generate an access fault
1623  //
1624  return STATUS_ACCESS_VIOLATION;
1625 }
1626 
1627 NTSTATUS
1628 NTAPI
1630  IN PVOID Address,
1632  IN PVOID TrapInformation)
1633 {
1634  KIRQL OldIrql = KeGetCurrentIrql(), LockIrql;
1635  PMMPTE ProtoPte = NULL;
1636  PMMPTE PointerPte = MiAddressToPte(Address);
1637  PMMPDE PointerPde = MiAddressToPde(Address);
1638 #if (_MI_PAGING_LEVELS >= 3)
1639  PMMPDE PointerPpe = MiAddressToPpe(Address);
1640 #if (_MI_PAGING_LEVELS == 4)
1641  PMMPDE PointerPxe = MiAddressToPxe(Address);
1642 #endif
1643 #endif
1644  MMPTE TempPte;
1645  PETHREAD CurrentThread;
1647  NTSTATUS Status;
1648  PMMSUPPORT WorkingSet;
1649  ULONG ProtectionCode;
1650  PMMVAD Vad = NULL;
1651  PFN_NUMBER PageFrameIndex;
1652  ULONG Color;
1653  BOOLEAN IsSessionAddress;
1654  PMMPFN Pfn1;
1655  DPRINT("ARM3 FAULT AT: %p\n", Address);
1656 
1657  /* Check for page fault on high IRQL */
1658  if (OldIrql > APC_LEVEL)
1659  {
1660 #if (_MI_PAGING_LEVELS < 3)
1661  /* Could be a page table for paged pool, which we'll allow */
1662  if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)) MiSynchronizeSystemPde((PMMPDE)PointerPte);
1663  MiCheckPdeForPagedPool(Address);
1664 #endif
1665  /* Check if any of the top-level pages are invalid */
1666  if (
1667 #if (_MI_PAGING_LEVELS == 4)
1668  (PointerPxe->u.Hard.Valid == 0) ||
1669 #endif
1670 #if (_MI_PAGING_LEVELS >= 3)
1671  (PointerPpe->u.Hard.Valid == 0) ||
1672 #endif
1673  (PointerPde->u.Hard.Valid == 0) ||
1674  (PointerPte->u.Hard.Valid == 0))
1675  {
1676  /* This fault is not valid, print out some debugging help */
1677  DbgPrint("MM:***PAGE FAULT AT IRQL > 1 Va %p, IRQL %lx\n",
1678  Address,
1679  OldIrql);
1680  if (TrapInformation)
1681  {
1682  PKTRAP_FRAME TrapFrame = TrapInformation;
1683 #ifdef _M_IX86
1684  DbgPrint("MM:***EIP %p, EFL %p\n", TrapFrame->Eip, TrapFrame->EFlags);
1685  DbgPrint("MM:***EAX %p, ECX %p EDX %p\n", TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
1686  DbgPrint("MM:***EBX %p, ESI %p EDI %p\n", TrapFrame->Ebx, TrapFrame->Esi, TrapFrame->Edi);
1687 #elif defined(_M_AMD64)
1688  DbgPrint("MM:***RIP %p, EFL %p\n", TrapFrame->Rip, TrapFrame->EFlags);
1689  DbgPrint("MM:***RAX %p, RCX %p RDX %p\n", TrapFrame->Rax, TrapFrame->Rcx, TrapFrame->Rdx);
1690  DbgPrint("MM:***RBX %p, RSI %p RDI %p\n", TrapFrame->Rbx, TrapFrame->Rsi, TrapFrame->Rdi);
1691 #elif defined(_M_ARM)
1692  DbgPrint("MM:***PC %p\n", TrapFrame->Pc);
1693  DbgPrint("MM:***R0 %p, R1 %p R2 %p, R3 %p\n", TrapFrame->R0, TrapFrame->R1, TrapFrame->R2, TrapFrame->R3);
1694  DbgPrint("MM:***R11 %p, R12 %p SP %p, LR %p\n", TrapFrame->R11, TrapFrame->R12, TrapFrame->Sp, TrapFrame->Lr);
1695 #endif
1696  }
1697 
1698  /* Tell the trap handler to fail */
1699  return STATUS_IN_PAGE_ERROR | 0x10000000;
1700  }
1701 
1702  /* Not yet implemented in ReactOS */
1703  ASSERT(MI_IS_PAGE_LARGE(PointerPde) == FALSE);
1704  ASSERT((!MI_IS_NOT_PRESENT_FAULT(FaultCode) && MI_IS_PAGE_COPY_ON_WRITE(PointerPte)) == FALSE);
1705 
1706  /* Check if this was a write */
1707  if (MI_IS_WRITE_ACCESS(FaultCode))
1708  {
1709  /* Was it to a read-only page? */
1710  Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1711  if (!(PointerPte->u.Long & PTE_READWRITE) &&
1713  {
1714  /* Crash with distinguished bugcheck code */
1715  KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1716  (ULONG_PTR)Address,
1717  PointerPte->u.Long,
1718  (ULONG_PTR)TrapInformation,
1719  10);
1720  }
1721  }
1722 
1723  /* Nothing is actually wrong */
1724  DPRINT1("Fault at IRQL %u is ok (%p)\n", OldIrql, Address);
1725  return STATUS_SUCCESS;
1726  }
1727 
1728  /* Check for kernel fault address */
1729  if (Address >= MmSystemRangeStart)
1730  {
1731  /* Bail out, if the fault came from user mode */
1732  if (Mode == UserMode) return STATUS_ACCESS_VIOLATION;
1733 
1734 #if (_MI_PAGING_LEVELS == 2)
1735  if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)) MiSynchronizeSystemPde((PMMPDE)PointerPte);
1736  MiCheckPdeForPagedPool(Address);
1737 #endif
1738 
1739  /* Check if the higher page table entries are invalid */
1740  if (
1741 #if (_MI_PAGING_LEVELS == 4)
1742  /* AMD64 system, check if PXE is invalid */
1743  (PointerPxe->u.Hard.Valid == 0) ||
1744 #endif
1745 #if (_MI_PAGING_LEVELS >= 3)
1746  /* PAE/AMD64 system, check if PPE is invalid */
1747  (PointerPpe->u.Hard.Valid == 0) ||
1748 #endif
1749  /* Always check if the PDE is valid */
1750  (PointerPde->u.Hard.Valid == 0))
1751  {
1752  /* PXE/PPE/PDE (still) not valid, kill the system */
1753  KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
1754  (ULONG_PTR)Address,
1755  FaultCode,
1756  (ULONG_PTR)TrapInformation,
1757  2);
1758  }
1759 
1760  /* Not handling session faults yet */
1761  IsSessionAddress = MI_IS_SESSION_ADDRESS(Address);
1762 
1763  /* The PDE is valid, so read the PTE */
1764  TempPte = *PointerPte;
1765  if (TempPte.u.Hard.Valid == 1)
1766  {
1767  /* Check if this was system space or session space */
1768  if (!IsSessionAddress)
1769  {
1770  /* Check if the PTE is still valid under PFN lock */
1771  OldIrql = MiAcquirePfnLock();
1772  TempPte = *PointerPte;
1773  if (TempPte.u.Hard.Valid)
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,
1785  (ULONG_PTR)Address,
1786  PointerPte->u.Long,
1787  (ULONG_PTR)TrapInformation,
1788  11);
1789  }
1790  }
1791 
1792  /* Check for execution of non-executable memory */
1793  if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
1794  !MI_IS_PAGE_EXECUTABLE(&TempPte))
1795  {
1796  KeBugCheckEx(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY,
1797  (ULONG_PTR)Address,
1798  (ULONG_PTR)TempPte.u.Long,
1799  (ULONG_PTR)TrapInformation,
1800  1);
1801  }
1802  }
1803 
1804  /* Release PFN lock and return all good */
1805  MiReleasePfnLock(OldIrql);
1806  return STATUS_SUCCESS;
1807  }
1808  }
1809 #if (_MI_PAGING_LEVELS == 2)
1810  /* Check if this was a session PTE that needs to remap the session PDE */
1811  if (MI_IS_SESSION_PTE(Address))
1812  {
1813  /* Do the remapping */
1814  Status = MiCheckPdeForSessionSpace(Address);
1815  if (!NT_SUCCESS(Status))
1816  {
1817  /* It failed, this address is invalid */
1818  KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
1819  (ULONG_PTR)Address,
1820  FaultCode,
1821  (ULONG_PTR)TrapInformation,
1822  6);
1823  }
1824  }
1825 #else
1826 
1827 _WARN("Session space stuff is not implemented yet!")
1828 
1829 #endif
1830 
1831  /* Check for a fault on the page table or hyperspace */
1832  if (MI_IS_PAGE_TABLE_OR_HYPER_ADDRESS(Address))
1833  {
1834 #if (_MI_PAGING_LEVELS < 3)
1835  /* Windows does this check but I don't understand why -- it's done above! */
1837 #endif
1838  /* Handle this as a user mode fault */
1839  goto UserFault;
1840  }
1841 
1842  /* Get the current thread */
1843  CurrentThread = PsGetCurrentThread();
1844 
1845  /* What kind of address is this */
1846  if (!IsSessionAddress)
1847  {
1848  /* Use the system working set */
1849  WorkingSet = &MmSystemCacheWs;
1850  CurrentProcess = NULL;
1851 
1852  /* Make sure we don't have a recursive working set lock */
1853  if ((CurrentThread->OwnsProcessWorkingSetExclusive) ||
1854  (CurrentThread->OwnsProcessWorkingSetShared) ||
1855  (CurrentThread->OwnsSystemWorkingSetExclusive) ||
1856  (CurrentThread->OwnsSystemWorkingSetShared) ||
1857  (CurrentThread->OwnsSessionWorkingSetExclusive) ||
1858  (CurrentThread->OwnsSessionWorkingSetShared))
1859  {
1860  /* Fail */
1861  return STATUS_IN_PAGE_ERROR | 0x10000000;
1862  }
1863  }
1864  else
1865  {
1866  /* Use the session process and working set */
1867  CurrentProcess = HYDRA_PROCESS;
1868  WorkingSet = &MmSessionSpace->GlobalVirtualAddress->Vm;
1869 
1870  /* Make sure we don't have a recursive working set lock */
1871  if ((CurrentThread->OwnsSessionWorkingSetExclusive) ||
1872  (CurrentThread->OwnsSessionWorkingSetShared))
1873  {
1874  /* Fail */
1875  return STATUS_IN_PAGE_ERROR | 0x10000000;
1876  }
1877  }
1878 
1879  /* Acquire the working set lock */
1880  KeRaiseIrql(APC_LEVEL, &LockIrql);
1881  MiLockWorkingSet(CurrentThread, WorkingSet);
1882 
1883  /* Re-read PTE now that we own the lock */
1884  TempPte = *PointerPte;
1885  if (TempPte.u.Hard.Valid == 1)
1886  {
1887  /* Check if this was a write */
1888  if (MI_IS_WRITE_ACCESS(FaultCode))
1889  {
1890  /* Was it to a read-only page that is not copy on write? */
1891  Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1892  if (!(TempPte.u.Long & PTE_READWRITE) &&
1893  !(Pfn1->OriginalPte.u.Soft.Protection & MM_READWRITE) &&
1894  !MI_IS_PAGE_COPY_ON_WRITE(&TempPte))
1895  {
1896  /* Case not yet handled */
1897  ASSERT(!IsSessionAddress);
1898 
1899  /* Crash with distinguished bugcheck code */
1900  KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1901  (ULONG_PTR)Address,
1902  TempPte.u.Long,
1903  (ULONG_PTR)TrapInformation,
1904  12);
1905  }
1906  }
1907 
1908  /* Check for execution of non-executable memory */
1909  if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
1910  !MI_IS_PAGE_EXECUTABLE(&TempPte))
1911  {
1912  KeBugCheckEx(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY,
1913  (ULONG_PTR)Address,
1914  (ULONG_PTR)TempPte.u.Long,
1915  (ULONG_PTR)TrapInformation,
1916  2);
1917  }
1918 
1919  /* Check for read-only write in session space */
1920  if ((IsSessionAddress) &&
1921  MI_IS_WRITE_ACCESS(FaultCode) &&
1922  !MI_IS_PAGE_WRITEABLE(&TempPte))
1923  {
1924  /* Sanity check */
1926 
1927  /* Was this COW? */
1928  if (!MI_IS_PAGE_COPY_ON_WRITE(&TempPte))
1929  {
1930  /* Then this is not allowed */
1931  KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1932  (ULONG_PTR)Address,
1933  (ULONG_PTR)TempPte.u.Long,
1934  (ULONG_PTR)TrapInformation,
1935  13);
1936  }
1937 
1938  /* Otherwise, handle COW */
1939  ASSERT(FALSE);
1940  }
1941 
1942  /* Release the working set */
1943  MiUnlockWorkingSet(CurrentThread, WorkingSet);
1944  KeLowerIrql(LockIrql);
1945 
1946  /* Otherwise, the PDE was probably invalid, and all is good now */
1947  return STATUS_SUCCESS;
1948  }
1949 
1950  /* Check one kind of prototype PTE */
1951  if (TempPte.u.Soft.Prototype)
1952  {
1953  /* Make sure protected pool is on, and that this is a pool address */
1955  (((Address >= MmNonPagedPoolStart) &&
1956  (Address < (PVOID)((ULONG_PTR)MmNonPagedPoolStart +
1958  ((Address >= MmNonPagedPoolExpansionStart) &&
1959  (Address < MmNonPagedPoolEnd))))
1960  {
1961  /* Bad boy, bad boy, whatcha gonna do, whatcha gonna do when ARM3 comes for you! */
1962  KeBugCheckEx(DRIVER_CAUGHT_MODIFYING_FREED_POOL,
1963  (ULONG_PTR)Address,
1964  FaultCode,
1965  Mode,
1966  4);
1967  }
1968 
1969  /* Get the prototype PTE! */
1970  ProtoPte = MiProtoPteToPte(&TempPte);
1971 
1972  /* Do we need to locate the prototype PTE in session space? */
1973  if ((IsSessionAddress) &&
1974  (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED))
1975  {
1976  /* Yep, go find it as well as the VAD for it */
1977  ProtoPte = MiCheckVirtualAddress(Address,
1978  &ProtectionCode,
1979  &Vad);
1980  ASSERT(ProtoPte != NULL);
1981  }
1982  }
1983  else
1984  {
1985  /* We don't implement transition PTEs */
1986  ASSERT(TempPte.u.Soft.Transition == 0);
1987 
1988  /* Check for no-access PTE */
1989  if (TempPte.u.Soft.Protection == MM_NOACCESS)
1990  {
1991  /* Bugcheck the system! */
1992  KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
1993  (ULONG_PTR)Address,
1994  FaultCode,
1995  (ULONG_PTR)TrapInformation,
1996  1);
1997  }
1998 
1999  /* Check for no protecton at all */
2000  if (TempPte.u.Soft.Protection == MM_ZERO_ACCESS)
2001  {
2002  /* Bugcheck the system! */
2003  KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
2004  (ULONG_PTR)Address,
2005  FaultCode,
2006  (ULONG_PTR)TrapInformation,
2007  0);
2008  }
2009  }
2010 
2011  /* Check for demand page */
2012  if (MI_IS_WRITE_ACCESS(FaultCode) &&
2013  !(ProtoPte) &&
2014  !(IsSessionAddress) &&
2015  !(TempPte.u.Hard.Valid))
2016  {
2017  /* Get the protection code */
2018  ASSERT(TempPte.u.Soft.Transition == 0);
2019  if (!(TempPte.u.Soft.Protection & MM_READWRITE))
2020  {
2021  /* Bugcheck the system! */
2022  KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
2023  (ULONG_PTR)Address,
2024  TempPte.u.Long,
2025  (ULONG_PTR)TrapInformation,
2026  14);
2027  }
2028  }
2029 
2030  /* Now do the real fault handling */
2031  Status = MiDispatchFault(FaultCode,
2032  Address,
2033  PointerPte,
2034  ProtoPte,
2035  FALSE,
2036  CurrentProcess,
2037  TrapInformation,
2038  NULL);
2039 
2040  /* Release the working set */
2042  MiUnlockWorkingSet(CurrentThread, WorkingSet);
2043  KeLowerIrql(LockIrql);
2044 
2045  /* We are done! */
2046  DPRINT("Fault resolved with status: %lx\n", Status);
2047  return Status;
2048  }
2049 
2050  /* This is a user fault */
2051 UserFault:
2052  CurrentThread = PsGetCurrentThread();
2053  CurrentProcess = (PEPROCESS)CurrentThread->Tcb.ApcState.Process;
2054 
2055  /* Lock the working set */
2056  MiLockProcessWorkingSet(CurrentProcess, CurrentThread);
2057 
2058  ProtectionCode = MM_INVALID_PROTECTION;
2059 
2060 #if (_MI_PAGING_LEVELS == 4)
2061  /* Check if the PXE is valid */
2062  if (PointerPxe->u.Hard.Valid == 0)
2063  {
2064  /* Right now, we only handle scenarios where the PXE is totally empty */
2065  ASSERT(PointerPxe->u.Long == 0);
2066 
2067  /* This is only possible for user mode addresses! */
2068  ASSERT(PointerPte <= MiHighestUserPte);
2069 
2070  /* Check if we have a VAD */
2071  MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2072  if (ProtectionCode == MM_NOACCESS)
2073  {
2074  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2075  return STATUS_ACCESS_VIOLATION;
2076  }
2077 
2078  /* Resolve a demand zero fault */
2079  MiResolveDemandZeroFault(PointerPpe,
2080  PointerPxe,
2081  MM_READWRITE,
2082  CurrentProcess,
2083  MM_NOIRQL);
2084 
2085  /* We should come back with a valid PXE */
2086  ASSERT(PointerPxe->u.Hard.Valid == 1);
2087  }
2088 #endif
2089 
2090 #if (_MI_PAGING_LEVELS >= 3)
2091  /* Check if the PPE is valid */
2092  if (PointerPpe->u.Hard.Valid == 0)
2093  {
2094  /* Right now, we only handle scenarios where the PPE is totally empty */
2095  ASSERT(PointerPpe->u.Long == 0);
2096 
2097  /* This is only possible for user mode addresses! */
2098  ASSERT(PointerPte <= MiHighestUserPte);
2099 
2100  /* Check if we have a VAD, unless we did this already */
2101  if (ProtectionCode == MM_INVALID_PROTECTION)
2102  {
2103  MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2104  }
2105 
2106  if (ProtectionCode == MM_NOACCESS)
2107  {
2108  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2109  return STATUS_ACCESS_VIOLATION;
2110  }
2111 
2112  /* Resolve a demand zero fault */
2113  MiResolveDemandZeroFault(PointerPde,
2114  PointerPpe,
2115  MM_READWRITE,
2116  CurrentProcess,
2117  MM_NOIRQL);
2118 
2119  /* We should come back with a valid PPE */
2120  ASSERT(PointerPpe->u.Hard.Valid == 1);
2121  }
2122 #endif
2123 
2124  /* Check if the PDE is invalid */
2125  if (PointerPde->u.Hard.Valid == 0)
2126  {
2127  /* Right now, we only handle scenarios where the PDE is totally empty */
2128  ASSERT(PointerPde->u.Long == 0);
2129 
2130  /* And go dispatch the fault on the PDE. This should handle the demand-zero */
2131 #if MI_TRACE_PFNS
2132  UserPdeFault = TRUE;
2133 #endif
2134  /* Check if we have a VAD, unless we did this already */
2135  if (ProtectionCode == MM_INVALID_PROTECTION)
2136  {
2137  MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2138  }
2139 
2140  if (ProtectionCode == MM_NOACCESS)
2141  {
2142 #if (_MI_PAGING_LEVELS == 2)
2143  /* Could be a page table for paged pool */
2144  MiCheckPdeForPagedPool(Address);
2145 #endif
2146  /* Has the code above changed anything -- is this now a valid PTE? */
2147  Status = (PointerPde->u.Hard.Valid == 1) ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
2148 
2149  /* Either this was a bogus VA or we've fixed up a paged pool PDE */
2150  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2151  return Status;
2152  }
2153 
2154  /* Resolve a demand zero fault */
2155  MiResolveDemandZeroFault(PointerPte,
2156  PointerPde,
2157  MM_READWRITE,
2158  CurrentProcess,
2159  MM_NOIRQL);
2160 #if MI_TRACE_PFNS
2161  UserPdeFault = FALSE;
2162 #endif
2163  /* We should come back with APCs enabled, and with a valid PDE */
2165  ASSERT(PointerPde->u.Hard.Valid == 1);
2166  }
2167  else
2168  {
2169  /* Not yet implemented in ReactOS */
2170  ASSERT(MI_IS_PAGE_LARGE(PointerPde) == FALSE);
2171  }
2172 
2173  /* Now capture the PTE. */
2174  TempPte = *PointerPte;
2175 
2176  /* Check if the PTE is valid */
2177  if (TempPte.u.Hard.Valid)
2178  {
2179  /* Check if this is a write on a readonly PTE */
2180  if (MI_IS_WRITE_ACCESS(FaultCode))
2181  {
2182  /* Is this a copy on write PTE? */
2183  if (MI_IS_PAGE_COPY_ON_WRITE(&TempPte))
2184  {
2185  PFN_NUMBER PageFrameIndex, OldPageFrameIndex;
2186  PMMPFN Pfn1;
2187 
2188  LockIrql = MiAcquirePfnLock();
2189 
2190  ASSERT(MmAvailablePages > 0);
2191 
2192  /* Allocate a new page and copy it */
2193  PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(CurrentProcess));
2194  OldPageFrameIndex = PFN_FROM_PTE(&TempPte);
2195 
2196  MiCopyPfn(PageFrameIndex, OldPageFrameIndex);
2197 
2198  /* Dereference whatever this PTE is referencing */
2199  Pfn1 = MI_PFN_ELEMENT(OldPageFrameIndex);
2200  ASSERT(Pfn1->u3.e1.PrototypePte == 1);
2201  ASSERT(!MI_IS_PFN_DELETED(Pfn1));
2202  ProtoPte = Pfn1->PteAddress;
2203  MiDeletePte(PointerPte, Address, CurrentProcess, ProtoPte);
2204 
2205  /* And make a new shiny one with our page */
2206  MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
2207  TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
2208  TempPte.u.Hard.Write = 1;
2209  TempPte.u.Hard.CopyOnWrite = 0;
2210 
2211  MI_WRITE_VALID_PTE(PointerPte, TempPte);
2212 
2213  MiReleasePfnLock(LockIrql);
2214 
2215  /* Return the status */
2216  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2218  }
2219 
2220  /* Is this a read-only PTE? */
2221  if (!MI_IS_PAGE_WRITEABLE(&TempPte))
2222  {
2223  /* Return the status */
2224  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2225  return STATUS_ACCESS_VIOLATION;
2226  }
2227  }
2228 
2229  /* Check for execution of non-executable memory */
2230  if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
2231  !MI_IS_PAGE_EXECUTABLE(&TempPte))
2232  {
2233  /* Return the status */
2234  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2235  return STATUS_ACCESS_VIOLATION;
2236  }
2237 
2238  /* The fault has already been resolved by a different thread */
2239  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2240  return STATUS_SUCCESS;
2241  }
2242 
2243  /* Quick check for demand-zero */
2244  if (TempPte.u.Long == (MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS))
2245  {
2246  /* Resolve the fault */
2247  MiResolveDemandZeroFault(Address,
2248  PointerPte,
2249  MM_READWRITE,
2250  CurrentProcess,
2251  MM_NOIRQL);
2252 
2253  /* Return the status */
2254  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2256  }
2257 
2258  /* Check for zero PTE */
2259  if (TempPte.u.Long == 0)
2260  {
2261  /* Check if this address range belongs to a valid allocation (VAD) */
2262  ProtoPte = MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2263  if (ProtectionCode == MM_NOACCESS)
2264  {
2265 #if (_MI_PAGING_LEVELS == 2)
2266  /* Could be a page table for paged pool */
2267  MiCheckPdeForPagedPool(Address);
2268 #endif
2269  /* Has the code above changed anything -- is this now a valid PTE? */
2270  Status = (PointerPte->u.Hard.Valid == 1) ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
2271 
2272  /* Either this was a bogus VA or we've fixed up a paged pool PDE */
2273  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2274  return Status;
2275  }
2276 
2277  /*
2278  * Check if this is a real user-mode address or actually a kernel-mode
2279  * page table for a user mode address
2280  */
2281  if (Address <= MM_HIGHEST_USER_ADDRESS)
2282  {
2283  /* Add an additional page table reference */
2285  }
2286 
2287  /* Is this a guard page? */
2288  if ((ProtectionCode & MM_PROTECT_SPECIAL) == MM_GUARDPAGE)
2289  {
2290  /* The VAD protection cannot be MM_DECOMMIT! */
2291  ASSERT(ProtectionCode != MM_DECOMMIT);
2292 
2293  /* Remove the bit */
2294  TempPte.u.Soft.Protection = ProtectionCode & ~MM_GUARDPAGE;
2295  MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2296 
2297  /* Not supported */
2298  ASSERT(ProtoPte == NULL);
2299  ASSERT(CurrentThread->ApcNeeded == 0);
2300 
2301  /* Drop the working set lock */
2302  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2303  ASSERT(KeGetCurrentIrql() == OldIrql);
2304 
2305  /* Handle stack expansion */
2306  return MiCheckForUserStackOverflow(Address, TrapInformation);
2307  }
2308 
2309  /* Did we get a prototype PTE back? */
2310  if (!ProtoPte)
2311  {
2312  /* Is this PTE actually part of the PDE-PTE self-mapping directory? */
2313  if (PointerPde == MiAddressToPde(PTE_BASE))
2314  {
2315  /* Then it's really a demand-zero PDE (on behalf of user-mode) */
2316 #ifdef _M_ARM
2317  _WARN("This is probably completely broken!");
2319 #else
2320  MI_WRITE_INVALID_PTE(PointerPte, DemandZeroPde);
2321 #endif
2322  }
2323  else
2324  {
2325  /* No, create a new PTE. First, write the protection */
2326  TempPte.u.Soft.Protection = ProtectionCode;
2327  MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2328  }
2329 
2330  /* Lock the PFN database since we're going to grab a page */
2331  OldIrql = MiAcquirePfnLock();
2332 
2333  /* Make sure we have enough pages */
2334  ASSERT(MmAvailablePages >= 32);
2335 
2336  /* Try to get a zero page */
2338  MI_SET_PROCESS2(CurrentProcess->ImageFileName);
2339  Color = MI_GET_NEXT_PROCESS_COLOR(CurrentProcess);
2340  PageFrameIndex = MiRemoveZeroPageSafe(Color);
2341  if (!PageFrameIndex)
2342  {
2343  /* Grab a page out of there. Later we should grab a colored zero page */
2344  PageFrameIndex = MiRemoveAnyPage(Color);
2345  ASSERT(PageFrameIndex);
2346 
2347  /* Release the lock since we need to do some zeroing */
2348  MiReleasePfnLock(OldIrql);
2349 
2350  /* Zero out the page, since it's for user-mode */
2351  MiZeroPfn(PageFrameIndex);
2352 
2353  /* Grab the lock again so we can initialize the PFN entry */
2354  OldIrql = MiAcquirePfnLock();
2355  }
2356 
2357  /* Initialize the PFN entry now */
2358  MiInitializePfn(PageFrameIndex, PointerPte, 1);
2359 
2360  /* Increment the count of pages in the process */
2361  CurrentProcess->NumberOfPrivatePages++;
2362 
2363  /* One more demand-zero fault */
2364  KeGetCurrentPrcb()->MmDemandZeroCount++;
2365 
2366  /* And we're done with the lock */
2367  MiReleasePfnLock(OldIrql);
2368 
2369  /* Fault on user PDE, or fault on user PTE? */
2370  if (PointerPte <= MiHighestUserPte)
2371  {
2372  /* User fault, build a user PTE */
2373  MI_MAKE_HARDWARE_PTE_USER(&TempPte,
2374  PointerPte,
2375  PointerPte->u.Soft.Protection,
2376  PageFrameIndex);
2377  }
2378  else
2379  {
2380  /* This is a user-mode PDE, create a kernel PTE for it */
2381  MI_MAKE_HARDWARE_PTE(&TempPte,
2382  PointerPte,
2383  PointerPte->u.Soft.Protection,
2384  PageFrameIndex);
2385  }
2386 
2387  /* Write the dirty bit for writeable pages */
2388  if (MI_IS_PAGE_WRITEABLE(&TempPte)) MI_MAKE_DIRTY_PAGE(&TempPte);
2389 
2390  /* And now write down the PTE, making the address valid */
2391  MI_WRITE_VALID_PTE(PointerPte, TempPte);
2392  Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
2393  ASSERT(Pfn1->u1.Event == NULL);
2394 
2395  /* Demand zero */
2397  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2399  }
2400 
2401  /* We should have a valid protection here */
2402  ASSERT(ProtectionCode != 0x100);
2403 
2404  /* Write the prototype PTE */
2405  TempPte = PrototypePte;
2406  TempPte.u.Soft.Protection = ProtectionCode;
2407  ASSERT(TempPte.u.Long != 0);
2408  MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2409  }
2410  else
2411  {
2412  /* Get the protection code and check if this is a proto PTE */
2413  ProtectionCode = (ULONG)TempPte.u.Soft.Protection;
2414  if (TempPte.u.Soft.Prototype)
2415  {
2416  /* Do we need to go find the real PTE? */
2417  if (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
2418  {
2419  /* Get the prototype pte and VAD for it */
2420  ProtoPte = MiCheckVirtualAddress(Address,
2421  &ProtectionCode,
2422  &Vad);
2423  if (!ProtoPte)
2424  {
2426  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2427  return STATUS_ACCESS_VIOLATION;
2428  }
2429  }
2430  else
2431  {
2432  /* Get the prototype PTE! */
2433  ProtoPte = MiProtoPteToPte(&TempPte);
2434 
2435  /* Is it read-only */
2436  if (TempPte.u.Proto.ReadOnly)
2437  {
2438  /* Set read-only code */
2439  ProtectionCode = MM_READONLY;
2440  }
2441  else
2442  {
2443  /* Set unknown protection */
2444  ProtectionCode = 0x100;
2445  ASSERT(CurrentProcess->CloneRoot != NULL);
2446  }
2447  }
2448  }
2449  }
2450 
2451  /* Do we have a valid protection code? */
2452  if (ProtectionCode != 0x100)
2453  {
2454  /* Run a software access check first, including to detect guard pages */
2455  Status = MiAccessCheck(PointerPte,
2456  !MI_IS_NOT_PRESENT_FAULT(FaultCode),
2457  Mode,
2458  ProtectionCode,
2459  TrapInformation,
2460  FALSE);
2461  if (Status != STATUS_SUCCESS)
2462  {
2463  /* Not supported */
2464  ASSERT(CurrentThread->ApcNeeded == 0);
2465 
2466  /* Drop the working set lock */
2467  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2468  ASSERT(KeGetCurrentIrql() == OldIrql);
2469 
2470  /* Did we hit a guard page? */
2471  if (Status == STATUS_GUARD_PAGE_VIOLATION)
2472  {
2473  /* Handle stack expansion */
2474  return MiCheckForUserStackOverflow(Address, TrapInformation);
2475  }
2476 
2477  /* Otherwise, fail back to the caller directly */
2478  return Status;
2479  }
2480  }
2481 
2482  /* Dispatch the fault */
2483  Status = MiDispatchFault(FaultCode,
2484  Address,
2485  PointerPte,
2486  ProtoPte,
2487  FALSE,
2488  CurrentProcess,
2489  TrapInformation,
2490  Vad);
2491 
2492  /* Return the status */
2494  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2495  return Status;
2496 }
2497 
2498 NTSTATUS
2499 NTAPI
2501 {
2504 
2505  *ExecuteOptions = 0;
2506 
2507  if (CurrentProcess->Flags.ExecuteDisable)
2508  {
2509  *ExecuteOptions |= MEM_EXECUTE_OPTION_DISABLE;
2510  }
2511 
2512  if (CurrentProcess->Flags.ExecuteEnable)
2513  {
2514  *ExecuteOptions |= MEM_EXECUTE_OPTION_ENABLE;
2515  }
2516 
2517  if (CurrentProcess->Flags.DisableThunkEmulation)
2518  {
2519  *ExecuteOptions |= MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION;
2520  }
2521 
2522  if (CurrentProcess->Flags.Permanent)
2523  {
2524  *ExecuteOptions |= MEM_EXECUTE_OPTION_PERMANENT;
2525  }
2526 
2527  if (CurrentProcess->Flags.ExecuteDispatchEnable)
2528  {
2529  *ExecuteOptions |= MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE;
2530  }
2531 
2532  if (CurrentProcess->Flags.ImageDispatchEnable)
2533  {
2534  *ExecuteOptions |= MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE;
2535  }
2536 
2537  return STATUS_SUCCESS;
2538 }
2539 
2540 NTSTATUS
2541 NTAPI
2543 {
2545  KLOCK_QUEUE_HANDLE ProcessLock;
2546  NTSTATUS Status = STATUS_ACCESS_DENIED;
2548 
2549  /* Only accept valid flags */
2550  if (ExecuteOptions & ~MEM_EXECUTE_OPTION_VALID_FLAGS)
2551  {
2552  /* Fail */
2553  DPRINT1("Invalid no-execute options\n");
2554  return STATUS_INVALID_PARAMETER;
2555  }
2556 
2557  /* Change the NX state in the process lock */
2558  KiAcquireProcessLock(CurrentProcess, &ProcessLock);
2559 
2560  /* Don't change anything if the permanent flag was set */
2561  if (!CurrentProcess->Flags.Permanent)
2562  {
2563  /* Start by assuming it's not disabled */
2564  CurrentProcess->Flags.ExecuteDisable = FALSE;
2565 
2566  /* Now process each flag and turn the equivalent bit on */
2567  if (ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE)
2568  {
2569  CurrentProcess->Flags.ExecuteDisable = TRUE;
2570  }
2571  if (ExecuteOptions & MEM_EXECUTE_OPTION_ENABLE)
2572  {
2573  CurrentProcess->Flags.ExecuteEnable = TRUE;
2574  }
2575  if (ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)
2576  {
2577  CurrentProcess->Flags.DisableThunkEmulation = TRUE;
2578  }
2579  if (ExecuteOptions & MEM_EXECUTE_OPTION_PERMANENT)
2580  {
2581  CurrentProcess->Flags.Permanent = TRUE;
2582  }
2583  if (ExecuteOptions & MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE)
2584  {
2585  CurrentProcess->Flags.ExecuteDispatchEnable = TRUE;
2586  }
2587  if (ExecuteOptions & MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE)
2588  {
2589  CurrentProcess->Flags.ImageDispatchEnable = TRUE;
2590  }
2591 
2592  /* These are turned on by default if no-execution is also eanbled */
2593  if (CurrentProcess->Flags.ExecuteEnable)
2594  {
2595  CurrentProcess->Flags.ExecuteDispatchEnable = TRUE;
2596  CurrentProcess->Flags.ImageDispatchEnable = TRUE;
2597  }
2598 
2599  /* All good */
2600  Status = STATUS_SUCCESS;
2601  }
2602 
2603  /* Release the lock and return status */
2604  KiReleaseProcessLock(&ProcessLock);
2605  return Status;
2606 }
2607 
2608 /* EOF */
DWORD *typedef PVOID
Definition: winlogon.h:52
union _MMVAD::@2474 u
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define _BYTE_MASK(Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7)
#define MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE
Definition: mmtypes.h:78
#define MI_IS_PAGE_TABLE_ADDRESS(Address)
Definition: miarm.h:146
ULONG64 Write
Definition: mmtypes.h:170
ULONG R12
Definition: ketypes.h:345
#define MM_HIGHEST_USER_ADDRESS
Definition: armddk.h:17
NTSTATUS NTAPI MmArmAccessFault(IN ULONG FaultCode, IN PVOID Address, IN KPROCESSOR_MODE Mode, IN PVOID TrapInformation)
Definition: pagfault.c:1629
VOID NTAPI MiInitializePfn(IN PFN_NUMBER PageFrameIndex, IN PMMPTE PointerPte, IN BOOLEAN Modified)
Definition: pfnlist.c:969
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
#define IN
Definition: typedefs.h:38
#define MM_INVALID_PROTECTION
Definition: miarm.h:71
MMPTE PrototypePte
Definition: init.c:42
#define _MI_PAGING_LEVELS
Definition: mm.h:6
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
PVOID ULONG Address
Definition: oprghdlr.h:14
UINT64 Rbx
Definition: ketypes.h:369
union _MMPFN::@1665 u3
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
PPEB Peb
Definition: dllmain.c:27
#define MI_IS_NOT_PRESENT_FAULT(FaultCode)
Definition: mm.h:117
#define MI_PAGE_WRITE_COMBINED(x)
Definition: mm.h:99
#define MI_ASSERT_PFN_LOCK_HELD()
Definition: mm.h:910
#define MiAddressToPde(x)
Definition: mmx86.c:20
BOOLEAN NTAPI KeAreAllApcsDisabled(VOID)
Definition: apc.c:985
VOID NTAPI MiUnlinkPageFromList(IN PMMPFN Pfn)
Definition: pfnlist.c:264
_In_ ULONG Mode
Definition: hubbusif.h:303
FORCEINLINE VOID MiDereferencePfnAndDropLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1434
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define DbgPrint
Definition: loader.c:25
#define MI_MAKE_ACCESSED_PAGE(x)
Definition: mm.h:96
ULONG OwnsSystemWorkingSetShared
Definition: pstypes.h:1155
signed short * PSHORT
Definition: retypes.h:6
PMMPDE PageTables
Definition: miarm.h:486
VOID Execute(LPTSTR Path)
Definition: stats.c:407
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:1277
ULONG PFN_COUNT
Definition: mmtypes.h:102
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel)?(CompletionRoutine!=NULL):TRUE)
static NTSTATUS NTAPI MiResolvePageFileFault(_In_ BOOLEAN StoreInstruction, _In_ PVOID FaultingAddress, _In_ PMMPTE PointerPte, _In_ PEPROCESS CurrentProcess, _Inout_ KIRQL *OldIrql)
Definition: pagfault.c:862
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
PMMPTE NTAPI MiReserveSystemPtes(IN ULONG NumberOfPtes, IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType)
Definition: syspte.c:246
USHORT ReadInProgress
Definition: mm.h:291
#define MI_IS_SESSION_ADDRESS(Address)
Definition: miarm.h:140
#define HYDRA_PROCESS
Definition: pagfault.c:20
return STATUS_SUCCESS
Definition: btrfs.c:2690
#define PAGE_GUARD
Definition: nt_native.h:1310
#define MM_DECOMMIT
Definition: miarm.h:68
#define MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE
Definition: mmtypes.h:77
NTSTATUS NTAPI MiReadPageFile(_In_ PFN_NUMBER Page, _In_ ULONG PageFileIndex, _In_ ULONG_PTR PageFileOffset)
Definition: pagefile.c:287
KTHREAD Tcb
Definition: pstypes.h:1034
#define MEM_EXECUTE_OPTION_VALID_FLAGS
Definition: mmtypes.h:79
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1054
PFN_NUMBER NumberOfPrivatePages
Definition: pstypes.h:1231
#define MI_IS_PAGE_EXECUTABLE(x)
Definition: mm.h:107
struct _EPROCESS * PEPROCESS
Definition: nt_native.h:30
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:147
FORCEINLINE VOID MiReferenceUnusedPageAndBumpLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1606
VOID NTAPI MiCopyPfn(_In_ PFN_NUMBER DestPage, _In_ PFN_NUMBER SrcPage)
Definition: pagfault.c:508
PVOID MmNonPagedPoolExpansionStart
Definition: init.c:25
#define MM_READWRITE
Definition: miarm.h:51
#define STATUS_GUARD_PAGE_VIOLATION
Definition: ntstatus.h:170
ULONG64 PageFrameNumber
Definition: mmtypes.h:107
#define MI_GET_NEXT_COLOR()
Definition: miarm.h:211
#define MI_PTE_LOOKUP_NEEDED
Definition: miarm.h:220
#define MM_NOACCESS
Definition: miarm.h:69
HARDWARE_PDE_ARMV6 TempPde
Definition: winldr.c:77
FORCEINLINE KIRQL MiAcquirePfnLock(VOID)
Definition: mm.h:875
PMM_SESSION_SPACE MmSessionSpace
Definition: session.c:21
FORCEINLINE VOID MiLockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1064
USHORT Modified
Definition: mm.h:290
PVOID MmPagedPoolEnd
Definition: init.c:26
union _MMPFN::@1663 u1
NTSTATUS NTAPI MmGetExecuteOptions(IN PULONG ExecuteOptions)
Definition: pagfault.c:2500
PVOID CloneRoot
Definition: pstypes.h:1230
#define MM_PTE_SOFTWARE_PROTECTION_BITS
Definition: mm.h:71
ULONG_PTR Protection
Definition: mmtypes.h:697
PVOID MiSessionSpaceWs
Definition: mminit.c:130
#define MI_IS_PAGE_COPY_ON_WRITE(x)
Definition: mm.h:106
GLenum GLclampf GLint GLenum GLuint GLenum GLenum GLsizei GLenum const GLvoid GLfloat GLfloat GLfloat GLfloat GLclampd GLint GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean GLboolean GLboolean GLboolean GLint GLenum GLsizei const GLvoid GLenum GLint GLenum GLint GLint GLsizei GLint GLenum GLint GLint GLint GLint GLsizei GLenum GLsizei const GLuint GLboolean GLenum GLenum GLint GLsizei GLenum GLsizei GLenum const GLvoid GLboolean const GLboolean GLenum const GLdouble * u
Definition: glfuncs.h:88
PMMPTE FORCEINLINE MiAddressToPpe(PVOID Address)
Definition: mm.h:150
#define MI_IS_WRITE_ACCESS(FaultCode)
Definition: mm.h:118
ULONG R3
Definition: ketypes.h:344
#define MM_SHARED_USER_DATA_VA
Definition: mmtypes.h:48
ULONG Esi
Definition: ketypes.h:261
PFN_NUMBER MmAvailablePages
Definition: freelist.c:26
static BOOL Write(PBYTE Address, PBYTE Data, SIZE_T Size)
Definition: vmhorizon.c:15
ULONG Pc
Definition: ketypes.h:349
ULONG Lr
Definition: ketypes.h:347
void DbgBreakPoint()
Definition: mach.c:558
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
#define FASTCALL
Definition: nt_native.h:50
#define MEM_COMMIT
Definition: nt_native.h:1313
union _MMPTE::@2171 u
UCHAR ExecuteDisable
Definition: ketypes.h:877
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
FORCEINLINE VOID MiReferenceUsedPageAndBumpLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1561
MMVAD_FLAGS VadFlags
Definition: mmtypes.h:735
FORCEINLINE VOID MiReleasePfnLock(_In_ KIRQL OldIrql)
Definition: mm.h:882
USHORT PageLocation
Definition: mm.h:295
struct Color Color
ULONG R2
Definition: ketypes.h:343
ULONG Edi
Definition: ketypes.h:260
VOID NTAPI MiDeletePte(IN PMMPTE PointerPte, IN PVOID VirtualAddress, IN PEPROCESS CurrentProcess, IN PMMPTE PrototypePte)
Definition: virtual.c:391
PFN_NUMBER NTAPI MiRemoveZeroPage(IN ULONG Color)
Definition: pfnlist.c:531
PVOID MmNonPagedPoolEnd
Definition: mminit.c:99
uint32_t ULONG_PTR
Definition: typedefs.h:63
ULONG R0
Definition: ketypes.h:341
#define STATUS_ALREADY_COMMITTED
Definition: ntstatus.h:256
USHORT PrototypePte
Definition: mm.h:293
ULONG NtGlobalFlag
Definition: ntddk_ex.h:274
static PMMPTE NTAPI MiCheckVirtualAddress(IN PVOID VirtualAddress, OUT PULONG ProtectCode, OUT PMMVAD *ProtoVad)
Definition: pagfault.c:216
UCHAR KIRQL
Definition: env_spec_w32.h:591
MMPFNENTRY e1
Definition: mm.h:327
#define STATUS_WAIT_1
Definition: ntstatus.h:71
#define MI_MAKE_DIRTY_PAGE(x)
Definition: mm.h:94
PVOID MmSessionBase
Definition: init.c:33
#define STATUS_PAGE_FAULT_GUARD_PAGE
Definition: ntstatus.h:97
#define MM_WRITECOPY
Definition: miarm.h:52
ULONG OwnsSessionWorkingSetShared
Definition: pstypes.h:1157
USHORT CacheAttribute
Definition: mm.h:297
#define MiAddressToPte(x)
Definition: mmx86.c:19
NTSTATUS NTAPI MmSetExecuteOptions(IN ULONG ExecuteOptions)
Definition: pagfault.c:2542
ULONG PFN_NUMBER
Definition: ke.h:8
ULONG Eax
Definition: ketypes.h:256
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
UINT64 Rsi
Definition: ketypes.h:371
PMMPTE LastPteForPagedPool
Definition: mm.h:415
#define FALSE
Definition: types.h:117
FORCEINLINE VOID MI_WRITE_VALID_PTE(IN PMMPTE PointerPte, IN MMPTE TempPte)
Definition: miarm.h:916
#define MI_MAKE_CLEAN_PAGE(x)
Definition: mm.h:95
ULONG_PTR ShareCount
Definition: mm.h:320
FORCEINLINE VOID MI_WRITE_INVALID_PDE(IN PMMPDE PointerPde, IN MMPDE InvalidPde)
Definition: miarm.h:985
#define _WARN(msg)
Definition: debug.h:261
UINT64 Rax
Definition: ketypes.h:318
KAPC_STATE ApcState
Definition: ketypes.h:1668
PKEVENT Event
Definition: mm.h:309
#define MI_SET_PROCESS2(x)
Definition: mm.h:252
ULONG OwnsSessionWorkingSetExclusive
Definition: pstypes.h:1156
BOOLEAN NTAPI KeIsAttachedProcess(VOID)
Definition: procobj.c:690
#define PsGetCurrentProcess
Definition: psfuncs.h:17
FORCEINLINE PFN_NUMBER MiRemoveZeroPageSafe(IN ULONG Color)
Definition: miarm.h:2257
UCHAR ImageDispatchEnable
Definition: ketypes.h:882
MM_PAGED_POOL_INFO MmPagedPoolInfo
Definition: pool.c:25
#define STATUS_PAGE_FAULT_TRANSITION
Definition: ntstatus.h:94
FORCEINLINE VOID MI_MAKE_TRANSITION_PTE(_Out_ PMMPTE NewPte, _In_ PFN_NUMBER Page, _In_ ULONG Protection)
Definition: miarm.h:886
MMSUPPORT MmSystemCacheWs
Definition: init.c:55
smooth NULL
Definition: ftsmooth.c:416
PVOID FORCEINLINE MiPteToAddress(PMMPTE PointerPte)
Definition: mm.h:197
PMMVAD NTAPI MiLocateAddress(IN PVOID VirtualAddress)
Definition: vadnode.c:48
struct _MMPTE * PMMPDE
ULONG ExtendableFile
Definition: mmtypes.h:713
#define FORCEINLINE
Definition: ntbasedef.h:221
#define MiProtoPteToPte(x)
Definition: mm.h:246
void DPRINT(...)
Definition: polytest.cpp:61
FORCEINLINE VOID MiUnlockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1249
#define MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)
Definition: miarm.h:149
#define MI_SET_USAGE(x)
Definition: mm.h:251
ULONG64 Protection
Definition: mmtypes.h:88
VOID NTAPI MiReleaseSystemPtes(IN PMMPTE StartingPte, IN ULONG NumberOfPtes, IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType)
Definition: syspte.c:275
ULONG_PTR StartingVpn
Definition: mmtypes.h:730
UCHAR DisableThunkEmulation
Definition: ketypes.h:879
FORCEINLINE BOOLEAN MiIsAccessAllowed(_In_ ULONG ProtectionMask, _In_ BOOLEAN Write, _In_ BOOLEAN Execute)
Definition: pagfault.c:117
PMMPTE MmSharedUserDataPte
Definition: mminit.c:28
MMVAD_FLAGS2 VadFlags2
Definition: mmtypes.h:743
ULONG_PTR MemCommit
Definition: mmtypes.h:696
FORCEINLINE ULONG_PTR MiDetermineUserGlobalPteMask(IN PVOID PointerPte)
Definition: miarm.h:711
#define NtCurrentProcess()
Definition: nt_native.h:1657
USHORT WriteInProgress
Definition: mm.h:292
#define MEM_EXECUTE_OPTION_ENABLE
Definition: mmtypes.h:74
PMMPDE MmSystemPagePtes
Definition: init.c:41
#define MM_ZERO_ACCESS
Definition: miarm.h:47
unsigned char BOOLEAN
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
union _MMPFN::@1668 u4
struct _MM_SESSION_SPACE * GlobalVirtualAddress
Definition: miarm.h:449
ULONG CurrentProcess
Definition: shell.c:125
LONG NTSTATUS
Definition: precomp.h:26
ULONG_PTR PrivateMemory
Definition: mmtypes.h:699
VOID FASTCALL KeZeroPages(IN PVOID Address, IN ULONG Size)
Definition: stubs.c:82
if(!(yy_init))
Definition: macro.lex.yy.c:717
MMPTE_TRANSITION Trans
Definition: mmtypes.h:220
#define MI_IS_SESSION_PTE(Pte)
Definition: miarm.h:143
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
PVOID DeallocationStack
Definition: compat.h:527
const ULONG64 MmProtectToPteMask[32]
Definition: page.c:32
#define MI_GET_NEXT_PROCESS_COLOR(x)
Definition: miarm.h:212
ULONG64 Valid
Definition: mmtypes.h:150
struct _MMPTE * PMMPTE
#define MI_IS_PFN_DELETED(x)
Definition: miarm.h:164
ULONG64 PageFileLow
Definition: mmtypes.h:87
static const UCHAR Index[8]
Definition: usbohci.c:11
ULONG64 CopyOnWrite
Definition: mmtypes.h:167
#define PAGE_ALIGN(Va)
#define STATUS_PAGE_FAULT_COPY_ON_WRITE
Definition: ntstatus.h:96
#define InterlockedIncrement16
Definition: interlocked.h:206
VOID NTAPI MiZeroPfn(IN PFN_NUMBER PageFrameNumber)
Definition: pagfault.c:462
HARDWARE_PTE_ARMV6 TempPte
Definition: winldr.c:75
#define MM_PROTECT_ACCESS
Definition: miarm.h:55
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define _Inout_
Definition: no_sal2.h:244
MMPTE ValidKernelPte
Definition: init.c:31
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
#define MI_PAGE_WRITE_THROUGH(x)
Definition: mm.h:98
FORCEINLINE VOID KiReleaseProcessLock(IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:652
union _MMVAD::@2475 u2
#define MI_IS_PAGE_LARGE(x)
Definition: mm.h:100
unsigned char UCHAR
Definition: xmlstorage.h:181
UINT64 Rdx
Definition: ketypes.h:320
#define InterlockedExchangeAddSizeT(a, b)
Definition: interlocked.h:196
FORCEINLINE PMMPFN MI_PFN_ELEMENT(IN PFN_NUMBER Pfn)
Definition: miarm.h:1393
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
ULONG64 PageFileHigh
Definition: mmtypes.h:93
#define MM_NOIRQL
Definition: miarm.h:205
#define MM_GUARDPAGE
Definition: miarm.h:61
struct _MMPFN::@1665::@1671 e2
FORCEINLINE VOID KiAcquireProcessLock(IN PKPROCESS Process, IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:643
FORCEINLINE VOID MiDropLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1404
Definition: mm.h:303
#define MI_IS_PAGE_WRITEABLE(x)
Definition: mm.h:102
#define InterlockedExchangePte(PointerPte, Value)
Definition: mm.h:155
PMMPTE FORCEINLINE MiAddressToPxe(PVOID Address)
Definition: mm.h:160
ULONG64 Prototype
Definition: mmtypes.h:89
#define MEM_EXECUTE_OPTION_DISABLE
Definition: mmtypes.h:73
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define PTE_BASE
Definition: mmx86.c:14
ULONG64 Valid
Definition: mmtypes.h:86
_In_ ULONG _In_ BOOLEAN _Must_inspect_result_ PVOID * VirtualAddress
Definition: ndis.h:3773
ULONG OwnsSystemWorkingSetExclusive
Definition: pstypes.h:1154
ULONG Ecx
Definition: ketypes.h:255
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
BOOLEAN MmProtectFreedNonPagedPool
Definition: pool.c:29
ULONG Eip
Definition: ketypes.h:265
LIST_ENTRY ImageList
Definition: miarm.h:468
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:914
NTSTATUS ReadStatus
Definition: mm.h:310
#define InterlockedExchange
Definition: armddk.h:54
UINT64 R11
Definition: ketypes.h:324
#define MI_IS_INSTRUCTION_FETCH(FaultCode)
Definition: mm.h:119
Status
Definition: gdiplustypes.h:24
#define MI_IS_PAGE_TABLE_OR_HYPER_ADDRESS(Address)
Definition: miarm.h:152
ULONG_PTR Long
Definition: mmtypes.h:215
#define FLG_DISABLE_STACK_EXTENSION
Definition: pstypes.h:71
PVOID MmPagedPoolStart
Definition: miarm.h:554
PVOID MmNonPagedPoolStart
Definition: init.c:24
FORCEINLINE VOID MI_MAKE_HARDWARE_PTE_USER(IN PMMPTE NewPte, IN PMMPTE MappingPte, IN ULONG_PTR ProtectionMask, IN PFN_NUMBER PageFrameNumber)
Definition: miarm.h:787
#define _In_
Definition: no_sal2.h:204
NTSTATUS FASTCALL MiCheckPdeForPagedPool(IN PVOID Address)
Definition: pagfault.c:454
PFN_NUMBER NTAPI MiRemoveAnyPage(IN ULONG Color)
Definition: pfnlist.c:475
ULONG_PTR SIZE_T
Definition: typedefs.h:78
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
#define SYSTEM_PD_SIZE
Definition: miarm.h:36
Definition: compat.h:484
FORCEINLINE VOID MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte, IN MMPTE InvalidPte)
Definition: miarm.h:945
#define MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION
Definition: mmtypes.h:75
ULONG Ebx
Definition: ketypes.h:262
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define InterlockedIncrement
Definition: armddk.h:53
PVOID MiSessionViewStart
Definition: init.c:30
PVOID StackBase
Definition: compat.h:372
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:228
ULONG Sp
Definition: ketypes.h:346
ULONG64 Transition
Definition: mmtypes.h:90
union _MMPFN::@1664 u2
static NTSTATUS NTAPI MiCheckForUserStackOverflow(IN PVOID Address, IN PVOID TrapInformation)
Definition: pagfault.c:30
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:947
PMMPTE PteAddress
Definition: mm.h:316
ULONG OwnsProcessWorkingSetShared
Definition: pstypes.h:1153
#define MI_PAGE_DISABLE_CACHE(x)
Definition: mm.h:97
MMPTE_SOFTWARE Soft
Definition: mmtypes.h:219
unsigned int * PULONG
Definition: retypes.h:1
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:737
MMPTE OriginalPte
Definition: mm.h:337
#define STATUS_STACK_OVERFLOW
Definition: ntstatus.h:475
UINT64 Rdi
Definition: ketypes.h:370
MMPDE DemandZeroPde
Definition: init.c:38
PVOID Teb
Definition: ketypes.h:1697
UCHAR ExecuteEnable
Definition: ketypes.h:878
#define MEM_EXECUTE_OPTION_PERMANENT
Definition: mmtypes.h:76
ULONG R1
Definition: ketypes.h:342
#define DPRINT1
Definition: precomp.h:8
KEXECUTE_OPTIONS Flags
Definition: ketypes.h:2020
#define MI_IS_SESSION_IMAGE_ADDRESS(Address)
Definition: miarm.h:137
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
UINT64 Rip
Definition: ketypes.h:379
#define OUT
Definition: typedefs.h:39
ULONG64 ReadOnly
Definition: mmtypes.h:119
FORCEINLINE VOID MiIncrementPageTableReferences(IN PVOID Address)
Definition: miarm.h:1637
CHAR ImageFileName[16]
Definition: pstypes.h:1257
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:565
#define ULONG_PTR
Definition: config.h:101
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:1079
ULONG64 PageFrameNumber
Definition: mmtypes.h:171
PMMPTE FirstPrototypePte
Definition: mmtypes.h:738
#define MM_READONLY
Definition: miarm.h:48
PVOID StackLimit
Definition: compat.h:373
#define MM_PROTECT_SPECIAL
Definition: miarm.h:63
ULONG OwnsProcessWorkingSetExclusive
Definition: pstypes.h:1152
#define STATUS_IN_PAGE_ERROR
Definition: ntstatus.h:229
ULONG_PTR InPageError
Definition: mm.h:349
ULONG MmSizeOfNonPagedPoolInBytes
Definition: init.c:21
FORCEINLINE VOID MiLockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1205
MMPTE MmDecommittedPte
Definition: init.c:46
PMMPTE MiHighestUserPte
Definition: mminit.c:233
static NTSTATUS NTAPI MiResolveDemandZeroFault(IN PVOID Address, IN PMMPTE PointerPte, IN ULONG Protection, IN PEPROCESS Process, IN KIRQL OldIrql)
Definition: pagfault.c:574
UINT64 Rcx
Definition: ketypes.h:319
FORCEINLINE BOOLEAN MI_IS_PHYSICAL_ADDRESS(IN PVOID Address)
Definition: miarm.h:902
UCHAR ExecuteDispatchEnable
Definition: ketypes.h:881
signed int * PLONG
Definition: retypes.h:5
#define STATUS_PAGE_FAULT_DEMAND_ZERO
Definition: ntstatus.h:95
NT_TIB NtTib
Definition: ntddk_ex.h:336
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define PFN_FROM_PTE(v)
Definition: mm.h:88
#define MmSystemRangeStart
Definition: mm.h:31
ULONG EFlags
Definition: ketypes.h:384
MMPTE_PROTOTYPE Proto
Definition: mmtypes.h:218
ULONG_PTR VadType
Definition: mmtypes.h:695
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:94
ULONG Edx
Definition: ketypes.h:254
FORCEINLINE VOID MI_MAKE_HARDWARE_PTE(IN PMMPTE NewPte, IN PMMPTE MappingPte, IN ULONG_PTR ProtectionMask, IN PFN_NUMBER PageFrameNumber)
Definition: miarm.h:771
FORCEINLINE VOID MiUnlockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1134
#define PAGE_READWRITE
Definition: nt_native.h:1304