ReactOS  0.4.15-dev-3303-g1ade494
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 */
647  OldIrql = MiAcquirePfnLock();
648  HaveLock = TRUE;
649  }
650 
651  /* We either manually locked the PFN DB, or already came with it locked */
653  ASSERT(PointerPte->u.Hard.Valid == 0);
654 
655  /* Assert we have enough pages */
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  else
678  {
679  /* Page guaranteed to be zero-filled */
680  NeedZero = FALSE;
681  }
682  }
683  else
684  {
685  /* Get a color, and see if we should grab a zero or non-zero page */
687  if (!NeedZero)
688  {
689  /* Process or system doesn't want a zero page, grab anything */
690  PageFrameNumber = MiRemoveAnyPage(Color);
691  }
692  else
693  {
694  /* System wants a zero page, obtain one */
695  PageFrameNumber = MiRemoveZeroPage(Color);
696  /* No need to zero-fill it */
697  NeedZero = FALSE;
698  }
699  }
700 
701  /* Initialize it */
702  MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
703 
704  /* Increment demand zero faults */
705  KeGetCurrentPrcb()->MmDemandZeroCount++;
706 
707  /* Do we have the lock? */
708  if (HaveLock)
709  {
710  /* Release it */
711  MiReleasePfnLock(OldIrql);
712 
713  /* Update performance counters */
714  if (Process > HYDRA_PROCESS) Process->NumberOfPrivatePages++;
715  }
716 
717  /* Zero the page if need be */
718  if (NeedZero) MiZeroPfn(PageFrameNumber);
719 
720  /* Fault on user PDE, or fault on user PTE? */
721  if (PointerPte <= MiHighestUserPte)
722  {
723  /* User fault, build a user PTE */
725  PointerPte,
726  Protection,
727  PageFrameNumber);
728  }
729  else
730  {
731  /* This is a user-mode PDE, create a kernel PTE for it */
733  PointerPte,
734  Protection,
735  PageFrameNumber);
736  }
737 
738  /* Set it dirty if it's a writable page */
740 
741  /* Write it */
742  MI_WRITE_VALID_PTE(PointerPte, TempPte);
743 
744  /* Did we manually acquire the lock */
745  if (HaveLock)
746  {
747  /* Get the PFN entry */
748  Pfn1 = MI_PFN_ELEMENT(PageFrameNumber);
749 
750  /* Windows does these sanity checks */
751  ASSERT(Pfn1->u1.Event == 0);
752  ASSERT(Pfn1->u3.e1.PrototypePte == 0);
753  }
754 
755  //
756  // It's all good now
757  //
758  DPRINT("Demand zero page has now been paged in\n");
760 }
761 
762 static
763 NTSTATUS
764 NTAPI
766  IN PVOID Address,
767  IN PMMPTE PointerPte,
768  IN PMMPTE PointerProtoPte,
769  IN KIRQL OldIrql,
770  IN PMMPFN* LockedProtoPfn)
771 {
772  MMPTE TempPte;
773  PMMPTE OriginalPte, PageTablePte;
774  ULONG_PTR Protection;
775  PFN_NUMBER PageFrameIndex;
776  PMMPFN Pfn1, Pfn2;
777  BOOLEAN OriginalProtection, DirtyPage;
778 
779  /* Must be called with an valid prototype PTE, with the PFN lock held */
781  ASSERT(PointerProtoPte->u.Hard.Valid == 1);
782 
783  /* Get the page */
784  PageFrameIndex = PFN_FROM_PTE(PointerProtoPte);
785 
786  /* Get the PFN entry and set it as a prototype PTE */
787  Pfn1 = MiGetPfnEntry(PageFrameIndex);
788  Pfn1->u3.e1.PrototypePte = 1;
789 
790  /* Increment the share count for the page table */
791  PageTablePte = MiAddressToPte(PointerPte);
792  Pfn2 = MiGetPfnEntry(PageTablePte->u.Hard.PageFrameNumber);
793  Pfn2->u2.ShareCount++;
794 
795  /* Check where we should be getting the protection information from */
796  if (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
797  {
798  /* Get the protection from the PTE, there's no real Proto PTE data */
799  Protection = PointerPte->u.Soft.Protection;
800 
801  /* Remember that we did not use the proto protection */
802  OriginalProtection = FALSE;
803  }
804  else
805  {
806  /* Get the protection from the original PTE link */
807  OriginalPte = &Pfn1->OriginalPte;
808  Protection = OriginalPte->u.Soft.Protection;
809 
810  /* Remember that we used the original protection */
811  OriginalProtection = TRUE;
812 
813  /* Check if this was a write on a read only proto */
814  if ((StoreInstruction) && !(Protection & MM_READWRITE))
815  {
816  /* Clear the flag */
817  StoreInstruction = 0;
818  }
819  }
820 
821  /* Check if this was a write on a non-COW page */
822  DirtyPage = FALSE;
823  if ((StoreInstruction) && ((Protection & MM_WRITECOPY) != MM_WRITECOPY))
824  {
825  /* Then the page should be marked dirty */
826  DirtyPage = TRUE;
827 
828  /* ReactOS check */
829  ASSERT(Pfn1->OriginalPte.u.Soft.Prototype != 0);
830  }
831 
832  /* Did we get a locked incoming PFN? */
833  if (*LockedProtoPfn)
834  {
835  /* Drop a reference */
836  ASSERT((*LockedProtoPfn)->u3.e2.ReferenceCount >= 1);
837  MiDereferencePfnAndDropLockCount(*LockedProtoPfn);
838  *LockedProtoPfn = NULL;
839  }
840 
841  /* Release the PFN lock */
842  MiReleasePfnLock(OldIrql);
843 
844  /* Remove special/caching bits */
845  Protection &= ~MM_PROTECT_SPECIAL;
846 
847  /* Setup caching */
848  if (Pfn1->u3.e1.CacheAttribute == MiWriteCombined)
849  {
850  /* Write combining, no caching */
853  }
854  else if (Pfn1->u3.e1.CacheAttribute == MiNonCached)
855  {
856  /* Write through, no caching */
859  }
860 
861  /* Check if this is a kernel or user address */
863  {
864  /* Build the user PTE */
865  MI_MAKE_HARDWARE_PTE_USER(&TempPte, PointerPte, Protection, PageFrameIndex);
866  }
867  else
868  {
869  /* Build the kernel PTE */
870  MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, Protection, PageFrameIndex);
871  }
872 
873  /* Set the dirty flag if needed */
874  if (DirtyPage) MI_MAKE_DIRTY_PAGE(&TempPte);
875 
876  /* Write the PTE */
877  MI_WRITE_VALID_PTE(PointerPte, TempPte);
878 
879  /* Reset the protection if needed */
880  if (OriginalProtection) Protection = MM_ZERO_ACCESS;
881 
882  /* Return success */
883  ASSERT(PointerPte == MiAddressToPte(Address));
884  return STATUS_SUCCESS;
885 }
886 
887 static
888 NTSTATUS
889 NTAPI
891  _In_ PVOID FaultingAddress,
892  _In_ PMMPTE PointerPte,
895 {
896  ULONG Color;
899  MMPTE TempPte = *PointerPte;
900  PMMPFN Pfn1;
901  ULONG PageFileIndex = TempPte.u.Soft.PageFileLow;
902  ULONG_PTR PageFileOffset = TempPte.u.Soft.PageFileHigh;
903  ULONG Protection = TempPte.u.Soft.Protection;
904 
905  /* Things we don't support yet */
907  ASSERT(*OldIrql != MM_NOIRQL);
908 
911 
912  /* We must hold the PFN lock */
914 
915  /* Some sanity checks */
916  ASSERT(TempPte.u.Hard.Valid == 0);
917  ASSERT(TempPte.u.Soft.PageFileHigh != 0);
918  ASSERT(TempPte.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED);
919 
920  /* Get any page, it will be overwritten */
923 
924  /* Initialize this PFN */
925  MiInitializePfn(Page, PointerPte, StoreInstruction);
926 
927  /* Sets the PFN as being in IO operation */
928  Pfn1 = MI_PFN_ELEMENT(Page);
929  ASSERT(Pfn1->u1.Event == NULL);
930  ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
931  ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
932  Pfn1->u3.e1.ReadInProgress = 1;
933 
934  /* We must write the PTE now as the PFN lock will be released while performing the IO operation */
935  MI_MAKE_TRANSITION_PTE(&TempPte, Page, Protection);
936 
937  MI_WRITE_INVALID_PTE(PointerPte, TempPte);
938 
939  /* Release the PFN lock while we proceed */
940  MiReleasePfnLock(*OldIrql);
941 
942  /* Do the paging IO */
943  Status = MiReadPageFile(Page, PageFileIndex, PageFileOffset);
944 
945  /* Lock the PFN database again */
946  *OldIrql = MiAcquirePfnLock();
947 
948  /* Nobody should have changed that while we were not looking */
949  ASSERT(Pfn1->u3.e1.ReadInProgress == 1);
950  ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
951 
952  if (!NT_SUCCESS(Status))
953  {
954  /* Malheur! */
955  ASSERT(FALSE);
956  Pfn1->u4.InPageError = 1;
957  Pfn1->u1.ReadStatus = Status;
958  }
959 
960  /* And the PTE can finally be valid */
961  MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, Protection, Page);
962  MI_WRITE_VALID_PTE(PointerPte, TempPte);
963 
964  Pfn1->u3.e1.ReadInProgress = 0;
965  /* Did someone start to wait on us while we proceeded ? */
966  if (Pfn1->u1.Event)
967  {
968  /* Tell them we're done */
970  }
971 
972  return Status;
973 }
974 
975 static
976 NTSTATUS
977 NTAPI
979  IN PVOID FaultingAddress,
980  IN PMMPTE PointerPte,
982  IN KIRQL OldIrql,
983  OUT PKEVENT **InPageBlock)
984 {
985  PFN_NUMBER PageFrameIndex;
986  PMMPFN Pfn1;
987  MMPTE TempPte;
988  PMMPTE PointerToPteForProtoPage;
989  DPRINT("Transition fault on 0x%p with PTE 0x%p in process %s\n",
990  FaultingAddress, PointerPte, CurrentProcess->ImageFileName);
991 
992  /* Windowss does this check */
993  ASSERT(*InPageBlock == NULL);
994 
995  /* ARM3 doesn't support this path */
997 
998  /* Capture the PTE and make sure it's in transition format */
999  TempPte = *PointerPte;
1000  ASSERT((TempPte.u.Soft.Valid == 0) &&
1001  (TempPte.u.Soft.Prototype == 0) &&
1002  (TempPte.u.Soft.Transition == 1));
1003 
1004  /* Get the PFN and the PFN entry */
1005  PageFrameIndex = TempPte.u.Trans.PageFrameNumber;
1006  DPRINT("Transition PFN: %lx\n", PageFrameIndex);
1007  Pfn1 = MiGetPfnEntry(PageFrameIndex);
1008 
1009  /* One more transition fault! */
1010  InterlockedIncrement(&KeGetCurrentPrcb()->MmTransitionCount);
1011 
1012  /* This is from ARM3 -- Windows normally handles this here */
1013  ASSERT(Pfn1->u4.InPageError == 0);
1014 
1015  /* See if we should wait before terminating the fault */
1016  if ((Pfn1->u3.e1.ReadInProgress == 1)
1017  || ((Pfn1->u3.e1.WriteInProgress == 1) && StoreInstruction))
1018  {
1019  DPRINT1("The page is currently in a page transition !\n");
1020  *InPageBlock = &Pfn1->u1.Event;
1021  if (PointerPte == Pfn1->PteAddress)
1022  {
1023  DPRINT1("And this if for this particular PTE.\n");
1024  /* The PTE will be made valid by the thread serving the fault */
1025  return STATUS_SUCCESS; // FIXME: Maybe something more descriptive
1026  }
1027  }
1028 
1029  /* Windows checks there's some free pages and this isn't an in-page error */
1030  ASSERT(MmAvailablePages > 0);
1031  ASSERT(Pfn1->u4.InPageError == 0);
1032 
1033  /* ReactOS checks for this */
1034  ASSERT(MmAvailablePages > 32);
1035 
1036  /* Was this a transition page in the valid list, or free/zero list? */
1037  if (Pfn1->u3.e1.PageLocation == ActiveAndValid)
1038  {
1039  /* All Windows does here is a bunch of sanity checks */
1040  DPRINT("Transition in active list\n");
1043  ASSERT(Pfn1->u2.ShareCount != 0);
1044  ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
1045  }
1046  else
1047  {
1048  /* Otherwise, the page is removed from its list */
1049  DPRINT("Transition page in free/zero list\n");
1050  MiUnlinkPageFromList(Pfn1);
1052  }
1053 
1054  /* At this point, there should no longer be any in-page errors */
1055  ASSERT(Pfn1->u4.InPageError == 0);
1056 
1057  /* Check if this was a PFN with no more share references */
1058  if (Pfn1->u2.ShareCount == 0) MiDropLockCount(Pfn1);
1059 
1060  /* Bump the share count and make the page valid */
1061  Pfn1->u2.ShareCount++;
1062  Pfn1->u3.e1.PageLocation = ActiveAndValid;
1063 
1064  /* Prototype PTEs are in paged pool, which itself might be in transition */
1065  if (FaultingAddress >= MmSystemRangeStart)
1066  {
1067  /* Check if this is a paged pool PTE in transition state */
1068  PointerToPteForProtoPage = MiAddressToPte(PointerPte);
1069  TempPte = *PointerToPteForProtoPage;
1070  if ((TempPte.u.Hard.Valid == 0) && (TempPte.u.Soft.Transition == 1))
1071  {
1072  /* This isn't yet supported */
1073  DPRINT1("Double transition fault not yet supported\n");
1074  ASSERT(FALSE);
1075  }
1076  }
1077 
1078  /* Build the final PTE */
1079  ASSERT(PointerPte->u.Hard.Valid == 0);
1080  ASSERT(PointerPte->u.Trans.Prototype == 0);
1081  ASSERT(PointerPte->u.Trans.Transition == 1);
1082  TempPte.u.Long = (PointerPte->u.Long & ~0xFFF) |
1083  (MmProtectToPteMask[PointerPte->u.Trans.Protection]) |
1084  MiDetermineUserGlobalPteMask(PointerPte);
1085 
1086  /* Is the PTE writeable? */
1087  if ((Pfn1->u3.e1.Modified) &&
1090  {
1091  /* Make it dirty */
1093  }
1094  else
1095  {
1096  /* Make it clean */
1098  }
1099 
1100  /* Write the valid PTE */
1101  MI_WRITE_VALID_PTE(PointerPte, TempPte);
1102 
1103  /* Return success */
1105 }
1106 
1107 static
1108 NTSTATUS
1109 NTAPI
1111  IN PVOID Address,
1112  IN PMMPTE PointerPte,
1113  IN PMMPTE PointerProtoPte,
1114  IN OUT PMMPFN *OutPfn,
1115  OUT PVOID *PageFileData,
1116  OUT PMMPTE PteValue,
1118  IN KIRQL OldIrql,
1119  IN PVOID TrapInformation)
1120 {
1121  MMPTE TempPte, PteContents;
1122  PMMPFN Pfn1;
1123  PFN_NUMBER PageFrameIndex;
1124  NTSTATUS Status;
1125  PKEVENT* InPageBlock = NULL;
1126  ULONG Protection;
1127 
1128  /* Must be called with an invalid, prototype PTE, with the PFN lock held */
1130  ASSERT(PointerPte->u.Hard.Valid == 0);
1131  ASSERT(PointerPte->u.Soft.Prototype == 1);
1132 
1133  /* Read the prototype PTE and check if it's valid */
1134  TempPte = *PointerProtoPte;
1135  if (TempPte.u.Hard.Valid == 1)
1136  {
1137  /* One more user of this mapped page */
1138  PageFrameIndex = PFN_FROM_PTE(&TempPte);
1139  Pfn1 = MiGetPfnEntry(PageFrameIndex);
1140  Pfn1->u2.ShareCount++;
1141 
1142  /* Call it a transition */
1143  InterlockedIncrement(&KeGetCurrentPrcb()->MmTransitionCount);
1144 
1145  /* Complete the prototype PTE fault -- this will release the PFN lock */
1146  return MiCompleteProtoPteFault(StoreInstruction,
1147  Address,
1148  PointerPte,
1149  PointerProtoPte,
1150  OldIrql,
1151  OutPfn);
1152  }
1153 
1154  /* Make sure there's some protection mask */
1155  if (TempPte.u.Long == 0)
1156  {
1157  /* Release the lock */
1158  DPRINT1("Access on reserved section?\n");
1159  MiReleasePfnLock(OldIrql);
1160  return STATUS_ACCESS_VIOLATION;
1161  }
1162 
1163  /* There is no such thing as a decommitted prototype PTE */
1164  ASSERT(TempPte.u.Long != MmDecommittedPte.u.Long);
1165 
1166  /* Check for access rights on the PTE proper */
1167  PteContents = *PointerPte;
1168  if (PteContents.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED)
1169  {
1170  if (!PteContents.u.Proto.ReadOnly)
1171  {
1172  Protection = TempPte.u.Soft.Protection;
1173  }
1174  else
1175  {
1176  Protection = MM_READONLY;
1177  }
1178  /* Check for page acess in software */
1179  Status = MiAccessCheck(PointerProtoPte,
1180  StoreInstruction,
1181  KernelMode,
1182  TempPte.u.Soft.Protection,
1183  TrapInformation,
1184  TRUE);
1186  }
1187  else
1188  {
1189  Protection = PteContents.u.Soft.Protection;
1190  }
1191 
1192  /* Check for writing copy on write page */
1193  if (((Protection & MM_WRITECOPY) == MM_WRITECOPY) && StoreInstruction)
1194  {
1195  PFN_NUMBER PageFrameIndex, ProtoPageFrameIndex;
1196  ULONG Color;
1197 
1198  /* Resolve the proto fault as if it was a read operation */
1200  Address,
1201  PointerPte,
1202  PointerProtoPte,
1203  OutPfn,
1204  PageFileData,
1205  PteValue,
1206  Process,
1207  OldIrql,
1208  TrapInformation);
1209 
1210  if (!NT_SUCCESS(Status))
1211  {
1212  return Status;
1213  }
1214 
1215  /* Lock again the PFN lock, MiResolveProtoPteFault unlocked it */
1216  OldIrql = MiAcquirePfnLock();
1217 
1218  /* And re-read the proto PTE */
1219  TempPte = *PointerProtoPte;
1220  ASSERT(TempPte.u.Hard.Valid == 1);
1221  ProtoPageFrameIndex = PFN_FROM_PTE(&TempPte);
1222 
1225 
1226  /* Get a new page for the private copy */
1227  if (Process > HYDRA_PROCESS)
1229  else
1231 
1232  PageFrameIndex = MiRemoveAnyPage(Color);
1233 
1234  /* Perform the copy */
1235  MiCopyPfn(PageFrameIndex, ProtoPageFrameIndex);
1236 
1237  /* This will drop everything MiResolveProtoPteFault referenced */
1238  MiDeletePte(PointerPte, Address, Process, PointerProtoPte);
1239 
1240  /* Because now we use this */
1241  Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1242  MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
1243 
1244  /* Fix the protection */
1245  Protection &= ~MM_WRITECOPY;
1246  Protection |= MM_READWRITE;
1248  {
1249  /* Build the user PTE */
1250  MI_MAKE_HARDWARE_PTE_USER(&PteContents, PointerPte, Protection, PageFrameIndex);
1251  }
1252  else
1253  {
1254  /* Build the kernel PTE */
1255  MI_MAKE_HARDWARE_PTE(&PteContents, PointerPte, Protection, PageFrameIndex);
1256  }
1257 
1258  /* And finally, write the valid PTE */
1259  MI_WRITE_VALID_PTE(PointerPte, PteContents);
1260 
1261  /* The caller expects us to release the PFN lock */
1262  MiReleasePfnLock(OldIrql);
1263  return Status;
1264  }
1265 
1266  /* Check for clone PTEs */
1267  if (PointerPte <= MiHighestUserPte) ASSERT(Process->CloneRoot == NULL);
1268 
1269  /* We don't support mapped files yet */
1270  ASSERT(TempPte.u.Soft.Prototype == 0);
1271 
1272  /* We might however have transition PTEs */
1273  if (TempPte.u.Soft.Transition == 1)
1274  {
1275  /* Resolve the transition fault */
1276  ASSERT(OldIrql != MM_NOIRQL);
1277  Status = MiResolveTransitionFault(StoreInstruction,
1278  Address,
1279  PointerProtoPte,
1280  Process,
1281  OldIrql,
1282  &InPageBlock);
1284  }
1285  else
1286  {
1287  /* We also don't support paged out pages */
1288  ASSERT(TempPte.u.Soft.PageFileHigh == 0);
1289 
1290  /* Resolve the demand zero fault */
1292  PointerProtoPte,
1293  (ULONG)TempPte.u.Soft.Protection,
1294  Process,
1295  OldIrql);
1296 #if MI_TRACE_PFNS
1297  /* Update debug info */
1298  if (TrapInformation)
1299  MiGetPfnEntry(PointerProtoPte->u.Hard.PageFrameNumber)->CallSite = (PVOID)((PKTRAP_FRAME)TrapInformation)->Eip;
1300  else
1301  MiGetPfnEntry(PointerProtoPte->u.Hard.PageFrameNumber)->CallSite = _ReturnAddress();
1302 #endif
1303 
1305  }
1306 
1307  /* Complete the prototype PTE fault -- this will release the PFN lock */
1308  ASSERT(PointerPte->u.Hard.Valid == 0);
1309  return MiCompleteProtoPteFault(StoreInstruction,
1310  Address,
1311  PointerPte,
1312  PointerProtoPte,
1313  OldIrql,
1314  OutPfn);
1315 }
1316 
1317 NTSTATUS
1318 NTAPI
1320  IN PVOID Address,
1321  IN PMMPTE PointerPte,
1322  IN PMMPTE PointerProtoPte,
1323  IN BOOLEAN Recursive,
1325  IN PVOID TrapInformation,
1326  IN PMMVAD Vad)
1327 {
1328  MMPTE TempPte;
1329  KIRQL OldIrql, LockIrql;
1330  NTSTATUS Status;
1331  PMMPTE SuperProtoPte;
1332  PMMPFN Pfn1, OutPfn = NULL;
1333  PFN_NUMBER PageFrameIndex;
1334  PFN_COUNT PteCount, ProcessedPtes;
1335  DPRINT("ARM3 Page Fault Dispatcher for address: %p in process: %p\n",
1336  Address,
1337  Process);
1338 
1339  /* Make sure the addresses are ok */
1340  ASSERT(PointerPte == MiAddressToPte(Address));
1341 
1342  //
1343  // Make sure APCs are off and we're not at dispatch
1344  //
1346  ASSERT(OldIrql <= APC_LEVEL);
1348 
1349  //
1350  // Grab a copy of the PTE
1351  //
1352  TempPte = *PointerPte;
1353 
1354  /* Do we have a prototype PTE? */
1355  if (PointerProtoPte)
1356  {
1357  /* This should never happen */
1358  ASSERT(!MI_IS_PHYSICAL_ADDRESS(PointerProtoPte));
1359 
1360  /* Check if this is a kernel-mode address */
1361  SuperProtoPte = MiAddressToPte(PointerProtoPte);
1362  if (Address >= MmSystemRangeStart)
1363  {
1364  /* Lock the PFN database */
1365  LockIrql = MiAcquirePfnLock();
1366 
1367  /* Has the PTE been made valid yet? */
1368  if (!SuperProtoPte->u.Hard.Valid)
1369  {
1370  ASSERT(FALSE);
1371  }
1372  else if (PointerPte->u.Hard.Valid == 1)
1373  {
1374  ASSERT(FALSE);
1375  }
1376 
1377  /* Resolve the fault -- this will release the PFN lock */
1379  Address,
1380  PointerPte,
1381  PointerProtoPte,
1382  &OutPfn,
1383  NULL,
1384  NULL,
1385  Process,
1386  LockIrql,
1387  TrapInformation);
1389 
1390  /* Complete this as a transition fault */
1392  ASSERT(OldIrql <= APC_LEVEL);
1394  return Status;
1395  }
1396  else
1397  {
1398  /* We only handle the lookup path */
1399  ASSERT(PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED);
1400 
1401  /* Is there a non-image VAD? */
1402  if ((Vad) &&
1403  (Vad->u.VadFlags.VadType != VadImageMap) &&
1404  !(Vad->u2.VadFlags2.ExtendableFile))
1405  {
1406  /* One day, ReactOS will cluster faults */
1408  DPRINT("Should cluster fault, but won't\n");
1409  }
1410 
1411  /* Only one PTE to handle for now */
1412  PteCount = 1;
1413  ProcessedPtes = 0;
1414 
1415  /* Lock the PFN database */
1416  LockIrql = MiAcquirePfnLock();
1417 
1418  /* We only handle the valid path */
1419  ASSERT(SuperProtoPte->u.Hard.Valid == 1);
1420 
1421  /* Capture the PTE */
1422  TempPte = *PointerProtoPte;
1423 
1424  /* Loop to handle future case of clustered faults */
1425  while (TRUE)
1426  {
1427  /* For our current usage, this should be true */
1428  if (TempPte.u.Hard.Valid == 1)
1429  {
1430  /* Bump the share count on the PTE */
1431  PageFrameIndex = PFN_FROM_PTE(&TempPte);
1432  Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1433  Pfn1->u2.ShareCount++;
1434  }
1435  else if ((TempPte.u.Soft.Prototype == 0) &&
1436  (TempPte.u.Soft.Transition == 1))
1437  {
1438  /* This is a standby page, bring it back from the cache */
1439  PageFrameIndex = TempPte.u.Trans.PageFrameNumber;
1440  DPRINT("oooh, shiny, a soft fault! 0x%lx\n", PageFrameIndex);
1441  Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1443 
1444  /* Should not yet happen in ReactOS */
1445  ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
1446  ASSERT(Pfn1->u4.InPageError == 0);
1447 
1448  /* Get the page */
1449  MiUnlinkPageFromList(Pfn1);
1450 
1451  /* Bump its reference count */
1452  ASSERT(Pfn1->u2.ShareCount == 0);
1453  InterlockedIncrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1454  Pfn1->u2.ShareCount++;
1455 
1456  /* Make it valid again */
1457  /* This looks like another macro.... */
1458  Pfn1->u3.e1.PageLocation = ActiveAndValid;
1459  ASSERT(PointerProtoPte->u.Hard.Valid == 0);
1460  ASSERT(PointerProtoPte->u.Trans.Prototype == 0);
1461  ASSERT(PointerProtoPte->u.Trans.Transition == 1);
1462  TempPte.u.Long = (PointerProtoPte->u.Long & ~0xFFF) |
1463  MmProtectToPteMask[PointerProtoPte->u.Trans.Protection];
1464  TempPte.u.Hard.Valid = 1;
1466 
1467  /* Is the PTE writeable? */
1468  if ((Pfn1->u3.e1.Modified) &&
1471  {
1472  /* Make it dirty */
1474  }
1475  else
1476  {
1477  /* Make it clean */
1479  }
1480 
1481  /* Write the valid PTE */
1482  MI_WRITE_VALID_PTE(PointerProtoPte, TempPte);
1483  ASSERT(PointerPte->u.Hard.Valid == 0);
1484  }
1485  else
1486  {
1487  /* Page is invalid, get out of the loop */
1488  break;
1489  }
1490 
1491  /* One more done, was it the last? */
1492  if (++ProcessedPtes == PteCount)
1493  {
1494  /* Complete the fault */
1496  Address,
1497  PointerPte,
1498  PointerProtoPte,
1499  LockIrql,
1500  &OutPfn);
1501 
1502  /* THIS RELEASES THE PFN LOCK! */
1503  break;
1504  }
1505 
1506  /* No clustered faults yet */
1507  ASSERT(FALSE);
1508  }
1509 
1510  /* Did we resolve the fault? */
1511  if (ProcessedPtes)
1512  {
1513  /* Bump the transition count */
1514  InterlockedExchangeAddSizeT(&KeGetCurrentPrcb()->MmTransitionCount, ProcessedPtes);
1515  ProcessedPtes--;
1516 
1517  /* Loop all the processing we did */
1518  ASSERT(ProcessedPtes == 0);
1519 
1520  /* Complete this as a transition fault */
1522  ASSERT(OldIrql <= APC_LEVEL);
1525  }
1526 
1527  /* We did not -- PFN lock is still held, prepare to resolve prototype PTE fault */
1528  OutPfn = MI_PFN_ELEMENT(SuperProtoPte->u.Hard.PageFrameNumber);
1530  ASSERT(OutPfn->u3.e2.ReferenceCount > 1);
1531  ASSERT(PointerPte->u.Hard.Valid == 0);
1532 
1533  /* Resolve the fault -- this will release the PFN lock */
1535  Address,
1536  PointerPte,
1537  PointerProtoPte,
1538  &OutPfn,
1539  NULL,
1540  NULL,
1541  Process,
1542  LockIrql,
1543  TrapInformation);
1544  //ASSERT(Status != STATUS_ISSUE_PAGING_IO);
1545  //ASSERT(Status != STATUS_REFAULT);
1546  //ASSERT(Status != STATUS_PTE_CHANGED);
1547 
1548  /* Did the routine clean out the PFN or should we? */
1549  if (OutPfn)
1550  {
1551  /* We had a locked PFN, so acquire the PFN lock to dereference it */
1552  ASSERT(PointerProtoPte != NULL);
1553  OldIrql = MiAcquirePfnLock();
1554 
1555  /* Dereference the locked PFN */
1557  ASSERT(OutPfn->u3.e2.ReferenceCount >= 1);
1558 
1559  /* And now release the lock */
1560  MiReleasePfnLock(OldIrql);
1561  }
1562 
1563  /* Complete this as a transition fault */
1565  ASSERT(OldIrql <= APC_LEVEL);
1567  return Status;
1568  }
1569  }
1570 
1571  /* Is this a transition PTE */
1572  if (TempPte.u.Soft.Transition)
1573  {
1574  PKEVENT* InPageBlock = NULL;
1575  PKEVENT PreviousPageEvent;
1576  KEVENT CurrentPageEvent;
1577 
1578  /* Lock the PFN database */
1579  LockIrql = MiAcquirePfnLock();
1580 
1581  /* Resolve */
1582  Status = MiResolveTransitionFault(!MI_IS_NOT_PRESENT_FAULT(FaultCode), Address, PointerPte, Process, LockIrql, &InPageBlock);
1583 
1585 
1586  if (InPageBlock != NULL)
1587  {
1588  /* Another thread is reading or writing this page. Put us into the waiting queue. */
1589  KeInitializeEvent(&CurrentPageEvent, NotificationEvent, FALSE);
1590  PreviousPageEvent = *InPageBlock;
1591  *InPageBlock = &CurrentPageEvent;
1592  }
1593 
1594  /* And now release the lock and leave*/
1595  MiReleasePfnLock(LockIrql);
1596 
1597  if (InPageBlock != NULL)
1598  {
1599  KeWaitForSingleObject(&CurrentPageEvent, WrPageIn, KernelMode, FALSE, NULL);
1600 
1601  /* Let's the chain go on */
1602  if (PreviousPageEvent)
1603  {
1604  KeSetEvent(PreviousPageEvent, IO_NO_INCREMENT, FALSE);
1605  }
1606  }
1607 
1609  ASSERT(OldIrql <= APC_LEVEL);
1611  return Status;
1612  }
1613 
1614  /* Should we page the data back in ? */
1615  if (TempPte.u.Soft.PageFileHigh != 0)
1616  {
1617  /* Lock the PFN database */
1618  LockIrql = MiAcquirePfnLock();
1619 
1620  /* Resolve */
1621  Status = MiResolvePageFileFault(!MI_IS_NOT_PRESENT_FAULT(FaultCode), Address, PointerPte, Process, &LockIrql);
1622 
1623  /* And now release the lock and leave*/
1624  MiReleasePfnLock(LockIrql);
1625 
1627  ASSERT(OldIrql <= APC_LEVEL);
1629  return Status;
1630  }
1631 
1632  //
1633  // The PTE must be invalid but not completely empty. It must also not be a
1634  // prototype a transition or a paged-out PTE as those scenarii should've been handled above.
1635  // These are all Windows checks
1636  //
1637  ASSERT(TempPte.u.Hard.Valid == 0);
1638  ASSERT(TempPte.u.Soft.Prototype == 0);
1639  ASSERT(TempPte.u.Soft.Transition == 0);
1640  ASSERT(TempPte.u.Soft.PageFileHigh == 0);
1641  ASSERT(TempPte.u.Long != 0);
1642 
1643  //
1644  // If we got this far, the PTE can only be a demand zero PTE, which is what
1645  // we want. Go handle it!
1646  //
1648  PointerPte,
1649  (ULONG)TempPte.u.Soft.Protection,
1650  Process,
1651  MM_NOIRQL);
1653  if (NT_SUCCESS(Status))
1654  {
1655 #if MI_TRACE_PFNS
1656  /* Update debug info */
1657  if (TrapInformation)
1658  MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = (PVOID)((PKTRAP_FRAME)TrapInformation)->Eip;
1659  else
1660  MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = _ReturnAddress();
1661 #endif
1662 
1663  //
1664  // Make sure we're returning in a sane state and pass the status down
1665  //
1668  return Status;
1669  }
1670 
1671  //
1672  // Generate an access fault
1673  //
1674  return STATUS_ACCESS_VIOLATION;
1675 }
1676 
1677 NTSTATUS
1678 NTAPI
1680  IN PVOID Address,
1682  IN PVOID TrapInformation)
1683 {
1684  KIRQL OldIrql = KeGetCurrentIrql(), LockIrql;
1685  PMMPTE ProtoPte = NULL;
1686  PMMPTE PointerPte = MiAddressToPte(Address);
1687  PMMPDE PointerPde = MiAddressToPde(Address);
1688 #if (_MI_PAGING_LEVELS >= 3)
1689  PMMPDE PointerPpe = MiAddressToPpe(Address);
1690 #if (_MI_PAGING_LEVELS == 4)
1691  PMMPDE PointerPxe = MiAddressToPxe(Address);
1692 #endif
1693 #endif
1694  MMPTE TempPte;
1695  PETHREAD CurrentThread;
1697  NTSTATUS Status;
1698  PMMSUPPORT WorkingSet;
1699  ULONG ProtectionCode;
1700  PMMVAD Vad = NULL;
1701  PFN_NUMBER PageFrameIndex;
1702  ULONG Color;
1703  BOOLEAN IsSessionAddress;
1704  PMMPFN Pfn1;
1705  DPRINT("ARM3 FAULT AT: %p\n", Address);
1706 
1707  /* Check for page fault on high IRQL */
1708  if (OldIrql > APC_LEVEL)
1709  {
1710 #if (_MI_PAGING_LEVELS < 3)
1711  /* Could be a page table for paged pool, which we'll allow */
1712  if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)) MiSynchronizeSystemPde((PMMPDE)PointerPte);
1714 #endif
1715  /* Check if any of the top-level pages are invalid */
1716  if (
1717 #if (_MI_PAGING_LEVELS == 4)
1718  (PointerPxe->u.Hard.Valid == 0) ||
1719 #endif
1720 #if (_MI_PAGING_LEVELS >= 3)
1721  (PointerPpe->u.Hard.Valid == 0) ||
1722 #endif
1723  (PointerPde->u.Hard.Valid == 0) ||
1724  (PointerPte->u.Hard.Valid == 0))
1725  {
1726  /* This fault is not valid, print out some debugging help */
1727  DbgPrint("MM:***PAGE FAULT AT IRQL > 1 Va %p, IRQL %lx\n",
1728  Address,
1729  OldIrql);
1730  if (TrapInformation)
1731  {
1732  PKTRAP_FRAME TrapFrame = TrapInformation;
1733 #ifdef _M_IX86
1734  DbgPrint("MM:***EIP %p, EFL %p\n", TrapFrame->Eip, TrapFrame->EFlags);
1735  DbgPrint("MM:***EAX %p, ECX %p EDX %p\n", TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
1736  DbgPrint("MM:***EBX %p, ESI %p EDI %p\n", TrapFrame->Ebx, TrapFrame->Esi, TrapFrame->Edi);
1737 #elif defined(_M_AMD64)
1738  DbgPrint("MM:***RIP %p, EFL %p\n", TrapFrame->Rip, TrapFrame->EFlags);
1739  DbgPrint("MM:***RAX %p, RCX %p RDX %p\n", TrapFrame->Rax, TrapFrame->Rcx, TrapFrame->Rdx);
1740  DbgPrint("MM:***RBX %p, RSI %p RDI %p\n", TrapFrame->Rbx, TrapFrame->Rsi, TrapFrame->Rdi);
1741 #elif defined(_M_ARM)
1742  DbgPrint("MM:***PC %p\n", TrapFrame->Pc);
1743  DbgPrint("MM:***R0 %p, R1 %p R2 %p, R3 %p\n", TrapFrame->R0, TrapFrame->R1, TrapFrame->R2, TrapFrame->R3);
1744  DbgPrint("MM:***R11 %p, R12 %p SP %p, LR %p\n", TrapFrame->R11, TrapFrame->R12, TrapFrame->Sp, TrapFrame->Lr);
1745 #endif
1746  }
1747 
1748  /* Tell the trap handler to fail */
1749  return STATUS_IN_PAGE_ERROR | 0x10000000;
1750  }
1751 
1752  /* Not yet implemented in ReactOS */
1753  ASSERT(MI_IS_PAGE_LARGE(PointerPde) == FALSE);
1754  ASSERT((!MI_IS_NOT_PRESENT_FAULT(FaultCode) && MI_IS_PAGE_COPY_ON_WRITE(PointerPte)) == FALSE);
1755 
1756  /* Check if this was a write */
1757  if (MI_IS_WRITE_ACCESS(FaultCode))
1758  {
1759  /* Was it to a read-only page? */
1760  Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1761  if (!(PointerPte->u.Long & PTE_READWRITE) &&
1763  {
1764  /* Crash with distinguished bugcheck code */
1765  KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1766  (ULONG_PTR)Address,
1767  PointerPte->u.Long,
1768  (ULONG_PTR)TrapInformation,
1769  10);
1770  }
1771  }
1772 
1773  /* Nothing is actually wrong */
1774  DPRINT1("Fault at IRQL %u is ok (%p)\n", OldIrql, Address);
1775  return STATUS_SUCCESS;
1776  }
1777 
1778  /* Check for kernel fault address */
1779  if (Address >= MmSystemRangeStart)
1780  {
1781  /* Bail out, if the fault came from user mode */
1782  if (Mode == UserMode) return STATUS_ACCESS_VIOLATION;
1783 
1784 #if (_MI_PAGING_LEVELS == 2)
1785  if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)) MiSynchronizeSystemPde((PMMPDE)PointerPte);
1787 #endif
1788 
1789  /* Check if the higher page table entries are invalid */
1790  if (
1791 #if (_MI_PAGING_LEVELS == 4)
1792  /* AMD64 system, check if PXE is invalid */
1793  (PointerPxe->u.Hard.Valid == 0) ||
1794 #endif
1795 #if (_MI_PAGING_LEVELS >= 3)
1796  /* PAE/AMD64 system, check if PPE is invalid */
1797  (PointerPpe->u.Hard.Valid == 0) ||
1798 #endif
1799  /* Always check if the PDE is valid */
1800  (PointerPde->u.Hard.Valid == 0))
1801  {
1802  /* PXE/PPE/PDE (still) not valid, kill the system */
1803  KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
1804  (ULONG_PTR)Address,
1805  FaultCode,
1806  (ULONG_PTR)TrapInformation,
1807  2);
1808  }
1809 
1810  /* Not handling session faults yet */
1811  IsSessionAddress = MI_IS_SESSION_ADDRESS(Address);
1812 
1813  /* The PDE is valid, so read the PTE */
1814  TempPte = *PointerPte;
1815  if (TempPte.u.Hard.Valid == 1)
1816  {
1817  /* Check if this was system space or session space */
1818  if (!IsSessionAddress)
1819  {
1820  /* Check if the PTE is still valid under PFN lock */
1821  OldIrql = MiAcquirePfnLock();
1822  TempPte = *PointerPte;
1823  if (TempPte.u.Hard.Valid)
1824  {
1825  /* Check if this was a write */
1826  if (MI_IS_WRITE_ACCESS(FaultCode))
1827  {
1828  /* Was it to a read-only page? */
1829  Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1830  if (!(PointerPte->u.Long & PTE_READWRITE) &&
1832  {
1833  /* Crash with distinguished bugcheck code */
1834  KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1835  (ULONG_PTR)Address,
1836  PointerPte->u.Long,
1837  (ULONG_PTR)TrapInformation,
1838  11);
1839  }
1840  }
1841 
1842  /* Check for execution of non-executable memory */
1843  if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
1845  {
1846  KeBugCheckEx(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY,
1847  (ULONG_PTR)Address,
1848  (ULONG_PTR)TempPte.u.Long,
1849  (ULONG_PTR)TrapInformation,
1850  1);
1851  }
1852  }
1853 
1854  /* Release PFN lock and return all good */
1855  MiReleasePfnLock(OldIrql);
1856  return STATUS_SUCCESS;
1857  }
1858  }
1859 #if (_MI_PAGING_LEVELS == 2)
1860  /* Check if this was a session PTE that needs to remap the session PDE */
1862  {
1863  /* Do the remapping */
1864  Status = MiCheckPdeForSessionSpace(Address);
1865  if (!NT_SUCCESS(Status))
1866  {
1867  /* It failed, this address is invalid */
1868  KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
1869  (ULONG_PTR)Address,
1870  FaultCode,
1871  (ULONG_PTR)TrapInformation,
1872  6);
1873  }
1874  }
1875 #else
1876 
1877 _WARN("Session space stuff is not implemented yet!")
1878 
1879 #endif
1880 
1881  /* Check for a fault on the page table or hyperspace */
1883  {
1884 #if (_MI_PAGING_LEVELS < 3)
1885  /* Windows does this check but I don't understand why -- it's done above! */
1887 #endif
1888  /* Handle this as a user mode fault */
1889  goto UserFault;
1890  }
1891 
1892  /* Get the current thread */
1893  CurrentThread = PsGetCurrentThread();
1894 
1895  /* What kind of address is this */
1896  if (!IsSessionAddress)
1897  {
1898  /* Use the system working set */
1899  WorkingSet = &MmSystemCacheWs;
1900  CurrentProcess = NULL;
1901 
1902  /* Make sure we don't have a recursive working set lock */
1903  if ((CurrentThread->OwnsProcessWorkingSetExclusive) ||
1904  (CurrentThread->OwnsProcessWorkingSetShared) ||
1905  (CurrentThread->OwnsSystemWorkingSetExclusive) ||
1906  (CurrentThread->OwnsSystemWorkingSetShared) ||
1907  (CurrentThread->OwnsSessionWorkingSetExclusive) ||
1908  (CurrentThread->OwnsSessionWorkingSetShared))
1909  {
1910  /* Fail */
1911  return STATUS_IN_PAGE_ERROR | 0x10000000;
1912  }
1913  }
1914  else
1915  {
1916  /* Use the session process and working set */
1918  WorkingSet = &MmSessionSpace->GlobalVirtualAddress->Vm;
1919 
1920  /* Make sure we don't have a recursive working set lock */
1921  if ((CurrentThread->OwnsSessionWorkingSetExclusive) ||
1922  (CurrentThread->OwnsSessionWorkingSetShared))
1923  {
1924  /* Fail */
1925  return STATUS_IN_PAGE_ERROR | 0x10000000;
1926  }
1927  }
1928 
1929  /* Acquire the working set lock */
1930  KeRaiseIrql(APC_LEVEL, &LockIrql);
1931  MiLockWorkingSet(CurrentThread, WorkingSet);
1932 
1933  /* Re-read PTE now that we own the lock */
1934  TempPte = *PointerPte;
1935  if (TempPte.u.Hard.Valid == 1)
1936  {
1937  /* Check if this was a write */
1938  if (MI_IS_WRITE_ACCESS(FaultCode))
1939  {
1940  /* Was it to a read-only page that is not copy on write? */
1941  Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1942  if (!(TempPte.u.Long & PTE_READWRITE) &&
1943  !(Pfn1->OriginalPte.u.Soft.Protection & MM_READWRITE) &&
1945  {
1946  /* Case not yet handled */
1947  ASSERT(!IsSessionAddress);
1948 
1949  /* Crash with distinguished bugcheck code */
1950  KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1951  (ULONG_PTR)Address,
1952  TempPte.u.Long,
1953  (ULONG_PTR)TrapInformation,
1954  12);
1955  }
1956  }
1957 
1958  /* Check for execution of non-executable memory */
1959  if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
1961  {
1962  KeBugCheckEx(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY,
1963  (ULONG_PTR)Address,
1964  (ULONG_PTR)TempPte.u.Long,
1965  (ULONG_PTR)TrapInformation,
1966  2);
1967  }
1968 
1969  /* Check for read-only write in session space */
1970  if ((IsSessionAddress) &&
1971  MI_IS_WRITE_ACCESS(FaultCode) &&
1973  {
1974  /* Sanity check */
1976 
1977  /* Was this COW? */
1979  {
1980  /* Then this is not allowed */
1981  KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1982  (ULONG_PTR)Address,
1983  (ULONG_PTR)TempPte.u.Long,
1984  (ULONG_PTR)TrapInformation,
1985  13);
1986  }
1987 
1988  /* Otherwise, handle COW */
1989  ASSERT(FALSE);
1990  }
1991 
1992  /* Release the working set */
1993  MiUnlockWorkingSet(CurrentThread, WorkingSet);
1994  KeLowerIrql(LockIrql);
1995 
1996  /* Otherwise, the PDE was probably invalid, and all is good now */
1997  return STATUS_SUCCESS;
1998  }
1999 
2000  /* Check one kind of prototype PTE */
2001  if (TempPte.u.Soft.Prototype)
2002  {
2003  /* Make sure protected pool is on, and that this is a pool address */
2005  (((Address >= MmNonPagedPoolStart) &&
2009  (Address < MmNonPagedPoolEnd))))
2010  {
2011  /* Bad boy, bad boy, whatcha gonna do, whatcha gonna do when ARM3 comes for you! */
2012  KeBugCheckEx(DRIVER_CAUGHT_MODIFYING_FREED_POOL,
2013  (ULONG_PTR)Address,
2014  FaultCode,
2015  Mode,
2016  4);
2017  }
2018 
2019  /* Get the prototype PTE! */
2020  ProtoPte = MiProtoPteToPte(&TempPte);
2021 
2022  /* Do we need to locate the prototype PTE in session space? */
2023  if ((IsSessionAddress) &&
2024  (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED))
2025  {
2026  /* Yep, go find it as well as the VAD for it */
2027  ProtoPte = MiCheckVirtualAddress(Address,
2028  &ProtectionCode,
2029  &Vad);
2030  ASSERT(ProtoPte != NULL);
2031  }
2032  }
2033  else
2034  {
2035  /* We don't implement transition PTEs */
2036  ASSERT(TempPte.u.Soft.Transition == 0);
2037 
2038  /* Check for no-access PTE */
2039  if (TempPte.u.Soft.Protection == MM_NOACCESS)
2040  {
2041  /* Bugcheck the system! */
2042  KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
2043  (ULONG_PTR)Address,
2044  FaultCode,
2045  (ULONG_PTR)TrapInformation,
2046  1);
2047  }
2048 
2049  /* Check for no protecton at all */
2050  if (TempPte.u.Soft.Protection == MM_ZERO_ACCESS)
2051  {
2052  /* Bugcheck the system! */
2053  KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
2054  (ULONG_PTR)Address,
2055  FaultCode,
2056  (ULONG_PTR)TrapInformation,
2057  0);
2058  }
2059  }
2060 
2061  /* Check for demand page */
2062  if (MI_IS_WRITE_ACCESS(FaultCode) &&
2063  !(ProtoPte) &&
2064  !(IsSessionAddress) &&
2065  !(TempPte.u.Hard.Valid))
2066  {
2067  /* Get the protection code */
2068  ASSERT(TempPte.u.Soft.Transition == 0);
2069  if (!(TempPte.u.Soft.Protection & MM_READWRITE))
2070  {
2071  /* Bugcheck the system! */
2072  KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
2073  (ULONG_PTR)Address,
2074  TempPte.u.Long,
2075  (ULONG_PTR)TrapInformation,
2076  14);
2077  }
2078  }
2079 
2080  /* Now do the real fault handling */
2081  Status = MiDispatchFault(FaultCode,
2082  Address,
2083  PointerPte,
2084  ProtoPte,
2085  FALSE,
2087  TrapInformation,
2088  NULL);
2089 
2090  /* Release the working set */
2092  MiUnlockWorkingSet(CurrentThread, WorkingSet);
2093  KeLowerIrql(LockIrql);
2094 
2095  /* We are done! */
2096  DPRINT("Fault resolved with status: %lx\n", Status);
2097  return Status;
2098  }
2099 
2100  /* This is a user fault */
2101 UserFault:
2102  CurrentThread = PsGetCurrentThread();
2103  CurrentProcess = (PEPROCESS)CurrentThread->Tcb.ApcState.Process;
2104 
2105  /* Lock the working set */
2106  MiLockProcessWorkingSet(CurrentProcess, CurrentThread);
2107 
2108  ProtectionCode = MM_INVALID_PROTECTION;
2109 
2110 #if (_MI_PAGING_LEVELS == 4)
2111  /* Check if the PXE is valid */
2112  if (PointerPxe->u.Hard.Valid == 0)
2113  {
2114  /* Right now, we only handle scenarios where the PXE is totally empty */
2115  ASSERT(PointerPxe->u.Long == 0);
2116 
2117  /* This is only possible for user mode addresses! */
2118  ASSERT(PointerPte <= MiHighestUserPte);
2119 
2120  /* Check if we have a VAD */
2121  MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2122  if (ProtectionCode == MM_NOACCESS)
2123  {
2124  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2125  return STATUS_ACCESS_VIOLATION;
2126  }
2127 
2128  /* Resolve a demand zero fault */
2129  MiResolveDemandZeroFault(PointerPpe,
2130  PointerPxe,
2133  MM_NOIRQL);
2134 
2135  /* We should come back with a valid PXE */
2136  ASSERT(PointerPxe->u.Hard.Valid == 1);
2137  }
2138 #endif
2139 
2140 #if (_MI_PAGING_LEVELS >= 3)
2141  /* Check if the PPE is valid */
2142  if (PointerPpe->u.Hard.Valid == 0)
2143  {
2144  /* Right now, we only handle scenarios where the PPE is totally empty */
2145  ASSERT(PointerPpe->u.Long == 0);
2146 
2147  /* This is only possible for user mode addresses! */
2148  ASSERT(PointerPte <= MiHighestUserPte);
2149 
2150  /* Check if we have a VAD, unless we did this already */
2151  if (ProtectionCode == MM_INVALID_PROTECTION)
2152  {
2153  MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2154  }
2155 
2156  if (ProtectionCode == MM_NOACCESS)
2157  {
2158  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2159  return STATUS_ACCESS_VIOLATION;
2160  }
2161 
2162  /* Resolve a demand zero fault */
2163  MiResolveDemandZeroFault(PointerPde,
2164  PointerPpe,
2167  MM_NOIRQL);
2168 
2169  /* We should come back with a valid PPE */
2170  ASSERT(PointerPpe->u.Hard.Valid == 1);
2171  MiIncrementPageTableReferences(PointerPde);
2172  }
2173 #endif
2174 
2175  /* Check if the PDE is invalid */
2176  if (PointerPde->u.Hard.Valid == 0)
2177  {
2178  /* Right now, we only handle scenarios where the PDE is totally empty */
2179  ASSERT(PointerPde->u.Long == 0);
2180 
2181  /* And go dispatch the fault on the PDE. This should handle the demand-zero */
2182 #if MI_TRACE_PFNS
2183  UserPdeFault = TRUE;
2184 #endif
2185  /* Check if we have a VAD, unless we did this already */
2186  if (ProtectionCode == MM_INVALID_PROTECTION)
2187  {
2188  MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2189  }
2190 
2191  if (ProtectionCode == MM_NOACCESS)
2192  {
2193 #if (_MI_PAGING_LEVELS == 2)
2194  /* Could be a page table for paged pool */
2196 #endif
2197  /* Has the code above changed anything -- is this now a valid PTE? */
2198  Status = (PointerPde->u.Hard.Valid == 1) ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
2199 
2200  /* Either this was a bogus VA or we've fixed up a paged pool PDE */
2201  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2202  return Status;
2203  }
2204 
2205  /* Resolve a demand zero fault */
2206  MiResolveDemandZeroFault(PointerPte,
2207  PointerPde,
2210  MM_NOIRQL);
2211 #if _MI_PAGING_LEVELS >= 3
2212  MiIncrementPageTableReferences(PointerPte);
2213 #endif
2214 
2215 #if MI_TRACE_PFNS
2216  UserPdeFault = FALSE;
2217  /* Update debug info */
2218  if (TrapInformation)
2219  MiGetPfnEntry(PointerPde->u.Hard.PageFrameNumber)->CallSite = (PVOID)((PKTRAP_FRAME)TrapInformation)->Eip;
2220  else
2221  MiGetPfnEntry(PointerPde->u.Hard.PageFrameNumber)->CallSite = _ReturnAddress();
2222 #endif
2223  /* We should come back with APCs enabled, and with a valid PDE */
2225  ASSERT(PointerPde->u.Hard.Valid == 1);
2226  }
2227  else
2228  {
2229  /* Not yet implemented in ReactOS */
2230  ASSERT(MI_IS_PAGE_LARGE(PointerPde) == FALSE);
2231  }
2232 
2233  /* Now capture the PTE. */
2234  TempPte = *PointerPte;
2235 
2236  /* Check if the PTE is valid */
2237  if (TempPte.u.Hard.Valid)
2238  {
2239  /* Check if this is a write on a readonly PTE */
2240  if (MI_IS_WRITE_ACCESS(FaultCode))
2241  {
2242  /* Is this a copy on write PTE? */
2244  {
2245  PFN_NUMBER PageFrameIndex, OldPageFrameIndex;
2246  PMMPFN Pfn1;
2247 
2248  LockIrql = MiAcquirePfnLock();
2249 
2250  ASSERT(MmAvailablePages > 0);
2251 
2254 
2255  /* Allocate a new page and copy it */
2257  OldPageFrameIndex = PFN_FROM_PTE(&TempPte);
2258 
2259  MiCopyPfn(PageFrameIndex, OldPageFrameIndex);
2260 
2261  /* Dereference whatever this PTE is referencing */
2262  Pfn1 = MI_PFN_ELEMENT(OldPageFrameIndex);
2263  ASSERT(Pfn1->u3.e1.PrototypePte == 1);
2264  ASSERT(!MI_IS_PFN_DELETED(Pfn1));
2265  ProtoPte = Pfn1->PteAddress;
2266  MiDeletePte(PointerPte, Address, CurrentProcess, ProtoPte);
2267 
2268  /* And make a new shiny one with our page */
2269  MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
2270  TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
2271  TempPte.u.Hard.Write = 1;
2272  TempPte.u.Hard.CopyOnWrite = 0;
2273 
2274  MI_WRITE_VALID_PTE(PointerPte, TempPte);
2275 
2276  MiReleasePfnLock(LockIrql);
2277 
2278  /* Return the status */
2279  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2281  }
2282 
2283  /* Is this a read-only PTE? */
2285  {
2286  /* Return the status */
2287  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2288  return STATUS_ACCESS_VIOLATION;
2289  }
2290  }
2291 
2292  /* Check for execution of non-executable memory */
2293  if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
2295  {
2296  /* Return the status */
2297  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2298  return STATUS_ACCESS_VIOLATION;
2299  }
2300 
2301  /* The fault has already been resolved by a different thread */
2302  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2303  return STATUS_SUCCESS;
2304  }
2305 
2306  /* Quick check for demand-zero */
2307  if ((TempPte.u.Long == (MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS)) ||
2309  {
2310  /* Resolve the fault */
2312  PointerPte,
2313  TempPte.u.Soft.Protection,
2315  MM_NOIRQL);
2316 
2317 #if MI_TRACE_PFNS
2318  /* Update debug info */
2319  if (TrapInformation)
2320  MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = (PVOID)((PKTRAP_FRAME)TrapInformation)->Eip;
2321  else
2322  MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = _ReturnAddress();
2323 #endif
2324 
2325  /* Return the status */
2326  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2328  }
2329 
2330  /* Check for zero PTE */
2331  if (TempPte.u.Long == 0)
2332  {
2333  /* Check if this address range belongs to a valid allocation (VAD) */
2334  ProtoPte = MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2335  if (ProtectionCode == MM_NOACCESS)
2336  {
2337 #if (_MI_PAGING_LEVELS == 2)
2338  /* Could be a page table for paged pool */
2340 #endif
2341  /* Has the code above changed anything -- is this now a valid PTE? */
2342  Status = (PointerPte->u.Hard.Valid == 1) ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
2343 
2344  /* Either this was a bogus VA or we've fixed up a paged pool PDE */
2345  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2346  return Status;
2347  }
2348 
2349  /*
2350  * Check if this is a real user-mode address or actually a kernel-mode
2351  * page table for a user mode address
2352  */
2354 #if _MI_PAGING_LEVELS >= 3
2355  || MiIsUserPte(Address)
2356 #if _MI_PAGING_LEVELS == 4
2357  || MiIsUserPde(Address)
2358 #endif
2359 #endif
2360  )
2361  {
2362  /* Add an additional page table reference */
2364  }
2365 
2366  /* Is this a guard page? */
2367  if ((ProtectionCode & MM_PROTECT_SPECIAL) == MM_GUARDPAGE)
2368  {
2369  /* The VAD protection cannot be MM_DECOMMIT! */
2370  ASSERT(ProtectionCode != MM_DECOMMIT);
2371 
2372  /* Remove the bit */
2373  TempPte.u.Soft.Protection = ProtectionCode & ~MM_GUARDPAGE;
2374  MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2375 
2376  /* Not supported */
2377  ASSERT(ProtoPte == NULL);
2378  ASSERT(CurrentThread->ApcNeeded == 0);
2379 
2380  /* Drop the working set lock */
2381  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2383 
2384  /* Handle stack expansion */
2385  return MiCheckForUserStackOverflow(Address, TrapInformation);
2386  }
2387 
2388  /* Did we get a prototype PTE back? */
2389  if (!ProtoPte)
2390  {
2391  /* Is this PTE actually part of the PDE-PTE self-mapping directory? */
2392  if (PointerPde == MiAddressToPde(PTE_BASE))
2393  {
2394  /* Then it's really a demand-zero PDE (on behalf of user-mode) */
2395 #ifdef _M_ARM
2396  _WARN("This is probably completely broken!");
2398 #else
2399  MI_WRITE_INVALID_PDE(PointerPte, DemandZeroPde);
2400 #endif
2401  }
2402  else
2403  {
2404  /* No, create a new PTE. First, write the protection */
2405  TempPte.u.Soft.Protection = ProtectionCode;
2406  MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2407  }
2408 
2409  /* Lock the PFN database since we're going to grab a page */
2410  OldIrql = MiAcquirePfnLock();
2411 
2412  /* Make sure we have enough pages */
2413  ASSERT(MmAvailablePages >= 32);
2414 
2415  /* Try to get a zero page */
2417  MI_SET_PROCESS2(CurrentProcess->ImageFileName);
2419  PageFrameIndex = MiRemoveZeroPageSafe(Color);
2420  if (!PageFrameIndex)
2421  {
2422  /* Grab a page out of there. Later we should grab a colored zero page */
2423  PageFrameIndex = MiRemoveAnyPage(Color);
2424  ASSERT(PageFrameIndex);
2425 
2426  /* Release the lock since we need to do some zeroing */
2427  MiReleasePfnLock(OldIrql);
2428 
2429  /* Zero out the page, since it's for user-mode */
2430  MiZeroPfn(PageFrameIndex);
2431 
2432  /* Grab the lock again so we can initialize the PFN entry */
2433  OldIrql = MiAcquirePfnLock();
2434  }
2435 
2436  /* Initialize the PFN entry now */
2437  MiInitializePfn(PageFrameIndex, PointerPte, 1);
2438 
2439  /* Increment the count of pages in the process */
2440  CurrentProcess->NumberOfPrivatePages++;
2441 
2442  /* One more demand-zero fault */
2443  KeGetCurrentPrcb()->MmDemandZeroCount++;
2444 
2445  /* And we're done with the lock */
2446  MiReleasePfnLock(OldIrql);
2447 
2448  /* Fault on user PDE, or fault on user PTE? */
2449  if (PointerPte <= MiHighestUserPte)
2450  {
2451  /* User fault, build a user PTE */
2453  PointerPte,
2454  PointerPte->u.Soft.Protection,
2455  PageFrameIndex);
2456  }
2457  else
2458  {
2459  /* This is a user-mode PDE, create a kernel PTE for it */
2461  PointerPte,
2462  PointerPte->u.Soft.Protection,
2463  PageFrameIndex);
2464  }
2465 
2466  /* Write the dirty bit for writeable pages */
2468 
2469  /* And now write down the PTE, making the address valid */
2470  MI_WRITE_VALID_PTE(PointerPte, TempPte);
2471  Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
2472  ASSERT(Pfn1->u1.Event == NULL);
2473 
2474  /* Demand zero */
2476  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2478  }
2479 
2480  /* We should have a valid protection here */
2481  ASSERT(ProtectionCode != 0x100);
2482 
2483  /* Write the prototype PTE */
2485  TempPte.u.Soft.Protection = ProtectionCode;
2486  ASSERT(TempPte.u.Long != 0);
2487  MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2488  }
2489  else
2490  {
2491  /* Get the protection code and check if this is a proto PTE */
2492  ProtectionCode = (ULONG)TempPte.u.Soft.Protection;
2493  if (TempPte.u.Soft.Prototype)
2494  {
2495  /* Do we need to go find the real PTE? */
2496  if (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
2497  {
2498  /* Get the prototype pte and VAD for it */
2499  ProtoPte = MiCheckVirtualAddress(Address,
2500  &ProtectionCode,
2501  &Vad);
2502  if (!ProtoPte)
2503  {
2505  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2506  return STATUS_ACCESS_VIOLATION;
2507  }
2508  }
2509  else
2510  {
2511  /* Get the prototype PTE! */
2512  ProtoPte = MiProtoPteToPte(&TempPte);
2513 
2514  /* Is it read-only */
2515  if (TempPte.u.Proto.ReadOnly)
2516  {
2517  /* Set read-only code */
2518  ProtectionCode = MM_READONLY;
2519  }
2520  else
2521  {
2522  /* Set unknown protection */
2523  ProtectionCode = 0x100;
2524  ASSERT(CurrentProcess->CloneRoot != NULL);
2525  }
2526  }
2527  }
2528  }
2529 
2530  /* Do we have a valid protection code? */
2531  if (ProtectionCode != 0x100)
2532  {
2533  /* Run a software access check first, including to detect guard pages */
2534  Status = MiAccessCheck(PointerPte,
2535  !MI_IS_NOT_PRESENT_FAULT(FaultCode),
2536  Mode,
2537  ProtectionCode,
2538  TrapInformation,
2539  FALSE);
2540  if (Status != STATUS_SUCCESS)
2541  {
2542  /* Not supported */
2543  ASSERT(CurrentThread->ApcNeeded == 0);
2544 
2545  /* Drop the working set lock */
2546  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2548 
2549  /* Did we hit a guard page? */
2551  {
2552  /* Handle stack expansion */
2553  return MiCheckForUserStackOverflow(Address, TrapInformation);
2554  }
2555 
2556  /* Otherwise, fail back to the caller directly */
2557  return Status;
2558  }
2559  }
2560 
2561  /* Dispatch the fault */
2562  Status = MiDispatchFault(FaultCode,
2563  Address,
2564  PointerPte,
2565  ProtoPte,
2566  FALSE,
2568  TrapInformation,
2569  Vad);
2570 
2571  /* Return the status */
2573  MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2574  return Status;
2575 }
2576 
2577 NTSTATUS
2578 NTAPI
2580 {
2583 
2584  *ExecuteOptions = 0;
2585 
2586  if (CurrentProcess->Flags.ExecuteDisable)
2587  {
2588  *ExecuteOptions |= MEM_EXECUTE_OPTION_DISABLE;
2589  }
2590 
2591  if (CurrentProcess->Flags.ExecuteEnable)
2592  {
2593  *ExecuteOptions |= MEM_EXECUTE_OPTION_ENABLE;
2594  }
2595 
2596  if (CurrentProcess->Flags.DisableThunkEmulation)
2597  {
2598  *ExecuteOptions |= MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION;
2599  }
2600 
2601  if (CurrentProcess->Flags.Permanent)
2602  {
2603  *ExecuteOptions |= MEM_EXECUTE_OPTION_PERMANENT;
2604  }
2605 
2606  if (CurrentProcess->Flags.ExecuteDispatchEnable)
2607  {
2608  *ExecuteOptions |= MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE;
2609  }
2610 
2611  if (CurrentProcess->Flags.ImageDispatchEnable)
2612  {
2613  *ExecuteOptions |= MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE;
2614  }
2615 
2616  return STATUS_SUCCESS;
2617 }
2618 
2619 NTSTATUS
2620 NTAPI
2622 {
2624  KLOCK_QUEUE_HANDLE ProcessLock;
2627 
2628  /* Only accept valid flags */
2629  if (ExecuteOptions & ~MEM_EXECUTE_OPTION_VALID_FLAGS)
2630  {
2631  /* Fail */
2632  DPRINT1("Invalid no-execute options\n");
2633  return STATUS_INVALID_PARAMETER;
2634  }
2635 
2636  /* Change the NX state in the process lock */
2638 
2639  /* Don't change anything if the permanent flag was set */
2640  if (!CurrentProcess->Flags.Permanent)
2641  {
2642  /* Start by assuming it's not disabled */
2643  CurrentProcess->Flags.ExecuteDisable = FALSE;
2644 
2645  /* Now process each flag and turn the equivalent bit on */
2646  if (ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE)
2647  {
2648  CurrentProcess->Flags.ExecuteDisable = TRUE;
2649  }
2650  if (ExecuteOptions & MEM_EXECUTE_OPTION_ENABLE)
2651  {
2652  CurrentProcess->Flags.ExecuteEnable = TRUE;
2653  }
2654  if (ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)
2655  {
2656  CurrentProcess->Flags.DisableThunkEmulation = TRUE;
2657  }
2658  if (ExecuteOptions & MEM_EXECUTE_OPTION_PERMANENT)
2659  {
2660  CurrentProcess->Flags.Permanent = TRUE;
2661  }
2662  if (ExecuteOptions & MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE)
2663  {
2664  CurrentProcess->Flags.ExecuteDispatchEnable = TRUE;
2665  }
2666  if (ExecuteOptions & MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE)
2667  {
2668  CurrentProcess->Flags.ImageDispatchEnable = TRUE;
2669  }
2670 
2671  /* These are turned on by default if no-execution is also eanbled */
2672  if (CurrentProcess->Flags.ExecuteEnable)
2673  {
2674  CurrentProcess->Flags.ExecuteDispatchEnable = TRUE;
2675  CurrentProcess->Flags.ImageDispatchEnable = TRUE;
2676  }
2677 
2678  /* All good */
2680  }
2681 
2682  /* Release the lock and return status */
2683  KiReleaseProcessLock(&ProcessLock);
2684  return Status;
2685 }
2686 
2687 /* EOF */
union _MMVAD::@2535 u
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:177
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:1679
VOID NTAPI MiInitializePfn(IN PFN_NUMBER PageFrameIndex, IN PMMPTE PointerPte, IN BOOLEAN Modified)
Definition: pfnlist.c:962
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
#define IN
Definition: typedefs.h:39
#define MM_INVALID_PROTECTION
Definition: miarm.h:67
MMPTE PrototypePte
Definition: init.c:40
#define _MI_PAGING_LEVELS
Definition: mm.h:6
union _MMPFN::@1747 u1
UINT64 Rbx
Definition: ketypes.h:373
PPEB Peb
Definition: dllmain.c:27
FORCEINLINE VOID KiAcquireProcessLockRaiseToSynch(IN PKPROCESS Process, IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:651
#define MI_IS_NOT_PRESENT_FAULT(FaultCode)
Definition: mm.h:121
#define _Inout_
Definition: ms_sal.h:378
#define MI_PAGE_WRITE_COMBINED(x)
Definition: mm.h:103
#define MI_ASSERT_PFN_LOCK_HELD()
Definition: mm.h:996
#define DbgPrint
Definition: hal.h:12
#define MiAddressToPde(x)
Definition: mmx86.c:20
BOOLEAN NTAPI KeAreAllApcsDisabled(VOID)
Definition: apc.c:985
VOID NTAPI MiUnlinkPageFromList(IN PMMPFN Pfn)
Definition: pfnlist.c:265
_In_ ULONG Mode
Definition: hubbusif.h:303
FORCEINLINE VOID MiDereferencePfnAndDropLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1620
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define MI_MAKE_ACCESSED_PAGE(x)
Definition: mm.h:100
ULONG OwnsSystemWorkingSetShared
Definition: pstypes.h:1224
signed short * PSHORT
Definition: retypes.h:6
PMMPDE PageTables
Definition: miarm.h:512
NTSTATUS NTAPI MiDispatchFault(IN ULONG FaultCode, IN PVOID Address, IN PMMPTE PointerPte, IN PMMPTE PointerProtoPte, IN BOOLEAN Recursive, IN PEPROCESS Process, IN PVOID TrapInformation, IN PMMVAD Vad)
Definition: pagfault.c:1319
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:890
#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:350
#define MI_IS_SESSION_ADDRESS(Address)
Definition: miarm.h:171
#define HYDRA_PROCESS
Definition: pagfault.c:20
#define PAGE_GUARD
Definition: nt_native.h:1310
#define MM_DECOMMIT
Definition: miarm.h:64
#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:1103
#define MEM_EXECUTE_OPTION_VALID_FLAGS
Definition: mmtypes.h:79
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1079
#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:1792
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:237
#define MI_PTE_LOOKUP_NEEDED
Definition: miarm.h:246
#define MM_NOACCESS
Definition: miarm.h:65
HARDWARE_PDE_ARMV6 TempPde
Definition: winldr.c:78
PMM_SESSION_SPACE MmSessionSpace
Definition: session.c:21
FORCEINLINE VOID MiLockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1129
USHORT Modified
Definition: mm.h:349
union _MMPFN::@1749 u3
PVOID MmPagedPoolEnd
Definition: init.c:26
NTSTATUS NTAPI MmGetExecuteOptions(IN PULONG ExecuteOptions)
Definition: pagfault.c:2579
#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
struct _MMPFN::@1749::@1755 e2
#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
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
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:1747
MMVAD_FLAGS VadFlags
Definition: mmtypes.h:731
USHORT PageLocation
Definition: mm.h:354
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:369
PFN_NUMBER NTAPI MiRemoveZeroPage(IN ULONG Color)
Definition: pfnlist.c:533
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:352
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:386
#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:48
ULONG OwnsSessionWorkingSetShared
Definition: pstypes.h:1226
USHORT CacheAttribute
Definition: mm.h:356
#define MiAddressToPte(x)
Definition: mmx86.c:19
NTSTATUS NTAPI MmSetExecuteOptions(IN ULONG ExecuteOptions)
Definition: pagfault.c:2621
#define MM_NOIRQL
Definition: mm.h:59
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:375
PMMPTE LastPteForPagedPool
Definition: mm.h:478
#define FALSE
Definition: types.h:117
FORCEINLINE VOID MI_WRITE_VALID_PTE(IN PMMPTE PointerPte, IN MMPTE TempPte)
Definition: miarm.h:964
#define MI_SET_PROCESS(x)
Definition: mm.h:307
VOID NTAPI DbgBreakPoint(VOID)
#define MI_MAKE_CLEAN_PAGE(x)
Definition: mm.h:99
ULONG_PTR ShareCount
Definition: mm.h:379
FORCEINLINE VOID MI_WRITE_INVALID_PDE(IN PMMPDE PointerPde, IN MMPDE InvalidPde)
Definition: miarm.h:1040
#define _WARN(msg)
Definition: debug.h:263
UINT64 Rax
Definition: ketypes.h:322
KAPC_STATE ApcState
Definition: ketypes.h:1710
PKEVENT Event
Definition: mm.h:368
FORCEINLINE BOOLEAN MiIsUserPde(PVOID Address)
Definition: miarm.h:722
#define MI_SET_PROCESS2(x)
Definition: mm.h:308
ULONG OwnsSessionWorkingSetExclusive
Definition: pstypes.h:1225
BOOLEAN NTAPI KeIsAttachedProcess(VOID)
Definition: procobj.c:693
#define PsGetCurrentProcess
Definition: psfuncs.h:17
FORCEINLINE PFN_NUMBER MiRemoveZeroPageSafe(IN ULONG Color)
Definition: miarm.h:2420
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:934
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:309
#define _In_
Definition: ms_sal.h:308
FORCEINLINE VOID MiUnlockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1356
union _MMVAD::@2536 u2
PFN_NUMBER Page
Definition: section.c:4923
#define MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)
Definition: miarm.h:180
#define MI_SET_USAGE(x)
Definition: mm.h:306
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:741
#define NtCurrentProcess()
Definition: nt_native.h:1657
USHORT WriteInProgress
Definition: mm.h:351
#define MEM_EXECUTE_OPTION_ENABLE
Definition: mmtypes.h:74
KIRQL OldIrql
Definition: mm.h:1502
PMMPDE MmSystemPagePtes
Definition: init.c:41
union _MMPFN::@1752 u4
#define MM_ZERO_ACCESS
Definition: miarm.h:43
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:475
ULONG CurrentProcess
Definition: shell.c:125
ULONG_PTR PrivateMemory
Definition: mmtypes.h:695
VOID FASTCALL KeZeroPages(IN PVOID Address, IN ULONG Size)
Definition: cpu.c:56
#define ASSERT(a)
Definition: mode.c:44
#define MI_IS_SESSION_PTE(Pte)
Definition: miarm.h:174
#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:238
ULONG64 Valid
Definition: mmtypes.h:150
struct _MMPTE * PMMPTE
#define MI_IS_PFN_DELETED(x)
Definition: miarm.h:195
#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
union _MMPTE::@2275 u
HARDWARE_PTE_ARMV6 TempPte
Definition: winldr.c:76
#define MM_PROTECT_ACCESS
Definition: miarm.h:51
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
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:660
FORCEINLINE BOOLEAN MiIsUserPte(PVOID Address)
Definition: miarm.h:730
#define MI_IS_PAGE_LARGE(x)
Definition: mm.h:104
unsigned char UCHAR
Definition: xmlstorage.h:181
UINT64 Rdx
Definition: ketypes.h:324
FORCEINLINE USHORT MiIncrementPageTableReferences(IN PVOID Address)
Definition: miarm.h:2478
#define InterlockedExchangeAddSizeT(a, b)
Definition: interlocked.h:196
FORCEINLINE PMMPFN MI_PFN_ELEMENT(IN PFN_NUMBER Pfn)
Definition: miarm.h:1579
#define MM_READWRITE
Definition: inbv.c:12
ULONG64 PageFileHigh
Definition: mmtypes.h:93
#define MM_GUARDPAGE
Definition: miarm.h:57
FORCEINLINE VOID MiDropLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1590
Definition: mm.h:362
#define MI_IS_PAGE_WRITEABLE(x)
Definition: mm.h:106
#define InterlockedExchangePte(PointerPte, Value)
Definition: mm.h:179
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:1223
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:494
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:1000
NTSTATUS ReadStatus
Definition: mm.h:369
#define InterlockedExchange
Definition: armddk.h:54
UINT64 R11
Definition: ketypes.h:328
#define MI_IS_INSTRUCTION_FETCH(FaultCode)
Definition: mm.h:123
#define MI_IS_PAGE_TABLE_OR_HYPER_ADDRESS(Address)
Definition: miarm.h:183
ULONG_PTR Long
Definition: mmtypes.h:215
#define FLG_DISABLE_STACK_EXTENSION
Definition: pstypes.h:71
PVOID MmPagedPoolStart
Definition: miarm.h:579
PVOID MmNonPagedPoolStart
Definition: init.c:24
#define MM_EXECUTE_READWRITE
Definition: miarm.h:49
FORCEINLINE VOID MI_MAKE_HARDWARE_PTE_USER(IN PMMPTE NewPte, IN PMMPTE MappingPte, IN ULONG_PTR ProtectionMask, IN PFN_NUMBER PageFrameNumber)
Definition: miarm.h:832
NTSTATUS FASTCALL MiCheckPdeForPagedPool(IN PVOID Address)
Definition: pagfault.c:475
PFN_NUMBER NTAPI MiRemoveAnyPage(IN ULONG Color)
Definition: pfnlist.c:477
ULONG_PTR SIZE_T
Definition: typedefs.h:80
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
#define SYSTEM_PD_SIZE
Definition: miarm.h:32
Definition: compat.h:694
FORCEINLINE VOID MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte, IN MMPTE InvalidPte)
Definition: miarm.h:997
#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
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:978
PMMPTE PteAddress
Definition: mm.h:375
ULONG OwnsProcessWorkingSetShared
Definition: pstypes.h:1222
#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:765
#define NULL
Definition: types.h:112
MMPTE OriginalPte
Definition: mm.h:396
#define STATUS_STACK_OVERFLOW
Definition: ntstatus.h:489
UINT64 Rdi
Definition: ketypes.h:374
MMPDE DemandZeroPde
Definition: init.c:36
VOID NTAPI KeRaiseIrql(KIRQL NewIrql, PKIRQL OldIrql)
Definition: spinlock.c:27
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
union _MMPFN::@1748 u2
#define MI_IS_SESSION_IMAGE_ADDRESS(Address)
Definition: miarm.h:168
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
void * _ReturnAddress(void)
UINT64 Rip
Definition: ketypes.h:383
#define OUT
Definition: typedefs.h:40
ULONG64 ReadOnly
Definition: mmtypes.h:119
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:598
#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:1110
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:59
ULONG OwnsProcessWorkingSetExclusive
Definition: pstypes.h:1221
#define STATUS_IN_PAGE_ERROR
Definition: ntstatus.h:243
ULONG_PTR InPageError
Definition: mm.h:408
#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:1270
MMPTE MmDecommittedPte
Definition: init.c:44
PMMPTE MiHighestUserPte
Definition: mminit.c:233
#define DPRINT
Definition: sndvol32.h:71
VOID NTAPI KeLowerIrql(KIRQL NewIrql)
Definition: spinlock.c:39
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:323
FORCEINLINE BOOLEAN MI_IS_PHYSICAL_ADDRESS(IN PVOID Address)
Definition: miarm.h:950
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:388
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:812
FORCEINLINE VOID MiUnlockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1199
ULONG PageFrameNumber
Definition: mmtypes.h:109
#define PAGE_READWRITE
Definition: nt_native.h:1304