xref: /reactos/ntoskrnl/mm/i386/pagepae.c (revision 139a3d66)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/mm/i386/pagepae.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 
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, MmInitGlobalKernelPageDirectory)
18 #endif
19 
20 /* GLOBALS *****************************************************************/
21 
22 #define PA_BIT_PRESENT   (0)
23 #define PA_BIT_READWRITE (1)
24 #define PA_BIT_USER      (2)
25 #define PA_BIT_WT        (3)
26 #define PA_BIT_CD        (4)
27 #define PA_BIT_ACCESSED  (5)
28 #define PA_BIT_DIRTY     (6)
29 #define PA_BIT_GLOBAL    (8)
30 
31 #define PA_PRESENT   (1 << PA_BIT_PRESENT)
32 #define PA_READWRITE (1 << PA_BIT_READWRITE)
33 #define PA_USER      (1 << PA_BIT_USER)
34 #define PA_DIRTY     (1 << PA_BIT_DIRTY)
35 #define PA_WT        (1 << PA_BIT_WT)
36 #define PA_CD        (1 << PA_BIT_CD)
37 #define PA_ACCESSED  (1 << PA_BIT_ACCESSED)
38 #define PA_GLOBAL    (1 << PA_BIT_GLOBAL)
39 
40 #define PAGEDIRECTORY_MAP       (0xc0000000 + (PTE_BASE / (1024)))
41 #define PAE_PAGEDIRECTORY_MAP   (0xc0000000 + (PTE_BASE / (512)))
42 
43 #define HYPERSPACE              (Ke386Pae ? 0xc0800000 : 0xc0400000)
44 #define IS_HYPERSPACE(v)        (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
45 
46 static ULONG MmGlobalKernelPageDirectory[1024];
47 static ULONGLONG MmGlobalKernelPageDirectoryForPAE[2048];
48 
49 #define PTE_TO_PFN(X)  ((X) >> PAGE_SHIFT)
50 #define PFN_TO_PTE(X)  ((X) << PAGE_SHIFT)
51 
52 #define PAE_PTE_TO_PFN(X)   (PAE_PAGE_MASK(X) >> PAGE_SHIFT)
53 #define PAE_PFN_TO_PTE(X)   ((X) << PAGE_SHIFT)
54 
55 #define PAGE_MASK(x)		((x)&(~0xfff))
56 #define PAE_PAGE_MASK(x)	((x)&(~0xfffLL))
57 
58 extern BOOLEAN Ke386Pae;
59 extern BOOLEAN Ke386NoExecute;
60 
61 /* FUNCTIONS ***************************************************************/
62 
63 BOOLEAN MmUnmapPageTable(PULONG Pt);
64 
65 ULONG_PTR
66 NTAPI
67 MiFlushTlbIpiRoutine(ULONG_PTR Address)
68 {
69    if (Address == (ULONGLONG)-1)
70    {
71       KeFlushCurrentTb();
72    }
73    else if (Address == (ULONGLONG)-2)
74    {
75       KeFlushCurrentTb();
76    }
77    else
78    {
79        __invlpg((PVOID)Address);
80    }
81    return 0;
82 }
83 
84 VOID
85 MiFlushTlb(PULONG Pt, PVOID Address)
86 {
87 #ifdef CONFIG_SMP
88    if (Pt)
89    {
90       MmUnmapPageTable(Pt);
91    }
92    if (KeNumberProcessors > 1)
93    {
94       KeIpiGenericCall(MiFlushTlbIpiRoutine, (ULONG_PTR)Address);
95    }
96    else
97    {
98       MiFlushTlbIpiRoutine((ULONG_PTR)Address);
99    }
100 #else
101    if ((Pt && MmUnmapPageTable(Pt)) || Address >= MmSystemRangeStart)
102    {
103       __invlpg(Address);
104    }
105 #endif
106 }
107 
108 static ULONG
109 ProtectToPTE(ULONG flProtect)
110 {
111    ULONG Attributes = 0;
112 
113    if (flProtect & (PAGE_NOACCESS|PAGE_GUARD))
114    {
115       Attributes = 0;
116    }
117    else if (flProtect & PAGE_IS_WRITABLE)
118    {
119       Attributes = PA_PRESENT | PA_READWRITE;
120    }
121    else if (flProtect & (PAGE_IS_READABLE | PAGE_IS_EXECUTABLE))
122    {
123       Attributes = PA_PRESENT;
124    }
125    else
126    {
127       DPRINT1("Unknown main protection type.\n");
128       ASSERT(FALSE);
129    }
130    if (Ke386NoExecute &&
131        !(flProtect & PAGE_IS_EXECUTABLE))
132    {
133       Attributes = Attributes | 0x80000000;
134    }
135 
136    if (flProtect & PAGE_SYSTEM)
137    {
138    }
139    else
140    {
141       Attributes = Attributes | PA_USER;
142    }
143    if (flProtect & PAGE_NOCACHE)
144    {
145       Attributes = Attributes | PA_CD;
146    }
147    if (flProtect & PAGE_WRITETHROUGH)
148    {
149       Attributes = Attributes | PA_WT;
150    }
151    return(Attributes);
152 }
153 
154 #define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (1024 * PAGE_SIZE))
155 
156 #define ADDR_TO_PDE(v) (PULONG)(PAGEDIRECTORY_MAP + \
157                                 ((((ULONG)(v)) / (1024 * 1024))&(~0x3)))
158 #define ADDR_TO_PTE(v) (PULONG)(PTE_BASE + ((((ULONG)(v) / 1024))&(~0x3)))
159 
160 #define ADDR_TO_PDE_OFFSET(v) ((((ULONG)(v)) / (1024 * PAGE_SIZE)))
161 
162 #define ADDR_TO_PTE_OFFSET(v)  ((((ULONG)(v)) % (1024 * PAGE_SIZE)) / PAGE_SIZE)
163 
164 
165 #define PAE_ADDR_TO_PAGE_TABLE(v)   (((ULONG)(v)) / (512 * PAGE_SIZE))
166 
167 #define PAE_ADDR_TO_PDE(v)          (PULONGLONG) (PAE_PAGEDIRECTORY_MAP + \
168                                                   ((((ULONG_PTR)(v)) / (512 * 512))&(~0x7)))
169 #define PAE_ADDR_TO_PTE(v)          (PULONGLONG) (PTE_BASE + ((((ULONG_PTR)(v) / 512))&(~0x7)))
170 
171 
172 #define PAE_ADDR_TO_PDTE_OFFSET(v)  (((ULONG_PTR)(v)) / (512 * 512 * PAGE_SIZE))
173 
174 #define PAE_ADDR_TO_PDE_PAGE_OFFSET(v)   ((((ULONG_PTR)(v)) % (512 * 512 * PAGE_SIZE)) / (512 * PAGE_SIZE))
175 
176 #define PAE_ADDR_TO_PDE_OFFSET(v)   (((ULONG_PTR)(v))/ (512 * PAGE_SIZE))
177 
178 #define PAE_ADDR_TO_PTE_OFFSET(v)   ((((ULONG_PTR)(v)) % (512 * PAGE_SIZE)) / PAGE_SIZE)
179 
180 BOOLEAN
181 NTAPI
182 MmCreateProcessAddressSpace(IN ULONG MinWs,
183                             IN PEPROCESS Process,
184                             IN PLARGE_INTEGER DirectoryTableBase)
185 {
186    NTSTATUS Status;
187    ULONG i, j;
188    PFN_NUMBER Pfn[7];
189    ULONG Count;
190 
191    DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", MinWs, Process);
192 
193    Count = Ke386Pae ? 7 : 2;
194 
195    for (i = 0; i < Count; i++)
196    {
197       Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn[i]);
198       if (!NT_SUCCESS(Status))
199       {
200           for (j = 0; j < i; j++)
201           {
202               MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn[j]);
203           }
204 
205           return FALSE;
206       }
207    }
208 
209    if (Ke386Pae)
210    {
211       PULONGLONG PageDirTable;
212       PULONGLONG PageDir;
213 
214       PageDirTable = MmCreateHyperspaceMapping(Pfn[0]);
215       for (i = 0; i < 4; i++)
216       {
217          PageDirTable[i] = PAE_PFN_TO_PTE(Pfn[1+i]) | PA_PRESENT;
218       }
219       MmDeleteHyperspaceMapping(PageDirTable);
220       for (i = PAE_ADDR_TO_PDTE_OFFSET(MmSystemRangeStart); i < 4; i++)
221       {
222          PageDir = (PULONGLONG)MmCreateHyperspaceMapping(Pfn[i+1]);
223          memcpy(PageDir, &MmGlobalKernelPageDirectoryForPAE[i * 512], 512 * sizeof(ULONGLONG));
224          if (PAE_ADDR_TO_PDTE_OFFSET(PTE_BASE) == i)
225          {
226             for (j = 0; j < 4; j++)
227             {
228                PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(PTE_BASE) + j] = PAE_PFN_TO_PTE(Pfn[1+j]) | PA_PRESENT | PA_READWRITE;
229             }
230          }
231          if (PAE_ADDR_TO_PDTE_OFFSET(HYPERSPACE) == i)
232          {
233             PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE)] = PAE_PFN_TO_PTE(Pfn[5]) | PA_PRESENT | PA_READWRITE;
234             PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE)+1] = PAE_PFN_TO_PTE(Pfn[6]) | PA_PRESENT | PA_READWRITE;
235          }
236          MmDeleteHyperspaceMapping(PageDir);
237       }
238    }
239    else
240    {
241       PULONG PageDirectory;
242       PageDirectory = MmCreateHyperspaceMapping(Pfn[0]);
243 
244       memcpy(PageDirectory + ADDR_TO_PDE_OFFSET(MmSystemRangeStart),
245              MmGlobalKernelPageDirectory + ADDR_TO_PDE_OFFSET(MmSystemRangeStart),
246              (1024 - ADDR_TO_PDE_OFFSET(MmSystemRangeStart)) * sizeof(ULONG));
247 
248       DPRINT("Addr %x\n",ADDR_TO_PDE_OFFSET(PTE_BASE));
249       PageDirectory[ADDR_TO_PDE_OFFSET(PTE_BASE)] = PFN_TO_PTE(Pfn[0]) | PA_PRESENT | PA_READWRITE;
250       PageDirectory[ADDR_TO_PDE_OFFSET(HYPERSPACE)] = PFN_TO_PTE(Pfn[1]) | PA_PRESENT | PA_READWRITE;
251 
252       MmDeleteHyperspaceMapping(PageDirectory);
253    }
254 
255    DirectoryTableBase->QuadPart = PFN_TO_PTE(Pfn[0]);
256    DPRINT("Finished MmCopyMmInfo(): %I64x\n", DirectoryTableBase->QuadPart);
257    return TRUE;
258 }
259 
260 VOID
261 NTAPI
262 MmFreePageTable(PEPROCESS Process, PVOID Address)
263 {
264    PEPROCESS CurrentProcess = PsGetCurrentProcess();
265    ULONG i;
266    PFN_NUMBER Pfn;
267 
268    DPRINT("ProcessId %d, Address %x\n", Process->UniqueProcessId, Address);
269    if (Process != NULL && Process != CurrentProcess)
270    {
271       KeAttachProcess(&Process->Pcb);
272    }
273    if (Ke386Pae)
274    {
275       PULONGLONG PageTable;
276       ULONGLONG ZeroPte = 0LL;
277       PageTable = (PULONGLONG)PAGE_ROUND_DOWN((PVOID)PAE_ADDR_TO_PTE(Address));
278       for (i = 0; i < 512; i++)
279       {
280          if (PageTable[i] != 0LL)
281          {
282             DbgPrint("Page table entry not clear at %x/%x (is %I64x)\n",
283                      ((ULONG)Address / (4*1024*1024)), i, PageTable[i]);
284             ASSERT(FALSE);
285          }
286       }
287       Pfn = PAE_PTE_TO_PFN(*(PAE_ADDR_TO_PDE(Address)));
288       (void)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address), &ZeroPte);
289       MiFlushTlb((PULONG)PAE_ADDR_TO_PDE(Address), PAE_ADDR_TO_PTE(Address));
290    }
291    else
292    {
293       PULONG PageTable;
294       PageTable = (PULONG)PAGE_ROUND_DOWN((PVOID)ADDR_TO_PTE(Address));
295       for (i = 0; i < 1024; i++)
296       {
297          if (PageTable[i] != 0)
298          {
299             DbgPrint("Page table entry not clear at %x/%x (is %x)\n",
300                      ((ULONG)Address / (4*1024*1024)), i, PageTable[i]);
301             ASSERT(FALSE);
302          }
303       }
304       Pfn = PTE_TO_PFN(*(ADDR_TO_PDE(Address)));
305       *(ADDR_TO_PDE(Address)) = 0;
306       MiFlushTlb(ADDR_TO_PDE(Address), ADDR_TO_PTE(Address));
307    }
308 
309    if (Address >= MmSystemRangeStart)
310    {
311       //    MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
312       ASSERT(FALSE);
313    }
314    else
315    {
316       MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
317    }
318    if (Process != NULL && Process != CurrentProcess)
319    {
320       KeDetachProcess();
321    }
322 }
323 
324 static PULONGLONG
325 MmGetPageTableForProcessForPAE(PEPROCESS Process, PVOID Address, BOOLEAN Create)
326 {
327    NTSTATUS Status;
328    PFN_NUMBER Pfn;
329    ULONGLONG Entry;
330    ULONGLONG ZeroEntry = 0LL;
331    PULONGLONG Pt;
332    PULONGLONG PageDir;
333    PULONGLONG PageDirTable;
334 
335    DPRINT("MmGetPageTableForProcessForPAE(%x %x %d)\n",
336           Process, Address, Create);
337    if (Address >= (PVOID)PTE_BASE && Address < (PVOID)((ULONG_PTR)PTE_BASE + 0x800000))
338    {
339       ASSERT(FALSE);
340    }
341    if (Address < MmSystemRangeStart && Process && Process != PsGetCurrentProcess())
342    {
343       PageDirTable = MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process->Pcb.DirectoryTableBase.QuadPart));
344       if (PageDirTable == NULL)
345       {
346          ASSERT(FALSE);
347       }
348       PageDir = MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDirTable[PAE_ADDR_TO_PDTE_OFFSET(Address)]));
349       MmDeleteHyperspaceMapping(PageDirTable);
350       if (PageDir == NULL)
351       {
352          ASSERT(FALSE);
353       }
354       PageDir += PAE_ADDR_TO_PDE_PAGE_OFFSET(Address);
355       Entry = ExfInterlockedCompareExchange64UL(PageDir, &ZeroEntry, &ZeroEntry);
356       if (Entry == 0LL)
357       {
358          if (Create == FALSE)
359          {
360             MmDeleteHyperspaceMapping(PageDir);
361             return NULL;
362          }
363          Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
364          if (!NT_SUCCESS(Status))
365          {
366             ASSERT(FALSE);
367          }
368          Entry = PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER;
369          Entry = ExfInterlockedCompareExchange64UL(PageDir, &Entry, &ZeroEntry);
370          if (Entry != 0LL)
371          {
372             MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
373             Pfn = PAE_PTE_TO_PFN(Entry);
374          }
375       }
376       else
377       {
378          Pfn = PAE_PTE_TO_PFN(Entry);
379       }
380       MmDeleteHyperspaceMapping(PageDir);
381       Pt = MmCreateHyperspaceMapping(Pfn);
382       if (Pt == NULL)
383       {
384          ASSERT(FALSE);
385       }
386       return Pt + PAE_ADDR_TO_PTE_OFFSET(Address);
387    }
388    PageDir = PAE_ADDR_TO_PDE(Address);
389    if (0LL == ExfInterlockedCompareExchange64UL(PageDir, &ZeroEntry, &ZeroEntry))
390    {
391       if (Address >= MmSystemRangeStart)
392       {
393          if (MmGlobalKernelPageDirectoryForPAE[PAE_ADDR_TO_PDE_OFFSET(Address)] == 0LL)
394          {
395             if (Create == FALSE)
396             {
397                return NULL;
398             }
399             Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
400             if (!NT_SUCCESS(Status))
401             {
402                ASSERT(FALSE);
403             }
404             Entry = PAE_PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE;
405             if (Ke386GlobalPagesEnabled)
406             {
407                Entry |= PA_GLOBAL;
408             }
409             if (0LL != ExfInterlockedCompareExchange64UL(&MmGlobalKernelPageDirectoryForPAE[PAE_ADDR_TO_PDE_OFFSET(Address)], &Entry, &ZeroEntry))
410             {
411                MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
412             }
413          }
414          (void)ExfInterlockedCompareExchange64UL(PageDir, &MmGlobalKernelPageDirectoryForPAE[PAE_ADDR_TO_PDE_OFFSET(Address)], &ZeroEntry);
415       }
416       else
417       {
418          if (Create == FALSE)
419          {
420             return NULL;
421          }
422          Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
423          if (!NT_SUCCESS(Status))
424          {
425             ASSERT(FALSE);
426          }
427          Entry = PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER;
428          Entry = ExfInterlockedCompareExchange64UL(PageDir, &Entry, &ZeroEntry);
429          if (Entry != 0LL)
430          {
431             MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
432          }
433       }
434    }
435    return (PULONGLONG)PAE_ADDR_TO_PTE(Address);
436 }
437 
438 static PULONG
439 MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
440 {
441    ULONG PdeOffset = ADDR_TO_PDE_OFFSET(Address);
442    NTSTATUS Status;
443    PFN_NUMBER Pfn;
444    ULONG Entry;
445    PULONG Pt, PageDir;
446 
447    if (Address < MmSystemRangeStart && Process && Process != PsGetCurrentProcess())
448    {
449       PageDir = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase.LowPart));
450       if (PageDir == NULL)
451       {
452          ASSERT(FALSE);
453       }
454       if (0 == InterlockedCompareExchangeUL(&PageDir[PdeOffset], 0, 0))
455       {
456          if (Create == FALSE)
457          {
458             MmDeleteHyperspaceMapping(PageDir);
459             return NULL;
460          }
461          Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
462          if (!NT_SUCCESS(Status) || Pfn == 0)
463          {
464             ASSERT(FALSE);
465          }
466          Entry = InterlockedCompareExchangeUL(&PageDir[PdeOffset], PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER, 0);
467          if (Entry != 0)
468          {
469             MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
470             Pfn = PTE_TO_PFN(Entry);
471          }
472       }
473       else
474       {
475          Pfn = PTE_TO_PFN(PageDir[PdeOffset]);
476       }
477       MmDeleteHyperspaceMapping(PageDir);
478       Pt = MmCreateHyperspaceMapping(Pfn);
479       if (Pt == NULL)
480       {
481          ASSERT(FALSE);
482       }
483       return Pt + ADDR_TO_PTE_OFFSET(Address);
484    }
485    PageDir = ADDR_TO_PDE(Address);
486    if (0 == InterlockedCompareExchangeUL(PageDir, 0, 0))
487    {
488       if (Address >= MmSystemRangeStart)
489       {
490          if (0 == InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory[PdeOffset], 0, 0))
491          {
492             if (Create == FALSE)
493             {
494                return NULL;
495             }
496             Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
497             if (!NT_SUCCESS(Status) || Pfn == 0)
498             {
499                ASSERT(FALSE);
500             }
501             Entry = PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE;
502             if (Ke386GlobalPagesEnabled)
503             {
504                Entry |= PA_GLOBAL;
505             }
506             if(0 != InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory[PdeOffset], Entry, 0))
507             {
508                MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
509             }
510          }
511          (void)InterlockedExchangeUL(PageDir, MmGlobalKernelPageDirectory[PdeOffset]);
512       }
513       else
514       {
515          if (Create == FALSE)
516          {
517             return NULL;
518          }
519          Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
520          if (!NT_SUCCESS(Status) || Pfn == 0)
521          {
522             ASSERT(FALSE);
523          }
524          Entry = InterlockedCompareExchangeUL(PageDir, PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER, 0);
525          if (Entry != 0)
526          {
527             MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
528          }
529       }
530    }
531    return (PULONG)ADDR_TO_PTE(Address);
532 }
533 
534 BOOLEAN MmUnmapPageTable(PULONG Pt)
535 {
536    if (Ke386Pae)
537    {
538       if ((PULONGLONG)Pt >= (PULONGLONG)PTE_BASE && (PULONGLONG)Pt < (PULONGLONG)PTE_BASE + 4*512*512)
539       {
540          return TRUE;
541       }
542    }
543    else
544    {
545       if (Pt >= (PULONG)PTE_BASE && Pt < (PULONG)PTE_BASE + 1024*1024)
546       {
547          return TRUE;
548       }
549    }
550    if (Pt)
551    {
552       MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pt));
553    }
554    return FALSE;
555 }
556 
557 static ULONGLONG MmGetPageEntryForProcessForPAE(PEPROCESS Process, PVOID Address)
558 {
559    ULONGLONG Pte;
560    PULONGLONG Pt;
561 
562    Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE);
563    if (Pt)
564    {
565       Pte = *Pt;
566       MmUnmapPageTable((PULONG)Pt);
567       return Pte;
568    }
569    return 0;
570 }
571 
572 static ULONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
573 {
574    ULONG Pte;
575    PULONG Pt;
576 
577    Pt = MmGetPageTableForProcess(Process, Address, FALSE);
578    if (Pt)
579    {
580       Pte = *Pt;
581       MmUnmapPageTable(Pt);
582       return Pte;
583    }
584    return 0;
585 }
586 
587 PFN_NUMBER
588 NTAPI
589 MmGetPfnForProcess(PEPROCESS Process,
590                    PVOID Address)
591 {
592 
593    if (Ke386Pae)
594    {
595       ULONGLONG Entry;
596       Entry = MmGetPageEntryForProcessForPAE(Process, Address);
597       if (!(Entry & PA_PRESENT))
598       {
599          return 0;
600       }
601       return(PAE_PTE_TO_PFN(Entry));
602    }
603    else
604    {
605       ULONG Entry;
606       Entry = MmGetPageEntryForProcess(Process, Address);
607       if (!(Entry & PA_PRESENT))
608       {
609          return 0;
610       }
611       return(PTE_TO_PFN(Entry));
612    }
613 }
614 
615 VOID
616 NTAPI
617 MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address,
618                        BOOLEAN* WasDirty, PPFN_NUMBER Page)
619 /*
620  * FUNCTION: Delete a virtual mapping
621  */
622 {
623    BOOLEAN WasValid = FALSE;
624    PFN_NUMBER Pfn;
625 
626    DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
627           Process, Address, WasDirty, Page);
628    if (Ke386Pae)
629    {
630       ULONGLONG Pte;
631       PULONGLONG Pt;
632 
633       Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE);
634       if (Pt == NULL)
635       {
636          if (WasDirty != NULL)
637          {
638             *WasDirty = FALSE;
639          }
640          if (Page != NULL)
641          {
642             *Page = 0;
643          }
644          return;
645       }
646 
647       /*
648        * Atomically set the entry to zero and get the old value.
649        */
650       Pte = 0LL;
651       Pte = ExfpInterlockedExchange64UL(Pt, &Pte);
652 
653       MiFlushTlb((PULONG)Pt, Address);
654 
655       WasValid = PAE_PAGE_MASK(Pte) != 0 ? TRUE : FALSE;
656       if (WasValid)
657       {
658          Pfn = PAE_PTE_TO_PFN(Pte);
659          MmMarkPageUnmapped(Pfn);
660       }
661       else
662       {
663          Pfn = 0;
664       }
665 
666       /*
667        * Return some information to the caller
668        */
669       if (WasDirty != NULL)
670       {
671          *WasDirty = Pte & PA_DIRTY ? TRUE : FALSE;
672       }
673       if (Page != NULL)
674       {
675          *Page = Pfn;
676       }
677    }
678    else
679    {
680       ULONG Pte;
681       PULONG Pt;
682 
683       Pt = MmGetPageTableForProcess(Process, Address, FALSE);
684 
685       if (Pt == NULL)
686       {
687          if (WasDirty != NULL)
688          {
689             *WasDirty = FALSE;
690          }
691          if (Page != NULL)
692          {
693             *Page = 0;
694          }
695          return;
696       }
697 
698       /*
699        * Atomically set the entry to zero and get the old value.
700        */
701       Pte = InterlockedExchangeUL(Pt, 0);
702 
703       MiFlushTlb(Pt, Address);
704 
705       WasValid = (PAGE_MASK(Pte) != 0);
706       if (WasValid)
707       {
708          Pfn = PTE_TO_PFN(Pte);
709          MmMarkPageUnmapped(Pfn);
710       }
711       else
712       {
713          Pfn = 0;
714       }
715 
716       /*
717        * Return some information to the caller
718        */
719       if (WasDirty != NULL)
720       {
721          *WasDirty = Pte & PA_DIRTY ? TRUE : FALSE;
722       }
723       if (Page != NULL)
724       {
725          *Page = Pfn;
726       }
727    }
728    /*
729     * Decrement the reference count for this page table.
730     */
731    if (Process != NULL && WasValid &&
732        ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
733        Address < MmSystemRangeStart)
734    {
735       PUSHORT Ptrc;
736       ULONG Idx;
737 
738       Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
739       Idx = Ke386Pae ? PAE_ADDR_TO_PAGE_TABLE(Address) : ADDR_TO_PAGE_TABLE(Address);
740 
741       Ptrc[Idx]--;
742       if (Ptrc[Idx] == 0)
743       {
744          MmFreePageTable(Process, Address);
745       }
746    }
747 }
748 
749 VOID
750 NTAPI
751 MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
752                         SWAPENTRY* SwapEntry)
753 /*
754  * FUNCTION: Delete a virtual mapping
755  */
756 {
757    if (Ke386Pae)
758    {
759       ULONGLONG Pte;
760       PULONGLONG Pt;
761 
762       Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE);
763       if (Pt == NULL)
764       {
765          *SwapEntry = 0;
766          return;
767       }
768 
769       /*
770        * Atomically set the entry to zero and get the old value.
771        */
772       Pte = 0LL;
773       Pte = ExfpInterlockedExchange64UL(Pt, &Pte);
774 
775       MiFlushTlb((PULONG)Pt, Address);
776 
777       /*
778        * Decrement the reference count for this page table.
779        */
780       if (Process != NULL && Pte &&
781           ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
782           Address < MmSystemRangeStart)
783       {
784          PUSHORT Ptrc;
785 
786          Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
787 
788          Ptrc[PAE_ADDR_TO_PAGE_TABLE(Address)]--;
789          if (Ptrc[PAE_ADDR_TO_PAGE_TABLE(Address)] == 0)
790          {
791             MmFreePageTable(Process, Address);
792          }
793       }
794 
795 
796       /*
797        * Return some information to the caller
798        */
799       *SwapEntry = Pte >> 1;
800    }
801    else
802    {
803       ULONG Pte;
804       PULONG Pt;
805 
806       Pt = MmGetPageTableForProcess(Process, Address, FALSE);
807 
808       if (Pt == NULL)
809       {
810          *SwapEntry = 0;
811          return;
812       }
813 
814       /*
815        * Atomically set the entry to zero and get the old value.
816        */
817       Pte = InterlockedExchangeUL(Pt, 0);
818 
819       MiFlushTlb(Pt, Address);
820 
821       /*
822        * Decrement the reference count for this page table.
823        */
824       if (Process != NULL && Pte &&
825           ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
826           Address < MmSystemRangeStart)
827       {
828          PUSHORT Ptrc;
829 
830          Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
831 
832          Ptrc[ADDR_TO_PAGE_TABLE(Address)]--;
833          if (Ptrc[ADDR_TO_PAGE_TABLE(Address)] == 0)
834          {
835             MmFreePageTable(Process, Address);
836          }
837       }
838 
839 
840       /*
841        * Return some information to the caller
842        */
843       *SwapEntry = Pte >> 1;
844    }
845 }
846 
847 BOOLEAN
848 Mmi386MakeKernelPageTableGlobal(PVOID PAddress)
849 {
850    if (Ke386Pae)
851    {
852       PULONGLONG Pt;
853       PULONGLONG Pde;
854       Pde = PAE_ADDR_TO_PDE(PAddress);
855       if (*Pde == 0LL)
856       {
857          Pt = MmGetPageTableForProcessForPAE(NULL, PAddress, FALSE);
858 #if 0
859          /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
860          FLASH_TLB_ONE(PAddress);
861 #endif
862          if (Pt != NULL)
863          {
864             return TRUE;
865          }
866       }
867    }
868    else
869    {
870       PULONG Pt, Pde;
871       Pde = ADDR_TO_PDE(PAddress);
872       if (*Pde == 0)
873       {
874          Pt = MmGetPageTableForProcess(NULL, PAddress, FALSE);
875 #if 0
876          /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
877          FLASH_TLB_ONE(PAddress);
878 #endif
879          if (Pt != NULL)
880          {
881             return TRUE;
882          }
883       }
884    }
885    return(FALSE);
886 }
887 
888 BOOLEAN
889 NTAPI
890 MmIsDirtyPage(PEPROCESS Process, PVOID Address)
891 {
892    if (Ke386Pae)
893    {
894       return MmGetPageEntryForProcessForPAE(Process, Address) & PA_DIRTY ? TRUE : FALSE;
895    }
896    else
897    {
898       return MmGetPageEntryForProcess(Process, Address) & PA_DIRTY ? TRUE : FALSE;
899    }
900 }
901 
902 VOID
903 NTAPI
904 MmSetCleanPage(PEPROCESS Process, PVOID Address)
905 {
906    if (Address < MmSystemRangeStart && Process == NULL)
907    {
908       DPRINT1("MmSetCleanPage is called for user space without a process.\n");
909       ASSERT(FALSE);
910    }
911    if (Ke386Pae)
912    {
913       PULONGLONG Pt;
914       ULONGLONG Pte;
915       ULONGLONG tmpPte;
916 
917       Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE);
918 
919       if (Pt == NULL)
920       {
921          ASSERT(FALSE);
922       }
923 
924       do
925       {
926          Pte = *Pt;
927          tmpPte = Pte & ~PA_DIRTY;
928       } while (Pte != ExfInterlockedCompareExchange64UL(Pt, &tmpPte, &Pte));
929 
930       if (Pte & PA_DIRTY)
931       {
932          MiFlushTlb((PULONG)Pt, Address);
933       }
934       else
935       {
936          MmUnmapPageTable((PULONG)Pt);
937       }
938    }
939    else
940    {
941       PULONG Pt;
942       ULONG Pte;
943 
944       Pt = MmGetPageTableForProcess(Process, Address, FALSE);
945 
946       if (Pt == NULL)
947       {
948          ASSERT(FALSE);
949       }
950 
951       do
952       {
953          Pte = *Pt;
954       } while (Pte != InterlockedCompareExchangeUL(Pt, Pte & ~PA_DIRTY, Pte));
955 
956       if (Pte & PA_DIRTY)
957       {
958          MiFlushTlb(Pt, Address);
959       }
960       else
961       {
962          MmUnmapPageTable(Pt);
963       }
964    }
965 }
966 
967 VOID
968 NTAPI
969 MmSetDirtyPage(PEPROCESS Process, PVOID Address)
970 {
971    if (Address < MmSystemRangeStart && Process == NULL)
972    {
973       DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
974       ASSERT(FALSE);
975    }
976    if (Ke386Pae)
977    {
978       PULONGLONG Pt;
979       ULONGLONG Pte;
980       ULONGLONG tmpPte;
981 
982       Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE);
983       if (Pt == NULL)
984       {
985          ASSERT(FALSE);
986       }
987 
988       do
989       {
990          Pte = *Pt;
991          tmpPte = Pte | PA_DIRTY;
992       } while (Pte != ExfInterlockedCompareExchange64UL(Pt, &tmpPte, &Pte));
993       if (!(Pte & PA_DIRTY))
994       {
995          MiFlushTlb((PULONG)Pt, Address);
996       }
997       else
998       {
999          MmUnmapPageTable((PULONG)Pt);
1000       }
1001    }
1002    else
1003    {
1004       PULONG Pt;
1005       ULONG Pte;
1006 
1007       Pt = MmGetPageTableForProcess(Process, Address, FALSE);
1008       if (Pt == NULL)
1009       {
1010          ASSERT(FALSE);
1011       }
1012 
1013       do
1014       {
1015          Pte = *Pt;
1016       } while (Pte != InterlockedCompareExchangeUL(Pt, Pte | PA_DIRTY, Pte));
1017       if (!(Pte & PA_DIRTY))
1018       {
1019          MiFlushTlb(Pt, Address);
1020       }
1021       else
1022       {
1023          MmUnmapPageTable(Pt);
1024       }
1025    }
1026 }
1027 
1028 BOOLEAN
1029 NTAPI
1030 MmIsPagePresent(PEPROCESS Process, PVOID Address)
1031 {
1032    if (Ke386Pae)
1033    {
1034       return MmGetPageEntryForProcessForPAE(Process, Address) & PA_PRESENT ? TRUE : FALSE;
1035    }
1036    else
1037    {
1038       return MmGetPageEntryForProcess(Process, Address) & PA_PRESENT ? TRUE : FALSE;
1039    }
1040 }
1041 
1042 BOOLEAN
1043 NTAPI
1044 MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
1045 {
1046    if (Ke386Pae)
1047    {
1048       ULONGLONG Entry;
1049       Entry = MmGetPageEntryForProcessForPAE(Process, Address);
1050       return !(Entry & PA_PRESENT) && Entry != 0 ? TRUE : FALSE;
1051    }
1052    else
1053    {
1054       ULONG Entry;
1055       Entry = MmGetPageEntryForProcess(Process, Address);
1056       return !(Entry & PA_PRESENT) && Entry != 0 ? TRUE : FALSE;
1057    }
1058 }
1059 
1060 NTSTATUS
1061 NTAPI
1062 MmCreatePageFileMapping(PEPROCESS Process,
1063                         PVOID Address,
1064                         SWAPENTRY SwapEntry)
1065 {
1066    if (Process == NULL && Address < MmSystemRangeStart)
1067    {
1068       DPRINT1("No process\n");
1069       ASSERT(FALSE);
1070    }
1071    if (Process != NULL && Address >= MmSystemRangeStart)
1072    {
1073       DPRINT1("Setting kernel address with process context\n");
1074       ASSERT(FALSE);
1075    }
1076    if (SwapEntry & (1 << 31))
1077    {
1078       ASSERT(FALSE);
1079    }
1080 
1081    if (Ke386Pae)
1082    {
1083       PULONGLONG Pt;
1084       ULONGLONG Pte;
1085       ULONGLONG tmpPte;
1086 
1087       Pt = MmGetPageTableForProcessForPAE(Process, Address, TRUE);
1088       if (Pt == NULL)
1089       {
1090          ASSERT(FALSE);
1091       }
1092       tmpPte = SwapEntry << 1;
1093       Pte = ExfpInterlockedExchange64UL(Pt, &tmpPte);
1094       if (PAE_PAGE_MASK((Pte)) != 0)
1095       {
1096          MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte)));
1097       }
1098 
1099       if (Pte != 0)
1100       {
1101          MiFlushTlb((PULONG)Pt, Address);
1102       }
1103       else
1104       {
1105          MmUnmapPageTable((PULONG)Pt);
1106       }
1107    }
1108    else
1109    {
1110       PULONG Pt;
1111       ULONG Pte;
1112 
1113       Pt = MmGetPageTableForProcess(Process, Address, TRUE);
1114       if (Pt == NULL)
1115       {
1116          ASSERT(FALSE);
1117       }
1118       Pte = *Pt;
1119       if (PAGE_MASK((Pte)) != 0)
1120       {
1121          MmMarkPageUnmapped(PTE_TO_PFN((Pte)));
1122       }
1123       (void)InterlockedExchangeUL(Pt, SwapEntry << 1);
1124       if (Pte != 0)
1125       {
1126          MiFlushTlb(Pt, Address);
1127       }
1128       else
1129       {
1130          MmUnmapPageTable(Pt);
1131       }
1132    }
1133    if (Process != NULL &&
1134        ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
1135        Address < MmSystemRangeStart)
1136    {
1137      PUSHORT Ptrc;
1138      ULONG Idx;
1139 
1140      Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
1141      Idx = Ke386Pae ? PAE_ADDR_TO_PAGE_TABLE(Address) : ADDR_TO_PAGE_TABLE(Address);
1142      Ptrc[Idx]++;
1143    }
1144    return(STATUS_SUCCESS);
1145 }
1146 
1147 
1148 NTSTATUS
1149 NTAPI
1150 MmCreateVirtualMappingUnsafe(PEPROCESS Process,
1151                              PVOID Address,
1152                              ULONG flProtect,
1153                              PPFN_NUMBER Pages,
1154                              ULONG PageCount)
1155 {
1156    ULONG Attributes;
1157    PVOID Addr;
1158    ULONG i;
1159    ULONG oldPdeOffset, PdeOffset;
1160    BOOLEAN NoExecute = FALSE;
1161 
1162    DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
1163           Process, Address, flProtect, Pages, *Pages, PageCount);
1164 
1165    if (Process == NULL)
1166    {
1167       if (Address < MmSystemRangeStart)
1168       {
1169          DPRINT1("No process\n");
1170          ASSERT(FALSE);
1171       }
1172       if (PageCount > 0x10000 ||
1173           (ULONG_PTR) Address / PAGE_SIZE + PageCount > 0x100000)
1174       {
1175          DPRINT1("Page count to large\n");
1176          ASSERT(FALSE);
1177       }
1178    }
1179    else
1180    {
1181       if (Address >= MmSystemRangeStart)
1182       {
1183          DPRINT1("Setting kernel address with process context\n");
1184          ASSERT(FALSE);
1185       }
1186       if (PageCount > (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE ||
1187           (ULONG_PTR) Address / PAGE_SIZE + PageCount >
1188           (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE)
1189       {
1190          DPRINT1("Page Count to large\n");
1191          ASSERT(FALSE);
1192       }
1193    }
1194 
1195    Attributes = ProtectToPTE(flProtect);
1196    if (Attributes & 0x80000000)
1197    {
1198       NoExecute = TRUE;
1199    }
1200    Attributes &= 0xfff;
1201    if (Address >= MmSystemRangeStart)
1202    {
1203       Attributes &= ~PA_USER;
1204       if (Ke386GlobalPagesEnabled)
1205       {
1206          Attributes |= PA_GLOBAL;
1207       }
1208    }
1209    else
1210    {
1211       Attributes |= PA_USER;
1212    }
1213 
1214    Addr = Address;
1215 
1216    if (Ke386Pae)
1217    {
1218       ULONGLONG Pte, tmpPte;
1219       PULONGLONG Pt = NULL;
1220 
1221       oldPdeOffset = PAE_ADDR_TO_PDE_OFFSET(Addr) + 1;
1222       for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
1223       {
1224          if (!(Attributes & PA_PRESENT) && Pages[i] != 0)
1225          {
1226             DPRINT1("Setting physical address but not allowing access at address "
1227                     "0x%.8X with attributes %x/%x.\n",
1228                     Addr, Attributes, flProtect);
1229             ASSERT(FALSE);
1230          }
1231          PdeOffset = PAE_ADDR_TO_PDE_OFFSET(Addr);
1232          if (oldPdeOffset != PdeOffset)
1233          {
1234             MmUnmapPageTable((PULONG)Pt);
1235             Pt = MmGetPageTableForProcessForPAE(Process, Addr, TRUE);
1236             if (Pt == NULL)
1237             {
1238                ASSERT(FALSE);
1239             }
1240          }
1241          else
1242          {
1243             Pt++;
1244          }
1245          oldPdeOffset = PdeOffset;
1246 
1247          MmMarkPageMapped(Pages[i]);
1248          tmpPte = PAE_PFN_TO_PTE(Pages[i]) | Attributes;
1249          if (NoExecute)
1250          {
1251             tmpPte |= 0x8000000000000000LL;
1252          }
1253          Pte = ExfpInterlockedExchange64UL(Pt, &tmpPte);
1254          if (PAE_PAGE_MASK((Pte)) != 0LL && !((Pte) & PA_PRESENT))
1255          {
1256             ASSERT(FALSE);
1257          }
1258          if (PAE_PAGE_MASK((Pte)) != 0LL)
1259          {
1260             MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte)));
1261          }
1262          if (Address < MmSystemRangeStart &&
1263              ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
1264              Attributes & PA_PRESENT)
1265          {
1266             PUSHORT Ptrc;
1267 
1268             Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
1269 
1270             Ptrc[PAE_ADDR_TO_PAGE_TABLE(Addr)]++;
1271          }
1272          if (Pte != 0LL)
1273          {
1274             if (Address > MmSystemRangeStart ||
1275                 (Pt >= (PULONGLONG)PTE_BASE && Pt < (PULONGLONG)PTE_BASE + 4*512*512))
1276             {
1277               MiFlushTlb((PULONG)Pt, Address);
1278             }
1279          }
1280       }
1281       if (Addr > Address)
1282       {
1283          MmUnmapPageTable((PULONG)Pt);
1284       }
1285    }
1286    else
1287    {
1288       PULONG Pt = NULL;
1289       ULONG Pte;
1290       oldPdeOffset = ADDR_TO_PDE_OFFSET(Addr) + 1;
1291       for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
1292       {
1293          if (!(Attributes & PA_PRESENT) && Pages[i] != 0)
1294          {
1295             DPRINT1("Setting physical address but not allowing access at address "
1296                     "0x%.8X with attributes %x/%x.\n",
1297                     Addr, Attributes, flProtect);
1298             ASSERT(FALSE);
1299          }
1300          PdeOffset = ADDR_TO_PDE_OFFSET(Addr);
1301          if (oldPdeOffset != PdeOffset)
1302          {
1303             MmUnmapPageTable(Pt);
1304             Pt = MmGetPageTableForProcess(Process, Addr, TRUE);
1305             if (Pt == NULL)
1306             {
1307                ASSERT(FALSE);
1308             }
1309          }
1310          else
1311          {
1312             Pt++;
1313          }
1314          oldPdeOffset = PdeOffset;
1315 
1316          Pte = *Pt;
1317          MmMarkPageMapped(Pages[i]);
1318          if (PAGE_MASK((Pte)) != 0 && !((Pte) & PA_PRESENT))
1319          {
1320             ASSERT(FALSE);
1321          }
1322          if (PAGE_MASK((Pte)) != 0)
1323          {
1324             MmMarkPageUnmapped(PTE_TO_PFN((Pte)));
1325          }
1326          (void)InterlockedExchangeUL(Pt, PFN_TO_PTE(Pages[i]) | Attributes);
1327          if (Address < MmSystemRangeStart &&
1328              ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
1329              Attributes & PA_PRESENT)
1330          {
1331             PUSHORT Ptrc;
1332 
1333             Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
1334 
1335             Ptrc[ADDR_TO_PAGE_TABLE(Addr)]++;
1336          }
1337          if (Pte != 0)
1338          {
1339             if (Address > MmSystemRangeStart ||
1340                 (Pt >= (PULONG)PTE_BASE && Pt < (PULONG)PTE_BASE + 1024*1024))
1341             {
1342                MiFlushTlb(Pt, Address);
1343             }
1344          }
1345       }
1346       if (Addr > Address)
1347       {
1348          MmUnmapPageTable(Pt);
1349       }
1350    }
1351    return(STATUS_SUCCESS);
1352 }
1353 
1354 NTSTATUS
1355 NTAPI
1356 MmCreateVirtualMapping(PEPROCESS Process,
1357                        PVOID Address,
1358                        ULONG flProtect,
1359                        PPFN_NUMBER Pages,
1360                        ULONG PageCount)
1361 {
1362    ULONG i;
1363 
1364    for (i = 0; i < PageCount; i++)
1365    {
1366       if (!MmIsPageInUse(Pages[i]))
1367       {
1368          DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages[i]));
1369          ASSERT(FALSE);
1370       }
1371    }
1372 
1373    return(MmCreateVirtualMappingUnsafe(Process,
1374                                        Address,
1375                                        flProtect,
1376                                        Pages,
1377                                        PageCount));
1378 }
1379 
1380 ULONG
1381 NTAPI
1382 MmGetPageProtect(PEPROCESS Process, PVOID Address)
1383 {
1384    ULONG Entry;
1385    ULONG Protect;
1386    if (Ke386Pae)
1387    {
1388       Entry = MmGetPageEntryForProcessForPAE(Process, Address);
1389    }
1390    else
1391    {
1392       Entry = MmGetPageEntryForProcess(Process, Address);
1393    }
1394 
1395    if (!(Entry & PA_PRESENT))
1396    {
1397       Protect = PAGE_NOACCESS;
1398    }
1399    else
1400    {
1401       if (Entry & PA_READWRITE)
1402       {
1403          Protect = PAGE_READWRITE;
1404       }
1405       else
1406       {
1407          Protect = PAGE_EXECUTE_READ;
1408       }
1409       if (Entry & PA_CD)
1410       {
1411          Protect |= PAGE_NOCACHE;
1412       }
1413       if (Entry & PA_WT)
1414       {
1415          Protect |= PAGE_WRITETHROUGH;
1416       }
1417       if (!(Entry & PA_USER))
1418       {
1419          Protect |= PAGE_SYSTEM;
1420       }
1421 
1422    }
1423    return(Protect);
1424 }
1425 
1426 VOID
1427 NTAPI
1428 MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
1429 {
1430    ULONG Attributes = 0;
1431    BOOLEAN NoExecute = FALSE;
1432 
1433    DPRINT("MmSetPageProtect(Process %x  Address %x  flProtect %x)\n",
1434           Process, Address, flProtect);
1435 
1436    Attributes = ProtectToPTE(flProtect);
1437    if (Attributes & 0x80000000)
1438    {
1439       NoExecute = TRUE;
1440    }
1441    Attributes &= 0xfff;
1442    if (Address >= MmSystemRangeStart)
1443    {
1444       Attributes &= ~PA_USER;
1445       if (Ke386GlobalPagesEnabled)
1446       {
1447          Attributes |= PA_GLOBAL;
1448       }
1449    }
1450    else
1451    {
1452       Attributes |= PA_USER;
1453    }
1454    if (Ke386Pae)
1455    {
1456       PULONGLONG Pt;
1457       ULONGLONG tmpPte, Pte;
1458 
1459       Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE);
1460       if (Pt == NULL)
1461       {
1462          DPRINT1("Address %x\n", Address);
1463          ASSERT(FALSE);
1464       }
1465       do
1466       {
1467         Pte = *Pt;
1468         tmpPte = PAE_PAGE_MASK(Pte) | Attributes | (Pte & (PA_ACCESSED|PA_DIRTY));
1469         if (NoExecute)
1470         {
1471            tmpPte |= 0x8000000000000000LL;
1472         }
1473         else
1474         {
1475            tmpPte &= ~0x8000000000000000LL;
1476         }
1477       } while (Pte != ExfInterlockedCompareExchange64UL(Pt, &tmpPte, &Pte));
1478 
1479       MiFlushTlb((PULONG)Pt, Address);
1480    }
1481    else
1482    {
1483       PULONG Pt;
1484 
1485       Pt = MmGetPageTableForProcess(Process, Address, FALSE);
1486       if (Pt == NULL)
1487       {
1488          ASSERT(FALSE);
1489       }
1490       InterlockedExchange((PLONG)Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY)));
1491       MiFlushTlb(Pt, Address);
1492    }
1493 }
1494 
1495 INIT_FUNCTION
1496 VOID
1497 NTAPI
1498 MmInitGlobalKernelPageDirectory(VOID)
1499 {
1500    ULONG i;
1501 
1502    DPRINT("MmInitGlobalKernelPageDirectory()\n");
1503 
1504    if (Ke386Pae)
1505    {
1506       PULONGLONG CurrentPageDirectory = (PULONGLONG)PAE_PAGEDIRECTORY_MAP;
1507       for (i = PAE_ADDR_TO_PDE_OFFSET(MmSystemRangeStart); i < 4 * 512; i++)
1508       {
1509          if (!(i >= PAE_ADDR_TO_PDE_OFFSET(PTE_BASE) && i < PAE_ADDR_TO_PDE_OFFSET(PTE_BASE) + 4) &&
1510              !(i >= PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE) && i < PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE) + 2) &&
1511              0LL == MmGlobalKernelPageDirectoryForPAE[i] && 0LL != CurrentPageDirectory[i])
1512          {
1513             (void)ExfpInterlockedExchange64UL(&MmGlobalKernelPageDirectoryForPAE[i], &CurrentPageDirectory[i]);
1514             if (Ke386GlobalPagesEnabled)
1515             {
1516                MmGlobalKernelPageDirectoryForPAE[i] |= PA_GLOBAL;
1517                CurrentPageDirectory[i] |= PA_GLOBAL;
1518             }
1519          }
1520       }
1521    }
1522    else
1523    {
1524       PULONG CurrentPageDirectory = (PULONG)PAGEDIRECTORY_MAP;
1525       for (i = ADDR_TO_PDE_OFFSET(MmSystemRangeStart); i < 1024; i++)
1526       {
1527          if (i != ADDR_TO_PDE_OFFSET(PTE_BASE) &&
1528              i != ADDR_TO_PDE_OFFSET(HYPERSPACE) &&
1529              0 == MmGlobalKernelPageDirectory[i] && 0 != CurrentPageDirectory[i])
1530          {
1531             MmGlobalKernelPageDirectory[i] = CurrentPageDirectory[i];
1532             if (Ke386GlobalPagesEnabled)
1533             {
1534                MmGlobalKernelPageDirectory[i] |= PA_GLOBAL;
1535                CurrentPageDirectory[i] |= PA_GLOBAL;
1536             }
1537          }
1538       }
1539    }
1540 }
1541 
1542 /* EOF */
1543