[NTOSKRNL/FREELDR/NDK]
[reactos.git] / reactos / ntoskrnl / mm / i386 / pagepae.c
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
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 VOID
1496 INIT_FUNCTION
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 */