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