ReactOS  0.4.10-dev-234-g15c29d0
page.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS kernel
4  * FILE: ntoskrnl/mm/i386/page.c
5  * PURPOSE: Low level memory managment manipulation
6  *
7  * PROGRAMMERS: David Welch (welch@cwcom.net)
8  */
9 
10 /* INCLUDES ***************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 #include <mm/ARM3/miarm.h>
16 
17 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, MmInitGlobalKernelPageDirectory)
19 #endif
20 
21 #define ADDR_TO_PDE_OFFSET MiAddressToPdeOffset
22 #define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (1024 * PAGE_SIZE))
23 
24 /* GLOBALS *****************************************************************/
25 
26 #define PA_BIT_PRESENT (0)
27 #define PA_BIT_READWRITE (1)
28 #define PA_BIT_USER (2)
29 #define PA_BIT_WT (3)
30 #define PA_BIT_CD (4)
31 #define PA_BIT_ACCESSED (5)
32 #define PA_BIT_DIRTY (6)
33 #define PA_BIT_GLOBAL (8)
34 
35 #define PA_PRESENT (1 << PA_BIT_PRESENT)
36 #define PA_READWRITE (1 << PA_BIT_READWRITE)
37 #define PA_USER (1 << PA_BIT_USER)
38 #define PA_DIRTY (1 << PA_BIT_DIRTY)
39 #define PA_WT (1 << PA_BIT_WT)
40 #define PA_CD (1 << PA_BIT_CD)
41 #define PA_ACCESSED (1 << PA_BIT_ACCESSED)
42 #define PA_GLOBAL (1 << PA_BIT_GLOBAL)
43 
44 #define IS_HYPERSPACE(v) (((ULONG)(v) >= HYPER_SPACE && (ULONG)(v) <= HYPER_SPACE_END))
45 
46 #define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT)
47 #define PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
48 
49 #define PAGE_MASK(x) ((x)&(~0xfff))
50 
51 const
52 ULONG
54 {
55  //
56  // These are the base MM_ protection flags
57  //
58  0,
59  PTE_READONLY | PTE_ENABLE_CACHE,
60  PTE_EXECUTE | PTE_ENABLE_CACHE,
61  PTE_EXECUTE_READ | PTE_ENABLE_CACHE,
62  PTE_READWRITE | PTE_ENABLE_CACHE,
63  PTE_WRITECOPY | PTE_ENABLE_CACHE,
64  PTE_EXECUTE_READWRITE | PTE_ENABLE_CACHE,
65  PTE_EXECUTE_WRITECOPY | PTE_ENABLE_CACHE,
66  //
67  // These OR in the MM_NOCACHE flag
68  //
69  0,
70  PTE_READONLY | PTE_DISABLE_CACHE,
71  PTE_EXECUTE | PTE_DISABLE_CACHE,
72  PTE_EXECUTE_READ | PTE_DISABLE_CACHE,
73  PTE_READWRITE | PTE_DISABLE_CACHE,
74  PTE_WRITECOPY | PTE_DISABLE_CACHE,
75  PTE_EXECUTE_READWRITE | PTE_DISABLE_CACHE,
76  PTE_EXECUTE_WRITECOPY | PTE_DISABLE_CACHE,
77  //
78  // These OR in the MM_DECOMMIT flag, which doesn't seem supported on x86/64/ARM
79  //
80  0,
81  PTE_READONLY | PTE_ENABLE_CACHE,
82  PTE_EXECUTE | PTE_ENABLE_CACHE,
83  PTE_EXECUTE_READ | PTE_ENABLE_CACHE,
84  PTE_READWRITE | PTE_ENABLE_CACHE,
85  PTE_WRITECOPY | PTE_ENABLE_CACHE,
86  PTE_EXECUTE_READWRITE | PTE_ENABLE_CACHE,
87  PTE_EXECUTE_WRITECOPY | PTE_ENABLE_CACHE,
88  //
89  // These OR in the MM_NOACCESS flag, which seems to enable WriteCombining?
90  //
91  0,
92  PTE_READONLY | PTE_WRITECOMBINED_CACHE,
93  PTE_EXECUTE | PTE_WRITECOMBINED_CACHE,
94  PTE_EXECUTE_READ | PTE_WRITECOMBINED_CACHE,
95  PTE_READWRITE | PTE_WRITECOMBINED_CACHE,
96  PTE_WRITECOPY | PTE_WRITECOMBINED_CACHE,
97  PTE_EXECUTE_READWRITE | PTE_WRITECOMBINED_CACHE,
98  PTE_EXECUTE_WRITECOPY | PTE_WRITECOMBINED_CACHE,
99 };
100 
101 const
103 {
106  PAGE_EXECUTE,
135  PAGE_WRITECOMBINE | PAGE_EXECUTE_WRITECOPY
136 };
137 
138 /* FUNCTIONS ***************************************************************/
139 
140 static BOOLEAN MmUnmapPageTable(PULONG Pt);
141 
142 VOID
144 {
145  if ((Pt && MmUnmapPageTable(Pt)) || Address >= MmSystemRangeStart)
146  {
147  KeInvalidateTlbEntry(Address);
148  }
149 }
150 
151 static ULONG
152 ProtectToPTE(ULONG flProtect)
153 {
154  ULONG Attributes = 0;
155 
156  if (flProtect & (PAGE_NOACCESS|PAGE_GUARD))
157  {
158  Attributes = 0;
159  }
160  else if (flProtect & PAGE_IS_WRITABLE)
161  {
162  Attributes = PA_PRESENT | PA_READWRITE;
163  }
164  else if (flProtect & (PAGE_IS_READABLE | PAGE_IS_EXECUTABLE))
165  {
166  Attributes = PA_PRESENT;
167  }
168  else
169  {
170  DPRINT1("Unknown main protection type.\n");
171  KeBugCheck(MEMORY_MANAGEMENT);
172  }
173 
174  if (flProtect & PAGE_SYSTEM)
175  {
176  }
177  else
178  {
179  Attributes = Attributes | PA_USER;
180  }
181  if (flProtect & PAGE_NOCACHE)
182  {
183  Attributes = Attributes | PA_CD;
184  }
185  if (flProtect & PAGE_WRITETHROUGH)
186  {
187  Attributes = Attributes | PA_WT;
188  }
189  return(Attributes);
190 }
191 
192 NTSTATUS
193 NTAPI
194 MiDispatchFault(IN ULONG FaultCode,
195  IN PVOID Address,
196  IN PMMPTE PointerPte,
197  IN PMMPTE PointerProtoPte,
198  IN BOOLEAN Recursive,
200  IN PVOID TrapInformation,
201  IN PVOID Vad);
202 
203 NTSTATUS
204 NTAPI
207 
208 static PULONG
210 {
211  PFN_NUMBER Pfn;
212  PULONG Pt;
213  PMMPDE PointerPde;
214 
215  if (Address < MmSystemRangeStart)
216  {
217  /* We should have a process for user land addresses */
218  ASSERT(Process != NULL);
219 
220  if(Process != PsGetCurrentProcess())
221  {
222  PMMPDE PdeBase;
223  ULONG PdeOffset = MiGetPdeOffset(Address);
224 
225  /* Nobody but page fault should ask for creating the PDE,
226  * Which imples that Process is the current one */
227  ASSERT(Create == FALSE);
228 
230  if (PdeBase == NULL)
231  {
232  KeBugCheck(MEMORY_MANAGEMENT);
233  }
234  PointerPde = PdeBase + PdeOffset;
235  if (PointerPde->u.Hard.Valid == 0)
236  {
237  MmDeleteHyperspaceMapping(PdeBase);
238  return NULL;
239  }
240  else
241  {
242  Pfn = PointerPde->u.Hard.PageFrameNumber;
243  }
244  MmDeleteHyperspaceMapping(PdeBase);
245  Pt = MmCreateHyperspaceMapping(Pfn);
246  if (Pt == NULL)
247  {
248  KeBugCheck(MEMORY_MANAGEMENT);
249  }
250  return Pt + MiAddressToPteOffset(Address);
251  }
252  /* This is for our process */
253  PointerPde = MiAddressToPde(Address);
254  Pt = (PULONG)MiAddressToPte(Address);
255  if (PointerPde->u.Hard.Valid == 0)
256  {
258  if (Create == FALSE)
259  {
260  return NULL;
261  }
262  ASSERT(PointerPde->u.Long == 0);
263 
264  MI_WRITE_INVALID_PTE(PointerPde, DemandZeroPde);
265  // Tiny HACK: Parameter 1 is the architecture specific FaultCode for an access violation (i.e. page is present)
266  Status = MiDispatchFault(0x1,
267  Pt,
268  PointerPde,
269  NULL,
270  FALSE,
272  NULL,
273  NULL);
276  ASSERT(PointerPde->u.Hard.Valid == 1);
277  }
278  return (PULONG)MiAddressToPte(Address);
279  }
280 
281  /* This is for kernel land address */
282  ASSERT(Process == NULL);
283  PointerPde = MiAddressToPde(Address);
284  Pt = (PULONG)MiAddressToPte(Address);
285  if (PointerPde->u.Hard.Valid == 0)
286  {
287  /* Let ARM3 synchronize the PDE */
288  if(!MiSynchronizeSystemPde(PointerPde))
289  {
290  /* PDE (still) not valid, let ARM3 allocate one if asked */
291  if(Create == FALSE)
292  return NULL;
294  }
295  }
296  return Pt;
297 }
298 
300 {
301  if (!IS_HYPERSPACE(Pt))
302  {
303  return TRUE;
304  }
305 
306  if (Pt)
307  {
309  }
310  return FALSE;
311 }
312 
314 {
315  ULONG Pte;
316  PULONG Pt;
317 
318  Pt = MmGetPageTableForProcess(Process, Address, FALSE);
319  if (Pt)
320  {
321  Pte = *Pt;
322  MmUnmapPageTable(Pt);
323  return Pte;
324  }
325  return 0;
326 }
327 
329 NTAPI
331  PVOID Address)
332 {
333  ULONG Entry;
334  Entry = MmGetPageEntryForProcess(Process, Address);
335  if (!(Entry & PA_PRESENT))
336  {
337  return 0;
338  }
339  return(PTE_TO_PFN(Entry));
340 }
341 
342 VOID
343 NTAPI
345  BOOLEAN* WasDirty, PPFN_NUMBER Page)
346 /*
347  * FUNCTION: Delete a virtual mapping
348  */
349 {
350  BOOLEAN WasValid = FALSE;
351  PFN_NUMBER Pfn;
352  ULONG Pte;
353  PULONG Pt;
354 
355  DPRINT("MmDeleteVirtualMapping(%p, %p, %p, %p)\n",
356  Process, Address, WasDirty, Page);
357 
358  Pt = MmGetPageTableForProcess(Process, Address, FALSE);
359 
360  if (Pt == NULL)
361  {
362  if (WasDirty != NULL)
363  {
364  *WasDirty = FALSE;
365  }
366  if (Page != NULL)
367  {
368  *Page = 0;
369  }
370  return;
371  }
372 
373  /*
374  * Atomically set the entry to zero and get the old value.
375  */
376  Pte = InterlockedExchangePte(Pt, 0);
377 
378  /* We count a mapping as valid if it's a present page, or it's a nonzero pfn with
379  * the swap bit unset, indicating a valid page protected to PAGE_NOACCESS. */
380  WasValid = (Pte & PA_PRESENT) || ((Pte >> PAGE_SHIFT) && !(Pte & 0x800));
381  if (WasValid)
382  {
383  /* Flush the TLB since we transitioned this PTE
384  * from valid to invalid so any stale translations
385  * are removed from the cache */
386  MiFlushTlb(Pt, Address);
387 
388  if (Address < MmSystemRangeStart)
389  {
390  /* Remove PDE reference */
393  }
394 
395  Pfn = PTE_TO_PFN(Pte);
396  }
397  else
398  {
399  MmUnmapPageTable(Pt);
400  Pfn = 0;
401  }
402 
403  /*
404  * Return some information to the caller
405  */
406  if (WasDirty != NULL)
407  {
408  *WasDirty = ((Pte & PA_DIRTY) && (Pte & PA_PRESENT)) ? TRUE : FALSE;
409  }
410  if (Page != NULL)
411  {
412  *Page = Pfn;
413  }
414 }
415 
416 VOID
417 NTAPI
419  SWAPENTRY* SwapEntry)
420 /*
421  * FUNCTION: Get a page file mapping
422  */
423 {
424  ULONG Entry = MmGetPageEntryForProcess(Process, Address);
425  *SwapEntry = Entry >> 1;
426 }
427 
428 VOID
429 NTAPI
431  SWAPENTRY* SwapEntry)
432 /*
433  * FUNCTION: Delete a virtual mapping
434  */
435 {
436  ULONG Pte;
437  PULONG Pt;
438 
439  Pt = MmGetPageTableForProcess(Process, Address, FALSE);
440 
441  if (Pt == NULL)
442  {
443  *SwapEntry = 0;
444  return;
445  }
446 
447  /*
448  * Atomically set the entry to zero and get the old value.
449  */
450  Pte = InterlockedExchangePte(Pt, 0);
451 
452  if (Address < MmSystemRangeStart)
453  {
454  /* Remove PDE reference */
457  }
458 
459  /* We don't need to flush here because page file entries
460  * are invalid translations, so the processor won't cache them */
461  MmUnmapPageTable(Pt);
462 
463  if ((Pte & PA_PRESENT) || !(Pte & 0x800))
464  {
465  DPRINT1("Pte %x (want not 1 and 0x800)\n", Pte);
466  KeBugCheck(MEMORY_MANAGEMENT);
467  }
468 
469  /*
470  * Return some information to the caller
471  */
472  *SwapEntry = Pte >> 1;
473 }
474 
475 BOOLEAN
477 {
478  PMMPDE PointerPde = MiAddressToPde(Address);
479  PMMPTE PointerPte = MiAddressToPte(Address);
480 
481  if (PointerPde->u.Hard.Valid == 0)
482  {
483  if(!MiSynchronizeSystemPde(PointerPde))
484  return FALSE;
485  return PointerPte->u.Hard.Valid != 0;
486  }
487  return FALSE;
488 }
489 
490 BOOLEAN
491 NTAPI
493 {
494  return MmGetPageEntryForProcess(Process, Address) & PA_DIRTY ? TRUE : FALSE;
495 }
496 
497 VOID
498 NTAPI
500 {
501  PULONG Pt;
502  ULONG Pte;
503 
504  if (Address < MmSystemRangeStart && Process == NULL)
505  {
506  DPRINT1("MmSetCleanPage is called for user space without a process.\n");
507  KeBugCheck(MEMORY_MANAGEMENT);
508  }
509 
510  Pt = MmGetPageTableForProcess(Process, Address, FALSE);
511  if (Pt == NULL)
512  {
513  KeBugCheck(MEMORY_MANAGEMENT);
514  }
515 
516  do
517  {
518  Pte = *Pt;
519  } while (Pte != InterlockedCompareExchangePte(Pt, Pte & ~PA_DIRTY, Pte));
520 
521  if (!(Pte & PA_PRESENT))
522  {
523  KeBugCheck(MEMORY_MANAGEMENT);
524  }
525  else if (Pte & PA_DIRTY)
526  {
527  MiFlushTlb(Pt, Address);
528  }
529  else
530  {
531  MmUnmapPageTable(Pt);
532  }
533 }
534 
535 VOID
536 NTAPI
538 {
539  PULONG Pt;
540  ULONG Pte;
541 
542  if (Address < MmSystemRangeStart && Process == NULL)
543  {
544  DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
545  KeBugCheck(MEMORY_MANAGEMENT);
546  }
547 
548  Pt = MmGetPageTableForProcess(Process, Address, FALSE);
549  if (Pt == NULL)
550  {
551  KeBugCheck(MEMORY_MANAGEMENT);
552  }
553 
554  do
555  {
556  Pte = *Pt;
557  } while (Pte != InterlockedCompareExchangePte(Pt, Pte | PA_DIRTY, Pte));
558 
559  if (!(Pte & PA_PRESENT))
560  {
561  KeBugCheck(MEMORY_MANAGEMENT);
562  }
563  else
564  {
565  /* The processor will never clear this bit itself, therefore
566  * we do not need to flush the TLB here when setting it */
567  MmUnmapPageTable(Pt);
568  }
569 }
570 
571 BOOLEAN
572 NTAPI
574 {
575  return MmGetPageEntryForProcess(Process, Address) & PA_PRESENT;
576 }
577 
578 BOOLEAN
579 NTAPI
581 {
582  ULONG_PTR Entry = MmGetPageEntryForProcess(Process, Address);
583  return !(Entry & PA_PRESENT) && !(Entry & 0x800) && (Entry >> PAGE_SHIFT);
584 }
585 
586 BOOLEAN
587 NTAPI
589 {
590  ULONG Entry;
591  Entry = MmGetPageEntryForProcess(Process, Address);
592  return !(Entry & PA_PRESENT) && (Entry & 0x800);
593 }
594 
595 NTSTATUS
596 NTAPI
598  PVOID Address,
599  SWAPENTRY SwapEntry)
600 {
601  PULONG Pt;
602  ULONG Pte;
603 
604  if (Process == NULL && Address < MmSystemRangeStart)
605  {
606  DPRINT1("No process\n");
607  KeBugCheck(MEMORY_MANAGEMENT);
608  }
609  if (Process != NULL && Address >= MmSystemRangeStart)
610  {
611  DPRINT1("Setting kernel address with process context\n");
612  KeBugCheck(MEMORY_MANAGEMENT);
613  }
614 
615  if (SwapEntry & (1 << 31))
616  {
617  KeBugCheck(MEMORY_MANAGEMENT);
618  }
619 
620  Pt = MmGetPageTableForProcess(Process, Address, FALSE);
621  if (Pt == NULL)
622  {
623  /* Nobody should page out an address that hasn't even been mapped */
624  /* But we might place a wait entry first, requiring the page table */
625  if (SwapEntry != MM_WAIT_ENTRY)
626  {
627  KeBugCheck(MEMORY_MANAGEMENT);
628  }
629  Pt = MmGetPageTableForProcess(Process, Address, TRUE);
630  }
631  Pte = InterlockedExchangePte(Pt, SwapEntry << 1);
632  if (Pte != 0)
633  {
634  KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
635  }
636 
637  if (Address < MmSystemRangeStart)
638  {
639  /* Add PDE reference */
642  }
643 
644  /* We don't need to flush the TLB here because it
645  * only caches valid translations and a zero PTE
646  * is not a valid translation */
647  MmUnmapPageTable(Pt);
648 
649  return(STATUS_SUCCESS);
650 }
651 
652 
653 NTSTATUS
654 NTAPI
656  PVOID Address,
657  ULONG flProtect,
658  PPFN_NUMBER Pages,
659  ULONG PageCount)
660 {
662  PVOID Addr;
663  ULONG i;
664  ULONG oldPdeOffset, PdeOffset;
665  PULONG Pt = NULL;
666  ULONG Pte;
667  DPRINT("MmCreateVirtualMappingUnsafe(%p, %p, %lu, %p (%x), %lu)\n",
668  Process, Address, flProtect, Pages, *Pages, PageCount);
669 
670  ASSERT(((ULONG_PTR)Address % PAGE_SIZE) == 0);
671 
672  if (Process == NULL)
673  {
674  if (Address < MmSystemRangeStart)
675  {
676  DPRINT1("NULL process given for user-mode mapping at %p -- %lu pages starting at %Ix\n", Address, PageCount, *Pages);
677  KeBugCheck(MEMORY_MANAGEMENT);
678  }
679  if (PageCount > 0x10000 ||
680  (ULONG_PTR) Address / PAGE_SIZE + PageCount > 0x100000)
681  {
682  DPRINT1("Page count too large for kernel-mode mapping at %p -- %lu pages starting at %Ix\n", Address, PageCount, *Pages);
683  KeBugCheck(MEMORY_MANAGEMENT);
684  }
685  }
686  else
687  {
688  if (Address >= MmSystemRangeStart)
689  {
690  DPRINT1("Process %p given for kernel-mode mapping at %p -- %lu pages starting at %Ix\n", Process, Address, PageCount, *Pages);
691  KeBugCheck(MEMORY_MANAGEMENT);
692  }
693  if (PageCount > (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE ||
694  (ULONG_PTR) Address / PAGE_SIZE + PageCount >
695  (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE)
696  {
697  DPRINT1("Page count too large for process %p user-mode mapping at %p -- %lu pages starting at %Ix\n", Process, Address, PageCount, *Pages);
698  KeBugCheck(MEMORY_MANAGEMENT);
699  }
700  }
701 
702  Attributes = ProtectToPTE(flProtect);
703  Attributes &= 0xfff;
704  if (Address >= MmSystemRangeStart)
705  {
706  Attributes &= ~PA_USER;
707  }
708  else
709  {
710  Attributes |= PA_USER;
711  }
712 
713  Addr = Address;
714  /* MmGetPageTableForProcess should be called on the first run, so
715  * let this trigger it */
716  oldPdeOffset = ADDR_TO_PDE_OFFSET(Addr) + 1;
717  for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
718  {
719  if (!(Attributes & PA_PRESENT) && Pages[i] != 0)
720  {
721  DPRINT1("Setting physical address but not allowing access at address "
722  "0x%p with attributes %x/%x.\n",
723  Addr, Attributes, flProtect);
724  KeBugCheck(MEMORY_MANAGEMENT);
725  }
726  PdeOffset = ADDR_TO_PDE_OFFSET(Addr);
727  if (oldPdeOffset != PdeOffset)
728  {
729  if(Pt) MmUnmapPageTable(Pt);
730  Pt = MmGetPageTableForProcess(Process, Addr, TRUE);
731  if (Pt == NULL)
732  {
733  KeBugCheck(MEMORY_MANAGEMENT);
734  }
735  }
736  else
737  {
738  Pt++;
739  }
740  oldPdeOffset = PdeOffset;
741 
742  Pte = InterlockedExchangePte(Pt, PFN_TO_PTE(Pages[i]) | Attributes);
743 
744  /* There should not be anything valid here */
745  if (Pte != 0)
746  {
747  DPRINT1("Bad PTE %lx at %p for %p + %lu\n", Pte, Pt, Address, i);
748  KeBugCheck(MEMORY_MANAGEMENT);
749  }
750 
751  /* We don't need to flush the TLB here because it only caches valid translations
752  * and we're moving this PTE from invalid to valid so it can't be cached right now */
753 
754  if (Addr < MmSystemRangeStart)
755  {
756  /* Add PDE reference */
759  }
760  }
761 
762  ASSERT(Addr > Address);
763  MmUnmapPageTable(Pt);
764 
765  return(STATUS_SUCCESS);
766 }
767 
768 NTSTATUS
769 NTAPI
771  PVOID Address,
772  ULONG flProtect,
773  PPFN_NUMBER Pages,
774  ULONG PageCount)
775 {
776  ULONG i;
777 
778  ASSERT((ULONG_PTR)Address % PAGE_SIZE == 0);
779  for (i = 0; i < PageCount; i++)
780  {
781  if (!MmIsPageInUse(Pages[i]))
782  {
783  DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages[i]));
784  KeBugCheck(MEMORY_MANAGEMENT);
785  }
786  }
787 
788  return(MmCreateVirtualMappingUnsafe(Process,
789  Address,
790  flProtect,
791  Pages,
792  PageCount));
793 }
794 
795 ULONG
796 NTAPI
798 {
799  ULONG Entry;
800  ULONG Protect;
801 
802  Entry = MmGetPageEntryForProcess(Process, Address);
803 
804 
805  if (!(Entry & PA_PRESENT))
806  {
807  Protect = PAGE_NOACCESS;
808  }
809  else
810  {
811  if (Entry & PA_READWRITE)
812  {
813  Protect = PAGE_READWRITE;
814  }
815  else
816  {
817  Protect = PAGE_EXECUTE_READ;
818  }
819  if (Entry & PA_CD)
820  {
821  Protect |= PAGE_NOCACHE;
822  }
823  if (Entry & PA_WT)
824  {
825  Protect |= PAGE_WRITETHROUGH;
826  }
827  if (!(Entry & PA_USER))
828  {
829  Protect |= PAGE_SYSTEM;
830  }
831 
832  }
833  return(Protect);
834 }
835 
836 VOID
837 NTAPI
839 {
840  ULONG Attributes = 0;
841  PULONG Pt;
842  ULONG Pte;
843 
844  DPRINT("MmSetPageProtect(Process %p Address %p flProtect %x)\n",
845  Process, Address, flProtect);
846 
847  Attributes = ProtectToPTE(flProtect);
848 
849  Attributes &= 0xfff;
850  if (Address >= MmSystemRangeStart)
851  {
852  Attributes &= ~PA_USER;
853  }
854  else
855  {
856  Attributes |= PA_USER;
857  }
858 
859  Pt = MmGetPageTableForProcess(Process, Address, FALSE);
860  if (Pt == NULL)
861  {
862  KeBugCheck(MEMORY_MANAGEMENT);
863  }
864  Pte = InterlockedExchangePte(Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY)));
865 
866  // We should be able to bring a page back from PAGE_NOACCESS
867  if ((Pte & 0x800) || !(Pte >> PAGE_SHIFT))
868  {
869  DPRINT1("Invalid Pte %lx\n", Pte);
870  KeBugCheck(MEMORY_MANAGEMENT);
871  }
872 
873  if((Pte & Attributes) != Attributes)
874  MiFlushTlb(Pt, Address);
875  else
876  MmUnmapPageTable(Pt);
877 }
878 
879 VOID
881 NTAPI
883 {
884  /* Nothing to do here */
885 }
886 
887 /* EOF */
#define PAGE_WRITETHROUGH
Definition: mm.h:85
DWORD *typedef PVOID
Definition: winlogon.h:52
#define PAGE_NOCACHE
Definition: nt_native.h:1311
VOID NTAPI MmDeletePageFileMapping(PEPROCESS Process, PVOID Address, SWAPENTRY *SwapEntry)
Definition: page.c:495
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
#define IN
Definition: typedefs.h:38
BOOLEAN Mmi386MakeKernelPageTableGlobal(PVOID Address)
Definition: page.c:476
#define TRUE
Definition: types.h:120
PVOID ULONG Address
Definition: oprghdlr.h:14
BOOLEAN NTAPI MmIsPagePresent(PEPROCESS Process, PVOID Address)
Definition: page.c:302
#define PAGE_IS_EXECUTABLE
Definition: mm.h:137
#define MiAddressToPde(x)
Definition: mmx86.c:20
BOOLEAN NTAPI KeAreAllApcsDisabled(VOID)
Definition: apc.c:985
struct _Entry Entry
Definition: kefuncs.h:640
ULONG_PTR DirectoryTableBase
Definition: ketypes.h:1977
USHORT UsedPageTableEntries[768]
Definition: mmtypes.h:870
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID _In_ ULONG_PTR _In_ SIZE_T _Inout_opt_ PLARGE_INTEGER _Inout_ PSIZE_T _In_ SECTION_INHERIT _In_ ULONG _In_ ULONG Protect
Definition: zwfuncs.h:214
BOOLEAN NTAPI MmIsDisabledPage(PEPROCESS Process, PVOID Address)
Definition: page.c:311
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel)?(CompletionRoutine!=NULL):TRUE)
BOOLEAN NTAPI MmIsPageInUse(PFN_NUMBER Page)
Definition: freelist.c:530
return STATUS_SUCCESS
Definition: btrfs.c:2690
_In_ BOOLEAN Create
Definition: pstypes.h:511
#define PAGE_GUARD
Definition: nt_native.h:1310
static ULONG ProtectToPTE(ULONG flProtect)
Definition: page.c:152
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG x1
Definition: winddi.h:3706
VOID NTAPI MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN *WasDirty, PPFN_NUMBER Page)
Definition: page.c:453
PMMWSL VmWorkingSetList
Definition: mmtypes.h:917
#define PA_DIRTY
Definition: page.c:38
_In_opt_ ULONG Base
Definition: rtlfuncs.h:2327
#define PAGE_ROUND_DOWN(x)
Definition: mmtypes.h:36
#define InterlockedExchangePte(pte1, pte2)
Definition: page.c:19
VOID NTAPI MmSetDirtyPage(PEPROCESS Process, PVOID Address)
Definition: page.c:431
#define MM_WAIT_ENTRY
Definition: mm.h:150
#define PTE_TO_PFN(X)
Definition: page.c:46
BOOLEAN NTAPI MmIsDirtyPage(PEPROCESS Process, PVOID Address)
Definition: page.c:370
VOID NTAPI MmInitGlobalKernelPageDirectory(VOID)
Definition: page.c:277
VOID NTAPI MmSetCleanPage(PEPROCESS Process, PVOID Address)
Definition: page.c:409
union _MMPTE::@2171 u
#define MiGetPdeOffset(x)
Definition: mm.h:184
#define PFN_TO_PTE(X)
Definition: page.c:47
#define PA_WT
Definition: page.c:39
uint32_t ULONG_PTR
Definition: typedefs.h:63
ULONG * PPFN_NUMBER
Definition: ke.h:8
GLenum GLclampf GLint i
Definition: glfuncs.h:14
#define MiAddressToPte(x)
Definition: mmx86.c:19
#define PAGE_EXECUTE_WRITECOPY
Definition: nt_native.h:1309
ULONG PFN_NUMBER
Definition: ke.h:8
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
#define PAGE_IS_WRITABLE
Definition: mm.h:131
#define PA_ACCESSED
Definition: page.c:41
NTSTATUS NTAPI MmCreatePageFileMapping(PEPROCESS Process, PVOID Address, SWAPENTRY SwapEntry)
Definition: page.c:503
BOOLEAN NTAPI MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
Definition: page.c:323
#define PsGetCurrentProcess
Definition: psfuncs.h:17
#define PAGE_NOACCESS
Definition: nt_native.h:1302
#define PA_PRESENT
Definition: page.c:35
smooth NULL
Definition: ftsmooth.c:416
#define PAGE_EXECUTE
Definition: nt_native.h:1306
ULONG NTAPI MmGetPageProtect(PEPROCESS Process, PVOID Address)
Definition: page.c:379
void DPRINT(...)
Definition: polytest.cpp:61
VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1469
NTSTATUS NTAPI MmCreateVirtualMappingUnsafe(PEPROCESS Process, PVOID Address, ULONG PageProtection, PPFN_NUMBER Pages, ULONG PageCount)
Definition: page.c:514
PFN_NUMBER NTAPI MmGetPfnForProcess(PEPROCESS Process, PVOID Address)
Definition: page.c:292
#define InterlockedCompareExchangePte(PointerPte, Exchange, Comperand)
Definition: mm.h:152
#define PA_READWRITE
Definition: page.c:36
#define DBG_UNREFERENCED_LOCAL_VARIABLE(L)
Definition: ntbasedef.h:326
#define IS_HYPERSPACE(v)
Definition: page.c:44
unsigned char BOOLEAN
FORCEINLINE VOID KeInvalidateTlbEntry(IN PVOID Address)
Definition: ke.h:201
#define PAGE_MASK(x)
Definition: page.c:49
LONG NTSTATUS
Definition: precomp.h:26
const ULONG64 MmProtectToPteMask[32]
Definition: page.c:32
ULONG64 Valid
Definition: mmtypes.h:150
VOID MiFlushTlb(PMMPTE Pte, PVOID Address)
Definition: page.c:128
#define PA_CD
Definition: page.c:40
MMPDE DemandZeroPde
Definition: page.c:114
NTSTATUS NTAPI MiFillSystemPageDirectory(IN PVOID Base, IN SIZE_T NumberOfBytes)
Definition: section.c:476
#define PAGE_SYSTEM
Definition: mm.h:86
#define PTE_COUNT
Definition: miarm.h:33
#define MmDeleteHyperspaceMapping(x)
Definition: mm.h:1008
IN SIZE_T NumberOfBytes
Definition: ndis.h:3915
#define ADDR_TO_PDE_OFFSET
Definition: page.c:21
#define PAGE_SIZE
Definition: env_spec_w32.h:49
BOOLEAN MmUnmapPageTable(PMMPTE Pt)
Definition: page.c:337
KPROCESS Pcb
Definition: pstypes.h:1193
const ULONG MmProtectToValue[32]
Definition: page.c:81
VOID NTAPI MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
Definition: page.c:390
MMSUPPORT Vm
Definition: pstypes.h:1287
Status
Definition: gdiplustypes.h:24
ULONG_PTR Long
Definition: mmtypes.h:215
static PULONG MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
Definition: page.c:209
ULONG_PTR SIZE_T
Definition: typedefs.h:78
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
FORCEINLINE VOID MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte, IN MMPTE InvalidPte)
Definition: miarm.h:945
#define PAGE_WRITECOMBINE
Definition: mmtypes.h:78
ULONG_PTR SWAPENTRY
Definition: mm.h:47
FORCEINLINE PVOID MmCreateHyperspaceMapping(IN PFN_NUMBER Page)
Definition: mm.h:1002
#define PA_USER
Definition: page.c:37
unsigned int * PULONG
Definition: retypes.h:1
VOID NTAPI MmGetPageFileMapping(PEPROCESS Process, PVOID Address, SWAPENTRY *SwapEntry)
Definition: page.c:359
#define PAGE_READONLY
Definition: compat.h:127
#define PAGE_WRITECOPY
Definition: nt_native.h:1305
#define DPRINT1
Definition: precomp.h:8
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
unsigned int ULONG
Definition: retypes.h:1
ULONG64 PageFrameNumber
Definition: mmtypes.h:171
#define PAGE_EXECUTE_READ
Definition: nt_native.h:1307
#define MiAddressToPteOffset(x)
Definition: mmx86.c:21
#define PAGE_EXECUTE_READWRITE
Definition: nt_native.h:1308
NTSTATUS NTAPI MiDispatchFault(IN ULONG FaultCode, IN PVOID Address, IN PMMPTE PointerPte, IN PMMPTE PointerProtoPte, IN BOOLEAN Recursive, IN PEPROCESS Process, IN PVOID TrapInformation, IN PVOID Vad)
#define MmSystemRangeStart
Definition: mm.h:31
NTSTATUS NTAPI MmCreateVirtualMapping(PEPROCESS Process, PVOID Address, ULONG Protect, PPFN_NUMBER Pages, ULONG PageCount)
Definition: page.c:568
base of all file and directory entries
Definition: entries.h:82
static ULONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
Definition: page.c:313
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:94
struct _ACPI_EFI_FILE_HANDLE CHAR16 UINT64 UINT64 Attributes
Definition: acefiex.h:335
#define PAGE_IS_READABLE
Definition: mm.h:123
#define INIT_FUNCTION
Definition: ntoskrnl.h:11
#define PAGE_READWRITE
Definition: nt_native.h:1304