ReactOS  0.4.15-dev-2355-gaf9df93
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_EXECUTE_READWRITE;
323  return NULL;
324  }
326  {
327  /* ReactOS does not have an image list yet, so bail out to failure case */
329  }
330 
331  /* Default case -- failure */
332  *ProtectCode = MM_NOACCESS;
333  return NULL;
334 }
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;
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 
904 
905  /* We must hold the PFN lock */
907 
908  /* Some sanity checks */
909  ASSERT(TempPte.u.Hard.Valid == 0);
910  ASSERT(TempPte.u.Soft.PageFileHigh != 0);
911  ASSERT(TempPte.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED);
912 
913  /* Get any page, it will be overwritten */
916 
917  /* Initialize this PFN */
918  MiInitializePfn(Page, PointerPte, StoreInstruction);
919 
920  /* Sets the PFN as being in IO operation */
921  Pfn1 = MI_PFN_ELEMENT(Page);
922  ASSERT(Pfn1->u1.Event == NULL);
923  ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
924  ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
925  Pfn1->u3.e1.ReadInProgress = 1;
926 
927  /* We must write the PTE now as the PFN lock will be released while performing the IO operation */
928  MI_MAKE_TRANSITION_PTE(&TempPte, Page, Protection);
929 
930  MI_WRITE_INVALID_PTE(PointerPte, TempPte);
931 
932  /* Release the PFN lock while we proceed */
934 
935  /* Do the paging IO */
936  Status = MiReadPageFile(Page, PageFileIndex, PageFileOffset);
937 
938  /* Lock the PFN database again */
940 
941  /* Nobody should have changed that while we were not looking */
942  ASSERT(Pfn1->u3.e1.ReadInProgress == 1);
943  ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
944 
945  if (!NT_SUCCESS(Status))
946  {
947  /* Malheur! */
948  ASSERT(FALSE);
949  Pfn1->u4.InPageError = 1;
950  Pfn1->u1.ReadStatus = Status;
951  }
952 
953  /* And the PTE can finally be valid */
954  MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, Protection, Page);
955  MI_WRITE_VALID_PTE(PointerPte, TempPte);
956 
957  Pfn1->u3.e1.ReadInProgress = 0;
958  /* Did someone start to wait on us while we proceeded ? */
959  if (Pfn1->u1.Event)
960  {
961  /* Tell them we're done */
963  }
964 
965  return Status;
966 }
967 
968 static
969 NTSTATUS
970 NTAPI
972  IN PVOID FaultingAddress,
973  IN PMMPTE PointerPte,
975  IN KIRQL OldIrql,
976  OUT PKEVENT **InPageBlock)
977 {
978  PFN_NUMBER PageFrameIndex;
979  PMMPFN Pfn1;
980  MMPTE TempPte;
981  PMMPTE PointerToPteForProtoPage;
982  DPRINT("Transition fault on 0x%p with PTE 0x%p in process %s\n",
983  FaultingAddress, PointerPte, CurrentProcess->ImageFileName);
984 
985  /* Windowss does this check */
986  ASSERT(*InPageBlock == NULL);
987 
988  /* ARM3 doesn't support this path */
990 
991  /* Capture the PTE and make sure it's in transition format */
992  TempPte = *PointerPte;
993  ASSERT((TempPte.u.Soft.Valid == 0) &&
994  (TempPte.u.Soft.Prototype == 0) &&
995  (TempPte.u.Soft.Transition == 1));
996 
997  /* Get the PFN and the PFN entry */
998  PageFrameIndex = TempPte.u.Trans.PageFrameNumber;
999  DPRINT("Transition PFN: %lx\n", PageFrameIndex);
1000  Pfn1 = MiGetPfnEntry(PageFrameIndex);
1001 
1002  /* One more transition fault! */
1003  InterlockedIncrement(&KeGetCurrentPrcb()->MmTransitionCount);
1004 
1005  /* This is from ARM3 -- Windows normally handles this here */
1006  ASSERT(Pfn1->u4.InPageError == 0);
1007 
1008  /* See if we should wait before terminating the fault */
1009  if ((Pfn1->u3.e1.ReadInProgress == 1)
1010  || ((Pfn1->u3.e1.WriteInProgress == 1) && StoreInstruction))
1011  {
1012  DPRINT1("The page is currently in a page transition !\n");
1013  *InPageBlock = &Pfn1->u1.Event;
1014  if (PointerPte == Pfn1->PteAddress)
1015  {
1016  DPRINT1("And this if for this particular PTE.\n");
1017  /* The PTE will be made valid by the thread serving the fault */
1018  return STATUS_SUCCESS; // FIXME: Maybe something more descriptive
1019  }
1020  }
1021 
1022  /* Windows checks there's some free pages and this isn't an in-page error */
1023  ASSERT(MmAvailablePages > 0);
1024  ASSERT(Pfn1->u4.InPageError == 0);
1025 
1026  /* ReactOS checks for this */
1027  ASSERT(MmAvailablePages > 32);
1028 
1029  /* Was this a transition page in the valid list, or free/zero list? */
1030  if (Pfn1->u3.e1.PageLocation == ActiveAndValid)
1031  {
1032  /* All Windows does here is a bunch of sanity checks */
1033  DPRINT("Transition in active list\n");
1036  ASSERT(Pfn1->u2.ShareCount != 0);
1037  ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
1038  }
1039  else
1040  {
1041  /* Otherwise, the page is removed from its list */
1042  DPRINT("Transition page in free/zero list\n");
1043  MiUnlinkPageFromList(Pfn1);
1045  }
1046 
1047  /* At this point, there should no longer be any in-page errors */
1048  ASSERT(Pfn1->u4.InPageError == 0);
1049 
1050  /* Check if this was a PFN with no more share references */
1051  if (Pfn1->u2.ShareCount == 0) MiDropLockCount(Pfn1);
1052 
1053  /* Bump the share count and make the page valid */
1054  Pfn1->u2.ShareCount++;
1055  Pfn1->u3.e1.PageLocation = ActiveAndValid;
1056 
1057  /* Prototype PTEs are in paged pool, which itself might be in transition */
1058  if (FaultingAddress >= MmSystemRangeStart)
1059  {
1060  /* Check if this is a paged pool PTE in transition state */
1061  PointerToPteForProtoPage = MiAddressToPte(PointerPte);
1062  TempPte = *PointerToPteForProtoPage;
1063  if ((TempPte.u.Hard.Valid == 0) && (TempPte.u.Soft.Transition == 1))
1064  {
1065  /* This isn't yet supported */
1066  DPRINT1("Double transition fault not yet supported\n");
1067  ASSERT(FALSE);
1068  }
1069  }
1070 
1071  /* Build the final PTE */
1072  ASSERT(PointerPte->u.Hard.Valid == 0);
1073  ASSERT(PointerPte->u.Trans.Prototype == 0);
1074  ASSERT(PointerPte->u.Trans.Transition == 1);
1075  TempPte.u.Long = (PointerPte->u.Long & ~0xFFF) |
1076  (MmProtectToPteMask[PointerPte->u.Trans.Protection]) |
1077  MiDetermineUserGlobalPteMask(PointerPte);
1078 
1079  /* Is the PTE writeable? */
1080  if ((Pfn1->u3.e1.Modified) &&
1083  {
1084  /* Make it dirty */
1086  }
1087  else
1088  {
1089  /* Make it clean */
1091  }
1092 
1093  /* Write the valid PTE */
1094  MI_WRITE_VALID_PTE(PointerPte, TempPte);
1095 
1096  /* Return success */
1098 }
1099 
1100 static
1101 NTSTATUS
1102 NTAPI
1104  IN PVOID Address,
1105  IN PMMPTE PointerPte,
1106  IN PMMPTE PointerProtoPte,
1107  IN OUT PMMPFN *OutPfn,
1108  OUT PVOID *PageFileData,
1109  OUT PMMPTE PteValue,
1111  IN KIRQL OldIrql,
1112  IN PVOID TrapInformation)
1113 {
1114  MMPTE TempPte, PteContents;
1115  PMMPFN Pfn1;
1116  PFN_NUMBER PageFrameIndex;
1117  NTSTATUS Status;
1118  PKEVENT* InPageBlock = NULL;
1119  ULONG Protection;
1120 
1121  /* Must be called with an invalid, prototype PTE, with the PFN lock held */
1123  ASSERT(PointerPte->u.Hard.Valid == 0);
1124  ASSERT(PointerPte->u.Soft.Prototype == 1);
1125 
1126  /* Read the prototype PTE and check if it's valid */
1127  TempPte = *PointerProtoPte;
1128  if (TempPte.u.Hard.Valid == 1)
1129  {
1130  /* One more user of this mapped page */
1131  PageFrameIndex = PFN_FROM_PTE(&TempPte);
1132  Pfn1 = MiGetPfnEntry(PageFrameIndex);
1133  Pfn1->u2.ShareCount++;
1134 
1135  /* Call it a transition */
1136  InterlockedIncrement(&KeGetCurrentPrcb()->MmTransitionCount);
1137 
1138  /* Complete the prototype PTE fault -- this will release the PFN lock */
1139  return MiCompleteProtoPteFault(StoreInstruction,
1140  Address,
1141  PointerPte,
1142  PointerProtoPte,
1143  OldIrql,
1144  OutPfn);
1145  }
1146 
1147  /* Make sure there's some protection mask */
1148  if (TempPte.u.Long == 0)
1149  {
1150  /* Release the lock */
1151  DPRINT1("Access on reserved section?\n");
1153  return STATUS_ACCESS_VIOLATION;
1154  }
1155 
1156  /* There is no such thing as a decommitted prototype PTE */
1157  ASSERT(TempPte.u.Long != MmDecommittedPte.u.Long);
1158 
1159  /* Check for access rights on the PTE proper */
1160  PteContents = *PointerPte;
1161  if (PteContents.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED)
1162  {
1163  if (!PteContents.u.Proto.ReadOnly)
1164  {
1165  Protection = TempPte.u.Soft.Protection;
1166  }
1167  else
1168  {
1169  Protection = MM_READONLY;
1170  }
1171  /* Check for page acess in software */
1172  Status = MiAccessCheck(PointerProtoPte,
1173  StoreInstruction,
1174  KernelMode,
1175  TempPte.u.Soft.Protection,
1176  TrapInformation,
1177  TRUE);
1179  }
1180  else
1181  {
1182  Protection = PteContents.u.Soft.Protection;
1183  }
1184 
1185  /* Check for writing copy on write page */
1186  if (((Protection & MM_WRITECOPY) == MM_WRITECOPY) && StoreInstruction)
1187  {
1188  PFN_NUMBER PageFrameIndex, ProtoPageFrameIndex;
1189  ULONG Color;
1190 
1191  /* Resolve the proto fault as if it was a read operation */
1193  Address,
1194  PointerPte,
1195  PointerProtoPte,
1196  OutPfn,
1197  PageFileData,
1198  PteValue,
1199  Process,
1200  OldIrql,
1201  TrapInformation);
1202 
1203  if (!NT_SUCCESS(Status))
1204  {
1205  return Status;
1206  }
1207 
1208  /* Lock again the PFN lock, MiResolveProtoPteFault unlocked it */
1210 
1211  /* And re-read the proto PTE */
1212  TempPte = *PointerProtoPte;
1213  ASSERT(TempPte.u.Hard.Valid == 1);
1214  ProtoPageFrameIndex = PFN_FROM_PTE(&TempPte);
1215 
1218 
1219  /* Get a new page for the private copy */
1220  if (Process > HYDRA_PROCESS)
1222  else
1224 
1225  PageFrameIndex = MiRemoveAnyPage(Color);
1226 
1227  /* Perform the copy */
1228  MiCopyPfn(PageFrameIndex, ProtoPageFrameIndex);
1229 
1230  /* This will drop everything MiResolveProtoPteFault referenced */
1231  MiDeletePte(PointerPte, Address, Process, PointerProtoPte);
1232 
1233  /* Because now we use this */
1234  Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1235  MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
1236 
1237  /* Fix the protection */
1238  Protection &= ~MM_WRITECOPY;
1239  Protection |= MM_READWRITE;
1241  {
1242  /* Build the user PTE */
1243  MI_MAKE_HARDWARE_PTE_USER(&PteContents, PointerPte, Protection, PageFrameIndex);
1244  }
1245  else
1246  {
1247  /* Build the kernel PTE */
1248  MI_MAKE_HARDWARE_PTE(&PteContents, PointerPte, Protection, PageFrameIndex);
1249  }
1250 
1251  /* And finally, write the valid PTE */
1252  MI_WRITE_VALID_PTE(PointerPte, PteContents);
1253 
1254  /* The caller expects us to release the PFN lock */
1256  return Status;
1257  }
1258 
1259  /* Check for clone PTEs */
1260  if (PointerPte <= MiHighestUserPte) ASSERT(Process->CloneRoot == NULL);
1261 
1262  /* We don't support mapped files yet */
1263  ASSERT(TempPte.u.Soft.Prototype == 0);
1264 
1265  /* We might however have transition PTEs */
1266  if (TempPte.u.Soft.Transition == 1)
1267  {
1268  /* Resolve the transition fault */
1269  ASSERT(OldIrql != MM_NOIRQL);
1270  Status = MiResolveTransitionFault(StoreInstruction,
1271  Address,
1272  PointerProtoPte,
1273  Process,
1274  OldIrql,
1275  &InPageBlock);
1277  }
1278  else
1279  {
1280  /* We also don't support paged out pages */
1281  ASSERT(TempPte.u.Soft.PageFileHigh == 0);
1282 
1283  /* Resolve the demand zero fault */
1285  PointerProtoPte,
1286  (ULONG)TempPte.u.Soft.Protection,
1287  Process,
1288  OldIrql);
1290  }
1291 
1292  /* Complete the prototype PTE fault -- this will release the PFN lock */
1293  ASSERT(PointerPte->u.Hard.Valid == 0);
1294  return MiCompleteProtoPteFault(StoreInstruction,
1295  Address,
1296  PointerPte,
1297  PointerProtoPte,
1298  OldIrql,
1299  OutPfn);
1300 }
1301 
1302 NTSTATUS
1303 NTAPI
1305  IN PVOID Address,
1306  IN PMMPTE PointerPte,
1307  IN PMMPTE PointerProtoPte,
1308  IN BOOLEAN Recursive,
1310  IN PVOID TrapInformation,
1311  IN PMMVAD Vad)
1312 {
1313  MMPTE TempPte;
1314  KIRQL OldIrql, LockIrql;
1315  NTSTATUS Status;
1316  PMMPTE SuperProtoPte;
1317  PMMPFN Pfn1, OutPfn = NULL;
1318  PFN_NUMBER PageFrameIndex;
1319  PFN_COUNT PteCount, ProcessedPtes;
1320  DPRINT("ARM3 Page Fault Dispatcher for address: %p in process: %p\n",
1321  Address,
1322  Process);
1323 
1324  /* Make sure the addresses are ok */
1325  ASSERT(PointerPte == MiAddressToPte(Address));
1326 
1327  //
1328  // Make sure APCs are off and we're not at dispatch
1329  //
1331  ASSERT(OldIrql <= APC_LEVEL);
1333 
1334  //
1335  // Grab a copy of the PTE
1336  //
1337  TempPte = *PointerPte;
1338 
1339  /* Do we have a prototype PTE? */
1340  if (PointerProtoPte)
1341  {
1342  /* This should never happen */
1343  ASSERT(!MI_IS_PHYSICAL_ADDRESS(PointerProtoPte));
1344 
1345  /* Check if this is a kernel-mode address */
1346  SuperProtoPte = MiAddressToPte(PointerProtoPte);
1347  if (Address >= MmSystemRangeStart)
1348  {
1349  /* Lock the PFN database */
1350  LockIrql = MiAcquirePfnLock();
1351 
1352  /* Has the PTE been made valid yet? */
1353  if (!SuperProtoPte->u.Hard.Valid)
1354  {
1355  ASSERT(FALSE);
1356  }
1357  else if (PointerPte->u.Hard.Valid == 1)
1358  {
1359  ASSERT(FALSE);
1360  }
1361 
1362  /* Resolve the fault -- this will release the PFN lock */
1364  Address,
1365  PointerPte,
1366  PointerProtoPte,
1367  &OutPfn,
1368  NULL,
1369  NULL,
1370  Process,
1371  LockIrql,
1372  TrapInformation);
1374 
1375  /* Complete this as a transition fault */
1377  ASSERT(OldIrql <= APC_LEVEL);
1379  return Status;
1380  }
1381  else
1382  {
1383  /* We only handle the lookup path */
1384  ASSERT(PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED);
1385 
1386  /* Is there a non-image VAD? */
1387  if ((Vad) &&
1388  (Vad->u.VadFlags.VadType != VadImageMap) &&
1389  !(Vad->u2.VadFlags2.ExtendableFile))
1390  {
1391  /* One day, ReactOS will cluster faults */
1393  DPRINT("Should cluster fault, but won't\n");
1394  }
1395 
1396  /* Only one PTE to handle for now */
1397  PteCount = 1;
1398  ProcessedPtes = 0;
1399 
1400  /* Lock the PFN database */
1401  LockIrql = MiAcquirePfnLock();
1402 
1403  /* We only handle the valid path */
1404  ASSERT(SuperProtoPte->u.Hard.Valid == 1);
1405 
1406  /* Capture the PTE */
1407  TempPte = *PointerProtoPte;
1408 
1409  /* Loop to handle future case of clustered faults */
1410  while (TRUE)
1411  {
1412  /* For our current usage, this should be true */
1413  if (TempPte.u.Hard.Valid == 1)
1414  {
1415  /* Bump the share count on the PTE */
1416  PageFrameIndex = PFN_FROM_PTE(&TempPte);
1417  Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1418  Pfn1->u2.ShareCount++;
1419  }
1420  else if ((TempPte.u.Soft.Prototype == 0) &&
1421  (TempPte.u.Soft.Transition == 1))
1422  {
1423  /* This is a standby page, bring it back from the cache */
1424  PageFrameIndex = TempPte.u.Trans.PageFrameNumber;
1425  DPRINT("oooh, shiny, a soft fault! 0x%lx\n", PageFrameIndex);
1426  Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1428 
1429  /* Should not yet happen in ReactOS */
1430  ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
1431  ASSERT(Pfn1->u4.InPageError == 0);
1432 
1433  /* Get the page */
1434  MiUnlinkPageFromList(Pfn1);
1435 
1436  /* Bump its reference count */
1437  ASSERT(Pfn1->u2.ShareCount == 0);
1438  InterlockedIncrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1439  Pfn1->u2.ShareCount++;
1440 
1441  /* Make it valid again */
1442  /* This looks like another macro.... */
1443  Pfn1->u3.e1.PageLocation = ActiveAndValid;
1444  ASSERT(PointerProtoPte->u.Hard.Valid == 0);
1445  ASSERT(PointerProtoPte->u.Trans.Prototype == 0);
1446  ASSERT(PointerProtoPte->u.Trans.Transition == 1);
1447  TempPte.u.Long = (PointerProtoPte->u.Long & ~0xFFF) |
1448  MmProtectToPteMask[PointerProtoPte->u.Trans.Protection];
1449  TempPte.u.Hard.Valid = 1;
1451 
1452  /* Is the PTE writeable? */
1453  if ((Pfn1->u3.e1.Modified) &&
1456  {
1457  /* Make it dirty */
1459  }
1460  else
1461  {
1462  /* Make it clean */
1464  }
1465 
1466  /* Write the valid PTE */
1467  MI_WRITE_VALID_PTE(PointerProtoPte, TempPte);
1468  ASSERT(PointerPte->u.Hard.Valid == 0);
1469  }
1470  else
1471  {
1472  /* Page is invalid, get out of the loop */
1473  break;
1474  }
1475 
1476  /* One more done, was it the last? */
1477  if (++ProcessedPtes == PteCount)
1478  {
1479  /* Complete the fault */
1481  Address,
1482  PointerPte,
1483  PointerProtoPte,
1484  LockIrql,
1485  &OutPfn);
1486 
1487  /* THIS RELEASES THE PFN LOCK! */
1488  break;
1489  }
1490 
1491  /* No clustered faults yet */
1492  ASSERT(FALSE);
1493  }
1494 
1495  /* Did we resolve the fault? */
1496  if (ProcessedPtes)
1497  {
1498  /* Bump the transition count */
1499  InterlockedExchangeAddSizeT(&KeGetCurrentPrcb()->MmTransitionCount, ProcessedPtes);
1500  ProcessedPtes--;
1501 
1502  /* Loop all the processing we did */
1503  ASSERT(ProcessedPtes == 0);
1504 
1505  /* Complete this as a transition fault */
1507  ASSERT(OldIrql <= APC_LEVEL);
1510  }
1511 
1512  /* We did not -- PFN lock is still held, prepare to resolve prototype PTE fault */
1513  OutPfn = MI_PFN_ELEMENT(SuperProtoPte->u.Hard.PageFrameNumber);
1515  ASSERT(OutPfn->u3.e2.ReferenceCount > 1);
1516  ASSERT(PointerPte->u.Hard.Valid == 0);
1517 
1518  /* Resolve the fault -- this will release the PFN lock */
1520  Address,
1521  PointerPte,
1522  PointerProtoPte,
1523  &OutPfn,
1524  NULL,
1525  NULL,
1526  Process,
1527  LockIrql,
1528  TrapInformation);
1529  //ASSERT(Status != STATUS_ISSUE_PAGING_IO);
1530  //ASSERT(Status != STATUS_REFAULT);
1531  //ASSERT(Status != STATUS_PTE_CHANGED);
1532 
1533  /* Did the routine clean out the PFN or should we? */
1534  if (OutPfn)
1535  {
1536  /* We had a locked PFN, so acquire the PFN lock to dereference it */
1537  ASSERT(PointerProtoPte != NULL);
1539 
1540  /* Dereference the locked PFN */
1542  ASSERT(OutPfn->u3.e2.ReferenceCount >= 1);
1543 
1544  /* And now release the lock */
1546  }
1547 
1548  /* Complete this as a transition fault */
1550  ASSERT(OldIrql <= APC_LEVEL);
1552  return Status;
1553  }
1554  }
1555 
1556  /* Is this a transition PTE */
1557  if (TempPte.u.Soft.Transition)
1558  {
1559  PKEVENT* InPageBlock = NULL;
1560  PKEVENT PreviousPageEvent;
1561  KEVENT CurrentPageEvent;
1562 
1563  /* Lock the PFN database */
1564  LockIrql = MiAcquirePfnLock();
1565 
1566  /* Resolve */
1567  Status = MiResolveTransitionFault(!MI_IS_NOT_PRESENT_FAULT(FaultCode), Address, PointerPte, Process, LockIrql, &InPageBlock);
1568 
1570 
1571  if (InPageBlock != NULL)
1572  {
1573  /* Another thread is reading or writing this page. Put us into the waiting queue. */
1574  KeInitializeEvent(&CurrentPageEvent, NotificationEvent, FALSE);
1575  PreviousPageEvent = *InPageBlock;
1576  *InPageBlock = &CurrentPageEvent;
1577  }
1578 
1579  /* And now release the lock and leave*/
1580  MiReleasePfnLock(LockIrql);
1581 
1582  if (InPageBlock != NULL)
1583  {
1584  KeWaitForSingleObject(&CurrentPageEvent, WrPageIn, KernelMode, FALSE, NULL);
1585 
1586  /* Let's the chain go on */
1587  if (PreviousPageEvent)
1588  {
1589  KeSetEvent(PreviousPageEvent, IO_NO_INCREMENT, FALSE);
1590  }
1591  }
1592 
1594  ASSERT(OldIrql <= APC_LEVEL);
1596  return Status;
1597  }
1598 
1599  /* Should we page the data back in ? */
1600  if (TempPte.u.Soft.PageFileHigh != 0)
1601  {
1602  /* Lock the PFN database */
1603  LockIrql = MiAcquirePfnLock();
1604 
1605  /* Resolve */
1606  Status = MiResolvePageFileFault(!MI_IS_NOT_PRESENT_FAULT(FaultCode), Address, PointerPte, Process, &LockIrql);
1607 
1608  /* And now release the lock and leave*/
1609  MiReleasePfnLock(LockIrql);
1610 
1612  ASSERT(OldIrql <= APC_LEVEL);
1614  return Status;
1615  }
1616 
1617  //
1618  // The PTE must be invalid but not completely empty. It must also not be a
1619  // prototype a transition or a paged-out PTE as those scenarii should've been handled above.
1620  // These are all Windows checks
1621  //
1622  ASSERT(TempPte.u.Hard.Valid == 0);
1623  ASSERT(TempPte.u.Soft.Prototype == 0);
1624  ASSERT(TempPte.u.Soft.Transition == 0);
1625  ASSERT(TempPte.u.Soft.PageFileHigh == 0);
1626  ASSERT(TempPte.u.Long != 0);
1627 
1628  //
1629  // If we got this far, the PTE can only be a demand zero PTE, which is what
1630  // we want. Go handle it!
1631  //
1633  PointerPte,
1634  (ULONG)TempPte.u.Soft.Protection,
1635  Process,
1636  MM_NOIRQL);
1638  if (NT_SUCCESS(Status))
1639  {
1640  //
1641  // Make sure we're returning in a sane state and pass the status down
1642  //
1645  return Status;
1646  }
1647 
1648  //
1649  // Generate an access fault
1650  //
1651  return STATUS_ACCESS_VIOLATION;
1652 }
1653 
1654 NTSTATUS
1655 NTAPI
1657  IN PVOID Address,
1659  IN PVOID TrapInformation)
1660 {
1661  KIRQL OldIrql = KeGetCurrentIrql(), LockIrql;
1662  PMMPTE ProtoPte = NULL;
1663  PMMPTE PointerPte = MiAddressToPte(Address);
1664  PMMPDE PointerPde = MiAddressToPde(Address);
1665 #if (_MI_PAGING_LEVELS >= 3)
1666  PMMPDE PointerPpe = MiAddressToPpe(Address);
1667 #if (_MI_PAGING_LEVELS == 4)
1668  PMMPDE PointerPxe = MiAddressToPxe(Address);
1669 #endif
1670 #endif
1671  MMPTE TempPte;
1672  PETHREAD CurrentThread;
1674  NTSTATUS Status;
1675  PMMSUPPORT WorkingSet;
1676  ULONG ProtectionCode;
1677  PMMVAD Vad = NULL;
1678  PFN_NUMBER PageFrameIndex;
1679  ULONG Color;
1680  BOOLEAN IsSessionAddress;
1681  PMMPFN Pfn1;
1682  DPRINT("ARM3 FAULT AT: %p\n", Address);
1683 
1684  /* Check for page fault on high IRQL */
1685  if (OldIrql > APC_LEVEL)
1686  {
1687 #if (_MI_PAGING_LEVELS < 3)
1688  /* Could be a page table for paged pool, which we'll allow */
1689  if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)) MiSynchronizeSystemPde((PMMPDE)PointerPte);
1691 #endif
1692  /* Check if any of the top-level pages are invalid */
1693  if (
1694 #if (_MI_PAGING_LEVELS == 4)
1695  (PointerPxe->u.Hard.Valid == 0) ||
1696 #endif
1697 #if (_MI_PAGING_LEVELS >= 3)
1698  (PointerPpe->u.Hard.Valid == 0) ||
1699 #endif
1700  (PointerPde->u.Hard.Valid == 0) ||
1701  (PointerPte->u.Hard.Valid == 0))
1702  {
1703  /* This fault is not valid, print out some debugging help */
1704  DbgPrint("MM:***PAGE FAULT AT IRQL > 1 Va %p, IRQL %lx\n",
1705  Address,
1706  OldIrql);
1707  if (TrapInformation)
1708  {
1709  PKTRAP_FRAME TrapFrame = TrapInformation;
1710 #ifdef _M_IX86
1711  DbgPrint("MM:***EIP %p, EFL %p\n", TrapFrame->Eip, TrapFrame->EFlags);
1712  DbgPrint("MM:***EAX %p, ECX %p EDX %p\n", TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
1713  DbgPrint("MM:***EBX %p, ESI %p EDI %p\n", TrapFrame->Ebx, TrapFrame->Esi, TrapFrame->Edi);
1714 #elif defined(_M_AMD64)
1715  DbgPrint("MM:***RIP %p, EFL %p\n", TrapFrame->Rip, TrapFrame->EFlags);
1716  DbgPrint("MM:***RAX %p, RCX %p RDX %p\n", TrapFrame->Rax, TrapFrame->Rcx, TrapFrame->Rdx);
1717  DbgPrint("MM:***RBX %p, RSI %p RDI %p\n", TrapFrame->Rbx, TrapFrame->Rsi, TrapFrame->Rdi);
1718 #elif defined(_M_ARM)
1719  DbgPrint("MM:***PC %p\n", TrapFrame->Pc);
1720  DbgPrint("MM:***R0 %p, R1 %p R2 %p, R3 %p\n", TrapFrame->R0, TrapFrame->R1, TrapFrame->R2, TrapFrame->R3);
1721  DbgPrint("MM:***R11 %p, R12 %p SP %p, LR %p\n", TrapFrame->R11, TrapFrame->R12, TrapFrame->Sp, TrapFrame->Lr);
1722 #endif
1723  }
1724 
1725  /* Tell the trap handler to fail */
1726  return STATUS_IN_PAGE_ERROR | 0x10000000;
1727  }
1728 
1729  /* Not yet implemented in ReactOS */
1730  ASSERT(MI_IS_PAGE_LARGE(PointerPde) == FALSE);
1731  ASSERT((!MI_IS_NOT_PRESENT_FAULT(FaultCode) && MI_IS_PAGE_COPY_ON_WRITE(PointerPte)) == FALSE);
1732 
1733  /* Check if this was a write */
1734  if (MI_IS_WRITE_ACCESS(FaultCode))
1735  {
1736  /* Was it to a read-only page? */
1737  Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1738  if (!(PointerPte->u.Long & PTE_READWRITE) &&
1740  {
1741  /* Crash with distinguished bugcheck code */
1742  KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1743  (ULONG_PTR)Address,
1744  PointerPte->u.Long,
1745  (ULONG_PTR)TrapInformation,
1746  10);
1747  }
1748  }
1749 
1750  /* Nothing is actually wrong */
1751  DPRINT1("Fault at IRQL %u is ok (%p)\n", OldIrql, Address);
1752  return STATUS_SUCCESS;
1753  }
1754 
1755  /* Check for kernel fault address */
1756  if (Address >= MmSystemRangeStart)
1757  {
1758  /* Bail out, if the fault came from user mode */
1759  if (Mode == UserMode) return STATUS_ACCESS_VIOLATION;
1760 
1761 #if (_MI_PAGING_LEVELS == 2)
1762  if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)) MiSynchronizeSystemPde((PMMPDE)PointerPte);
1764 #endif
1765 
1766  /* Check if the higher page table entries are invalid */
1767  if (
1768 #if (_MI_PAGING_LEVELS == 4)
1769  /* AMD64 system, check if PXE is invalid */
1770  (PointerPxe->u.Hard.Valid == 0) ||
1771 #endif
1772 #if (_MI_PAGING_LEVELS >= 3)
1773  /* PAE/AMD64 system, check if PPE is invalid */
1774  (PointerPpe->u.Hard.Valid == 0) ||
1775 #endif
1776  /* Always check if the PDE is valid */
1777  (PointerPde->u.Hard.Valid == 0))
1778  {
1779  /* PXE/PPE/PDE (still) not valid, kill the system */
1780  KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
1781  (ULONG_PTR)Address,
1782  FaultCode,
1783  (ULONG_PTR)TrapInformation,
1784  2);
1785  }
1786 
1787  /* Not handling session faults yet */
1788  IsSessionAddress = MI_IS_SESSION_ADDRESS(Address);
1789 
1790  /* The PDE is valid, so read the PTE */
1791  TempPte = *PointerPte;
1792  if (TempPte.u.Hard.Valid == 1)
1793  {
1794  /* Check if this was system space or session space */
1795  if (!IsSessionAddress)
1796  {
1797  /* Check if the PTE is still valid under PFN lock */
1799  TempPte = *PointerPte;
1800  if (TempPte.u.Hard.Valid)
1801  {
1802  /* Check if this was a write */
1803  if (MI_IS_WRITE_ACCESS(FaultCode))
1804  {
1805  /* Was it to a read-only page? */
1806  Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1807  if (!(PointerPte->u.Long & PTE_READWRITE) &&
1809  {
1810  /* Crash with distinguished bugcheck code */
1811  KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1812  (ULONG_PTR)Address,
1813  PointerPte->u.Long,
1814  (ULONG_PTR)TrapInformation,
1815  11);
1816  }
1817  }
1818 
1819  /* Check for execution of non-executable memory */
1820  if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
1822  {
1823  KeBugCheckEx(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY,
1824  (ULONG_PTR)Address,
1825  (ULONG_PTR)TempPte.u.Long,
1826  (ULONG_PTR)TrapInformation,
1827  1);
1828  }
1829  }
1830 
1831  /* Release PFN lock and return all good */
1833  return STATUS_SUCCESS;
1834  }
1835  }
1836 #if (_MI_PAGING_LEVELS == 2)
1837  /* Check if this was a session PTE that needs to remap the session PDE */
1839  {
1840  /* Do the remapping */
1841  Status = MiCheckPdeForSessionSpace(Address);
1842  if (!NT_SUCCESS(Status))
1843  {
1844  /* It failed, this address is invalid */
1845  KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
1846  (ULONG_PTR)Address,
1847  FaultCode,
1848  (ULONG_PTR)TrapInformation,
1849  6);
1850  }
1851  }
1852 #else
1853 
1854 _WARN("Session space stuff is not implemented yet!")
1855 
1856 #endif
1857 
1858  /* Check for a fault on the page table or hyperspace */
1860  {
1861 #if (_MI_PAGING_LEVELS < 3)
1862  /* Windows does this check but I don't understand why -- it's done above! */
1864 #endif
1865  /* Handle this as a user mode fault */
1866  goto UserFault;
1867  }
1868 
1869  /* Get the current thread */
1870  CurrentThread = PsGetCurrentThread();
1871 
1872  /* What kind of address is this */
1873  if (!IsSessionAddress)
1874  {
1875  /* Use the system working set */
1876  WorkingSet = &MmSystemCacheWs;
1877  CurrentProcess = NULL;
1878 
1879  /* Make sure we don't have a recursive working set lock */
1880  if ((CurrentThread->OwnsProcessWorkingSetExclusive) ||
1881  (CurrentThread->OwnsProcessWorkingSetShared) ||
1882  (CurrentThread->OwnsSystemWorkingSetExclusive) ||
1883  (CurrentThread->OwnsSystemWorkingSetShared) ||
1884  (CurrentThread->OwnsSessionWorkingSetExclusive) ||
1885  (CurrentThread->OwnsSessionWorkingSetShared))
1886  {
1887  /* Fail */
1888  return STATUS_IN_PAGE_ERROR | 0x10000000;
1889  }
1890  }
1891  else
1892  {
1893  /* Use the session process and working set */
1895  WorkingSet = &MmSessionSpace->GlobalVirtualAddress->Vm;
1896 
1897  /* Make sure we don't have a recursive working set lock */
1898  if ((CurrentThread->OwnsSessionWorkingSetExclusive) ||
1899  (CurrentThread->OwnsSessionWorkingSetShared))
1900  {
1901  /* Fail */
1902  return STATUS_IN_PAGE_ERROR | 0x10000000;
1903  }
1904  }
1905 
1906  /* Acquire the working set lock */
1907  KeRaiseIrql(APC_LEVEL, &LockIrql);
1908  MiLockWorkingSet(CurrentThread, WorkingSet);
1909 
1910  /* Re-read PTE now that we own the lock */
1911  TempPte = *PointerPte;
1912  if (TempPte.u.Hard.Valid == 1)
1913  {
1914  /* Check if this was a write */
1915  if (MI_IS_WRITE_ACCESS(FaultCode))
1916  {
1917  /* Was it to a read-only page that is not copy on write? */
1918  Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1919  if (!(TempPte.u.Long & PTE_READWRITE) &&
1920  !(Pfn1->OriginalPte.u.Soft.Protection & MM_READWRITE) &&
1922  {
1923  /* Case not yet handled */
1924  ASSERT(!IsSessionAddress);
1925 
1926  /* Crash with distinguished bugcheck code */
1927  KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1928  (ULONG_PTR)Address,
1929  TempPte.u.Long,
1930  (ULONG_PTR)TrapInformation,
1931  12);
1932  }
1933  }
1934 
1935  /* Check for execution of non-executable memory */
1936  if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
1938  {
1939  KeBugCheckEx(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY,
1940  (ULONG_PTR)Address,
1941  (ULONG_PTR)TempPte.u.Long,
1942  (ULONG_PTR)TrapInformation,
1943  2);
1944  }
1945 
1946  /* Check for read-only write in session space */
1947  if ((IsSessionAddress) &&
1948  MI_IS_WRITE_ACCESS(FaultCode) &&
1950  {
1951  /* Sanity check */
1953 
1954  /* Was this COW? */
1956  {
1957  /* Then this is not allowed */
1958  KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1959  (ULONG_PTR)Address,
1960  (ULONG_PTR)TempPte.u.Long,
1961  (ULONG_PTR)TrapInformation,
1962  13);
1963  }
1964 
1965  /* Otherwise, handle COW */
1966  ASSERT(FALSE);
1967  }
1968 
1969  /* Release the working set */
1970  MiUnlockWorkingSet(CurrentThread, WorkingSet);
1971  KeLowerIrql(LockIrql);
1972 
1973  /* Otherwise, the PDE was probably invalid, and all is good now */
1974  return STATUS_SUCCESS;
1975  }
1976 
1977  /* Check one kind of prototype PTE */
1978  if (TempPte.u.Soft.Prototype)
1979  {
1980  /* Make sure protected pool is on, and that this is a pool address */
1982  (((Address >= MmNonPagedPoolStart) &&
1986  (Address < MmNonPagedPoolEnd))))
1987  {
1988  /* Bad boy, bad boy, whatcha gonna do, whatcha gonna do when ARM3 comes for you! */
1989  KeBugCheckEx(DRIVER_CAUGHT_MODIFYING_FREED_POOL,
1990  (ULONG_PTR)Address,
1991  FaultCode,
1992  Mode,
1993  4);
1994  }
1995 
1996  /* Get the prototype PTE! */
1997  ProtoPte = MiProtoPteToPte(&TempPte);
1998 
1999  /* Do we need to locate the prototype PTE in session space? */
2000  if ((IsSessionAddress) &&
2001  (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED))
2002  {
2003  /* Yep, go find it as well as the VAD for it */
2004  ProtoPte = MiCheckVirtualAddress(Address,
2005  &ProtectionCode,
2006  &Vad);
2007  ASSERT(ProtoPte != NULL);
2008  }
2009  }
2010  else
2011  {
2012  /* We don't implement transition PTEs */
2013  ASSERT(TempPte.u.Soft.Transition == 0);
2014 
2015  /* Check for no-access PTE */
2016  if (TempPte.u.Soft.Protection == MM_NOACCESS)
2017  {
2018  /* Bugcheck the system! */
2019  KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
2020  (ULONG_PTR)Address,
2021  FaultCode,
2022  (ULONG_PTR)TrapInformation,
2023  1);
2024  }
2025 
2026  /* Check for no protecton at all */
2027  if (TempPte.u.Soft.Protection == MM_ZERO_ACCESS)
2028  {
2029  /* Bugcheck the system! */
2030  KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
2031  (ULONG_PTR)Address,
2032  FaultCode,
2033  (ULONG_PTR)TrapInformation,
2034  0);
2035  }
2036  }
2037 
2038  /* Check for demand page */
2039  if (MI_IS_WRITE_ACCESS(FaultCode) &&
2040  !(ProtoPte) &&
2041  !(IsSessionAddress) &&
2042  !(TempPte.u.Hard.Valid))
2043  {
2044  /* Get the protection code */
2045  ASSERT(TempPte.u.Soft.Transition == 0);
2046  if (!(TempPte.u.Soft.Protection & MM_READWRITE))
2047  {
2048  /* Bugcheck the system! */
2049  KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
2050  (ULONG_PTR)Address,
2051  TempPte.u.Long,
2052  (ULONG_PTR)TrapInformation,
2053  14);
2054  }
2055  }
2056 
2057  /* Now do the real fault handling */
2058  Status = MiDispatchFault(FaultCode,
2059  Address,
2060  PointerPte,
2061  ProtoPte,
2062  FALSE,
2064  TrapInformation,
2065  NULL);
2066 
2067  /* Release the working set */
2069  MiUnlockWorkingSet(CurrentThread, WorkingSet);
2070  KeLowerIrql(LockIrql);
2071 
2072  /* We are done! */
2073  DPRINT("Fault resolved with status: %lx\n", Status);
2074  return Status;
2075  }
2076 
2077  /* This is a user fault */
2078 UserFault:
2079  CurrentThread = PsGetCurrentThread();
2080  CurrentProcess = (PEPROCESS)CurrentThread->Tcb.ApcState.Process;
2081 
2082  /* Lock the working set */
2083  MiLockProcessWorkingSet(CurrentProcess, CurrentThread);
2084 
2085  ProtectionCode = MM_INVALID_PROTECTION;
2086 
2087 #if (_MI_PAGING_LEVELS == 4)
2088  /* Check if the PXE is valid */
2089  if (PointerPxe->u.Hard.Valid == 0)
2090  {
2091  /* Right now, we only handle scenarios where the PXE is totally empty */
2092  ASSERT(PointerPxe->u.Long == 0);
2093 
2094  /* This is only possible for user mode addresses! */
2095  ASSERT(PointerPte <= MiHighestUserPte);
2096 
2097  /* Check if we have a VAD */
2098  MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2099  if (ProtectionCode == MM_NOACCESS)
2100  {
2101  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2102  return STATUS_ACCESS_VIOLATION;
2103  }
2104 
2105  /* Resolve a demand zero fault */
2106  MiResolveDemandZeroFault(PointerPpe,
2107  PointerPxe,
2110  MM_NOIRQL);
2111 
2112  /* We should come back with a valid PXE */
2113  ASSERT(PointerPxe->u.Hard.Valid == 1);
2114  }
2115 #endif
2116 
2117 #if (_MI_PAGING_LEVELS >= 3)
2118  /* Check if the PPE is valid */
2119  if (PointerPpe->u.Hard.Valid == 0)
2120  {
2121  /* Right now, we only handle scenarios where the PPE is totally empty */
2122  ASSERT(PointerPpe->u.Long == 0);
2123 
2124  /* This is only possible for user mode addresses! */
2125  ASSERT(PointerPte <= MiHighestUserPte);
2126 
2127  /* Check if we have a VAD, unless we did this already */
2128  if (ProtectionCode == MM_INVALID_PROTECTION)
2129  {
2130  MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2131  }
2132 
2133  if (ProtectionCode == MM_NOACCESS)
2134  {
2135  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2136  return STATUS_ACCESS_VIOLATION;
2137  }
2138 
2139  /* Resolve a demand zero fault */
2140  MiResolveDemandZeroFault(PointerPde,
2141  PointerPpe,
2144  MM_NOIRQL);
2145 
2146  /* We should come back with a valid PPE */
2147  ASSERT(PointerPpe->u.Hard.Valid == 1);
2148  }
2149 #endif
2150 
2151  /* Check if the PDE is invalid */
2152  if (PointerPde->u.Hard.Valid == 0)
2153  {
2154  /* Right now, we only handle scenarios where the PDE is totally empty */
2155  ASSERT(PointerPde->u.Long == 0);
2156 
2157  /* And go dispatch the fault on the PDE. This should handle the demand-zero */
2158 #if MI_TRACE_PFNS
2159  UserPdeFault = TRUE;
2160 #endif
2161  /* Check if we have a VAD, unless we did this already */
2162  if (ProtectionCode == MM_INVALID_PROTECTION)
2163  {
2164  MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2165  }
2166 
2167  if (ProtectionCode == MM_NOACCESS)
2168  {
2169 #if (_MI_PAGING_LEVELS == 2)
2170  /* Could be a page table for paged pool */
2172 #endif
2173  /* Has the code above changed anything -- is this now a valid PTE? */
2174  Status = (PointerPde->u.Hard.Valid == 1) ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
2175 
2176  /* Either this was a bogus VA or we've fixed up a paged pool PDE */
2177  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2178  return Status;
2179  }
2180 
2181  /* Resolve a demand zero fault */
2182  MiResolveDemandZeroFault(PointerPte,
2183  PointerPde,
2186  MM_NOIRQL);
2187 #if MI_TRACE_PFNS
2188  UserPdeFault = FALSE;
2189 #endif
2190  /* We should come back with APCs enabled, and with a valid PDE */
2192  ASSERT(PointerPde->u.Hard.Valid == 1);
2193  }
2194  else
2195  {
2196  /* Not yet implemented in ReactOS */
2197  ASSERT(MI_IS_PAGE_LARGE(PointerPde) == FALSE);
2198  }
2199 
2200  /* Now capture the PTE. */
2201  TempPte = *PointerPte;
2202 
2203  /* Check if the PTE is valid */
2204  if (TempPte.u.Hard.Valid)
2205  {
2206  /* Check if this is a write on a readonly PTE */
2207  if (MI_IS_WRITE_ACCESS(FaultCode))
2208  {
2209  /* Is this a copy on write PTE? */
2211  {
2212  PFN_NUMBER PageFrameIndex, OldPageFrameIndex;
2213  PMMPFN Pfn1;
2214 
2215  LockIrql = MiAcquirePfnLock();
2216 
2217  ASSERT(MmAvailablePages > 0);
2218 
2221 
2222  /* Allocate a new page and copy it */
2224  OldPageFrameIndex = PFN_FROM_PTE(&TempPte);
2225 
2226  MiCopyPfn(PageFrameIndex, OldPageFrameIndex);
2227 
2228  /* Dereference whatever this PTE is referencing */
2229  Pfn1 = MI_PFN_ELEMENT(OldPageFrameIndex);
2230  ASSERT(Pfn1->u3.e1.PrototypePte == 1);
2231  ASSERT(!MI_IS_PFN_DELETED(Pfn1));
2232  ProtoPte = Pfn1->PteAddress;
2233  MiDeletePte(PointerPte, Address, CurrentProcess, ProtoPte);
2234 
2235  /* And make a new shiny one with our page */
2236  MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
2237  TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
2238  TempPte.u.Hard.Write = 1;
2239  TempPte.u.Hard.CopyOnWrite = 0;
2240 
2241  MI_WRITE_VALID_PTE(PointerPte, TempPte);
2242 
2243  MiReleasePfnLock(LockIrql);
2244 
2245  /* Return the status */
2246  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2248  }
2249 
2250  /* Is this a read-only PTE? */
2252  {
2253  /* Return the status */
2254  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2255  return STATUS_ACCESS_VIOLATION;
2256  }
2257  }
2258 
2259  /* Check for execution of non-executable memory */
2260  if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
2262  {
2263  /* Return the status */
2264  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2265  return STATUS_ACCESS_VIOLATION;
2266  }
2267 
2268  /* The fault has already been resolved by a different thread */
2269  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2270  return STATUS_SUCCESS;
2271  }
2272 
2273  /* Quick check for demand-zero */
2274  if ((TempPte.u.Long == (MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS)) ||
2276  {
2277  /* Resolve the fault */
2279  PointerPte,
2280  TempPte.u.Soft.Protection,
2282  MM_NOIRQL);
2283 
2284  /* Return the status */
2285  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2287  }
2288 
2289  /* Check for zero PTE */
2290  if (TempPte.u.Long == 0)
2291  {
2292  /* Check if this address range belongs to a valid allocation (VAD) */
2293  ProtoPte = MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2294  if (ProtectionCode == MM_NOACCESS)
2295  {
2296 #if (_MI_PAGING_LEVELS == 2)
2297  /* Could be a page table for paged pool */
2299 #endif
2300  /* Has the code above changed anything -- is this now a valid PTE? */
2301  Status = (PointerPte->u.Hard.Valid == 1) ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
2302 
2303  /* Either this was a bogus VA or we've fixed up a paged pool PDE */
2304  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2305  return Status;
2306  }
2307 
2308  /*
2309  * Check if this is a real user-mode address or actually a kernel-mode
2310  * page table for a user mode address
2311  */
2313  {
2314  /* Add an additional page table reference */
2316  }
2317 
2318  /* Is this a guard page? */
2319  if ((ProtectionCode & MM_PROTECT_SPECIAL) == MM_GUARDPAGE)
2320  {
2321  /* The VAD protection cannot be MM_DECOMMIT! */
2322  ASSERT(ProtectionCode != MM_DECOMMIT);
2323 
2324  /* Remove the bit */
2325  TempPte.u.Soft.Protection = ProtectionCode & ~MM_GUARDPAGE;
2326  MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2327 
2328  /* Not supported */
2329  ASSERT(ProtoPte == NULL);
2330  ASSERT(CurrentThread->ApcNeeded == 0);
2331 
2332  /* Drop the working set lock */
2333  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2335 
2336  /* Handle stack expansion */
2337  return MiCheckForUserStackOverflow(Address, TrapInformation);
2338  }
2339 
2340  /* Did we get a prototype PTE back? */
2341  if (!ProtoPte)
2342  {
2343  /* Is this PTE actually part of the PDE-PTE self-mapping directory? */
2344  if (PointerPde == MiAddressToPde(PTE_BASE))
2345  {
2346  /* Then it's really a demand-zero PDE (on behalf of user-mode) */
2347 #ifdef _M_ARM
2348  _WARN("This is probably completely broken!");
2350 #else
2351  MI_WRITE_INVALID_PDE(PointerPte, DemandZeroPde);
2352 #endif
2353  }
2354  else
2355  {
2356  /* No, create a new PTE. First, write the protection */
2357  TempPte.u.Soft.Protection = ProtectionCode;
2358  MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2359  }
2360 
2361  /* Lock the PFN database since we're going to grab a page */
2363 
2364  /* Make sure we have enough pages */
2365  ASSERT(MmAvailablePages >= 32);
2366 
2367  /* Try to get a zero page */
2369  MI_SET_PROCESS2(CurrentProcess->ImageFileName);
2371  PageFrameIndex = MiRemoveZeroPageSafe(Color);
2372  if (!PageFrameIndex)
2373  {
2374  /* Grab a page out of there. Later we should grab a colored zero page */
2375  PageFrameIndex = MiRemoveAnyPage(Color);
2376  ASSERT(PageFrameIndex);
2377 
2378  /* Release the lock since we need to do some zeroing */
2380 
2381  /* Zero out the page, since it's for user-mode */
2382  MiZeroPfn(PageFrameIndex);
2383 
2384  /* Grab the lock again so we can initialize the PFN entry */
2386  }
2387 
2388  /* Initialize the PFN entry now */
2389  MiInitializePfn(PageFrameIndex, PointerPte, 1);
2390 
2391  /* Increment the count of pages in the process */
2392  CurrentProcess->NumberOfPrivatePages++;
2393 
2394  /* One more demand-zero fault */
2395  KeGetCurrentPrcb()->MmDemandZeroCount++;
2396 
2397  /* And we're done with the lock */
2399 
2400  /* Fault on user PDE, or fault on user PTE? */
2401  if (PointerPte <= MiHighestUserPte)
2402  {
2403  /* User fault, build a user PTE */
2405  PointerPte,
2406  PointerPte->u.Soft.Protection,
2407  PageFrameIndex);
2408  }
2409  else
2410  {
2411  /* This is a user-mode PDE, create a kernel PTE for it */
2413  PointerPte,
2414  PointerPte->u.Soft.Protection,
2415  PageFrameIndex);
2416  }
2417 
2418  /* Write the dirty bit for writeable pages */
2420 
2421  /* And now write down the PTE, making the address valid */
2422  MI_WRITE_VALID_PTE(PointerPte, TempPte);
2423  Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
2424  ASSERT(Pfn1->u1.Event == NULL);
2425 
2426  /* Demand zero */
2428  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2430  }
2431 
2432  /* We should have a valid protection here */
2433  ASSERT(ProtectionCode != 0x100);
2434 
2435  /* Write the prototype PTE */
2437  TempPte.u.Soft.Protection = ProtectionCode;
2438  ASSERT(TempPte.u.Long != 0);
2439  MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2440  }
2441  else
2442  {
2443  /* Get the protection code and check if this is a proto PTE */
2444  ProtectionCode = (ULONG)TempPte.u.Soft.Protection;
2445  if (TempPte.u.Soft.Prototype)
2446  {
2447  /* Do we need to go find the real PTE? */
2448  if (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
2449  {
2450  /* Get the prototype pte and VAD for it */
2451  ProtoPte = MiCheckVirtualAddress(Address,
2452  &ProtectionCode,
2453  &Vad);
2454  if (!ProtoPte)
2455  {
2457  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2458  return STATUS_ACCESS_VIOLATION;
2459  }
2460  }
2461  else
2462  {
2463  /* Get the prototype PTE! */
2464  ProtoPte = MiProtoPteToPte(&TempPte);
2465 
2466  /* Is it read-only */
2467  if (TempPte.u.Proto.ReadOnly)
2468  {
2469  /* Set read-only code */
2470  ProtectionCode = MM_READONLY;
2471  }
2472  else
2473  {
2474  /* Set unknown protection */
2475  ProtectionCode = 0x100;
2476  ASSERT(CurrentProcess->CloneRoot != NULL);
2477  }
2478  }
2479  }
2480  }
2481 
2482  /* Do we have a valid protection code? */
2483  if (ProtectionCode != 0x100)
2484  {
2485  /* Run a software access check first, including to detect guard pages */
2486  Status = MiAccessCheck(PointerPte,
2487  !MI_IS_NOT_PRESENT_FAULT(FaultCode),
2488  Mode,
2489  ProtectionCode,
2490  TrapInformation,
2491  FALSE);
2492  if (Status != STATUS_SUCCESS)
2493  {
2494  /* Not supported */
2495  ASSERT(CurrentThread->ApcNeeded == 0);
2496 
2497  /* Drop the working set lock */
2498  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2500 
2501  /* Did we hit a guard page? */
2503  {
2504  /* Handle stack expansion */
2505  return MiCheckForUserStackOverflow(Address, TrapInformation);
2506  }
2507 
2508  /* Otherwise, fail back to the caller directly */
2509  return Status;
2510  }
2511  }
2512 
2513  /* Dispatch the fault */
2514  Status = MiDispatchFault(FaultCode,
2515  Address,
2516  PointerPte,
2517  ProtoPte,
2518  FALSE,
2520  TrapInformation,
2521  Vad);
2522 
2523  /* Return the status */
2525  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2526  return Status;
2527 }
2528 
2529 NTSTATUS
2530 NTAPI
2532 {
2535 
2536  *ExecuteOptions = 0;
2537 
2538  if (CurrentProcess->Flags.ExecuteDisable)
2539  {
2540  *ExecuteOptions |= MEM_EXECUTE_OPTION_DISABLE;
2541  }
2542 
2543  if (CurrentProcess->Flags.ExecuteEnable)
2544  {
2545  *ExecuteOptions |= MEM_EXECUTE_OPTION_ENABLE;
2546  }
2547 
2548  if (CurrentProcess->Flags.DisableThunkEmulation)
2549  {
2550  *ExecuteOptions |= MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION;
2551  }
2552 
2553  if (CurrentProcess->Flags.Permanent)
2554  {
2555  *ExecuteOptions |= MEM_EXECUTE_OPTION_PERMANENT;
2556  }
2557 
2558  if (CurrentProcess->Flags.ExecuteDispatchEnable)
2559  {
2560  *ExecuteOptions |= MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE;
2561  }
2562 
2563  if (CurrentProcess->Flags.ImageDispatchEnable)
2564  {
2565  *ExecuteOptions |= MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE;
2566  }
2567 
2568  return STATUS_SUCCESS;
2569 }
2570 
2571 NTSTATUS
2572 NTAPI
2574 {
2576  KLOCK_QUEUE_HANDLE ProcessLock;
2579 
2580  /* Only accept valid flags */
2581  if (ExecuteOptions & ~MEM_EXECUTE_OPTION_VALID_FLAGS)
2582  {
2583  /* Fail */
2584  DPRINT1("Invalid no-execute options\n");
2585  return STATUS_INVALID_PARAMETER;
2586  }
2587 
2588  /* Change the NX state in the process lock */
2590 
2591  /* Don't change anything if the permanent flag was set */
2592  if (!CurrentProcess->Flags.Permanent)
2593  {
2594  /* Start by assuming it's not disabled */
2595  CurrentProcess->Flags.ExecuteDisable = FALSE;
2596 
2597  /* Now process each flag and turn the equivalent bit on */
2598  if (ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE)
2599  {
2600  CurrentProcess->Flags.ExecuteDisable = TRUE;
2601  }
2602  if (ExecuteOptions & MEM_EXECUTE_OPTION_ENABLE)
2603  {
2604  CurrentProcess->Flags.ExecuteEnable = TRUE;
2605  }
2606  if (ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)
2607  {
2608  CurrentProcess->Flags.DisableThunkEmulation = TRUE;
2609  }
2610  if (ExecuteOptions & MEM_EXECUTE_OPTION_PERMANENT)
2611  {
2612  CurrentProcess->Flags.Permanent = TRUE;
2613  }
2614  if (ExecuteOptions & MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE)
2615  {
2616  CurrentProcess->Flags.ExecuteDispatchEnable = TRUE;
2617  }
2618  if (ExecuteOptions & MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE)
2619  {
2620  CurrentProcess->Flags.ImageDispatchEnable = TRUE;
2621  }
2622 
2623  /* These are turned on by default if no-execution is also eanbled */
2624  if (CurrentProcess->Flags.ExecuteEnable)
2625  {
2626  CurrentProcess->Flags.ExecuteDispatchEnable = TRUE;
2627  CurrentProcess->Flags.ImageDispatchEnable = TRUE;
2628  }
2629 
2630  /* All good */
2632  }
2633 
2634  /* Release the lock and return status */
2635  KiReleaseProcessLock(&ProcessLock);
2636  return Status;
2637 }
2638 
2639 /* 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:173
ULONG R12
Definition: ketypes.h:363
#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:1656
VOID NTAPI MiInitializePfn(IN PFN_NUMBER PageFrameIndex, IN PMMPTE PointerPte, IN BOOLEAN Modified)
Definition: pfnlist.c:968
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
#define IN
Definition: typedefs.h:39
#define MM_INVALID_PROTECTION
Definition: miarm.h:63
MMPTE PrototypePte
Definition: init.c:40
#define _MI_PAGING_LEVELS
Definition: mm.h:6
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
UINT64 Rbx
Definition: ketypes.h:369
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
PPEB Peb
Definition: dllmain.c:27
FORCEINLINE VOID KiAcquireProcessLockRaiseToSynch(IN PKPROCESS Process, IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:646
#define MI_IS_NOT_PRESENT_FAULT(FaultCode)
Definition: mm.h:121
#define MI_PAGE_WRITE_COMBINED(x)
Definition: mm.h:103
#define MI_ASSERT_PFN_LOCK_HELD()
Definition: mm.h:954
#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
union _MMPTE::@2304 u
#define DbgPrint
Definition: loader.c:25
#define MI_MAKE_ACCESSED_PAGE(x)
Definition: mm.h:100
ULONG OwnsSystemWorkingSetShared
Definition: pstypes.h:1183
signed short * PSHORT
Definition: retypes.h:6
PMMPDE PageTables
Definition: miarm.h:513
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:1304
ULONG PFN_COUNT
Definition: mmtypes.h:102
#define TRUE
Definition: types.h:120
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:329
#define MI_IS_SESSION_ADDRESS(Address)
Definition: miarm.h:167
#define HYDRA_PROCESS
Definition: pagfault.c:20
#define PAGE_GUARD
Definition: nt_native.h:1310
struct _MMPFN::@1778::@1784 e2
#define MM_DECOMMIT
Definition: miarm.h:60
#define MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE
Definition: mmtypes.h:77
LONG NTSTATUS
Definition: precomp.h:26
FORCEINLINE PMMPTE MiAddressToPpe(PVOID Address)
Definition: mm.h:154
NTSTATUS NTAPI MiReadPageFile(_In_ PFN_NUMBER Page, _In_ ULONG PageFileIndex, _In_ ULONG_PTR PageFileOffset)
Definition: pagefile.c:194
KTHREAD Tcb
Definition: pstypes.h:1062
#define MEM_EXECUTE_OPTION_VALID_FLAGS
Definition: mmtypes.h:79
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1075
#define MI_IS_PAGE_EXECUTABLE(x)
Definition: mm.h:111
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:182
#define MI_GET_NEXT_COLOR()
Definition: miarm.h:238
#define MI_PTE_LOOKUP_NEEDED
Definition: miarm.h:247
#define MM_NOACCESS
Definition: miarm.h:61
HARDWARE_PDE_ARMV6 TempPde
Definition: winldr.c:78
FORCEINLINE KIRQL MiAcquirePfnLock(VOID)
Definition: mm.h:919
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:328
PVOID MmPagedPoolEnd
Definition: init.c:26
NTSTATUS NTAPI MmGetExecuteOptions(IN PULONG ExecuteOptions)
Definition: pagfault.c:2531
#define MM_PTE_SOFTWARE_PROTECTION_BITS
Definition: mm.h:75
ULONG_PTR Protection
Definition: mmtypes.h:693
PVOID MiSessionSpaceWs
Definition: mminit.c:130
#define MI_IS_PAGE_COPY_ON_WRITE(x)
Definition: mm.h:110
#define MI_IS_WRITE_ACCESS(FaultCode)
Definition: mm.h:122
ULONG R3
Definition: ketypes.h:362
#define MM_SHARED_USER_DATA_VA
Definition: mmtypes.h:48
ULONG Esi
Definition: ketypes.h:263
if(dx==0 &&dy==0)
Definition: linetemp.h:174
PFN_NUMBER MmAvailablePages
Definition: freelist.c:26
union _MMVAD::@2565 u2
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
union _MMPFN::@1781 u4
_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:731
FORCEINLINE VOID MiReleasePfnLock(_In_ KIRQL OldIrql)
Definition: mm.h:926
union _MMPFN::@1778 u3
USHORT PageLocation
Definition: mm.h:333
struct Color Color
ULONG R2
Definition: ketypes.h:361
ULONG Edi
Definition: ketypes.h:262
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:65
ULONG R0
Definition: ketypes.h:359
#define STATUS_ALREADY_COMMITTED
Definition: ntstatus.h:270
USHORT PrototypePte
Definition: mm.h:331
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:365
#define STATUS_WAIT_1
Definition: ntstatus.h:71
#define MI_MAKE_DIRTY_PAGE(x)
Definition: mm.h:98
PVOID MmSessionBase
Definition: init.c:33
#define STATUS_PAGE_FAULT_GUARD_PAGE
Definition: ntstatus.h:97
#define MM_WRITECOPY
Definition: miarm.h:44
ULONG OwnsSessionWorkingSetShared
Definition: pstypes.h:1185
USHORT CacheAttribute
Definition: mm.h:335
#define MiAddressToPte(x)
Definition: mmx86.c:19
NTSTATUS NTAPI MmSetExecuteOptions(IN ULONG ExecuteOptions)
Definition: pagfault.c:2573
union _MMPFN::@1776 u1
ULONG PFN_NUMBER
Definition: ke.h:9
ULONG Eax
Definition: ketypes.h:258
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
const ULONG MmProtectToPteMask[32]
Definition: page.c:22
UINT64 Rsi
Definition: ketypes.h:371
PMMPTE LastPteForPagedPool
Definition: mm.h:456
#define FALSE
Definition: types.h:117
FORCEINLINE VOID MI_WRITE_VALID_PTE(IN PMMPTE PointerPte, IN MMPTE TempPte)
Definition: miarm.h:942
#define MI_SET_PROCESS(x)
Definition: mm.h:286
#define MI_MAKE_CLEAN_PAGE(x)
Definition: mm.h:99
ULONG_PTR ShareCount
Definition: mm.h:358
FORCEINLINE VOID MI_WRITE_INVALID_PDE(IN PMMPDE PointerPde, IN MMPDE InvalidPde)
Definition: miarm.h:1018
#define _WARN(msg)
Definition: debug.h:263
UINT64 Rax
Definition: ketypes.h:318
KAPC_STATE ApcState
Definition: ketypes.h:1710
PKEVENT Event
Definition: mm.h:347
#define MI_SET_PROCESS2(x)
Definition: mm.h:287
ULONG OwnsSessionWorkingSetExclusive
Definition: pstypes.h:1184
BOOLEAN NTAPI KeIsAttachedProcess(VOID)
Definition: procobj.c:690
#define PsGetCurrentProcess
Definition: psfuncs.h:17
FORCEINLINE PFN_NUMBER MiRemoveZeroPageSafe(IN ULONG Color)
Definition: miarm.h:2296
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:912
MMSUPPORT MmSystemCacheWs
Definition: init.c:55
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:709
#define MiProtoPteToPte(x)
Definition: mm.h:250
FORCEINLINE VOID MiUnlockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1284
PFN_NUMBER Page
Definition: section.c:4756
#define MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)
Definition: miarm.h:176
#define MI_SET_USAGE(x)
Definition: mm.h:285
ULONG64 Protection
Definition: mmtypes.h:88
_Must_inspect_result_ _In_ WDFDMATRANSACTION _In_ PFN_WDF_PROGRAM_DMA _In_ WDF_DMA_DIRECTION _In_ PMDL _In_ PVOID VirtualAddress
void * PVOID
Definition: retypes.h:9
VOID NTAPI MiReleaseSystemPtes(IN PMMPTE StartingPte, IN ULONG NumberOfPtes, IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType)
Definition: syspte.c:264
ULONG_PTR StartingVpn
Definition: mmtypes.h:726
FORCEINLINE BOOLEAN MiIsAccessAllowed(_In_ ULONG ProtectionMask, _In_ BOOLEAN Write, _In_ BOOLEAN Execute)
Definition: pagfault.c:138
PMMPTE MmSharedUserDataPte
Definition: mminit.c:26
MMVAD_FLAGS2 VadFlags2
Definition: mmtypes.h:739
ULONG_PTR MemCommit
Definition: mmtypes.h:692
FORCEINLINE ULONG_PTR MiDetermineUserGlobalPteMask(IN PVOID PointerPte)
Definition: miarm.h:737
#define NtCurrentProcess()
Definition: nt_native.h:1657
USHORT WriteInProgress
Definition: mm.h:330
#define MEM_EXECUTE_OPTION_ENABLE
Definition: mmtypes.h:74
PMMPDE MmSystemPagePtes
Definition: init.c:41
#define MM_ZERO_ACCESS
Definition: miarm.h:39
Status
Definition: gdiplustypes.h:24
#define MM_READONLY
Definition: inbv.c:11
FORCEINLINE PMMPTE MiAddressToPxe(PVOID Address)
Definition: mm.h:164
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
ULONG GuaranteedStackBytes
Definition: winternl.h:279
struct _MM_SESSION_SPACE * GlobalVirtualAddress
Definition: miarm.h:476
ULONG CurrentProcess
Definition: shell.c:125
ULONG_PTR PrivateMemory
Definition: mmtypes.h:695
VOID FASTCALL KeZeroPages(IN PVOID Address, IN ULONG Size)
Definition: stubs.c:91
#define ASSERT(a)
Definition: mode.c:45
#define MI_IS_SESSION_PTE(Pte)
Definition: miarm.h:170
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
PVOID DeallocationStack
Definition: compat.h:737
_In_ WDFCOLLECTION _In_ ULONG Index
#define MI_GET_NEXT_PROCESS_COLOR(x)
Definition: miarm.h:239
ULONG64 Valid
Definition: mmtypes.h:150
struct _MMPTE * PMMPTE
#define MI_IS_PFN_DELETED(x)
Definition: miarm.h:191
#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:47
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define _Inout_
Definition: no_sal2.h:162
MMPTE ValidKernelPte
Definition: init.c:29
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
#define MI_PAGE_WRITE_THROUGH(x)
Definition: mm.h:102
FORCEINLINE VOID KiReleaseProcessLock(IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:655
#define MI_IS_PAGE_LARGE(x)
Definition: mm.h:104
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:790
#define MM_READWRITE
Definition: inbv.c:12
ULONG64 PageFileHigh
Definition: mmtypes.h:93
#define MM_NOIRQL
Definition: miarm.h:232
#define MM_GUARDPAGE
Definition: miarm.h:53
FORCEINLINE VOID MiDropLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1439
Definition: mm.h:341
#define MI_IS_PAGE_WRITEABLE(x)
Definition: mm.h:106
#define InterlockedExchangePte(PointerPte, Value)
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
ULONG OwnsSystemWorkingSetExclusive
Definition: pstypes.h:1182
ULONG Ecx
Definition: ketypes.h:257
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
BOOLEAN MmProtectFreedNonPagedPool
Definition: pool.c:29
ULONG Eip
Definition: ketypes.h:267
LIST_ENTRY ImageList
Definition: miarm.h:495
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:958
NTSTATUS ReadStatus
Definition: mm.h:348
#define InterlockedExchange
Definition: armddk.h:54
UINT64 R11
Definition: ketypes.h:324
#define MI_IS_INSTRUCTION_FETCH(FaultCode)
Definition: mm.h:123
#define MI_IS_PAGE_TABLE_OR_HYPER_ADDRESS(Address)
Definition: miarm.h:179
ULONG_PTR Long
Definition: mmtypes.h:215
#define FLG_DISABLE_STACK_EXTENSION
Definition: pstypes.h:71
PVOID MmPagedPoolStart
Definition: miarm.h:581
PVOID MmNonPagedPoolStart
Definition: init.c:24
#define MM_EXECUTE_READWRITE
Definition: miarm.h:45
FORCEINLINE VOID MI_MAKE_HARDWARE_PTE_USER(IN PMMPTE NewPte, IN PMMPTE MappingPte, IN ULONG_PTR ProtectionMask, IN PFN_NUMBER PageFrameNumber)
Definition: miarm.h:813
#define _In_
Definition: no_sal2.h:158
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:80
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
#define SYSTEM_PD_SIZE
Definition: miarm.h:28
Definition: compat.h:694
FORCEINLINE VOID MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte, IN MMPTE InvalidPte)
Definition: miarm.h:975
#define MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION
Definition: mmtypes.h:75
ULONG Ebx
Definition: ketypes.h:264
#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:571
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:242
static INT Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
Definition: cmd.c:347
ULONG Sp
Definition: ketypes.h:364
union _MMVAD::@2564 u
static NTSTATUS NTAPI MiCheckForUserStackOverflow(IN PVOID Address, IN PVOID TrapInformation)
Definition: pagfault.c:30
#define FORCEINLINE
Definition: wdftypes.h:67
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:971
PMMPTE PteAddress
Definition: mm.h:354
ULONG OwnsProcessWorkingSetShared
Definition: pstypes.h:1181
#define MI_PAGE_DISABLE_CACHE(x)
Definition: mm.h:101
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
#define NULL
Definition: types.h:112
MMPTE OriginalPte
Definition: mm.h:375
#define STATUS_STACK_OVERFLOW
Definition: ntstatus.h:489
UINT64 Rdi
Definition: ketypes.h:370
MMPDE DemandZeroPde
Definition: init.c:36
PVOID Teb
Definition: ketypes.h:1739
#define MEM_EXECUTE_OPTION_PERMANENT
Definition: mmtypes.h:76
ULONG R1
Definition: ketypes.h:360
#define DPRINT1
Definition: precomp.h:8
#define MI_IS_SESSION_IMAGE_ADDRESS(Address)
Definition: miarm.h:164
_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:40
ULONG64 ReadOnly
Definition: mmtypes.h:119
FORCEINLINE VOID MiIncrementPageTableReferences(IN PVOID Address)
Definition: miarm.h:1672
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:598
union _MMPFN::@1777 u2
#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:1103
ULONG64 PageFrameNumber
Definition: mmtypes.h:171
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
PMMPTE FirstPrototypePte
Definition: mmtypes.h:734
PVOID StackLimit
Definition: compat.h:572
#define MM_PROTECT_SPECIAL
Definition: miarm.h:55
ULONG OwnsProcessWorkingSetExclusive
Definition: pstypes.h:1180
#define STATUS_IN_PAGE_ERROR
Definition: ntstatus.h:243
ULONG_PTR InPageError
Definition: mm.h:387
#define STATUS_SUCCESS
Definition: shellext.h:65
ULONG MmSizeOfNonPagedPoolInBytes
Definition: init.c:21
FORCEINLINE VOID MiLockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1240
MMPTE MmDecommittedPte
Definition: init.c:44
PMMPTE MiHighestUserPte
Definition: mminit.c:233
#define DPRINT
Definition: sndvol32.h:71
FORCEINLINE PVOID MiPteToAddress(PMMPTE PointerPte)
Definition: mm.h:201
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
FORCEINLINE BOOLEAN MI_IS_PHYSICAL_ADDRESS(IN PVOID Address)
Definition: miarm.h:928
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:92
#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:691
VOID NTAPI KeBugCheckEx(_In_ ULONG BugCheckCode, _In_ ULONG_PTR BugCheckParameter1, _In_ ULONG_PTR BugCheckParameter2, _In_ ULONG_PTR BugCheckParameter3, _In_ ULONG_PTR BugCheckParameter4)
Definition: rtlcompat.c:108
ULONG Edx
Definition: ketypes.h:256
FORCEINLINE VOID MI_MAKE_HARDWARE_PTE(IN PMMPTE NewPte, IN PMMPTE MappingPte, IN ULONG_PTR ProtectionMask, IN PFN_NUMBER PageFrameNumber)
Definition: miarm.h:797
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