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