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 /* 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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