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