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