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