Sync with trunk (48237)
[reactos.git] / ntoskrnl / mm / i386 / page.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 #pragma alloc_text(INIT, MiInitPageDirectoryMap)
19 #endif
20
21
22 /* GLOBALS *****************************************************************/
23
24 #define PA_BIT_PRESENT (0)
25 #define PA_BIT_READWRITE (1)
26 #define PA_BIT_USER (2)
27 #define PA_BIT_WT (3)
28 #define PA_BIT_CD (4)
29 #define PA_BIT_ACCESSED (5)
30 #define PA_BIT_DIRTY (6)
31 #define PA_BIT_GLOBAL (8)
32
33 #define PA_PRESENT (1 << PA_BIT_PRESENT)
34 #define PA_READWRITE (1 << PA_BIT_READWRITE)
35 #define PA_USER (1 << PA_BIT_USER)
36 #define PA_DIRTY (1 << PA_BIT_DIRTY)
37 #define PA_WT (1 << PA_BIT_WT)
38 #define PA_CD (1 << PA_BIT_CD)
39 #define PA_ACCESSED (1 << PA_BIT_ACCESSED)
40 #define PA_GLOBAL (1 << PA_BIT_GLOBAL)
41
42 #define HYPERSPACE (0xc0400000)
43 #define IS_HYPERSPACE(v) (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
44
45 ULONG MmGlobalKernelPageDirectory[1024];
46
47 #define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT)
48 #define PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
49
50 #if defined(__GNUC__)
51 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
52 #else
53 __inline LARGE_INTEGER PTE_TO_PAGE(ULONG npage)
54 {
55 LARGE_INTEGER dummy;
56 dummy.QuadPart = (LONGLONG)(PAGE_MASK(npage));
57 return dummy;
58 }
59 #endif
60
61 /* FUNCTIONS ***************************************************************/
62
63 BOOLEAN MmUnmapPageTable(PULONG Pt);
64
65 VOID
66 MiFlushTlb(PULONG Pt, PVOID Address)
67 {
68 if ((Pt && MmUnmapPageTable(Pt)) || Address >= MmSystemRangeStart)
69 {
70 KeInvalidateTlbEntry(Address);
71 }
72 }
73
74 static ULONG
75 ProtectToPTE(ULONG flProtect)
76 {
77 ULONG Attributes = 0;
78
79 if (flProtect & (PAGE_NOACCESS|PAGE_GUARD))
80 {
81 Attributes = 0;
82 }
83 else if (flProtect & PAGE_IS_WRITABLE)
84 {
85 Attributes = PA_PRESENT | PA_READWRITE;
86 }
87 else if (flProtect & (PAGE_IS_READABLE | PAGE_IS_EXECUTABLE))
88 {
89 Attributes = PA_PRESENT;
90 }
91 else
92 {
93 DPRINT1("Unknown main protection type.\n");
94 KeBugCheck(MEMORY_MANAGEMENT);
95 }
96
97 if (flProtect & PAGE_SYSTEM)
98 {
99 }
100 else
101 {
102 Attributes = Attributes | PA_USER;
103 }
104 if (flProtect & PAGE_NOCACHE)
105 {
106 Attributes = Attributes | PA_CD;
107 }
108 if (flProtect & PAGE_WRITETHROUGH)
109 {
110 Attributes = Attributes | PA_WT;
111 }
112 return(Attributes);
113 }
114
115 static PULONG
116 MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
117 {
118 ULONG PdeOffset = ADDR_TO_PDE_OFFSET(Address);
119 NTSTATUS Status;
120 PFN_NUMBER Pfn;
121 ULONG Entry;
122 PULONG Pt, PageDir;
123
124 if (Address < MmSystemRangeStart && Process && Process != PsGetCurrentProcess())
125 {
126 PageDir = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase[0]));
127 if (PageDir == NULL)
128 {
129 KeBugCheck(MEMORY_MANAGEMENT);
130 }
131 if (0 == InterlockedCompareExchangePte(&PageDir[PdeOffset], 0, 0))
132 {
133 if (Create == FALSE)
134 {
135 MmDeleteHyperspaceMapping(PageDir);
136 return NULL;
137 }
138 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
139 if (!NT_SUCCESS(Status) || Pfn == 0)
140 {
141 KeBugCheck(MEMORY_MANAGEMENT);
142 }
143 Entry = InterlockedCompareExchangePte(&PageDir[PdeOffset], PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER, 0);
144 if (Entry != 0)
145 {
146 MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
147 Pfn = PTE_TO_PFN(Entry);
148 }
149 }
150 else
151 {
152 Pfn = PTE_TO_PFN(PageDir[PdeOffset]);
153 }
154 MmDeleteHyperspaceMapping(PageDir);
155 Pt = MmCreateHyperspaceMapping(Pfn);
156 if (Pt == NULL)
157 {
158 KeBugCheck(MEMORY_MANAGEMENT);
159 }
160 return Pt + ADDR_TO_PTE_OFFSET(Address);
161 }
162 PageDir = (PULONG)MiAddressToPde(Address);
163 if (0 == InterlockedCompareExchangePte(PageDir, 0, 0))
164 {
165 if (Address >= MmSystemRangeStart)
166 {
167 if (0 == InterlockedCompareExchangePte(&MmGlobalKernelPageDirectory[PdeOffset], 0, 0))
168 {
169 if (Create == FALSE)
170 {
171 return NULL;
172 }
173 Status = MmRequestPageMemoryConsumer(MC_SYSTEM, FALSE, &Pfn);
174 if (!NT_SUCCESS(Status) || Pfn == 0)
175 {
176 KeBugCheck(MEMORY_MANAGEMENT);
177 }
178 Entry = PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE;
179 if(0 != InterlockedCompareExchangePte(&MmGlobalKernelPageDirectory[PdeOffset], Entry, 0))
180 {
181 MmReleasePageMemoryConsumer(MC_SYSTEM, Pfn);
182 }
183 InterlockedExchangePte(PageDir, MmGlobalKernelPageDirectory[PdeOffset]);
184 RtlZeroMemory(MiPteToAddress(PageDir), PAGE_SIZE);
185 return (PULONG)MiAddressToPte(Address);
186 }
187 InterlockedExchangePte(PageDir, MmGlobalKernelPageDirectory[PdeOffset]);
188 }
189 else
190 {
191 if (Create == FALSE)
192 {
193 return NULL;
194 }
195 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
196 if (!NT_SUCCESS(Status) || Pfn == 0)
197 {
198 KeBugCheck(MEMORY_MANAGEMENT);
199 }
200 Entry = InterlockedCompareExchangePte(PageDir, PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER, 0);
201 if (Entry != 0)
202 {
203 MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
204 }
205 }
206 }
207 return (PULONG)MiAddressToPte(Address);
208 }
209
210 BOOLEAN MmUnmapPageTable(PULONG Pt)
211 {
212 if (Pt >= (PULONG)PAGETABLE_MAP && Pt < (PULONG)PAGETABLE_MAP + 1024*1024)
213 {
214 return TRUE;
215 }
216
217 if (Pt)
218 {
219 MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pt));
220 }
221 return FALSE;
222 }
223
224 static ULONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
225 {
226 ULONG Pte;
227 PULONG Pt;
228
229 Pt = MmGetPageTableForProcess(Process, Address, FALSE);
230 if (Pt)
231 {
232 Pte = *Pt;
233 MmUnmapPageTable(Pt);
234 return Pte;
235 }
236 return 0;
237 }
238
239 PFN_NUMBER
240 NTAPI
241 MmGetPfnForProcess(PEPROCESS Process,
242 PVOID Address)
243 {
244 ULONG Entry;
245 Entry = MmGetPageEntryForProcess(Process, Address);
246 if (!(Entry & PA_PRESENT))
247 {
248 return 0;
249 }
250 return(PTE_TO_PFN(Entry));
251 }
252
253 VOID
254 NTAPI
255 MmDisableVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN* WasDirty, PPFN_NUMBER Page)
256 /*
257 * FUNCTION: Delete a virtual mapping
258 */
259 {
260 BOOLEAN WasValid;
261 ULONG Pte;
262 PULONG Pt;
263
264 Pt = MmGetPageTableForProcess(Process, Address, FALSE);
265 if (Pt == NULL)
266 {
267 KeBugCheck(MEMORY_MANAGEMENT);
268 }
269 /*
270 * Atomically disable the present bit and get the old value.
271 */
272 do
273 {
274 Pte = *Pt;
275 } while (Pte != InterlockedCompareExchangePte(Pt, Pte & ~PA_PRESENT, Pte));
276
277 MiFlushTlb(Pt, Address);
278 WasValid = (PAGE_MASK(Pte) != 0);
279 if (!WasValid)
280 {
281 KeBugCheck(MEMORY_MANAGEMENT);
282 }
283
284 /*
285 * Return some information to the caller
286 */
287 if (WasDirty != NULL)
288 {
289 *WasDirty = Pte & PA_DIRTY;
290 }
291 if (Page != NULL)
292 {
293 *Page = PTE_TO_PFN(Pte);
294 }
295 }
296
297 VOID
298 NTAPI
299 MmRawDeleteVirtualMapping(PVOID Address)
300 {
301 PULONG Pt;
302
303 Pt = MmGetPageTableForProcess(NULL, Address, FALSE);
304 if (Pt && *Pt)
305 {
306 /*
307 * Set the entry to zero
308 */
309 InterlockedExchangePte(Pt, 0);
310 MiFlushTlb(Pt, Address);
311 }
312 }
313
314 VOID
315 NTAPI
316 MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN FreePage,
317 BOOLEAN* WasDirty, PPFN_NUMBER Page)
318 /*
319 * FUNCTION: Delete a virtual mapping
320 */
321 {
322 BOOLEAN WasValid = FALSE;
323 PFN_NUMBER Pfn;
324 ULONG Pte;
325 PULONG Pt;
326
327 DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
328 Process, Address, FreePage, WasDirty, Page);
329
330 Pt = MmGetPageTableForProcess(Process, Address, FALSE);
331
332 if (Pt == NULL)
333 {
334 if (WasDirty != NULL)
335 {
336 *WasDirty = FALSE;
337 }
338 if (Page != NULL)
339 {
340 *Page = 0;
341 }
342 return;
343 }
344
345 /*
346 * Atomically set the entry to zero and get the old value.
347 */
348 Pte = InterlockedExchangePte(Pt, 0);
349
350 MiFlushTlb(Pt, Address);
351
352 WasValid = (PAGE_MASK(Pte) != 0);
353 if (WasValid)
354 {
355 Pfn = PTE_TO_PFN(Pte);
356 }
357 else
358 {
359 Pfn = 0;
360 }
361
362 if (FreePage && WasValid)
363 {
364 MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
365 }
366
367 /*
368 * Return some information to the caller
369 */
370 if (WasDirty != NULL)
371 {
372 *WasDirty = Pte & PA_DIRTY ? TRUE : FALSE;
373 }
374 if (Page != NULL)
375 {
376 *Page = Pfn;
377 }
378 }
379
380 VOID
381 NTAPI
382 MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
383 SWAPENTRY* SwapEntry)
384 /*
385 * FUNCTION: Delete a virtual mapping
386 */
387 {
388 ULONG Pte;
389 PULONG Pt;
390
391 Pt = MmGetPageTableForProcess(Process, Address, FALSE);
392
393 if (Pt == NULL)
394 {
395 *SwapEntry = 0;
396 return;
397 }
398
399 /*
400 * Atomically set the entry to zero and get the old value.
401 */
402 Pte = InterlockedExchangePte(Pt, 0);
403
404 MiFlushTlb(Pt, Address);
405
406 /*
407 * Return some information to the caller
408 */
409 *SwapEntry = Pte >> 1;
410 }
411
412 BOOLEAN
413 Mmi386MakeKernelPageTableGlobal(PVOID PAddress)
414 {
415 PULONG Pt, Pde;
416 Pde = (PULONG)MiAddressToPde(PAddress);
417 if (*Pde == 0)
418 {
419 Pt = MmGetPageTableForProcess(NULL, PAddress, FALSE);
420 if (Pt != NULL)
421 {
422 return TRUE;
423 }
424 }
425 return(FALSE);
426 }
427
428 BOOLEAN
429 NTAPI
430 MmIsDirtyPage(PEPROCESS Process, PVOID Address)
431 {
432 return MmGetPageEntryForProcess(Process, Address) & PA_DIRTY ? TRUE : FALSE;
433 }
434
435 VOID
436 NTAPI
437 MmSetCleanPage(PEPROCESS Process, PVOID Address)
438 {
439 PULONG Pt;
440 ULONG Pte;
441
442 if (Address < MmSystemRangeStart && Process == NULL)
443 {
444 DPRINT1("MmSetCleanPage is called for user space without a process.\n");
445 KeBugCheck(MEMORY_MANAGEMENT);
446 }
447
448 Pt = MmGetPageTableForProcess(Process, Address, FALSE);
449
450 if (Pt == NULL)
451 {
452 KeBugCheck(MEMORY_MANAGEMENT);
453 }
454
455 do
456 {
457 Pte = *Pt;
458 } while (Pte != InterlockedCompareExchangePte(Pt, Pte & ~PA_DIRTY, Pte));
459
460 if (Pte & PA_DIRTY)
461 {
462 MiFlushTlb(Pt, Address);
463 }
464 else
465 {
466 MmUnmapPageTable(Pt);
467 }
468 }
469
470 VOID
471 NTAPI
472 MmSetDirtyPage(PEPROCESS Process, PVOID Address)
473 {
474 PULONG Pt;
475 ULONG Pte;
476
477 if (Address < MmSystemRangeStart && Process == NULL)
478 {
479 DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
480 KeBugCheck(MEMORY_MANAGEMENT);
481 }
482
483 Pt = MmGetPageTableForProcess(Process, Address, FALSE);
484 if (Pt == NULL)
485 {
486 KeBugCheck(MEMORY_MANAGEMENT);
487 }
488
489 do
490 {
491 Pte = *Pt;
492 } while (Pte != InterlockedCompareExchangePte(Pt, Pte | PA_DIRTY, Pte));
493 if (!(Pte & PA_DIRTY))
494 {
495 MiFlushTlb(Pt, Address);
496 }
497 else
498 {
499 MmUnmapPageTable(Pt);
500 }
501 }
502
503 VOID
504 NTAPI
505 MmEnableVirtualMapping(PEPROCESS Process, PVOID Address)
506 {
507 PULONG Pt;
508 ULONG Pte;
509
510 Pt = MmGetPageTableForProcess(Process, Address, FALSE);
511 if (Pt == NULL)
512 {
513 KeBugCheck(MEMORY_MANAGEMENT);
514 }
515
516 do
517 {
518 Pte = *Pt;
519 } while (Pte != InterlockedCompareExchangePte(Pt, Pte | PA_PRESENT, Pte));
520 if (!(Pte & PA_PRESENT))
521 {
522 MiFlushTlb(Pt, Address);
523 }
524 else
525 {
526 MmUnmapPageTable(Pt);
527 }
528 }
529
530 BOOLEAN
531 NTAPI
532 MmIsPagePresent(PEPROCESS Process, PVOID Address)
533 {
534 return MmGetPageEntryForProcess(Process, Address) & PA_PRESENT;
535 }
536
537 BOOLEAN
538 NTAPI
539 MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
540 {
541 ULONG Entry;
542 Entry = MmGetPageEntryForProcess(Process, Address);
543 return !(Entry & PA_PRESENT) && (Entry & 0x800) && Entry != 0;
544 }
545
546 NTSTATUS
547 NTAPI
548 MmCreatePageFileMapping(PEPROCESS Process,
549 PVOID Address,
550 SWAPENTRY SwapEntry)
551 {
552 PULONG Pt;
553 ULONG Pte;
554
555 if (Process == NULL && Address < MmSystemRangeStart)
556 {
557 DPRINT1("No process\n");
558 KeBugCheck(MEMORY_MANAGEMENT);
559 }
560 if (Process != NULL && Address >= MmSystemRangeStart)
561 {
562 DPRINT1("Setting kernel address with process context\n");
563 KeBugCheck(MEMORY_MANAGEMENT);
564 }
565
566 if (SwapEntry & (1 << 31))
567 {
568 KeBugCheck(MEMORY_MANAGEMENT);
569 }
570
571 Pt = MmGetPageTableForProcess(Process, Address, TRUE);
572 if (Pt == NULL)
573 {
574 KeBugCheck(MEMORY_MANAGEMENT);
575 }
576 Pte = *Pt;
577 InterlockedExchangePte(Pt, SwapEntry << 1);
578 if (Pte != 0)
579 {
580 MiFlushTlb(Pt, Address);
581 }
582 else
583 {
584 MmUnmapPageTable(Pt);
585 }
586
587 return(STATUS_SUCCESS);
588 }
589
590
591 NTSTATUS
592 NTAPI
593 MmCreateVirtualMappingUnsafe(PEPROCESS Process,
594 PVOID Address,
595 ULONG flProtect,
596 PPFN_NUMBER Pages,
597 ULONG PageCount)
598 {
599 ULONG Attributes;
600 PVOID Addr;
601 ULONG i;
602 ULONG oldPdeOffset, PdeOffset;
603 PULONG Pt = NULL;
604 ULONG Pte;
605 BOOLEAN NoExecute = FALSE;
606
607 DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
608 Process, Address, flProtect, Pages, *Pages, PageCount);
609
610 if (Process == NULL)
611 {
612 if (Address < MmSystemRangeStart)
613 {
614 DPRINT1("No process\n");
615 KeBugCheck(MEMORY_MANAGEMENT);
616 }
617 if (PageCount > 0x10000 ||
618 (ULONG_PTR) Address / PAGE_SIZE + PageCount > 0x100000)
619 {
620 DPRINT1("Page count too large\n");
621 KeBugCheck(MEMORY_MANAGEMENT);
622 }
623 }
624 else
625 {
626 if (Address >= MmSystemRangeStart)
627 {
628 DPRINT1("Setting kernel address with process context\n");
629 KeBugCheck(MEMORY_MANAGEMENT);
630 }
631 if (PageCount > (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE ||
632 (ULONG_PTR) Address / PAGE_SIZE + PageCount >
633 (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE)
634 {
635 DPRINT1("Page Count too large\n");
636 KeBugCheck(MEMORY_MANAGEMENT);
637 }
638 }
639
640 Attributes = ProtectToPTE(flProtect);
641 if (Attributes & 0x80000000)
642 {
643 NoExecute = TRUE;
644 }
645 Attributes &= 0xfff;
646 if (Address >= MmSystemRangeStart)
647 {
648 Attributes &= ~PA_USER;
649 }
650 else
651 {
652 Attributes |= PA_USER;
653 }
654
655 Addr = Address;
656 oldPdeOffset = ADDR_TO_PDE_OFFSET(Addr) + 1;
657 for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
658 {
659 if (!(Attributes & PA_PRESENT) && Pages[i] != 0)
660 {
661 DPRINT1("Setting physical address but not allowing access at address "
662 "0x%.8X with attributes %x/%x.\n",
663 Addr, Attributes, flProtect);
664 KeBugCheck(MEMORY_MANAGEMENT);
665 }
666 PdeOffset = ADDR_TO_PDE_OFFSET(Addr);
667 if (oldPdeOffset != PdeOffset)
668 {
669 MmUnmapPageTable(Pt);
670 Pt = MmGetPageTableForProcess(Process, Addr, TRUE);
671 if (Pt == NULL)
672 {
673 KeBugCheck(MEMORY_MANAGEMENT);
674 }
675 }
676 else
677 {
678 Pt++;
679 }
680 oldPdeOffset = PdeOffset;
681
682 Pte = *Pt;
683 if (PAGE_MASK(Pte) != 0 && !(Pte & PA_PRESENT) && (Pte & 0x800))
684 {
685 DPRINT1("Bad PTE %lx\n", Pte);
686 KeBugCheck(MEMORY_MANAGEMENT);
687 }
688 InterlockedExchangePte(Pt, PFN_TO_PTE(Pages[i]) | Attributes);
689 if (Pte != 0)
690 {
691 if (Address > MmSystemRangeStart ||
692 (Pt >= (PULONG)PAGETABLE_MAP && Pt < (PULONG)PAGETABLE_MAP + 1024*1024))
693 {
694 MiFlushTlb(Pt, Address);
695 }
696 }
697 }
698 if (Addr > Address)
699 {
700 MmUnmapPageTable(Pt);
701 }
702
703 return(STATUS_SUCCESS);
704 }
705
706 NTSTATUS
707 NTAPI
708 MmCreateVirtualMapping(PEPROCESS Process,
709 PVOID Address,
710 ULONG flProtect,
711 PPFN_NUMBER Pages,
712 ULONG PageCount)
713 {
714 ULONG i;
715
716 for (i = 0; i < PageCount; i++)
717 {
718 if (!MmIsPageInUse(Pages[i]))
719 {
720 DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages[i]));
721 KeBugCheck(MEMORY_MANAGEMENT);
722 }
723 }
724
725 return(MmCreateVirtualMappingUnsafe(Process,
726 Address,
727 flProtect,
728 Pages,
729 PageCount));
730 }
731
732 ULONG
733 NTAPI
734 MmGetPageProtect(PEPROCESS Process, PVOID Address)
735 {
736 ULONG Entry;
737 ULONG Protect;
738
739 Entry = MmGetPageEntryForProcess(Process, Address);
740
741
742 if (!(Entry & PA_PRESENT))
743 {
744 Protect = PAGE_NOACCESS;
745 }
746 else
747 {
748 if (Entry & PA_READWRITE)
749 {
750 Protect = PAGE_READWRITE;
751 }
752 else
753 {
754 Protect = PAGE_EXECUTE_READ;
755 }
756 if (Entry & PA_CD)
757 {
758 Protect |= PAGE_NOCACHE;
759 }
760 if (Entry & PA_WT)
761 {
762 Protect |= PAGE_WRITETHROUGH;
763 }
764 if (!(Entry & PA_USER))
765 {
766 Protect |= PAGE_SYSTEM;
767 }
768
769 }
770 return(Protect);
771 }
772
773 VOID
774 NTAPI
775 MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
776 {
777 ULONG Attributes = 0;
778 BOOLEAN NoExecute = FALSE;
779 PULONG Pt;
780
781 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
782 Process, Address, flProtect);
783
784 Attributes = ProtectToPTE(flProtect);
785
786 if (Attributes & 0x80000000)
787 {
788 NoExecute = TRUE;
789 }
790 Attributes &= 0xfff;
791 if (Address >= MmSystemRangeStart)
792 {
793 Attributes &= ~PA_USER;
794 }
795 else
796 {
797 Attributes |= PA_USER;
798 }
799
800 Pt = MmGetPageTableForProcess(Process, Address, FALSE);
801 if (Pt == NULL)
802 {
803 KeBugCheck(MEMORY_MANAGEMENT);
804 }
805 InterlockedExchangePte(Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY)));
806 MiFlushTlb(Pt, Address);
807 }
808
809 /*
810 * @implemented
811 */
812 PHYSICAL_ADDRESS NTAPI
813 MmGetPhysicalAddress(PVOID vaddr)
814 /*
815 * FUNCTION: Returns the physical address corresponding to a virtual address
816 */
817 {
818 PHYSICAL_ADDRESS p;
819 ULONG Pte;
820
821 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr);
822 Pte = MmGetPageEntryForProcess(NULL, vaddr);
823 if (Pte != 0 && Pte & PA_PRESENT)
824 {
825 p.QuadPart = PAGE_MASK(Pte);
826 p.u.LowPart |= (ULONG_PTR)vaddr & (PAGE_SIZE - 1);
827 }
828 else
829 {
830 p.QuadPart = 0;
831 }
832 return p;
833 }
834
835 VOID
836 NTAPI
837 MmUpdatePageDir(PEPROCESS Process, PVOID Address, ULONG Size)
838 {
839 ULONG StartOffset, EndOffset, Offset;
840 PULONG Pde;
841
842 //
843 // Check if the process isn't there anymore
844 // This is probably a bad sign, since it means the caller is setting cr3 to
845 // 0 or something...
846 //
847 if ((PTE_TO_PFN(Process->Pcb.DirectoryTableBase[0]) == 0) && (Process != PsGetCurrentProcess()))
848 {
849 DPRINT1("Process: %16s is dead: %p\n", Process->ImageFileName, Process->Pcb.DirectoryTableBase[0]);
850 ASSERT(FALSE);
851 return;
852 }
853
854 if (Address < MmSystemRangeStart)
855 {
856 KeBugCheck(MEMORY_MANAGEMENT);
857 }
858
859 StartOffset = ADDR_TO_PDE_OFFSET(Address);
860 EndOffset = ADDR_TO_PDE_OFFSET((PVOID)((ULONG_PTR)Address + Size));
861
862 if (Process != NULL && Process != PsGetCurrentProcess())
863 {
864 Pde = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase[0]));
865 }
866 else
867 {
868 Pde = (PULONG)PAGEDIRECTORY_MAP;
869 }
870 for (Offset = StartOffset; Offset <= EndOffset; Offset++)
871 {
872 if (Offset != ADDR_TO_PDE_OFFSET(PAGETABLE_MAP))
873 {
874 InterlockedCompareExchangePte(&Pde[Offset], MmGlobalKernelPageDirectory[Offset], 0);
875 }
876 }
877 if (Pde != (PULONG)PAGEDIRECTORY_MAP)
878 {
879 MmDeleteHyperspaceMapping(Pde);
880 }
881 }
882
883 VOID
884 INIT_FUNCTION
885 NTAPI
886 MmInitGlobalKernelPageDirectory(VOID)
887 {
888 ULONG i;
889 PULONG CurrentPageDirectory = (PULONG)PAGEDIRECTORY_MAP;
890
891 DPRINT("MmInitGlobalKernelPageDirectory()\n");
892
893 for (i = ADDR_TO_PDE_OFFSET(MmSystemRangeStart); i < 1024; i++)
894 {
895 if (i != ADDR_TO_PDE_OFFSET(PAGETABLE_MAP) &&
896 i != ADDR_TO_PDE_OFFSET(HYPERSPACE) &&
897 0 == MmGlobalKernelPageDirectory[i] && 0 != CurrentPageDirectory[i])
898 {
899 MmGlobalKernelPageDirectory[i] = CurrentPageDirectory[i];
900 }
901 }
902 }
903
904 /* EOF */