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