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