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