1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: ntoskrnl/mm/ARM3/section.c 5 * PURPOSE: ARM Memory Manager Section Support 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 #define MODULE_INVOLVED_IN_ARM3 16 #include <mm/ARM3/miarm.h> 17 18 /* GLOBALS ********************************************************************/ 19 20 ACCESS_MASK MmMakeSectionAccess[8] = 21 { 22 SECTION_MAP_READ, 23 SECTION_MAP_READ, 24 SECTION_MAP_EXECUTE, 25 SECTION_MAP_EXECUTE | SECTION_MAP_READ, 26 SECTION_MAP_WRITE, 27 SECTION_MAP_READ, 28 SECTION_MAP_EXECUTE | SECTION_MAP_WRITE, 29 SECTION_MAP_EXECUTE | SECTION_MAP_READ 30 }; 31 32 ACCESS_MASK MmMakeFileAccess[8] = 33 { 34 FILE_READ_DATA, 35 FILE_READ_DATA, 36 FILE_EXECUTE, 37 FILE_EXECUTE | FILE_READ_DATA, 38 FILE_WRITE_DATA | FILE_READ_DATA, 39 FILE_READ_DATA, 40 FILE_EXECUTE | FILE_WRITE_DATA | FILE_READ_DATA, 41 FILE_EXECUTE | FILE_READ_DATA 42 }; 43 44 CHAR MmUserProtectionToMask1[16] = 45 { 46 0, 47 MM_NOACCESS, 48 MM_READONLY, 49 (CHAR)MM_INVALID_PROTECTION, 50 MM_READWRITE, 51 (CHAR)MM_INVALID_PROTECTION, 52 (CHAR)MM_INVALID_PROTECTION, 53 (CHAR)MM_INVALID_PROTECTION, 54 MM_WRITECOPY, 55 (CHAR)MM_INVALID_PROTECTION, 56 (CHAR)MM_INVALID_PROTECTION, 57 (CHAR)MM_INVALID_PROTECTION, 58 (CHAR)MM_INVALID_PROTECTION, 59 (CHAR)MM_INVALID_PROTECTION, 60 (CHAR)MM_INVALID_PROTECTION, 61 (CHAR)MM_INVALID_PROTECTION 62 }; 63 64 CHAR MmUserProtectionToMask2[16] = 65 { 66 0, 67 MM_EXECUTE, 68 MM_EXECUTE_READ, 69 (CHAR)MM_INVALID_PROTECTION, 70 MM_EXECUTE_READWRITE, 71 (CHAR)MM_INVALID_PROTECTION, 72 (CHAR)MM_INVALID_PROTECTION, 73 (CHAR)MM_INVALID_PROTECTION, 74 MM_EXECUTE_WRITECOPY, 75 (CHAR)MM_INVALID_PROTECTION, 76 (CHAR)MM_INVALID_PROTECTION, 77 (CHAR)MM_INVALID_PROTECTION, 78 (CHAR)MM_INVALID_PROTECTION, 79 (CHAR)MM_INVALID_PROTECTION, 80 (CHAR)MM_INVALID_PROTECTION, 81 (CHAR)MM_INVALID_PROTECTION 82 }; 83 84 ULONG MmCompatibleProtectionMask[8] = 85 { 86 PAGE_NOACCESS, 87 88 PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY, 89 90 PAGE_NOACCESS | PAGE_EXECUTE, 91 92 PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY | PAGE_EXECUTE | 93 PAGE_EXECUTE_READ, 94 95 PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY | PAGE_READWRITE, 96 97 PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY, 98 99 PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY | PAGE_READWRITE | 100 PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | 101 PAGE_EXECUTE_WRITECOPY, 102 103 PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY | PAGE_EXECUTE | 104 PAGE_EXECUTE_READ | PAGE_EXECUTE_WRITECOPY 105 }; 106 107 MMSESSION MmSession; 108 KGUARDED_MUTEX MmSectionCommitMutex; 109 MM_AVL_TABLE MmSectionBasedRoot; 110 KGUARDED_MUTEX MmSectionBasedMutex; 111 PVOID MmHighSectionBase; 112 113 /* PRIVATE FUNCTIONS **********************************************************/ 114 115 BOOLEAN 116 NTAPI 117 MiIsProtectionCompatible(IN ULONG SectionPageProtection, 118 IN ULONG NewSectionPageProtection) 119 { 120 ULONG ProtectionMask, CompatibleMask; 121 122 /* Calculate the protection mask and make sure it's valid */ 123 ProtectionMask = MiMakeProtectionMask(SectionPageProtection); 124 if (ProtectionMask == MM_INVALID_PROTECTION) 125 { 126 DPRINT1("Invalid protection mask\n"); 127 return FALSE; 128 } 129 130 /* Calculate the compatible mask */ 131 CompatibleMask = MmCompatibleProtectionMask[ProtectionMask & 0x7] | 132 PAGE_GUARD | PAGE_NOCACHE | PAGE_WRITECOMBINE; 133 134 /* See if the mapping protection is compatible with the create protection */ 135 return ((CompatibleMask | NewSectionPageProtection) == CompatibleMask); 136 } 137 138 ACCESS_MASK 139 NTAPI 140 MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection) 141 { 142 ULONG ProtectionMask; 143 144 /* Calculate the protection mask and make sure it's valid */ 145 ProtectionMask = MiMakeProtectionMask(SectionPageProtection); 146 if (ProtectionMask == MM_INVALID_PROTECTION) 147 { 148 DPRINT1("Invalid protection mask\n"); 149 return STATUS_INVALID_PAGE_PROTECTION; 150 } 151 152 /* Now convert it to the required file access */ 153 return MmMakeFileAccess[ProtectionMask & 0x7]; 154 } 155 156 ULONG 157 NTAPI 158 MiMakeProtectionMask(IN ULONG Protect) 159 { 160 ULONG Mask1, Mask2, ProtectMask; 161 162 /* PAGE_EXECUTE_WRITECOMBINE is theoretically the maximum */ 163 if (Protect >= (PAGE_WRITECOMBINE * 2)) return MM_INVALID_PROTECTION; 164 165 /* 166 * Windows API protection mask can be understood as two bitfields, differing 167 * by whether or not execute rights are being requested 168 */ 169 Mask1 = Protect & 0xF; 170 Mask2 = (Protect >> 4) & 0xF; 171 172 /* Check which field is there */ 173 if (!Mask1) 174 { 175 /* Mask2 must be there, use it to determine the PTE protection */ 176 if (!Mask2) return MM_INVALID_PROTECTION; 177 ProtectMask = MmUserProtectionToMask2[Mask2]; 178 } 179 else 180 { 181 /* Mask2 should not be there, use Mask1 to determine the PTE mask */ 182 if (Mask2) return MM_INVALID_PROTECTION; 183 ProtectMask = MmUserProtectionToMask1[Mask1]; 184 } 185 186 /* Make sure the final mask is a valid one */ 187 if (ProtectMask == MM_INVALID_PROTECTION) return MM_INVALID_PROTECTION; 188 189 /* Check for PAGE_GUARD option */ 190 if (Protect & PAGE_GUARD) 191 { 192 /* It's not valid on no-access, nocache, or writecombine pages */ 193 if ((ProtectMask == MM_NOACCESS) || 194 (Protect & (PAGE_NOCACHE | PAGE_WRITECOMBINE))) 195 { 196 /* Fail such requests */ 197 return MM_INVALID_PROTECTION; 198 } 199 200 /* This actually turns on guard page in this scenario! */ 201 ProtectMask |= MM_GUARDPAGE; 202 } 203 204 /* Check for nocache option */ 205 if (Protect & PAGE_NOCACHE) 206 { 207 /* The earlier check should've eliminated this possibility */ 208 ASSERT((Protect & PAGE_GUARD) == 0); 209 210 /* Check for no-access page or write combine page */ 211 if ((ProtectMask == MM_NOACCESS) || (Protect & PAGE_WRITECOMBINE)) 212 { 213 /* Such a request is invalid */ 214 return MM_INVALID_PROTECTION; 215 } 216 217 /* Add the PTE flag */ 218 ProtectMask |= MM_NOCACHE; 219 } 220 221 /* Check for write combine option */ 222 if (Protect & PAGE_WRITECOMBINE) 223 { 224 /* The two earlier scenarios should've caught this */ 225 ASSERT((Protect & (PAGE_GUARD | PAGE_NOACCESS)) == 0); 226 227 /* Don't allow on no-access pages */ 228 if (ProtectMask == MM_NOACCESS) return MM_INVALID_PROTECTION; 229 230 /* This actually turns on write-combine in this scenario! */ 231 ProtectMask |= MM_NOACCESS; 232 } 233 234 /* Return the final MM PTE protection mask */ 235 return ProtectMask; 236 } 237 238 BOOLEAN 239 NTAPI 240 MiInitializeSystemSpaceMap(IN PMMSESSION InputSession OPTIONAL) 241 { 242 SIZE_T AllocSize, BitmapSize, Size; 243 PVOID ViewStart; 244 PMMSESSION Session; 245 246 /* Check if this a session or system space */ 247 if (InputSession) 248 { 249 /* Use the input session */ 250 Session = InputSession; 251 ViewStart = MiSessionViewStart; 252 Size = MmSessionViewSize; 253 } 254 else 255 { 256 /* Use the system space "session" */ 257 Session = &MmSession; 258 ViewStart = MiSystemViewStart; 259 Size = MmSystemViewSize; 260 } 261 262 /* Initialize the system space lock */ 263 Session->SystemSpaceViewLockPointer = &Session->SystemSpaceViewLock; 264 KeInitializeGuardedMutex(Session->SystemSpaceViewLockPointer); 265 266 /* Set the start address */ 267 Session->SystemSpaceViewStart = ViewStart; 268 269 /* Create a bitmap to describe system space */ 270 BitmapSize = sizeof(RTL_BITMAP) + ((((Size / MI_SYSTEM_VIEW_BUCKET_SIZE) + 31) / 32) * sizeof(ULONG)); 271 Session->SystemSpaceBitMap = ExAllocatePoolWithTag(NonPagedPool, 272 BitmapSize, 273 TAG_MM); 274 ASSERT(Session->SystemSpaceBitMap); 275 RtlInitializeBitMap(Session->SystemSpaceBitMap, 276 (PULONG)(Session->SystemSpaceBitMap + 1), 277 (ULONG)(Size / MI_SYSTEM_VIEW_BUCKET_SIZE)); 278 279 /* Set system space fully empty to begin with */ 280 RtlClearAllBits(Session->SystemSpaceBitMap); 281 282 /* Set default hash flags */ 283 Session->SystemSpaceHashSize = 31; 284 Session->SystemSpaceHashKey = Session->SystemSpaceHashSize - 1; 285 Session->SystemSpaceHashEntries = 0; 286 287 /* Calculate how much space for the hash views we'll need */ 288 AllocSize = sizeof(MMVIEW) * Session->SystemSpaceHashSize; 289 ASSERT(AllocSize < PAGE_SIZE); 290 291 /* Allocate and zero the view table */ 292 Session->SystemSpaceViewTable = ExAllocatePoolWithTag(Session == &MmSession ? 293 NonPagedPool : 294 PagedPool, 295 AllocSize, 296 TAG_MM); 297 ASSERT(Session->SystemSpaceViewTable != NULL); 298 RtlZeroMemory(Session->SystemSpaceViewTable, AllocSize); 299 300 /* Success */ 301 return TRUE; 302 } 303 304 PVOID 305 NTAPI 306 MiInsertInSystemSpace(IN PMMSESSION Session, 307 IN ULONG Buckets, 308 IN PCONTROL_AREA ControlArea) 309 { 310 PVOID Base; 311 ULONG Entry, Hash, i, HashSize; 312 PMMVIEW OldTable; 313 PAGED_CODE(); 314 315 /* Stay within 4GB */ 316 ASSERT(Buckets < MI_SYSTEM_VIEW_BUCKET_SIZE); 317 318 /* Lock system space */ 319 KeAcquireGuardedMutex(Session->SystemSpaceViewLockPointer); 320 321 /* Check if we're going to exhaust hash entries */ 322 if ((Session->SystemSpaceHashEntries + 8) > Session->SystemSpaceHashSize) 323 { 324 /* Double the hash size */ 325 HashSize = Session->SystemSpaceHashSize * 2; 326 327 /* Save the old table and allocate a new one */ 328 OldTable = Session->SystemSpaceViewTable; 329 Session->SystemSpaceViewTable = ExAllocatePoolWithTag(Session == 330 &MmSession ? 331 NonPagedPool : 332 PagedPool, 333 HashSize * 334 sizeof(MMVIEW), 335 TAG_MM); 336 if (!Session->SystemSpaceViewTable) 337 { 338 /* Failed to allocate a new table, keep the old one for now */ 339 Session->SystemSpaceViewTable = OldTable; 340 } 341 else 342 { 343 /* Clear the new table and set the new ahsh and key */ 344 RtlZeroMemory(Session->SystemSpaceViewTable, HashSize * sizeof(MMVIEW)); 345 Session->SystemSpaceHashSize = HashSize; 346 Session->SystemSpaceHashKey = Session->SystemSpaceHashSize - 1; 347 348 /* Loop the old table */ 349 for (i = 0; i < Session->SystemSpaceHashSize / 2; i++) 350 { 351 /* Check if the entry was valid */ 352 if (OldTable[i].Entry) 353 { 354 /* Re-hash the old entry and search for space in the new table */ 355 Hash = (OldTable[i].Entry >> 16) % Session->SystemSpaceHashKey; 356 while (Session->SystemSpaceViewTable[Hash].Entry) 357 { 358 /* Loop back at the beginning if we had an overflow */ 359 if (++Hash >= Session->SystemSpaceHashSize) Hash = 0; 360 } 361 362 /* Write the old entry in the new table */ 363 Session->SystemSpaceViewTable[Hash] = OldTable[i]; 364 } 365 } 366 367 /* Free the old table */ 368 ExFreePool(OldTable); 369 } 370 } 371 372 /* Check if we ran out */ 373 if (Session->SystemSpaceHashEntries == Session->SystemSpaceHashSize) 374 { 375 DPRINT1("Ran out of system view hash entries\n"); 376 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 377 return NULL; 378 } 379 380 /* Find space where to map this view */ 381 i = RtlFindClearBitsAndSet(Session->SystemSpaceBitMap, Buckets, 0); 382 if (i == 0xFFFFFFFF) 383 { 384 /* Out of space, fail */ 385 Session->BitmapFailures++; 386 DPRINT1("Out of system view space\n"); 387 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 388 return NULL; 389 } 390 391 /* Compute the base address */ 392 Base = (PVOID)((ULONG_PTR)Session->SystemSpaceViewStart + (i * MI_SYSTEM_VIEW_BUCKET_SIZE)); 393 394 /* Get the hash entry for this allocation */ 395 Entry = ((ULONG_PTR)Base & ~(MI_SYSTEM_VIEW_BUCKET_SIZE - 1)) + Buckets; 396 Hash = (Entry >> 16) % Session->SystemSpaceHashKey; 397 398 /* Loop hash entries until a free one is found */ 399 while (Session->SystemSpaceViewTable[Hash].Entry) 400 { 401 /* Unless we overflow, in which case loop back at hash o */ 402 if (++Hash >= Session->SystemSpaceHashSize) Hash = 0; 403 } 404 405 /* Add this entry into the hash table */ 406 Session->SystemSpaceViewTable[Hash].Entry = Entry; 407 Session->SystemSpaceViewTable[Hash].ControlArea = ControlArea; 408 409 /* Hash entry found, increment total and return the base address */ 410 Session->SystemSpaceHashEntries++; 411 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 412 return Base; 413 } 414 415 static 416 NTSTATUS 417 MiAddMappedPtes(IN PMMPTE FirstPte, 418 IN PFN_NUMBER PteCount, 419 IN PCONTROL_AREA ControlArea, 420 IN LONGLONG SectionOffset) 421 { 422 MMPTE TempPte; 423 PMMPTE PointerPte, ProtoPte, LastProtoPte, LastPte; 424 PSUBSECTION Subsection; 425 426 /* Mapping at offset not supported yet */ 427 ASSERT(SectionOffset == 0); 428 429 /* ARM3 doesn't support this yet */ 430 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 431 ASSERT(ControlArea->u.Flags.Rom == 0); 432 ASSERT(ControlArea->FilePointer == NULL); 433 434 /* Sanity checks */ 435 ASSERT(PteCount != 0); 436 ASSERT(ControlArea->NumberOfMappedViews >= 1); 437 ASSERT(ControlArea->NumberOfUserReferences >= 1); 438 ASSERT(ControlArea->NumberOfSectionReferences != 0); 439 ASSERT(ControlArea->u.Flags.BeingCreated == 0); 440 ASSERT(ControlArea->u.Flags.BeingDeleted == 0); 441 ASSERT(ControlArea->u.Flags.BeingPurged == 0); 442 443 /* Get the PTEs for the actual mapping */ 444 PointerPte = FirstPte; 445 LastPte = FirstPte + PteCount; 446 447 /* Get the prototype PTEs that desribe the section mapping in the subsection */ 448 Subsection = (PSUBSECTION)(ControlArea + 1); 449 ProtoPte = Subsection->SubsectionBase; 450 LastProtoPte = &Subsection->SubsectionBase[Subsection->PtesInSubsection]; 451 452 /* Loop the PTEs for the mapping */ 453 while (PointerPte < LastPte) 454 { 455 /* We may have run out of prototype PTEs in this subsection */ 456 if (ProtoPte >= LastProtoPte) 457 { 458 /* But we don't handle this yet */ 459 ASSERT(FALSE); 460 } 461 462 /* The PTE should be completely clear */ 463 ASSERT(PointerPte->u.Long == 0); 464 465 /* Build the prototype PTE and write it */ 466 MI_MAKE_PROTOTYPE_PTE(&TempPte, ProtoPte); 467 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 468 469 /* Keep going */ 470 PointerPte++; 471 ProtoPte++; 472 } 473 474 /* No failure path */ 475 return STATUS_SUCCESS; 476 } 477 478 VOID 479 NTAPI 480 MiFillSystemPageDirectory(IN PVOID Base, 481 IN SIZE_T NumberOfBytes) 482 { 483 PMMPDE PointerPde, LastPde, SystemMapPde; 484 MMPDE TempPde; 485 PFN_NUMBER PageFrameIndex, ParentPage; 486 KIRQL OldIrql; 487 PAGED_CODE(); 488 489 /* Find the PDEs needed for this mapping */ 490 PointerPde = MiAddressToPde(Base); 491 LastPde = MiAddressToPde((PVOID)((ULONG_PTR)Base + NumberOfBytes - 1)); 492 493 #if (_MI_PAGING_LEVELS == 2) 494 /* Find the system double-mapped PDE that describes this mapping */ 495 SystemMapPde = &MmSystemPagePtes[((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE)]; 496 #else 497 /* We don't have a double mapping */ 498 SystemMapPde = PointerPde; 499 #endif 500 501 /* Use the PDE template and loop the PDEs */ 502 TempPde = ValidKernelPde; 503 while (PointerPde <= LastPde) 504 { 505 /* Lock the PFN database */ 506 OldIrql = MiAcquirePfnLock(); 507 508 /* Check if we don't already have this PDE mapped */ 509 if (SystemMapPde->u.Hard.Valid == 0) 510 { 511 /* Grab a page for it */ 512 MI_SET_USAGE(MI_USAGE_PAGE_TABLE); 513 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName); 514 PageFrameIndex = MiRemoveZeroPage(MI_GET_NEXT_COLOR()); 515 ASSERT(PageFrameIndex); 516 TempPde.u.Hard.PageFrameNumber = PageFrameIndex; 517 518 #if (_MI_PAGING_LEVELS == 2) 519 ParentPage = MmSystemPageDirectory[(PointerPde - MiAddressToPde(NULL)) / PDE_PER_PAGE]; 520 #else 521 ParentPage = MiPdeToPpe(PointerPde)->u.Hard.PageFrameNumber; 522 #endif 523 /* Initialize its PFN entry, with the parent system page directory page table */ 524 MiInitializePfnForOtherProcess(PageFrameIndex, 525 (PMMPTE)PointerPde, 526 ParentPage); 527 528 /* Make the system PDE entry valid */ 529 MI_WRITE_VALID_PDE(SystemMapPde, TempPde); 530 531 /* The system PDE entry might be the PDE itself, so check for this */ 532 if (PointerPde->u.Hard.Valid == 0) 533 { 534 /* It's different, so make the real PDE valid too */ 535 MI_WRITE_VALID_PDE(PointerPde, TempPde); 536 } 537 } 538 539 /* Release the lock and keep going with the next PDE */ 540 MiReleasePfnLock(OldIrql); 541 SystemMapPde++; 542 PointerPde++; 543 } 544 } 545 546 NTSTATUS 547 NTAPI 548 MiCheckPurgeAndUpMapCount(IN PCONTROL_AREA ControlArea, 549 IN BOOLEAN FailIfSystemViews) 550 { 551 KIRQL OldIrql; 552 553 /* Flag not yet supported */ 554 ASSERT(FailIfSystemViews == FALSE); 555 556 /* Lock the PFN database */ 557 OldIrql = MiAcquirePfnLock(); 558 559 /* State not yet supported */ 560 ASSERT(ControlArea->u.Flags.BeingPurged == 0); 561 562 /* Increase the reference counts */ 563 ControlArea->NumberOfMappedViews++; 564 ControlArea->NumberOfUserReferences++; 565 ASSERT(ControlArea->NumberOfSectionReferences != 0); 566 567 /* Release the PFN lock and return success */ 568 MiReleasePfnLock(OldIrql); 569 return STATUS_SUCCESS; 570 } 571 572 PSUBSECTION 573 NTAPI 574 MiLocateSubsection(IN PMMVAD Vad, 575 IN ULONG_PTR Vpn) 576 { 577 PSUBSECTION Subsection; 578 PCONTROL_AREA ControlArea; 579 ULONG_PTR PteOffset; 580 581 /* Get the control area */ 582 ControlArea = Vad->ControlArea; 583 ASSERT(ControlArea->u.Flags.Rom == 0); 584 ASSERT(ControlArea->u.Flags.Image == 0); 585 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 586 587 /* Get the subsection */ 588 Subsection = (PSUBSECTION)(ControlArea + 1); 589 590 /* We only support single-subsection segments */ 591 ASSERT(Subsection->SubsectionBase != NULL); 592 ASSERT(Vad->FirstPrototypePte >= Subsection->SubsectionBase); 593 ASSERT(Vad->FirstPrototypePte < &Subsection->SubsectionBase[Subsection->PtesInSubsection]); 594 595 /* Compute the PTE offset */ 596 PteOffset = Vpn - Vad->StartingVpn; 597 PteOffset += Vad->FirstPrototypePte - Subsection->SubsectionBase; 598 599 /* Again, we only support single-subsection segments */ 600 ASSERT(PteOffset < 0xF0000000); 601 ASSERT(PteOffset < Subsection->PtesInSubsection); 602 603 /* Return the subsection */ 604 return Subsection; 605 } 606 607 VOID 608 NTAPI 609 MiSegmentDelete(IN PSEGMENT Segment) 610 { 611 PCONTROL_AREA ControlArea; 612 SEGMENT_FLAGS SegmentFlags; 613 PSUBSECTION Subsection; 614 PMMPTE PointerPte, LastPte, PteForProto; 615 PMMPFN Pfn1; 616 PFN_NUMBER PageFrameIndex; 617 MMPTE TempPte; 618 KIRQL OldIrql; 619 620 /* Capture data */ 621 SegmentFlags = Segment->SegmentFlags; 622 ControlArea = Segment->ControlArea; 623 624 /* Make sure control area is on the right delete path */ 625 ASSERT(ControlArea->u.Flags.BeingDeleted == 1); 626 ASSERT(ControlArea->WritableUserReferences == 0); 627 628 /* These things are not supported yet */ 629 ASSERT(ControlArea->DereferenceList.Flink == NULL); 630 ASSERT(!(ControlArea->u.Flags.Image) && !(ControlArea->u.Flags.File)); 631 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 632 ASSERT(ControlArea->u.Flags.Rom == 0); 633 634 /* Get the subsection and PTEs for this segment */ 635 Subsection = (PSUBSECTION)(ControlArea + 1); 636 PointerPte = Subsection->SubsectionBase; 637 LastPte = PointerPte + Segment->NonExtendedPtes; 638 639 /* Lock the PFN database */ 640 OldIrql = MiAcquirePfnLock(); 641 642 /* Check if the master PTE is invalid */ 643 PteForProto = MiAddressToPte(PointerPte); 644 if (!PteForProto->u.Hard.Valid) 645 { 646 /* Fault it in */ 647 MiMakeSystemAddressValidPfn(PointerPte, OldIrql); 648 } 649 650 /* Loop all the segment PTEs */ 651 while (PointerPte < LastPte) 652 { 653 /* Check if it's time to switch master PTEs if we passed a PDE boundary */ 654 if (MiIsPteOnPdeBoundary(PointerPte) && 655 (PointerPte != Subsection->SubsectionBase)) 656 { 657 /* Check if the master PTE is invalid */ 658 PteForProto = MiAddressToPte(PointerPte); 659 if (!PteForProto->u.Hard.Valid) 660 { 661 /* Fault it in */ 662 MiMakeSystemAddressValidPfn(PointerPte, OldIrql); 663 } 664 } 665 666 /* This should be a prototype PTE */ 667 TempPte = *PointerPte; 668 ASSERT(SegmentFlags.LargePages == 0); 669 ASSERT(TempPte.u.Hard.Valid == 0); 670 671 /* See if we should clean things up */ 672 if (!(ControlArea->u.Flags.Image) && !(ControlArea->u.Flags.File)) 673 { 674 /* 675 * This is a section backed by the pagefile. Now that it doesn't exist anymore, 676 * we can give everything back to the system. 677 */ 678 ASSERT(TempPte.u.Soft.Prototype == 0); 679 680 if (TempPte.u.Soft.Transition == 1) 681 { 682 /* We can give the page back for other use */ 683 DPRINT("Releasing page for transition PTE %p\n", PointerPte); 684 PageFrameIndex = PFN_FROM_PTE(&TempPte); 685 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 686 687 /* As this is a paged-backed section, nobody should reference it anymore (no cache or whatever) */ 688 ASSERT(Pfn1->u3.ReferenceCount == 0); 689 690 /* And it should be in standby or modified list */ 691 ASSERT((Pfn1->u3.e1.PageLocation == ModifiedPageList) || (Pfn1->u3.e1.PageLocation == StandbyPageList)); 692 693 /* Unlink it and put it back in free list */ 694 MiUnlinkPageFromList(Pfn1); 695 696 /* Temporarily mark this as active and make it free again */ 697 Pfn1->u3.e1.PageLocation = ActiveAndValid; 698 MI_SET_PFN_DELETED(Pfn1); 699 700 MiInsertPageInFreeList(PageFrameIndex); 701 } 702 else if (TempPte.u.Soft.PageFileHigh != 0) 703 { 704 /* Should not happen for now */ 705 ASSERT(FALSE); 706 } 707 } 708 else 709 { 710 /* unsupported for now */ 711 ASSERT(FALSE); 712 713 /* File-backed section must have prototype PTEs */ 714 ASSERT(TempPte.u.Soft.Prototype == 1); 715 } 716 717 /* Zero the PTE and keep going */ 718 PointerPte->u.Long = 0; 719 PointerPte++; 720 } 721 722 /* Release the PFN lock */ 723 MiReleasePfnLock(OldIrql); 724 725 /* Free the structures */ 726 ExFreePool(ControlArea); 727 ExFreePool(Segment); 728 } 729 730 VOID 731 NTAPI 732 MiCheckControlArea(IN PCONTROL_AREA ControlArea, 733 IN KIRQL OldIrql) 734 { 735 BOOLEAN DeleteSegment = FALSE; 736 MI_ASSERT_PFN_LOCK_HELD(); 737 738 /* Check if this is the last reference or view */ 739 if (!(ControlArea->NumberOfMappedViews) && 740 !(ControlArea->NumberOfSectionReferences)) 741 { 742 /* There should be no more user references either */ 743 ASSERT(ControlArea->NumberOfUserReferences == 0); 744 745 /* Not yet supported */ 746 ASSERT(ControlArea->FilePointer == NULL); 747 748 /* The control area is being destroyed */ 749 ControlArea->u.Flags.BeingDeleted = TRUE; 750 DeleteSegment = TRUE; 751 } 752 753 /* Release the PFN lock */ 754 MiReleasePfnLock(OldIrql); 755 756 /* Delete the segment if needed */ 757 if (DeleteSegment) 758 { 759 /* No more user write references at all */ 760 ASSERT(ControlArea->WritableUserReferences == 0); 761 MiSegmentDelete(ControlArea->Segment); 762 } 763 } 764 765 VOID 766 NTAPI 767 MiDereferenceControlArea(IN PCONTROL_AREA ControlArea) 768 { 769 KIRQL OldIrql; 770 771 /* Lock the PFN database */ 772 OldIrql = MiAcquirePfnLock(); 773 774 /* Drop reference counts */ 775 ControlArea->NumberOfMappedViews--; 776 ControlArea->NumberOfUserReferences--; 777 778 /* Check if it's time to delete the CA. This releases the lock */ 779 MiCheckControlArea(ControlArea, OldIrql); 780 } 781 782 VOID 783 NTAPI 784 MiRemoveMappedView(IN PEPROCESS CurrentProcess, 785 IN PMMVAD Vad) 786 { 787 KIRQL OldIrql; 788 PCONTROL_AREA ControlArea; 789 PETHREAD CurrentThread = PsGetCurrentThread(); 790 791 /* Get the control area */ 792 ControlArea = Vad->ControlArea; 793 794 /* We only support non-extendable, non-image, pagefile-backed regular sections */ 795 ASSERT(Vad->u.VadFlags.VadType == VadNone); 796 ASSERT(Vad->u2.VadFlags2.ExtendableFile == FALSE); 797 ASSERT(ControlArea); 798 ASSERT(ControlArea->FilePointer == NULL); 799 800 /* Delete the actual virtual memory pages */ 801 MiDeleteVirtualAddresses(Vad->StartingVpn << PAGE_SHIFT, 802 (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1), 803 Vad); 804 805 /* Release the working set */ 806 MiUnlockProcessWorkingSetUnsafe(CurrentProcess, CurrentThread); 807 808 /* Lock the PFN database */ 809 OldIrql = MiAcquirePfnLock(); 810 811 /* Remove references */ 812 ControlArea->NumberOfMappedViews--; 813 ControlArea->NumberOfUserReferences--; 814 815 /* Check if it should be destroyed */ 816 MiCheckControlArea(ControlArea, OldIrql); 817 } 818 819 NTSTATUS 820 NTAPI 821 MiUnmapViewOfSection(IN PEPROCESS Process, 822 IN PVOID BaseAddress, 823 IN ULONG Flags) 824 { 825 PMEMORY_AREA MemoryArea; 826 BOOLEAN Attached = FALSE; 827 KAPC_STATE ApcState; 828 PMMVAD Vad; 829 PVOID DbgBase = NULL; 830 SIZE_T RegionSize; 831 NTSTATUS Status; 832 PETHREAD CurrentThread = PsGetCurrentThread(); 833 PEPROCESS CurrentProcess = PsGetCurrentProcess(); 834 PAGED_CODE(); 835 836 /* Check if we need to lock the address space */ 837 if (!Flags) MmLockAddressSpace(&Process->Vm); 838 839 /* Check for Mm Region */ 840 MemoryArea = MmLocateMemoryAreaByAddress(&Process->Vm, BaseAddress); 841 if ((MemoryArea) && (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3)) 842 { 843 /* Call Mm API */ 844 NTSTATUS Status = MiRosUnmapViewOfSection(Process, BaseAddress, Process->ProcessExiting); 845 if (!Flags) MmUnlockAddressSpace(&Process->Vm); 846 return Status; 847 } 848 849 /* Check if we should attach to the process */ 850 if (CurrentProcess != Process) 851 { 852 /* The process is different, do an attach */ 853 KeStackAttachProcess(&Process->Pcb, &ApcState); 854 Attached = TRUE; 855 } 856 857 /* Check if the process is already dead */ 858 if (Process->VmDeleted) 859 { 860 /* Fail the call */ 861 DPRINT1("Process died!\n"); 862 if (!Flags) MmUnlockAddressSpace(&Process->Vm); 863 Status = STATUS_PROCESS_IS_TERMINATING; 864 goto Quickie; 865 } 866 867 /* Find the VAD for the address and make sure it's a section VAD */ 868 Vad = MiLocateAddress(BaseAddress); 869 if (!(Vad) || (Vad->u.VadFlags.PrivateMemory)) 870 { 871 /* Couldn't find it, or invalid VAD, fail */ 872 DPRINT1("No VAD or invalid VAD\n"); 873 if (!Flags) MmUnlockAddressSpace(&Process->Vm); 874 Status = STATUS_NOT_MAPPED_VIEW; 875 goto Quickie; 876 } 877 878 /* We should be attached */ 879 ASSERT(Process == PsGetCurrentProcess()); 880 881 /* We need the base address for the debugger message on image-backed VADs */ 882 if (Vad->u.VadFlags.VadType == VadImageMap) 883 { 884 DbgBase = (PVOID)(Vad->StartingVpn >> PAGE_SHIFT); 885 } 886 887 /* Compute the size of the VAD region */ 888 RegionSize = PAGE_SIZE + ((Vad->EndingVpn - Vad->StartingVpn) << PAGE_SHIFT); 889 890 /* For SEC_NO_CHANGE sections, we need some extra checks */ 891 if (Vad->u.VadFlags.NoChange == 1) 892 { 893 /* Are we allowed to mess with this VAD? */ 894 Status = MiCheckSecuredVad(Vad, 895 (PVOID)(Vad->StartingVpn >> PAGE_SHIFT), 896 RegionSize, 897 MM_DELETE_CHECK); 898 if (!NT_SUCCESS(Status)) 899 { 900 /* We failed */ 901 DPRINT1("Trying to unmap protected VAD!\n"); 902 if (!Flags) MmUnlockAddressSpace(&Process->Vm); 903 goto Quickie; 904 } 905 } 906 907 /* Not currently supported */ 908 ASSERT(Vad->u.VadFlags.VadType != VadRotatePhysical); 909 910 /* FIXME: Remove VAD charges */ 911 912 /* Lock the working set */ 913 MiLockProcessWorkingSetUnsafe(Process, CurrentThread); 914 915 /* Remove the VAD */ 916 ASSERT(Process->VadRoot.NumberGenericTableElements >= 1); 917 MiRemoveNode((PMMADDRESS_NODE)Vad, &Process->VadRoot); 918 919 /* Remove the PTEs for this view, which also releases the working set lock */ 920 MiRemoveMappedView(Process, Vad); 921 922 /* FIXME: Remove commitment */ 923 924 /* Update performance counter and release the lock */ 925 Process->VirtualSize -= RegionSize; 926 if (!Flags) MmUnlockAddressSpace(&Process->Vm); 927 928 /* Destroy the VAD and return success */ 929 ExFreePool(Vad); 930 Status = STATUS_SUCCESS; 931 932 /* Failure and success case -- send debugger message, detach, and return */ 933 Quickie: 934 if (DbgBase) DbgkUnMapViewOfSection(DbgBase); 935 if (Attached) KeUnstackDetachProcess(&ApcState); 936 return Status; 937 } 938 939 NTSTATUS 940 NTAPI 941 MiSessionCommitPageTables(IN PVOID StartVa, 942 IN PVOID EndVa) 943 { 944 KIRQL OldIrql; 945 ULONG Color, Index; 946 PMMPDE StartPde, EndPde; 947 MMPDE TempPde = ValidKernelPdeLocal; 948 PMMPFN Pfn1; 949 PFN_NUMBER PageCount = 0, ActualPages = 0, PageFrameNumber; 950 951 /* Windows sanity checks */ 952 ASSERT(StartVa >= (PVOID)MmSessionBase); 953 ASSERT(EndVa < (PVOID)MiSessionSpaceEnd); 954 ASSERT(PAGE_ALIGN(EndVa) == EndVa); 955 956 /* Get the start and end PDE, then loop each one */ 957 StartPde = MiAddressToPde(StartVa); 958 EndPde = MiAddressToPde((PVOID)((ULONG_PTR)EndVa - 1)); 959 Index = ((ULONG_PTR)StartVa - (ULONG_PTR)MmSessionBase) >> 22; 960 while (StartPde <= EndPde) 961 { 962 #ifndef _M_AMD64 963 /* If we don't already have a page table for it, increment count */ 964 if (MmSessionSpace->PageTables[Index].u.Long == 0) PageCount++; 965 #endif 966 /* Move to the next one */ 967 StartPde++; 968 Index++; 969 } 970 971 /* If there's no page tables to create, bail out */ 972 if (PageCount == 0) return STATUS_SUCCESS; 973 974 /* Reset the start PDE and index */ 975 StartPde = MiAddressToPde(StartVa); 976 Index = ((ULONG_PTR)StartVa - (ULONG_PTR)MmSessionBase) >> 22; 977 978 /* Loop each PDE while holding the working set lock */ 979 // MiLockWorkingSet(PsGetCurrentThread(), 980 // &MmSessionSpace->GlobalVirtualAddress->Vm); 981 #ifdef _M_AMD64 982 _WARN("MiSessionCommitPageTables halfplemented for amd64") 983 DBG_UNREFERENCED_LOCAL_VARIABLE(OldIrql); 984 DBG_UNREFERENCED_LOCAL_VARIABLE(Color); 985 DBG_UNREFERENCED_LOCAL_VARIABLE(TempPde); 986 DBG_UNREFERENCED_LOCAL_VARIABLE(Pfn1); 987 DBG_UNREFERENCED_LOCAL_VARIABLE(PageFrameNumber); 988 ASSERT(FALSE); 989 #else 990 while (StartPde <= EndPde) 991 { 992 /* Check if we already have a page table */ 993 if (MmSessionSpace->PageTables[Index].u.Long == 0) 994 { 995 /* We don't, so the PDE shouldn't be ready yet */ 996 ASSERT(StartPde->u.Hard.Valid == 0); 997 998 /* ReactOS check to avoid MiEnsureAvailablePageOrWait */ 999 ASSERT(MmAvailablePages >= 32); 1000 1001 /* Acquire the PFN lock and grab a zero page */ 1002 OldIrql = MiAcquirePfnLock(); 1003 MI_SET_USAGE(MI_USAGE_PAGE_TABLE); 1004 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName); 1005 Color = (++MmSessionSpace->Color) & MmSecondaryColorMask; 1006 PageFrameNumber = MiRemoveZeroPage(Color); 1007 TempPde.u.Hard.PageFrameNumber = PageFrameNumber; 1008 MI_WRITE_VALID_PDE(StartPde, TempPde); 1009 1010 /* Write the page table in session space structure */ 1011 ASSERT(MmSessionSpace->PageTables[Index].u.Long == 0); 1012 MmSessionSpace->PageTables[Index] = TempPde; 1013 1014 /* Initialize the PFN */ 1015 MiInitializePfnForOtherProcess(PageFrameNumber, 1016 StartPde, 1017 MmSessionSpace->SessionPageDirectoryIndex); 1018 1019 /* And now release the lock */ 1020 MiReleasePfnLock(OldIrql); 1021 1022 /* Get the PFN entry and make sure there's no event for it */ 1023 Pfn1 = MI_PFN_ELEMENT(PageFrameNumber); 1024 ASSERT(Pfn1->u1.Event == NULL); 1025 1026 /* Increment the number of pages */ 1027 ActualPages++; 1028 } 1029 1030 /* Move to the next PDE */ 1031 StartPde++; 1032 Index++; 1033 } 1034 #endif 1035 1036 /* Make sure we didn't do more pages than expected */ 1037 ASSERT(ActualPages <= PageCount); 1038 1039 /* Release the working set lock */ 1040 // MiUnlockWorkingSet(PsGetCurrentThread(), 1041 // &MmSessionSpace->GlobalVirtualAddress->Vm); 1042 1043 1044 /* If we did at least one page... */ 1045 if (ActualPages) 1046 { 1047 /* Update the performance counters! */ 1048 InterlockedExchangeAddSizeT(&MmSessionSpace->NonPageablePages, ActualPages); 1049 InterlockedExchangeAddSizeT(&MmSessionSpace->CommittedPages, ActualPages); 1050 } 1051 1052 /* Return status */ 1053 return STATUS_SUCCESS; 1054 } 1055 1056 NTSTATUS 1057 MiMapViewInSystemSpace( 1058 _In_ PVOID Section, 1059 _In_ PMMSESSION Session, 1060 _Outptr_result_bytebuffer_ (*ViewSize) PVOID *MappedBase, 1061 _Inout_ PSIZE_T ViewSize, 1062 _Inout_ PLARGE_INTEGER SectionOffset) 1063 { 1064 PVOID Base; 1065 PCONTROL_AREA ControlArea; 1066 ULONG Buckets; 1067 LONGLONG SectionSize; 1068 NTSTATUS Status; 1069 PAGED_CODE(); 1070 1071 /* Get the control area, check for any flags ARM3 doesn't yet support */ 1072 ControlArea = ((PSECTION)Section)->Segment->ControlArea; 1073 ASSERT(ControlArea->u.Flags.Image == 0); 1074 ASSERT(ControlArea->FilePointer == NULL); 1075 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 1076 ASSERT(ControlArea->u.Flags.Rom == 0); 1077 ASSERT(ControlArea->u.Flags.WasPurged == 0); 1078 1079 /* Increase the reference and map count on the control area, no purges yet */ 1080 Status = MiCheckPurgeAndUpMapCount(ControlArea, FALSE); 1081 ASSERT(NT_SUCCESS(Status)); 1082 1083 /* Get the section size at creation time */ 1084 SectionSize = ((PSECTION)Section)->SizeOfSection.QuadPart; 1085 1086 /* If the caller didn't specify a view size, assume until the end of the section */ 1087 if (!(*ViewSize)) 1088 { 1089 /* Check for overflow first */ 1090 if ((SectionSize - SectionOffset->QuadPart) > SIZE_T_MAX) 1091 { 1092 DPRINT1("Section end is too far away from the specified offset.\n"); 1093 MiDereferenceControlArea(ControlArea); 1094 return STATUS_INVALID_VIEW_SIZE; 1095 } 1096 *ViewSize = SectionSize - SectionOffset->QuadPart; 1097 } 1098 1099 /* Check overflow */ 1100 if ((SectionOffset->QuadPart + *ViewSize) < SectionOffset->QuadPart) 1101 { 1102 DPRINT1("Integer overflow between size & offset!\n"); 1103 MiDereferenceControlArea(ControlArea); 1104 return STATUS_INVALID_VIEW_SIZE; 1105 } 1106 1107 /* Check if the caller wanted a larger section than the view */ 1108 if (SectionOffset->QuadPart + *ViewSize > SectionSize) 1109 { 1110 /* Fail */ 1111 DPRINT1("View is too large\n"); 1112 MiDereferenceControlArea(ControlArea); 1113 return STATUS_INVALID_VIEW_SIZE; 1114 } 1115 1116 /* Get the number of 64K buckets required for this mapping */ 1117 Buckets = (ULONG)(*ViewSize / MI_SYSTEM_VIEW_BUCKET_SIZE); 1118 if (*ViewSize & (MI_SYSTEM_VIEW_BUCKET_SIZE - 1)) Buckets++; 1119 1120 /* Check if the view is more than 4GB large */ 1121 if (Buckets >= MI_SYSTEM_VIEW_BUCKET_SIZE) 1122 { 1123 /* Fail */ 1124 DPRINT1("View is too large\n"); 1125 MiDereferenceControlArea(ControlArea); 1126 return STATUS_INVALID_VIEW_SIZE; 1127 } 1128 1129 /* Insert this view into system space and get a base address for it */ 1130 Base = MiInsertInSystemSpace(Session, Buckets, ControlArea); 1131 if (!Base) 1132 { 1133 /* Fail */ 1134 DPRINT1("Out of system space\n"); 1135 MiDereferenceControlArea(ControlArea); 1136 return STATUS_NO_MEMORY; 1137 } 1138 1139 /* What's the underlying session? */ 1140 if (Session == &MmSession) 1141 { 1142 /* Create the PDEs needed for this mapping, and double-map them if needed */ 1143 MiFillSystemPageDirectory(Base, Buckets * MI_SYSTEM_VIEW_BUCKET_SIZE); 1144 Status = STATUS_SUCCESS; 1145 } 1146 else 1147 { 1148 /* Create the PDEs needed for this mapping */ 1149 Status = MiSessionCommitPageTables(Base, 1150 (PVOID)((ULONG_PTR)Base + 1151 Buckets * MI_SYSTEM_VIEW_BUCKET_SIZE)); 1152 ASSERT(NT_SUCCESS(Status)); 1153 } 1154 1155 /* Create the actual prototype PTEs for this mapping */ 1156 Status = MiAddMappedPtes(MiAddressToPte(Base), 1157 BYTES_TO_PAGES(*ViewSize), 1158 ControlArea, 1159 SectionOffset->QuadPart); 1160 ASSERT(NT_SUCCESS(Status)); 1161 1162 /* Return the base adress of the mapping and success */ 1163 *MappedBase = Base; 1164 return STATUS_SUCCESS; 1165 } 1166 1167 VOID 1168 NTAPI 1169 MiSetControlAreaSymbolsLoaded(IN PCONTROL_AREA ControlArea) 1170 { 1171 KIRQL OldIrql; 1172 1173 ASSERT(KeGetCurrentIrql() <= APC_LEVEL); 1174 1175 OldIrql = MiAcquirePfnLock(); 1176 ControlArea->u.Flags.DebugSymbolsLoaded |= 1; 1177 1178 ASSERT(OldIrql <= APC_LEVEL); 1179 MiReleasePfnLock(OldIrql); 1180 ASSERT(KeGetCurrentIrql() <= APC_LEVEL); 1181 } 1182 1183 VOID 1184 NTAPI 1185 MiLoadUserSymbols(IN PCONTROL_AREA ControlArea, 1186 IN PVOID BaseAddress, 1187 IN PEPROCESS Process) 1188 { 1189 NTSTATUS Status; 1190 ANSI_STRING FileNameA; 1191 PLIST_ENTRY NextEntry; 1192 PUNICODE_STRING FileName; 1193 PIMAGE_NT_HEADERS NtHeaders; 1194 PLDR_DATA_TABLE_ENTRY LdrEntry; 1195 1196 FileName = &ControlArea->FilePointer->FileName; 1197 if (FileName->Length == 0) 1198 { 1199 return; 1200 } 1201 1202 /* Acquire module list lock */ 1203 KeEnterCriticalRegion(); 1204 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE); 1205 1206 /* Browse list to try to find current module */ 1207 for (NextEntry = MmLoadedUserImageList.Flink; 1208 NextEntry != &MmLoadedUserImageList; 1209 NextEntry = NextEntry->Flink) 1210 { 1211 /* Get the entry */ 1212 LdrEntry = CONTAINING_RECORD(NextEntry, 1213 LDR_DATA_TABLE_ENTRY, 1214 InLoadOrderLinks); 1215 1216 /* If already in the list, increase load count */ 1217 if (LdrEntry->DllBase == BaseAddress) 1218 { 1219 ++LdrEntry->LoadCount; 1220 break; 1221 } 1222 } 1223 1224 /* Not in the list, we'll add it */ 1225 if (NextEntry == &MmLoadedUserImageList) 1226 { 1227 /* Allocate our element, taking to the name string and its null char */ 1228 LdrEntry = ExAllocatePoolWithTag(NonPagedPool, FileName->Length + sizeof(UNICODE_NULL) + sizeof(*LdrEntry), 'bDmM'); 1229 if (LdrEntry) 1230 { 1231 memset(LdrEntry, 0, FileName->Length + sizeof(UNICODE_NULL) + sizeof(*LdrEntry)); 1232 1233 _SEH2_TRY 1234 { 1235 /* Get image checksum and size */ 1236 NtHeaders = RtlImageNtHeader(BaseAddress); 1237 if (NtHeaders) 1238 { 1239 LdrEntry->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage; 1240 LdrEntry->CheckSum = NtHeaders->OptionalHeader.CheckSum; 1241 } 1242 } 1243 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1244 { 1245 ExFreePoolWithTag(LdrEntry, 'bDmM'); 1246 ExReleaseResourceLite(&PsLoadedModuleResource); 1247 KeLeaveCriticalRegion(); 1248 _SEH2_YIELD(return); 1249 } 1250 _SEH2_END; 1251 1252 /* Fill all the details */ 1253 LdrEntry->DllBase = BaseAddress; 1254 LdrEntry->FullDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry + sizeof(*LdrEntry)); 1255 LdrEntry->FullDllName.Length = FileName->Length; 1256 LdrEntry->FullDllName.MaximumLength = FileName->Length + sizeof(UNICODE_NULL); 1257 memcpy(LdrEntry->FullDllName.Buffer, FileName->Buffer, FileName->Length); 1258 LdrEntry->FullDllName.Buffer[LdrEntry->FullDllName.Length / sizeof(WCHAR)] = UNICODE_NULL; 1259 LdrEntry->LoadCount = 1; 1260 1261 /* Insert! */ 1262 InsertHeadList(&MmLoadedUserImageList, &LdrEntry->InLoadOrderLinks); 1263 } 1264 } 1265 1266 /* Release locks */ 1267 ExReleaseResourceLite(&PsLoadedModuleResource); 1268 KeLeaveCriticalRegion(); 1269 1270 /* Load symbols */ 1271 Status = RtlUnicodeStringToAnsiString(&FileNameA, FileName, TRUE); 1272 if (NT_SUCCESS(Status)) 1273 { 1274 DbgLoadImageSymbols(&FileNameA, BaseAddress, (ULONG_PTR)Process->UniqueProcessId); 1275 RtlFreeAnsiString(&FileNameA); 1276 } 1277 } 1278 1279 NTSTATUS 1280 NTAPI 1281 MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea, 1282 IN PEPROCESS Process, 1283 IN PVOID *BaseAddress, 1284 IN PLARGE_INTEGER SectionOffset, 1285 IN PSIZE_T ViewSize, 1286 IN PSECTION Section, 1287 IN SECTION_INHERIT InheritDisposition, 1288 IN ULONG ProtectionMask, 1289 IN SIZE_T CommitSize, 1290 IN ULONG_PTR ZeroBits, 1291 IN ULONG AllocationType) 1292 { 1293 PMMVAD_LONG Vad; 1294 ULONG_PTR StartAddress; 1295 ULONG_PTR ViewSizeInPages; 1296 PSUBSECTION Subsection; 1297 PSEGMENT Segment; 1298 PFN_NUMBER PteOffset; 1299 NTSTATUS Status; 1300 ULONG QuotaCharge = 0, QuotaExcess = 0; 1301 PMMPTE PointerPte, LastPte; 1302 MMPTE TempPte; 1303 ULONG Granularity = MM_VIRTMEM_GRANULARITY; 1304 1305 DPRINT("Mapping ARM3 data section\n"); 1306 1307 /* Get the segment for this section */ 1308 Segment = ControlArea->Segment; 1309 1310 #ifdef _M_IX86 1311 /* ALlow being less restrictive on x86. */ 1312 if (AllocationType & MEM_DOS_LIM) 1313 Granularity = PAGE_SIZE; 1314 #endif 1315 1316 /* One can only reserve a file-based mapping, not shared memory! */ 1317 if ((AllocationType & MEM_RESERVE) && !(ControlArea->FilePointer)) 1318 { 1319 return STATUS_INVALID_PARAMETER_9; 1320 } 1321 1322 /* First, increase the map count. No purging is supported yet */ 1323 Status = MiCheckPurgeAndUpMapCount(ControlArea, FALSE); 1324 if (!NT_SUCCESS(Status)) return Status; 1325 1326 /* Check if the caller specified the view size */ 1327 if (!(*ViewSize)) 1328 { 1329 LONGLONG ViewSizeLL; 1330 1331 /* The caller did not, so pick a 64K aligned view size based on the offset */ 1332 SectionOffset->LowPart &= ~(_64K - 1); 1333 1334 /* Calculate size and make sure this fits */ 1335 if (!NT_SUCCESS(RtlLongLongSub(Section->SizeOfSection.QuadPart, SectionOffset->QuadPart, &ViewSizeLL)) 1336 || !NT_SUCCESS(RtlLongLongToSIZET(ViewSizeLL, ViewSize)) 1337 || (*ViewSize > MAXLONG_PTR)) 1338 { 1339 MiDereferenceControlArea(ControlArea); 1340 return STATUS_INVALID_VIEW_SIZE; 1341 } 1342 } 1343 else 1344 { 1345 /* A size was specified, align it to a 64K boundary 1346 * and check for overflow or huge value. */ 1347 if (!NT_SUCCESS(RtlSIZETAdd(*ViewSize, SectionOffset->LowPart & (_64K - 1), ViewSize)) 1348 || (*ViewSize > MAXLONG_PTR)) 1349 { 1350 MiDereferenceControlArea(ControlArea); 1351 return STATUS_INVALID_VIEW_SIZE; 1352 } 1353 1354 /* Align the offset as well to make this an aligned map */ 1355 SectionOffset->LowPart &= ~((ULONG)_64K - 1); 1356 } 1357 1358 /* We must be dealing with a 64KB aligned offset. This is a Windows ASSERT */ 1359 ASSERT((SectionOffset->LowPart & ((ULONG)_64K - 1)) == 0); 1360 1361 /* Windows ASSERTs for this flag */ 1362 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 1363 1364 /* Get the subsection. We don't support LARGE_CONTROL_AREA in ARM3 */ 1365 ASSERT(ControlArea->u.Flags.Rom == 0); 1366 Subsection = (PSUBSECTION)(ControlArea + 1); 1367 1368 /* Sections with extended segments are not supported in ARM3 */ 1369 ASSERT(Segment->SegmentFlags.TotalNumberOfPtes4132 == 0); 1370 1371 /* Within this section, figure out which PTEs will describe the view */ 1372 PteOffset = (PFN_NUMBER)(SectionOffset->QuadPart >> PAGE_SHIFT); 1373 1374 /* The offset must be in this segment's PTE chunk and it must be valid. Windows ASSERTs */ 1375 ASSERT(PteOffset < Segment->TotalNumberOfPtes); 1376 ASSERT(((SectionOffset->QuadPart + *ViewSize + PAGE_SIZE - 1) >> PAGE_SHIFT) >= PteOffset); 1377 1378 /* In ARM3, only one subsection is used for now. It must contain these PTEs */ 1379 ASSERT(PteOffset < Subsection->PtesInSubsection); 1380 1381 /* In ARM3, only page-file backed sections (shared memory) are supported now */ 1382 ASSERT(ControlArea->FilePointer == NULL); 1383 1384 /* Windows ASSERTs for this too -- there must be a subsection base address */ 1385 ASSERT(Subsection->SubsectionBase != NULL); 1386 1387 /* Compute how much commit space the segment will take */ 1388 if ((CommitSize) && (Segment->NumberOfCommittedPages < Segment->TotalNumberOfPtes)) 1389 { 1390 /* Charge for the maximum pages */ 1391 QuotaCharge = BYTES_TO_PAGES(CommitSize); 1392 } 1393 1394 /* ARM3 does not currently support large pages */ 1395 ASSERT(Segment->SegmentFlags.LargePages == 0); 1396 1397 /* Calculate how many pages the region spans */ 1398 ViewSizeInPages = BYTES_TO_PAGES(*ViewSize); 1399 1400 /* A VAD can now be allocated. Do so and zero it out */ 1401 /* FIXME: we are allocating a LONG VAD for ReactOS compatibility only */ 1402 ASSERT((AllocationType & MEM_RESERVE) == 0); /* ARM3 does not support this */ 1403 Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV'); 1404 if (!Vad) 1405 { 1406 MiDereferenceControlArea(ControlArea); 1407 return STATUS_INSUFFICIENT_RESOURCES; 1408 } 1409 1410 RtlZeroMemory(Vad, sizeof(MMVAD_LONG)); 1411 Vad->u4.Banked = (PVOID)(ULONG_PTR)0xDEADBABEDEADBABEULL; 1412 1413 /* Write all the data required in the VAD for handling a fault */ 1414 Vad->ControlArea = ControlArea; 1415 Vad->u.VadFlags.CommitCharge = 0; 1416 Vad->u.VadFlags.Protection = ProtectionMask; 1417 Vad->u2.VadFlags2.FileOffset = (ULONG)(SectionOffset->QuadPart >> 16); 1418 Vad->u2.VadFlags2.Inherit = (InheritDisposition == ViewShare); 1419 if ((AllocationType & SEC_NO_CHANGE) || (Section->u.Flags.NoChange)) 1420 { 1421 /* This isn't really implemented yet, but handle setting the flag */ 1422 Vad->u.VadFlags.NoChange = 1; 1423 Vad->u2.VadFlags2.SecNoChange = 1; 1424 } 1425 1426 /* Finally, write down the first and last prototype PTE */ 1427 Vad->FirstPrototypePte = &Subsection->SubsectionBase[PteOffset]; 1428 PteOffset += ViewSizeInPages - 1; 1429 ASSERT(PteOffset < Subsection->PtesInSubsection); 1430 Vad->LastContiguousPte = &Subsection->SubsectionBase[PteOffset]; 1431 1432 /* Make sure the prototype PTE ranges make sense, this is a Windows ASSERT */ 1433 ASSERT(Vad->FirstPrototypePte <= Vad->LastContiguousPte); 1434 1435 /* FIXME: Should setup VAD bitmap */ 1436 Status = STATUS_SUCCESS; 1437 1438 /* Check if anything was committed */ 1439 if (QuotaCharge) 1440 { 1441 /* Set the start and end PTE addresses, and pick the template PTE */ 1442 PointerPte = Vad->FirstPrototypePte; 1443 LastPte = PointerPte + BYTES_TO_PAGES(CommitSize); 1444 TempPte = Segment->SegmentPteTemplate; 1445 1446 /* Acquire the commit lock and loop all prototype PTEs to be committed */ 1447 KeAcquireGuardedMutex(&MmSectionCommitMutex); 1448 while (PointerPte < LastPte) 1449 { 1450 /* Make sure the PTE is already invalid */ 1451 if (PointerPte->u.Long == 0) 1452 { 1453 /* And write the invalid PTE */ 1454 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 1455 } 1456 else 1457 { 1458 /* The PTE is valid, so skip it */ 1459 QuotaExcess++; 1460 } 1461 1462 /* Move to the next PTE */ 1463 PointerPte++; 1464 } 1465 1466 /* Now check how many pages exactly we committed, and update accounting */ 1467 ASSERT(QuotaCharge >= QuotaExcess); 1468 QuotaCharge -= QuotaExcess; 1469 Segment->NumberOfCommittedPages += QuotaCharge; 1470 ASSERT(Segment->NumberOfCommittedPages <= Segment->TotalNumberOfPtes); 1471 1472 /* Now that we're done, release the lock */ 1473 KeReleaseGuardedMutex(&MmSectionCommitMutex); 1474 } 1475 1476 /* Is it SEC_BASED, or did the caller manually specify an address? */ 1477 if (*BaseAddress != NULL) 1478 { 1479 /* Just align what the caller gave us */ 1480 StartAddress = ALIGN_DOWN_BY((ULONG_PTR)*BaseAddress, Granularity); 1481 } 1482 else if (Section->Address.StartingVpn != 0) 1483 { 1484 /* It is a SEC_BASED mapping, use the address that was generated */ 1485 StartAddress = Section->Address.StartingVpn + SectionOffset->LowPart; 1486 } 1487 else 1488 { 1489 StartAddress = 0; 1490 } 1491 1492 /* Insert the VAD */ 1493 Status = MiInsertVadEx((PMMVAD)Vad, 1494 &StartAddress, 1495 ViewSizeInPages * PAGE_SIZE, 1496 MAXULONG_PTR >> ZeroBits, 1497 Granularity, 1498 AllocationType); 1499 if (!NT_SUCCESS(Status)) 1500 { 1501 return Status; 1502 } 1503 1504 /* Windows stores this for accounting purposes, do so as well */ 1505 if (!Segment->u2.FirstMappedVa) Segment->u2.FirstMappedVa = (PVOID)StartAddress; 1506 1507 /* Finally, let the caller know where, and for what size, the view was mapped */ 1508 *ViewSize = ViewSizeInPages * PAGE_SIZE; 1509 *BaseAddress = (PVOID)StartAddress; 1510 DPRINT("Start and region: 0x%p, 0x%p\n", *BaseAddress, *ViewSize); 1511 return STATUS_SUCCESS; 1512 } 1513 1514 VOID 1515 NTAPI 1516 MiSubsectionConsistent(IN PSUBSECTION Subsection) 1517 { 1518 /* ReactOS only supports systems with 4K pages and 4K sectors */ 1519 ASSERT(Subsection->u.SubsectionFlags.SectorEndOffset == 0); 1520 1521 /* Therefore, then number of PTEs should be equal to the number of sectors */ 1522 if (Subsection->NumberOfFullSectors != Subsection->PtesInSubsection) 1523 { 1524 /* Break and warn if this is inconsistent */ 1525 DPRINT1("Mm: Subsection inconsistent (%x vs %x)\n", 1526 Subsection->NumberOfFullSectors, Subsection->PtesInSubsection); 1527 DbgBreakPoint(); 1528 } 1529 } 1530 1531 NTSTATUS 1532 NTAPI 1533 MiCreateDataFileMap(IN PFILE_OBJECT File, 1534 OUT PSEGMENT *Segment, 1535 IN PSIZE_T MaximumSize, 1536 IN ULONG SectionPageProtection, 1537 IN ULONG AllocationAttributes, 1538 IN ULONG IgnoreFileSizing) 1539 { 1540 /* Not yet implemented */ 1541 ASSERT(FALSE); 1542 *Segment = NULL; 1543 return STATUS_NOT_IMPLEMENTED; 1544 } 1545 1546 static 1547 NTSTATUS 1548 NTAPI 1549 MiCreatePagingFileMap(OUT PSEGMENT *Segment, 1550 IN PLARGE_INTEGER MaximumSize, 1551 IN ULONG ProtectionMask, 1552 IN ULONG AllocationAttributes) 1553 { 1554 ULONGLONG SizeLimit; 1555 PFN_COUNT PteCount; 1556 PMMPTE PointerPte; 1557 MMPTE TempPte; 1558 PCONTROL_AREA ControlArea; 1559 PSEGMENT NewSegment; 1560 PSUBSECTION Subsection; 1561 PAGED_CODE(); 1562 1563 /* No large pages in ARM3 yet */ 1564 ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0); 1565 1566 /* Pagefile-backed sections need a known size */ 1567 if (!MaximumSize || !MaximumSize->QuadPart || MaximumSize->QuadPart < 0) 1568 return STATUS_INVALID_PARAMETER_4; 1569 1570 /* Calculate the maximum size possible, given the Prototype PTEs we'll need */ 1571 SizeLimit = MmSizeOfPagedPoolInBytes - sizeof(SEGMENT); 1572 SizeLimit /= sizeof(MMPTE); 1573 SizeLimit <<= PAGE_SHIFT; 1574 1575 /* Fail if this size is too big */ 1576 if (MaximumSize->QuadPart > SizeLimit) 1577 { 1578 return STATUS_SECTION_TOO_BIG; 1579 } 1580 1581 /* Calculate how many Prototype PTEs will be needed */ 1582 PteCount = (PFN_COUNT)((MaximumSize->QuadPart + PAGE_SIZE - 1) >> PAGE_SHIFT); 1583 1584 /* For commited memory, we must have a valid protection mask */ 1585 if (AllocationAttributes & SEC_COMMIT) ASSERT(ProtectionMask != 0); 1586 1587 /* The segment contains all the Prototype PTEs, allocate it in paged pool */ 1588 NewSegment = ExAllocatePoolWithTag(PagedPool, 1589 sizeof(SEGMENT) + 1590 sizeof(MMPTE) * (PteCount - 1), 1591 'tSmM'); 1592 if (!NewSegment) 1593 { 1594 return STATUS_INSUFFICIENT_RESOURCES; 1595 } 1596 *Segment = NewSegment; 1597 1598 /* Now allocate the control area, which has the subsection structure */ 1599 ControlArea = ExAllocatePoolWithTag(NonPagedPool, 1600 sizeof(CONTROL_AREA) + sizeof(SUBSECTION), 1601 'tCmM'); 1602 if (!ControlArea) 1603 { 1604 ExFreePoolWithTag(Segment, 'tSmM'); 1605 return STATUS_INSUFFICIENT_RESOURCES; 1606 } 1607 1608 /* And zero it out, filling the basic segmnet pointer and reference fields */ 1609 RtlZeroMemory(ControlArea, sizeof(CONTROL_AREA) + sizeof(SUBSECTION)); 1610 ControlArea->Segment = NewSegment; 1611 ControlArea->NumberOfSectionReferences = 1; 1612 ControlArea->NumberOfUserReferences = 1; 1613 1614 /* Convert allocation attributes to control area flags */ 1615 if (AllocationAttributes & SEC_BASED) ControlArea->u.Flags.Based = 1; 1616 if (AllocationAttributes & SEC_RESERVE) ControlArea->u.Flags.Reserve = 1; 1617 if (AllocationAttributes & SEC_COMMIT) ControlArea->u.Flags.Commit = 1; 1618 1619 /* We just allocated it */ 1620 ControlArea->u.Flags.BeingCreated = 1; 1621 1622 /* The subsection follows, write the mask, PTE count and point back to the CA */ 1623 Subsection = (PSUBSECTION)(ControlArea + 1); 1624 Subsection->ControlArea = ControlArea; 1625 Subsection->PtesInSubsection = PteCount; 1626 Subsection->u.SubsectionFlags.Protection = ProtectionMask; 1627 1628 /* Zero out the segment's prototype PTEs, and link it with the control area */ 1629 PointerPte = &NewSegment->ThePtes[0]; 1630 RtlZeroMemory(NewSegment, sizeof(SEGMENT)); 1631 NewSegment->PrototypePte = PointerPte; 1632 NewSegment->ControlArea = ControlArea; 1633 1634 /* Save some extra accounting data for the segment as well */ 1635 NewSegment->u1.CreatingProcess = PsGetCurrentProcess(); 1636 NewSegment->SizeOfSegment = ((ULONGLONG)PteCount) * PAGE_SIZE; 1637 NewSegment->TotalNumberOfPtes = PteCount; 1638 NewSegment->NonExtendedPtes = PteCount; 1639 1640 /* The subsection's base address is the first Prototype PTE in the segment */ 1641 Subsection->SubsectionBase = PointerPte; 1642 1643 /* Start with an empty PTE, unless this is a commit operation */ 1644 TempPte.u.Long = 0; 1645 if (AllocationAttributes & SEC_COMMIT) 1646 { 1647 /* In which case, write down the protection mask in the Prototype PTEs */ 1648 TempPte.u.Soft.Protection = ProtectionMask; 1649 1650 /* For accounting, also mark these pages as being committed */ 1651 NewSegment->NumberOfCommittedPages = PteCount; 1652 } 1653 1654 /* The template PTE itself for the segment should also have the mask set */ 1655 NewSegment->SegmentPteTemplate.u.Soft.Protection = ProtectionMask; 1656 1657 /* Write out the prototype PTEs, for now they're simply demand zero */ 1658 #ifdef _WIN64 1659 RtlFillMemoryUlonglong(PointerPte, PteCount * sizeof(MMPTE), TempPte.u.Long); 1660 #else 1661 RtlFillMemoryUlong(PointerPte, PteCount * sizeof(MMPTE), TempPte.u.Long); 1662 #endif 1663 return STATUS_SUCCESS; 1664 } 1665 1666 NTSTATUS 1667 NTAPI 1668 MiGetFileObjectForSectionAddress( 1669 IN PVOID Address, 1670 OUT PFILE_OBJECT *FileObject) 1671 { 1672 PMMVAD Vad; 1673 PCONTROL_AREA ControlArea; 1674 1675 /* Get the VAD */ 1676 Vad = MiLocateAddress(Address); 1677 if (Vad == NULL) 1678 { 1679 /* Fail, the address does not exist */ 1680 DPRINT1("Invalid address\n"); 1681 return STATUS_INVALID_ADDRESS; 1682 } 1683 1684 /* Check if this is a RosMm memory area */ 1685 if (Vad->u.VadFlags.Spare != 0) 1686 { 1687 PMEMORY_AREA MemoryArea = (PMEMORY_AREA)Vad; 1688 1689 /* Check if it's a section view (RosMm section) */ 1690 if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) 1691 { 1692 /* Get the section pointer to the SECTION_OBJECT */ 1693 *FileObject = MemoryArea->SectionData.Segment->FileObject; 1694 } 1695 else 1696 { 1697 #ifdef NEWCC 1698 ASSERT(MemoryArea->Type == MEMORY_AREA_CACHE); 1699 DPRINT1("Address is a cache section!\n"); 1700 return STATUS_SECTION_NOT_IMAGE; 1701 #else 1702 ASSERT(FALSE); 1703 return STATUS_SECTION_NOT_IMAGE; 1704 #endif 1705 } 1706 } 1707 else 1708 { 1709 /* Make sure it's not a VM VAD */ 1710 if (Vad->u.VadFlags.PrivateMemory == 1) 1711 { 1712 DPRINT1("Address is not a section\n"); 1713 return STATUS_SECTION_NOT_IMAGE; 1714 } 1715 1716 /* Get the control area */ 1717 ControlArea = Vad->ControlArea; 1718 if (!(ControlArea) || !(ControlArea->u.Flags.Image)) 1719 { 1720 DPRINT1("Address is not a section\n"); 1721 return STATUS_SECTION_NOT_IMAGE; 1722 } 1723 1724 /* Get the file object */ 1725 *FileObject = ControlArea->FilePointer; 1726 } 1727 1728 /* Return success */ 1729 return STATUS_SUCCESS; 1730 } 1731 1732 PFILE_OBJECT 1733 NTAPI 1734 MmGetFileObjectForSection(IN PVOID SectionObject) 1735 { 1736 PSECTION Section = SectionObject; 1737 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); 1738 ASSERT(SectionObject != NULL); 1739 1740 /* Check if it's an ARM3, or ReactOS section */ 1741 if (MiIsRosSectionObject(SectionObject) == FALSE) 1742 { 1743 /* Return the file pointer stored in the control area */ 1744 return Section->Segment->ControlArea->FilePointer; 1745 } 1746 1747 /* Return the file object */ 1748 return ((PMM_SECTION_SEGMENT)Section->Segment)->FileObject; 1749 } 1750 1751 static 1752 PFILE_OBJECT 1753 MiGetFileObjectForVad( 1754 _In_ PMMVAD Vad) 1755 { 1756 PCONTROL_AREA ControlArea; 1757 PFILE_OBJECT FileObject; 1758 1759 /* Check if this is a RosMm memory area */ 1760 if (Vad->u.VadFlags.Spare != 0) 1761 { 1762 PMEMORY_AREA MemoryArea = (PMEMORY_AREA)Vad; 1763 1764 /* Check if it's a section view (RosMm section) */ 1765 if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) 1766 { 1767 /* Get the section pointer to the SECTION_OBJECT */ 1768 FileObject = MemoryArea->SectionData.Segment->FileObject; 1769 } 1770 else 1771 { 1772 #ifdef NEWCC 1773 ASSERT(MemoryArea->Type == MEMORY_AREA_CACHE); 1774 DPRINT1("VAD is a cache section!\n"); 1775 #else 1776 ASSERT(FALSE); 1777 #endif 1778 return NULL; 1779 } 1780 } 1781 else 1782 { 1783 /* Make sure it's not a VM VAD */ 1784 if (Vad->u.VadFlags.PrivateMemory == 1) 1785 { 1786 DPRINT1("VAD is not a section\n"); 1787 return NULL; 1788 } 1789 1790 /* Get the control area */ 1791 ControlArea = Vad->ControlArea; 1792 if ((ControlArea == NULL) || !ControlArea->u.Flags.Image) 1793 { 1794 DPRINT1("Address is not a section\n"); 1795 return NULL; 1796 } 1797 1798 /* Get the file object */ 1799 FileObject = ControlArea->FilePointer; 1800 } 1801 1802 /* Return the file object */ 1803 return FileObject; 1804 } 1805 1806 VOID 1807 NTAPI 1808 MmGetImageInformation (OUT PSECTION_IMAGE_INFORMATION ImageInformation) 1809 { 1810 PSECTION SectionObject; 1811 1812 /* Get the section object of this process*/ 1813 SectionObject = PsGetCurrentProcess()->SectionObject; 1814 ASSERT(SectionObject != NULL); 1815 ASSERT(MiIsRosSectionObject(SectionObject) == TRUE); 1816 1817 if (SectionObject->u.Flags.Image == 0) 1818 { 1819 RtlZeroMemory(ImageInformation, sizeof(*ImageInformation)); 1820 return; 1821 } 1822 1823 /* Return the image information */ 1824 *ImageInformation = ((PMM_IMAGE_SECTION_OBJECT)SectionObject->Segment)->ImageInformation; 1825 } 1826 1827 NTSTATUS 1828 NTAPI 1829 MmGetFileNameForFileObject(IN PFILE_OBJECT FileObject, 1830 OUT POBJECT_NAME_INFORMATION *ModuleName) 1831 { 1832 POBJECT_NAME_INFORMATION ObjectNameInfo; 1833 NTSTATUS Status; 1834 ULONG ReturnLength; 1835 1836 /* Allocate memory for our structure */ 1837 ObjectNameInfo = ExAllocatePoolWithTag(PagedPool, 1024, TAG_MM); 1838 if (!ObjectNameInfo) return STATUS_NO_MEMORY; 1839 1840 /* Query the name */ 1841 Status = ObQueryNameString(FileObject, 1842 ObjectNameInfo, 1843 1024, 1844 &ReturnLength); 1845 if (!NT_SUCCESS(Status)) 1846 { 1847 /* Failed, free memory */ 1848 DPRINT1("Name query failed\n"); 1849 ExFreePoolWithTag(ObjectNameInfo, TAG_MM); 1850 *ModuleName = NULL; 1851 return Status; 1852 } 1853 1854 /* Success */ 1855 *ModuleName = ObjectNameInfo; 1856 return STATUS_SUCCESS; 1857 } 1858 1859 NTSTATUS 1860 NTAPI 1861 MmGetFileNameForSection(IN PVOID Section, 1862 OUT POBJECT_NAME_INFORMATION *ModuleName) 1863 { 1864 PFILE_OBJECT FileObject; 1865 PSECTION SectionObject = Section; 1866 1867 /* Make sure it's an image section */ 1868 if (SectionObject->u.Flags.Image == 0) 1869 { 1870 /* It's not, fail */ 1871 DPRINT1("Not an image section\n"); 1872 return STATUS_SECTION_NOT_IMAGE; 1873 } 1874 1875 /* Get the file object */ 1876 FileObject = MmGetFileObjectForSection(Section); 1877 return MmGetFileNameForFileObject(FileObject, ModuleName); 1878 } 1879 1880 NTSTATUS 1881 NTAPI 1882 MmGetFileNameForAddress(IN PVOID Address, 1883 OUT PUNICODE_STRING ModuleName) 1884 { 1885 POBJECT_NAME_INFORMATION ModuleNameInformation; 1886 PVOID AddressSpace; 1887 NTSTATUS Status; 1888 PMMVAD Vad; 1889 PFILE_OBJECT FileObject = NULL; 1890 1891 /* Lock address space */ 1892 AddressSpace = MmGetCurrentAddressSpace(); 1893 MmLockAddressSpace(AddressSpace); 1894 1895 /* Get the VAD */ 1896 Vad = MiLocateAddress(Address); 1897 if (Vad == NULL) 1898 { 1899 /* Fail, the address does not exist */ 1900 DPRINT1("No VAD at address %p\n", Address); 1901 MmUnlockAddressSpace(AddressSpace); 1902 return STATUS_INVALID_ADDRESS; 1903 } 1904 1905 /* Get the file object pointer for the VAD */ 1906 FileObject = MiGetFileObjectForVad(Vad); 1907 if (FileObject == NULL) 1908 { 1909 DPRINT1("Failed to get file object for Address %p\n", Address); 1910 MmUnlockAddressSpace(AddressSpace); 1911 return STATUS_SECTION_NOT_IMAGE; 1912 } 1913 1914 /* Reference the file object */ 1915 ObReferenceObject(FileObject); 1916 1917 /* Unlock address space */ 1918 MmUnlockAddressSpace(AddressSpace); 1919 1920 /* Get the filename of the file object */ 1921 Status = MmGetFileNameForFileObject(FileObject, &ModuleNameInformation); 1922 1923 /* Dereference the file object */ 1924 ObDereferenceObject(FileObject); 1925 1926 /* Check if we were able to get the file object name */ 1927 if (NT_SUCCESS(Status)) 1928 { 1929 /* Init modulename */ 1930 RtlCreateUnicodeString(ModuleName, ModuleNameInformation->Name.Buffer); 1931 1932 /* Free temp taged buffer from MmGetFileNameForFileObject() */ 1933 ExFreePoolWithTag(ModuleNameInformation, TAG_MM); 1934 DPRINT("Found ModuleName %S by address %p\n", ModuleName->Buffer, Address); 1935 } 1936 1937 /* Return status */ 1938 return Status; 1939 } 1940 1941 NTSTATUS 1942 NTAPI 1943 MiQueryMemorySectionName(IN HANDLE ProcessHandle, 1944 IN PVOID BaseAddress, 1945 OUT PVOID MemoryInformation, 1946 IN SIZE_T MemoryInformationLength, 1947 OUT PSIZE_T ReturnLength) 1948 { 1949 PEPROCESS Process; 1950 NTSTATUS Status; 1951 UNICODE_STRING ModuleFileName; 1952 PMEMORY_SECTION_NAME SectionName = NULL; 1953 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1954 1955 Status = ObReferenceObjectByHandle(ProcessHandle, 1956 PROCESS_QUERY_INFORMATION, 1957 NULL, 1958 PreviousMode, 1959 (PVOID*)(&Process), 1960 NULL); 1961 1962 if (!NT_SUCCESS(Status)) 1963 { 1964 DPRINT("MiQueryMemorySectionName: ObReferenceObjectByHandle returned %x\n",Status); 1965 return Status; 1966 } 1967 1968 Status = MmGetFileNameForAddress(BaseAddress, &ModuleFileName); 1969 1970 if (NT_SUCCESS(Status)) 1971 { 1972 SectionName = MemoryInformation; 1973 if (PreviousMode != KernelMode) 1974 { 1975 _SEH2_TRY 1976 { 1977 RtlInitEmptyUnicodeString(&SectionName->SectionFileName, 1978 (PWSTR)(SectionName + 1), 1979 MemoryInformationLength - sizeof(MEMORY_SECTION_NAME)); 1980 RtlCopyUnicodeString(&SectionName->SectionFileName, &ModuleFileName); 1981 1982 if (ReturnLength) *ReturnLength = ModuleFileName.Length + sizeof(MEMORY_SECTION_NAME); 1983 1984 } 1985 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1986 { 1987 Status = _SEH2_GetExceptionCode(); 1988 } 1989 _SEH2_END; 1990 } 1991 else 1992 { 1993 RtlInitEmptyUnicodeString(&SectionName->SectionFileName, 1994 (PWSTR)(SectionName + 1), 1995 MemoryInformationLength - sizeof(MEMORY_SECTION_NAME)); 1996 RtlCopyUnicodeString(&SectionName->SectionFileName, &ModuleFileName); 1997 1998 if (ReturnLength) *ReturnLength = ModuleFileName.Length + sizeof(MEMORY_SECTION_NAME); 1999 2000 } 2001 2002 RtlFreeUnicodeString(&ModuleFileName); 2003 } 2004 ObDereferenceObject(Process); 2005 return Status; 2006 } 2007 2008 VOID 2009 NTAPI 2010 MiFlushTbAndCapture(IN PMMVAD FoundVad, 2011 IN PMMPTE PointerPte, 2012 IN ULONG ProtectionMask, 2013 IN PMMPFN Pfn1, 2014 IN BOOLEAN UpdateDirty) 2015 { 2016 MMPTE TempPte, PreviousPte; 2017 KIRQL OldIrql; 2018 BOOLEAN RebuildPte = FALSE; 2019 2020 // 2021 // User for sanity checking later on 2022 // 2023 PreviousPte = *PointerPte; 2024 2025 // 2026 // Build the PTE and acquire the PFN lock 2027 // 2028 MI_MAKE_HARDWARE_PTE_USER(&TempPte, 2029 PointerPte, 2030 ProtectionMask, 2031 PreviousPte.u.Hard.PageFrameNumber); 2032 OldIrql = MiAcquirePfnLock(); 2033 2034 // 2035 // We don't support I/O mappings in this path yet 2036 // 2037 ASSERT(Pfn1 != NULL); 2038 ASSERT(Pfn1->u3.e1.CacheAttribute != MiWriteCombined); 2039 2040 // 2041 // Make sure new protection mask doesn't get in conflict and fix it if it does 2042 // 2043 if (Pfn1->u3.e1.CacheAttribute == MiCached) 2044 { 2045 // 2046 // This is a cached PFN 2047 // 2048 if (ProtectionMask & (MM_NOCACHE | MM_NOACCESS)) 2049 { 2050 RebuildPte = TRUE; 2051 ProtectionMask &= ~(MM_NOCACHE | MM_NOACCESS); 2052 } 2053 } 2054 else if (Pfn1->u3.e1.CacheAttribute == MiNonCached) 2055 { 2056 // 2057 // This is a non-cached PFN 2058 // 2059 if ((ProtectionMask & (MM_NOCACHE | MM_NOACCESS)) != MM_NOCACHE) 2060 { 2061 RebuildPte = TRUE; 2062 ProtectionMask &= ~MM_NOACCESS; 2063 ProtectionMask |= MM_NOCACHE; 2064 } 2065 } 2066 2067 if (RebuildPte) 2068 { 2069 MI_MAKE_HARDWARE_PTE_USER(&TempPte, 2070 PointerPte, 2071 ProtectionMask, 2072 PreviousPte.u.Hard.PageFrameNumber); 2073 } 2074 2075 // 2076 // Write the new PTE, making sure we are only changing the bits 2077 // 2078 MI_UPDATE_VALID_PTE(PointerPte, TempPte); 2079 2080 // 2081 // Flush the TLB 2082 // 2083 ASSERT(PreviousPte.u.Hard.Valid == 1); 2084 KeFlushCurrentTb(); 2085 ASSERT(PreviousPte.u.Hard.Valid == 1); 2086 2087 // 2088 // Windows updates the relevant PFN1 information, we currently don't. 2089 // 2090 if (UpdateDirty && PreviousPte.u.Hard.Dirty) 2091 { 2092 if (!Pfn1->u3.e1.Modified) 2093 { 2094 DPRINT1("FIXME: Mark PFN as dirty\n"); 2095 } 2096 } 2097 2098 // 2099 // Not supported in ARM3 2100 // 2101 ASSERT(FoundVad->u.VadFlags.VadType != VadWriteWatch); 2102 2103 // 2104 // Release the PFN lock, we are done 2105 // 2106 MiReleasePfnLock(OldIrql); 2107 } 2108 2109 // 2110 // NOTE: This function gets a lot more complicated if we want Copy-on-Write support 2111 // 2112 NTSTATUS 2113 NTAPI 2114 MiSetProtectionOnSection(IN PEPROCESS Process, 2115 IN PMMVAD FoundVad, 2116 IN PVOID StartingAddress, 2117 IN PVOID EndingAddress, 2118 IN ULONG NewProtect, 2119 OUT PULONG CapturedOldProtect, 2120 IN ULONG DontCharge, 2121 OUT PULONG Locked) 2122 { 2123 PMMPTE PointerPte, LastPte; 2124 MMPTE TempPte, PteContents; 2125 PMMPDE PointerPde; 2126 PMMPFN Pfn1; 2127 ULONG ProtectionMask, QuotaCharge = 0; 2128 PETHREAD Thread = PsGetCurrentThread(); 2129 PAGED_CODE(); 2130 2131 // 2132 // Tell caller nothing is being locked 2133 // 2134 *Locked = FALSE; 2135 2136 // 2137 // This function should only be used for section VADs. Windows ASSERT */ 2138 // 2139 ASSERT(FoundVad->u.VadFlags.PrivateMemory == 0); 2140 2141 // 2142 // We don't support these features in ARM3 2143 // 2144 ASSERT(FoundVad->u.VadFlags.VadType != VadImageMap); 2145 ASSERT(FoundVad->u2.VadFlags2.CopyOnWrite == 0); 2146 2147 // 2148 // Convert and validate the protection mask 2149 // 2150 ProtectionMask = MiMakeProtectionMask(NewProtect); 2151 if (ProtectionMask == MM_INVALID_PROTECTION) 2152 { 2153 DPRINT1("Invalid section protect\n"); 2154 return STATUS_INVALID_PAGE_PROTECTION; 2155 } 2156 2157 // 2158 // Get the PTE and PDE for the address, as well as the final PTE 2159 // 2160 MiLockProcessWorkingSetUnsafe(Process, Thread); 2161 PointerPde = MiAddressToPde(StartingAddress); 2162 PointerPte = MiAddressToPte(StartingAddress); 2163 LastPte = MiAddressToPte(EndingAddress); 2164 2165 // 2166 // Make the PDE valid, and check the status of the first PTE 2167 // 2168 MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL); 2169 if (PointerPte->u.Long) 2170 { 2171 // 2172 // Not supported in ARM3 2173 // 2174 ASSERT(FoundVad->u.VadFlags.VadType != VadRotatePhysical); 2175 2176 // 2177 // Capture the page protection and make the PDE valid 2178 // 2179 *CapturedOldProtect = MiGetPageProtection(PointerPte); 2180 MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL); 2181 } 2182 else 2183 { 2184 // 2185 // Only pagefile-backed section VADs are supported for now 2186 // 2187 ASSERT(FoundVad->u.VadFlags.VadType != VadImageMap); 2188 2189 // 2190 // Grab the old protection from the VAD itself 2191 // 2192 *CapturedOldProtect = MmProtectToValue[FoundVad->u.VadFlags.Protection]; 2193 } 2194 2195 // 2196 // Loop all the PTEs now 2197 // 2198 MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL); 2199 while (PointerPte <= LastPte) 2200 { 2201 // 2202 // Check if we've crossed a PDE boundary and make the new PDE valid too 2203 // 2204 if (MiIsPteOnPdeBoundary(PointerPte)) 2205 { 2206 PointerPde = MiPteToPde(PointerPte); 2207 MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL); 2208 } 2209 2210 // 2211 // Capture the PTE and see what we're dealing with 2212 // 2213 PteContents = *PointerPte; 2214 if (PteContents.u.Long == 0) 2215 { 2216 // 2217 // This used to be a zero PTE and it no longer is, so we must add a 2218 // reference to the pagetable. 2219 // 2220 MiIncrementPageTableReferences(MiPteToAddress(PointerPte)); 2221 2222 // 2223 // Create the demand-zero prototype PTE 2224 // 2225 TempPte = PrototypePte; 2226 TempPte.u.Soft.Protection = ProtectionMask; 2227 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 2228 } 2229 else if (PteContents.u.Hard.Valid == 1) 2230 { 2231 // 2232 // Get the PFN entry 2233 // 2234 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents)); 2235 2236 // 2237 // We don't support these yet 2238 // 2239 ASSERT((NewProtect & (PAGE_NOACCESS | PAGE_GUARD)) == 0); 2240 ASSERT(Pfn1->u3.e1.PrototypePte == 0); 2241 2242 // 2243 // Write the protection mask and write it with a TLB flush 2244 // 2245 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask; 2246 MiFlushTbAndCapture(FoundVad, 2247 PointerPte, 2248 ProtectionMask, 2249 Pfn1, 2250 TRUE); 2251 } 2252 else 2253 { 2254 // 2255 // We don't support these cases yet 2256 // 2257 ASSERT(PteContents.u.Soft.Prototype == 0); 2258 ASSERT(PteContents.u.Soft.Transition == 0); 2259 2260 // 2261 // The PTE is already demand-zero, just update the protection mask 2262 // 2263 PointerPte->u.Soft.Protection = ProtectionMask; 2264 } 2265 2266 PointerPte++; 2267 } 2268 2269 // 2270 // Unlock the working set and update quota charges if needed, then return 2271 // 2272 MiUnlockProcessWorkingSetUnsafe(Process, Thread); 2273 if ((QuotaCharge > 0) && (!DontCharge)) 2274 { 2275 FoundVad->u.VadFlags.CommitCharge -= QuotaCharge; 2276 Process->CommitCharge -= QuotaCharge; 2277 } 2278 return STATUS_SUCCESS; 2279 } 2280 2281 VOID 2282 NTAPI 2283 MiRemoveMappedPtes(IN PVOID BaseAddress, 2284 IN ULONG NumberOfPtes, 2285 IN PCONTROL_AREA ControlArea, 2286 IN PMMSUPPORT Ws) 2287 { 2288 PMMPTE PointerPte, ProtoPte;//, FirstPte; 2289 PMMPDE PointerPde, SystemMapPde; 2290 PMMPFN Pfn1, Pfn2; 2291 MMPTE PteContents; 2292 KIRQL OldIrql; 2293 DPRINT("Removing mapped view at: 0x%p\n", BaseAddress); 2294 2295 ASSERT(Ws == NULL); 2296 2297 /* Get the PTE and loop each one */ 2298 PointerPte = MiAddressToPte(BaseAddress); 2299 //FirstPte = PointerPte; 2300 while (NumberOfPtes) 2301 { 2302 /* Check if the PTE is already valid */ 2303 PteContents = *PointerPte; 2304 if (PteContents.u.Hard.Valid == 1) 2305 { 2306 /* Get the PFN entry */ 2307 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents)); 2308 2309 /* Get the PTE */ 2310 PointerPde = MiPteToPde(PointerPte); 2311 2312 /* Lock the PFN database and make sure this isn't a mapped file */ 2313 OldIrql = MiAcquirePfnLock(); 2314 ASSERT(((Pfn1->u3.e1.PrototypePte) && (Pfn1->OriginalPte.u.Soft.Prototype)) == 0); 2315 2316 /* Mark the page as modified accordingly */ 2317 if (MI_IS_PAGE_DIRTY(&PteContents)) 2318 Pfn1->u3.e1.Modified = 1; 2319 2320 /* Was the PDE invalid */ 2321 if (PointerPde->u.Long == 0) 2322 { 2323 #if (_MI_PAGING_LEVELS == 2) 2324 /* Find the system double-mapped PDE that describes this mapping */ 2325 SystemMapPde = &MmSystemPagePtes[((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE)]; 2326 2327 /* Make it valid */ 2328 ASSERT(SystemMapPde->u.Hard.Valid == 1); 2329 MI_WRITE_VALID_PDE(PointerPde, *SystemMapPde); 2330 #else 2331 DBG_UNREFERENCED_LOCAL_VARIABLE(SystemMapPde); 2332 ASSERT(FALSE); 2333 #endif 2334 } 2335 2336 /* Dereference the PDE and the PTE */ 2337 Pfn2 = MiGetPfnEntry(PFN_FROM_PTE(PointerPde)); 2338 MiDecrementShareCount(Pfn2, PFN_FROM_PTE(PointerPde)); 2339 DBG_UNREFERENCED_LOCAL_VARIABLE(Pfn2); 2340 MiDecrementShareCount(Pfn1, PFN_FROM_PTE(&PteContents)); 2341 2342 /* Release the PFN lock */ 2343 MiReleasePfnLock(OldIrql); 2344 } 2345 else 2346 { 2347 /* Windows ASSERT */ 2348 ASSERT((PteContents.u.Long == 0) || (PteContents.u.Soft.Prototype == 1)); 2349 2350 /* Check if this is a prototype pointer PTE */ 2351 if (PteContents.u.Soft.Prototype == 1) 2352 { 2353 /* Get the prototype PTE */ 2354 ProtoPte = MiProtoPteToPte(&PteContents); 2355 2356 /* We don't support anything else atm */ 2357 ASSERT(ProtoPte->u.Long == 0); 2358 } 2359 } 2360 2361 /* Make the PTE into a zero PTE */ 2362 PointerPte->u.Long = 0; 2363 2364 /* Move to the next PTE */ 2365 PointerPte++; 2366 NumberOfPtes--; 2367 } 2368 2369 /* Flush the TLB */ 2370 KeFlushCurrentTb(); 2371 2372 /* Acquire the PFN lock */ 2373 OldIrql = MiAcquirePfnLock(); 2374 2375 /* Decrement the accounting counters */ 2376 ControlArea->NumberOfUserReferences--; 2377 ControlArea->NumberOfMappedViews--; 2378 2379 /* Check if we should destroy the CA and release the lock */ 2380 MiCheckControlArea(ControlArea, OldIrql); 2381 } 2382 2383 ULONG 2384 NTAPI 2385 MiRemoveFromSystemSpace(IN PMMSESSION Session, 2386 IN PVOID Base, 2387 OUT PCONTROL_AREA *ControlArea) 2388 { 2389 ULONG Hash, Size, Count = 0; 2390 ULONG_PTR Entry; 2391 PAGED_CODE(); 2392 2393 /* Compute the hash for this entry and loop trying to find it */ 2394 Entry = (ULONG_PTR)Base >> 16; 2395 Hash = Entry % Session->SystemSpaceHashKey; 2396 while ((Session->SystemSpaceViewTable[Hash].Entry >> 16) != Entry) 2397 { 2398 /* Check if we overflew past the end of the hash table */ 2399 if (++Hash >= Session->SystemSpaceHashSize) 2400 { 2401 /* Reset the hash to zero and keep searching from the bottom */ 2402 Hash = 0; 2403 if (++Count == 2) 2404 { 2405 /* But if we overflew twice, then this is not a real mapping */ 2406 KeBugCheckEx(DRIVER_UNMAPPING_INVALID_VIEW, 2407 (ULONG_PTR)Base, 2408 1, 2409 0, 2410 0); 2411 } 2412 } 2413 } 2414 2415 /* One less entry */ 2416 Session->SystemSpaceHashEntries--; 2417 2418 /* Extract the size and clear the entry */ 2419 Size = Session->SystemSpaceViewTable[Hash].Entry & 0xFFFF; 2420 Session->SystemSpaceViewTable[Hash].Entry = 0; 2421 2422 /* Return the control area and the size */ 2423 *ControlArea = Session->SystemSpaceViewTable[Hash].ControlArea; 2424 return Size; 2425 } 2426 2427 NTSTATUS 2428 NTAPI 2429 MiUnmapViewInSystemSpace(IN PMMSESSION Session, 2430 IN PVOID MappedBase) 2431 { 2432 ULONG Size; 2433 PCONTROL_AREA ControlArea; 2434 PAGED_CODE(); 2435 2436 /* Remove this mapping */ 2437 KeAcquireGuardedMutex(Session->SystemSpaceViewLockPointer); 2438 Size = MiRemoveFromSystemSpace(Session, MappedBase, &ControlArea); 2439 2440 /* Clear the bits for this mapping */ 2441 RtlClearBits(Session->SystemSpaceBitMap, 2442 (ULONG)(((ULONG_PTR)MappedBase - (ULONG_PTR)Session->SystemSpaceViewStart) >> 16), 2443 Size); 2444 2445 /* Convert the size from a bit size into the actual size */ 2446 Size = Size * (_64K >> PAGE_SHIFT); 2447 2448 /* Remove the PTEs now */ 2449 MiRemoveMappedPtes(MappedBase, Size, ControlArea, NULL); 2450 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 2451 2452 /* Return success */ 2453 return STATUS_SUCCESS; 2454 } 2455 2456 /* PUBLIC FUNCTIONS ***********************************************************/ 2457 2458 /* 2459 * @implemented 2460 */ 2461 NTSTATUS 2462 NTAPI 2463 MmCreateArm3Section(OUT PVOID *SectionObject, 2464 IN ACCESS_MASK DesiredAccess, 2465 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 2466 IN PLARGE_INTEGER InputMaximumSize, 2467 IN ULONG SectionPageProtection, 2468 IN ULONG AllocationAttributes, 2469 IN HANDLE FileHandle OPTIONAL, 2470 IN PFILE_OBJECT FileObject OPTIONAL) 2471 { 2472 SECTION Section; 2473 PSECTION NewSection; 2474 PSUBSECTION Subsection; 2475 PSEGMENT NewSegment, Segment; 2476 NTSTATUS Status; 2477 PCONTROL_AREA ControlArea; 2478 ULONG ProtectionMask, ControlAreaSize, Size, NonPagedCharge, PagedCharge; 2479 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 2480 BOOLEAN FileLock = FALSE, KernelCall = FALSE; 2481 KIRQL OldIrql; 2482 PFILE_OBJECT File; 2483 BOOLEAN UserRefIncremented = FALSE; 2484 PVOID PreviousSectionPointer; 2485 2486 /* Make the same sanity checks that the Nt interface should've validated */ 2487 ASSERT((AllocationAttributes & ~(SEC_COMMIT | SEC_RESERVE | SEC_BASED | 2488 SEC_LARGE_PAGES | SEC_IMAGE | SEC_NOCACHE | 2489 SEC_NO_CHANGE)) == 0); 2490 ASSERT((AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_IMAGE)) != 0); 2491 ASSERT(!((AllocationAttributes & SEC_IMAGE) && 2492 (AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | 2493 SEC_NOCACHE | SEC_NO_CHANGE)))); 2494 ASSERT(!((AllocationAttributes & SEC_COMMIT) && (AllocationAttributes & SEC_RESERVE))); 2495 ASSERT(!((SectionPageProtection & PAGE_NOCACHE) || 2496 (SectionPageProtection & PAGE_WRITECOMBINE) || 2497 (SectionPageProtection & PAGE_GUARD) || 2498 (SectionPageProtection & PAGE_NOACCESS))); 2499 2500 /* Convert section flag to page flag */ 2501 if (AllocationAttributes & SEC_NOCACHE) SectionPageProtection |= PAGE_NOCACHE; 2502 2503 /* Check to make sure the protection is correct. Nt* does this already */ 2504 ProtectionMask = MiMakeProtectionMask(SectionPageProtection); 2505 if (ProtectionMask == MM_INVALID_PROTECTION) return STATUS_INVALID_PAGE_PROTECTION; 2506 2507 /* Check if this is going to be a data or image backed file section */ 2508 if ((FileHandle) || (FileObject)) 2509 { 2510 /* These cannot be mapped with large pages */ 2511 if (AllocationAttributes & SEC_LARGE_PAGES) return STATUS_INVALID_PARAMETER_6; 2512 2513 /* For now, only support the mechanism through a file handle */ 2514 ASSERT(FileObject == NULL); 2515 2516 /* Reference the file handle to get the object */ 2517 Status = ObReferenceObjectByHandle(FileHandle, 2518 MmMakeFileAccess[ProtectionMask], 2519 IoFileObjectType, 2520 PreviousMode, 2521 (PVOID*)&File, 2522 NULL); 2523 if (!NT_SUCCESS(Status)) return Status; 2524 2525 /* Make sure Cc has been doing its job */ 2526 if (!File->SectionObjectPointer) 2527 { 2528 /* This is not a valid file system-based file, fail */ 2529 ObDereferenceObject(File); 2530 return STATUS_INVALID_FILE_FOR_SECTION; 2531 } 2532 2533 /* Image-file backed sections are not yet supported */ 2534 ASSERT((AllocationAttributes & SEC_IMAGE) == 0); 2535 2536 /* Compute the size of the control area, and allocate it */ 2537 ControlAreaSize = sizeof(CONTROL_AREA) + sizeof(MSUBSECTION); 2538 ControlArea = ExAllocatePoolWithTag(NonPagedPool, ControlAreaSize, 'aCmM'); 2539 if (!ControlArea) 2540 { 2541 ObDereferenceObject(File); 2542 return STATUS_INSUFFICIENT_RESOURCES; 2543 } 2544 2545 /* Zero it out */ 2546 RtlZeroMemory(ControlArea, ControlAreaSize); 2547 2548 /* Did we get a handle, or an object? */ 2549 if (FileHandle) 2550 { 2551 /* We got a file handle so we have to lock down the file */ 2552 #if 0 2553 Status = FsRtlAcquireToCreateMappedSection(File, SectionPageProtection); 2554 if (!NT_SUCCESS(Status)) 2555 { 2556 ExFreePool(ControlArea); 2557 ObDereferenceObject(File); 2558 return Status; 2559 } 2560 #else 2561 /* ReactOS doesn't support this API yet, so do nothing */ 2562 Status = STATUS_SUCCESS; 2563 #endif 2564 /* Update the top-level IRP so that drivers know what's happening */ 2565 IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP); 2566 FileLock = TRUE; 2567 } 2568 2569 /* Lock the PFN database while we play with the section pointers */ 2570 OldIrql = MiAcquirePfnLock(); 2571 2572 /* Image-file backed sections are not yet supported */ 2573 ASSERT((AllocationAttributes & SEC_IMAGE) == 0); 2574 2575 /* There should not already be a control area for this file */ 2576 ASSERT(File->SectionObjectPointer->DataSectionObject == NULL); 2577 NewSegment = NULL; 2578 2579 /* Write down that this CA is being created, and set it */ 2580 ControlArea->u.Flags.BeingCreated = TRUE; 2581 ASSERT((AllocationAttributes & SEC_IMAGE) == 0); 2582 PreviousSectionPointer = File->SectionObjectPointer; 2583 File->SectionObjectPointer->DataSectionObject = ControlArea; 2584 2585 /* We can release the PFN lock now */ 2586 MiReleasePfnLock(OldIrql); 2587 2588 /* We don't support previously-mapped file */ 2589 ASSERT(NewSegment == NULL); 2590 2591 /* Image-file backed sections are not yet supported */ 2592 ASSERT((AllocationAttributes & SEC_IMAGE) == 0); 2593 2594 /* So we always create a data file map */ 2595 Status = MiCreateDataFileMap(File, 2596 &Segment, 2597 (PSIZE_T)InputMaximumSize, 2598 SectionPageProtection, 2599 AllocationAttributes, 2600 KernelCall); 2601 if (!NT_SUCCESS(Status)) 2602 { 2603 /* Lock the PFN database while we play with the section pointers */ 2604 OldIrql = MiAcquirePfnLock(); 2605 2606 /* Reset the waiting-for-deletion event */ 2607 ASSERT(ControlArea->WaitingForDeletion == NULL); 2608 ControlArea->WaitingForDeletion = NULL; 2609 2610 /* Set the file pointer NULL flag */ 2611 ASSERT(ControlArea->u.Flags.FilePointerNull == 0); 2612 ControlArea->u.Flags.FilePointerNull = TRUE; 2613 2614 /* Delete the data section object */ 2615 ASSERT((AllocationAttributes & SEC_IMAGE) == 0); 2616 File->SectionObjectPointer->DataSectionObject = NULL; 2617 2618 /* No longer being created */ 2619 ControlArea->u.Flags.BeingCreated = FALSE; 2620 2621 /* We can release the PFN lock now */ 2622 MiReleasePfnLock(OldIrql); 2623 2624 /* Check if we locked and set the IRP */ 2625 if (FileLock) 2626 { 2627 /* Undo */ 2628 IoSetTopLevelIrp(NULL); 2629 //FsRtlReleaseFile(File); 2630 } 2631 2632 /* Free the control area and de-ref the file object */ 2633 ExFreePool(ControlArea); 2634 ObDereferenceObject(File); 2635 2636 /* All done */ 2637 return Status; 2638 } 2639 2640 /* On success, we expect this */ 2641 ASSERT(PreviousSectionPointer == File->SectionObjectPointer); 2642 2643 /* Check if a maximum size was specified */ 2644 if (!InputMaximumSize->QuadPart) 2645 { 2646 /* Nope, use the segment size */ 2647 Section.SizeOfSection.QuadPart = (LONGLONG)Segment->SizeOfSegment; 2648 } 2649 else 2650 { 2651 /* Yep, use the entered size */ 2652 Section.SizeOfSection.QuadPart = InputMaximumSize->QuadPart; 2653 } 2654 } 2655 else 2656 { 2657 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */ 2658 if (AllocationAttributes & SEC_IMAGE) return STATUS_INVALID_FILE_FOR_SECTION; 2659 2660 /* Not yet supported */ 2661 ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0); 2662 2663 /* So this must be a pagefile-backed section, create the mappings needed */ 2664 Status = MiCreatePagingFileMap(&NewSegment, 2665 InputMaximumSize, 2666 ProtectionMask, 2667 AllocationAttributes); 2668 if (!NT_SUCCESS(Status)) return Status; 2669 2670 /* Set the size here, and read the control area */ 2671 Section.SizeOfSection.QuadPart = NewSegment->SizeOfSegment; 2672 ControlArea = NewSegment->ControlArea; 2673 2674 /* MiCreatePagingFileMap increments user references */ 2675 UserRefIncremented = TRUE; 2676 } 2677 2678 /* Did we already have a segment? */ 2679 if (!NewSegment) 2680 { 2681 /* This must be the file path and we created a segment */ 2682 NewSegment = Segment; 2683 ASSERT(File != NULL); 2684 2685 /* Acquire the PFN lock while we set control area flags */ 2686 OldIrql = MiAcquirePfnLock(); 2687 2688 /* We don't support this race condition yet, so assume no waiters */ 2689 ASSERT(ControlArea->WaitingForDeletion == NULL); 2690 ControlArea->WaitingForDeletion = NULL; 2691 2692 /* Image-file backed sections are not yet supported, nor ROM images */ 2693 ASSERT((AllocationAttributes & SEC_IMAGE) == 0); 2694 ASSERT(Segment->ControlArea->u.Flags.Rom == 0); 2695 2696 /* Take off the being created flag, and then release the lock */ 2697 ControlArea->u.Flags.BeingCreated = FALSE; 2698 MiReleasePfnLock(OldIrql); 2699 } 2700 2701 /* Check if we locked the file earlier */ 2702 if (FileLock) 2703 { 2704 /* Reset the top-level IRP and release the lock */ 2705 IoSetTopLevelIrp(NULL); 2706 //FsRtlReleaseFile(File); 2707 FileLock = FALSE; 2708 } 2709 2710 /* Set the initial section object data */ 2711 Section.InitialPageProtection = SectionPageProtection; 2712 2713 /* The mapping created a control area and segment, save the flags */ 2714 Section.Segment = NewSegment; 2715 Section.u.LongFlags = ControlArea->u.LongFlags; 2716 2717 /* Check if this is a user-mode read-write non-image file mapping */ 2718 if (!(FileObject) && 2719 (SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)) && 2720 !(ControlArea->u.Flags.Image) && 2721 (ControlArea->FilePointer)) 2722 { 2723 /* Add a reference and set the flag */ 2724 Section.u.Flags.UserWritable = TRUE; 2725 InterlockedIncrement((volatile LONG*)&ControlArea->WritableUserReferences); 2726 } 2727 2728 /* Check for image mappings or page file mappings */ 2729 if ((ControlArea->u.Flags.Image) || !(ControlArea->FilePointer)) 2730 { 2731 /* Charge the segment size, and allocate a subsection */ 2732 PagedCharge = sizeof(SECTION) + NewSegment->TotalNumberOfPtes * sizeof(MMPTE); 2733 Size = sizeof(SUBSECTION); 2734 } 2735 else 2736 { 2737 /* Charge nothing, and allocate a mapped subsection */ 2738 PagedCharge = 0; 2739 Size = sizeof(MSUBSECTION); 2740 } 2741 2742 /* Check if this is a normal CA */ 2743 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 2744 ASSERT(ControlArea->u.Flags.Rom == 0); 2745 2746 /* Charge only a CA, and the subsection is right after */ 2747 NonPagedCharge = sizeof(CONTROL_AREA); 2748 Subsection = (PSUBSECTION)(ControlArea + 1); 2749 2750 /* We only support single-subsection mappings */ 2751 NonPagedCharge += Size; 2752 ASSERT(Subsection->NextSubsection == NULL); 2753 2754 /* Create the actual section object, with enough space for the prototype PTEs */ 2755 Status = ObCreateObject(PreviousMode, 2756 MmSectionObjectType, 2757 ObjectAttributes, 2758 PreviousMode, 2759 NULL, 2760 sizeof(SECTION), 2761 PagedCharge, 2762 NonPagedCharge, 2763 (PVOID*)&NewSection); 2764 if (!NT_SUCCESS(Status)) 2765 { 2766 /* Check if this is a user-mode read-write non-image file mapping */ 2767 if (!(FileObject) && 2768 (SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)) && 2769 !(ControlArea->u.Flags.Image) && 2770 (ControlArea->FilePointer)) 2771 { 2772 /* Remove a reference and check the flag */ 2773 ASSERT(Section.u.Flags.UserWritable == 1); 2774 InterlockedDecrement((volatile LONG*)&ControlArea->WritableUserReferences); 2775 } 2776 2777 /* Check if a user reference was added */ 2778 if (UserRefIncremented) 2779 { 2780 /* Acquire the PFN lock while we change counters */ 2781 OldIrql = MiAcquirePfnLock(); 2782 2783 /* Decrement the accounting counters */ 2784 ControlArea->NumberOfSectionReferences--; 2785 ASSERT((LONG)ControlArea->NumberOfUserReferences > 0); 2786 ControlArea->NumberOfUserReferences--; 2787 2788 /* Check if we should destroy the CA and release the lock */ 2789 MiCheckControlArea(ControlArea, OldIrql); 2790 } 2791 2792 /* Return the failure code */ 2793 return Status; 2794 } 2795 2796 /* NOTE: Past this point, all failures will be handled by Ob upon ref->0 */ 2797 2798 /* Now copy the local section object from the stack into this new object */ 2799 RtlCopyMemory(NewSection, &Section, sizeof(SECTION)); 2800 NewSection->Address.StartingVpn = 0; 2801 2802 /* For now, only user calls are supported */ 2803 ASSERT(KernelCall == FALSE); 2804 NewSection->u.Flags.UserReference = TRUE; 2805 2806 /* Is this a "based" allocation, in which all mappings are identical? */ 2807 if (AllocationAttributes & SEC_BASED) 2808 { 2809 /* Lock the VAD tree during the search */ 2810 KeAcquireGuardedMutex(&MmSectionBasedMutex); 2811 2812 /* Is it a brand new ControArea ? */ 2813 if (ControlArea->u.Flags.BeingCreated == 1) 2814 { 2815 ASSERT(ControlArea->u.Flags.Based == 1); 2816 /* Then we must find a global address, top-down */ 2817 Status = MiFindEmptyAddressRangeDownBasedTree((SIZE_T)ControlArea->Segment->SizeOfSegment, 2818 (ULONG_PTR)MmHighSectionBase, 2819 _64K, 2820 &MmSectionBasedRoot, 2821 (ULONG_PTR*)&ControlArea->Segment->BasedAddress); 2822 2823 if (!NT_SUCCESS(Status)) 2824 { 2825 /* No way to find a valid range. */ 2826 KeReleaseGuardedMutex(&MmSectionBasedMutex); 2827 ControlArea->u.Flags.Based = 0; 2828 NewSection->u.Flags.Based = 0; 2829 ObDereferenceObject(NewSection); 2830 return Status; 2831 } 2832 2833 /* Compute the ending address and insert it into the VAD tree */ 2834 NewSection->Address.StartingVpn = (ULONG_PTR)ControlArea->Segment->BasedAddress; 2835 NewSection->Address.EndingVpn = NewSection->Address.StartingVpn + NewSection->SizeOfSection.LowPart - 1; 2836 MiInsertBasedSection(NewSection); 2837 } 2838 else 2839 { 2840 /* FIXME : Should we deny section creation if SEC_BASED is not set ? Can we have two different section objects on the same based address ? Investigate !*/ 2841 ASSERT(FALSE); 2842 } 2843 2844 KeReleaseGuardedMutex(&MmSectionBasedMutex); 2845 } 2846 2847 /* The control area is not being created anymore */ 2848 if (ControlArea->u.Flags.BeingCreated == 1) 2849 { 2850 /* Acquire the PFN lock while we set control area flags */ 2851 OldIrql = MiAcquirePfnLock(); 2852 2853 /* Take off the being created flag, and then release the lock */ 2854 ControlArea->u.Flags.BeingCreated = 0; 2855 NewSection->u.Flags.BeingCreated = 0; 2856 2857 MiReleasePfnLock(OldIrql); 2858 } 2859 2860 /* Migrate the attribute into a flag */ 2861 if (AllocationAttributes & SEC_NO_CHANGE) NewSection->u.Flags.NoChange = TRUE; 2862 2863 /* If R/W access is not requested, this might eventually become a CoW mapping */ 2864 if (!(SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE))) 2865 { 2866 NewSection->u.Flags.CopyOnWrite = TRUE; 2867 } 2868 2869 /* Write down if this was a kernel call */ 2870 ControlArea->u.Flags.WasPurged |= KernelCall; 2871 ASSERT(ControlArea->u.Flags.WasPurged == FALSE); 2872 2873 /* Make sure the segment and the section are the same size, or the section is smaller */ 2874 ASSERT((ULONG64)NewSection->SizeOfSection.QuadPart <= NewSection->Segment->SizeOfSegment); 2875 2876 /* Return the object and the creation status */ 2877 *SectionObject = (PVOID)NewSection; 2878 return Status; 2879 } 2880 2881 /* 2882 * @implemented 2883 */ 2884 NTSTATUS 2885 NTAPI 2886 MmMapViewOfArm3Section(IN PVOID SectionObject, 2887 IN PEPROCESS Process, 2888 IN OUT PVOID *BaseAddress, 2889 IN ULONG_PTR ZeroBits, 2890 IN SIZE_T CommitSize, 2891 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, 2892 IN OUT PSIZE_T ViewSize, 2893 IN SECTION_INHERIT InheritDisposition, 2894 IN ULONG AllocationType, 2895 IN ULONG Protect) 2896 { 2897 KAPC_STATE ApcState; 2898 BOOLEAN Attached = FALSE; 2899 PSECTION Section; 2900 PCONTROL_AREA ControlArea; 2901 ULONG ProtectionMask; 2902 NTSTATUS Status; 2903 ULONG64 CalculatedViewSize; 2904 PAGED_CODE(); 2905 2906 /* Get the segment and control area */ 2907 Section = (PSECTION)SectionObject; 2908 ControlArea = Section->Segment->ControlArea; 2909 2910 /* These flags/states are not yet supported by ARM3 */ 2911 ASSERT(Section->u.Flags.Image == 0); 2912 ASSERT(Section->u.Flags.NoCache == 0); 2913 ASSERT(Section->u.Flags.WriteCombined == 0); 2914 ASSERT(ControlArea->u.Flags.PhysicalMemory == 0); 2915 2916 /* FIXME */ 2917 if ((AllocationType & MEM_RESERVE) != 0) 2918 { 2919 DPRINT1("MmMapViewOfArm3Section called with MEM_RESERVE, this is not implemented yet!!!\n"); 2920 return STATUS_NOT_IMPLEMENTED; 2921 } 2922 2923 /* Check if the mapping protection is compatible with the create */ 2924 if (!MiIsProtectionCompatible(Section->InitialPageProtection, Protect)) 2925 { 2926 DPRINT1("Mapping protection is incompatible\n"); 2927 return STATUS_SECTION_PROTECTION; 2928 } 2929 2930 /* Check if the offset and size would cause an overflow */ 2931 if (((ULONG64)SectionOffset->QuadPart + *ViewSize) < 2932 (ULONG64)SectionOffset->QuadPart) 2933 { 2934 DPRINT1("Section offset overflows\n"); 2935 return STATUS_INVALID_VIEW_SIZE; 2936 } 2937 2938 /* Check if the offset and size are bigger than the section itself */ 2939 if (((ULONG64)SectionOffset->QuadPart + *ViewSize) > 2940 (ULONG64)Section->SizeOfSection.QuadPart) 2941 { 2942 DPRINT1("Section offset is larger than section\n"); 2943 return STATUS_INVALID_VIEW_SIZE; 2944 } 2945 2946 /* Check if the caller did not specify a view size */ 2947 if (!(*ViewSize)) 2948 { 2949 /* Compute it for the caller */ 2950 CalculatedViewSize = Section->SizeOfSection.QuadPart - 2951 SectionOffset->QuadPart; 2952 2953 /* Check if it's larger than 4GB or overflows into kernel-mode */ 2954 if (!NT_SUCCESS(RtlULongLongToSIZET(CalculatedViewSize, ViewSize)) || 2955 (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - (ULONG_PTR)*BaseAddress) < CalculatedViewSize)) 2956 { 2957 DPRINT1("Section view won't fit\n"); 2958 return STATUS_INVALID_VIEW_SIZE; 2959 } 2960 } 2961 2962 /* Check if the commit size is larger than the view size */ 2963 if (CommitSize > *ViewSize) 2964 { 2965 DPRINT1("Attempting to commit more than the view itself\n"); 2966 return STATUS_INVALID_PARAMETER_5; 2967 } 2968 2969 /* Check if the view size is larger than the section */ 2970 if (*ViewSize > (ULONG64)Section->SizeOfSection.QuadPart) 2971 { 2972 DPRINT1("The view is larger than the section\n"); 2973 return STATUS_INVALID_VIEW_SIZE; 2974 } 2975 2976 /* Compute and validate the protection mask */ 2977 ProtectionMask = MiMakeProtectionMask(Protect); 2978 if (ProtectionMask == MM_INVALID_PROTECTION) 2979 { 2980 DPRINT1("The protection is invalid\n"); 2981 return STATUS_INVALID_PAGE_PROTECTION; 2982 } 2983 2984 /* We only handle pagefile-backed sections, which cannot be writecombined */ 2985 if (Protect & PAGE_WRITECOMBINE) 2986 { 2987 DPRINT1("Cannot write combine a pagefile-backed section\n"); 2988 return STATUS_INVALID_PARAMETER_10; 2989 } 2990 2991 /* Start by attaching to the current process if needed */ 2992 if (PsGetCurrentProcess() != Process) 2993 { 2994 KeStackAttachProcess(&Process->Pcb, &ApcState); 2995 Attached = TRUE; 2996 } 2997 2998 /* Do the actual mapping */ 2999 Status = MiMapViewOfDataSection(ControlArea, 3000 Process, 3001 BaseAddress, 3002 SectionOffset, 3003 ViewSize, 3004 Section, 3005 InheritDisposition, 3006 ProtectionMask, 3007 CommitSize, 3008 ZeroBits, 3009 AllocationType); 3010 3011 /* Detach if needed, then return status */ 3012 if (Attached) KeUnstackDetachProcess(&ApcState); 3013 return Status; 3014 } 3015 3016 /* 3017 * @unimplemented 3018 */ 3019 BOOLEAN 3020 NTAPI 3021 MmDisableModifiedWriteOfSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer) 3022 { 3023 UNIMPLEMENTED; 3024 return FALSE; 3025 } 3026 3027 /* 3028 * @unimplemented 3029 */ 3030 BOOLEAN 3031 NTAPI 3032 MmForceSectionClosed(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, 3033 IN BOOLEAN DelayClose) 3034 { 3035 UNIMPLEMENTED; 3036 return FALSE; 3037 } 3038 3039 /* 3040 * @implemented 3041 */ 3042 NTSTATUS 3043 NTAPI 3044 MmMapViewInSessionSpace(IN PVOID Section, 3045 OUT PVOID *MappedBase, 3046 IN OUT PSIZE_T ViewSize) 3047 { 3048 PAGED_CODE(); 3049 LARGE_INTEGER SectionOffset; 3050 3051 // HACK 3052 if (MiIsRosSectionObject(Section)) 3053 { 3054 return MmMapViewInSystemSpace(Section, MappedBase, ViewSize); 3055 } 3056 3057 /* Process must be in a session */ 3058 if (PsGetCurrentProcess()->ProcessInSession == FALSE) 3059 { 3060 DPRINT1("Process is not in session\n"); 3061 return STATUS_NOT_MAPPED_VIEW; 3062 } 3063 3064 /* Use the system space API, but with the session view instead */ 3065 ASSERT(MmIsAddressValid(MmSessionSpace) == TRUE); 3066 SectionOffset.QuadPart = 0; 3067 return MiMapViewInSystemSpace(Section, 3068 &MmSessionSpace->Session, 3069 MappedBase, 3070 ViewSize, 3071 &SectionOffset); 3072 } 3073 3074 /* 3075 * @implemented 3076 */ 3077 NTSTATUS 3078 NTAPI 3079 MmUnmapViewInSessionSpace(IN PVOID MappedBase) 3080 { 3081 PAGED_CODE(); 3082 3083 // HACK 3084 if (!MI_IS_SESSION_ADDRESS(MappedBase)) 3085 { 3086 return MmUnmapViewInSystemSpace(MappedBase); 3087 } 3088 3089 /* Process must be in a session */ 3090 if (PsGetCurrentProcess()->ProcessInSession == FALSE) 3091 { 3092 DPRINT1("Proess is not in session\n"); 3093 return STATUS_NOT_MAPPED_VIEW; 3094 } 3095 3096 /* Use the system space API, but with the session view instead */ 3097 ASSERT(MmIsAddressValid(MmSessionSpace) == TRUE); 3098 return MiUnmapViewInSystemSpace(&MmSessionSpace->Session, 3099 MappedBase); 3100 } 3101 3102 /* 3103 * @implemented 3104 */ 3105 NTSTATUS 3106 NTAPI 3107 MmUnmapViewOfSection(IN PEPROCESS Process, 3108 IN PVOID BaseAddress) 3109 { 3110 return MiUnmapViewOfSection(Process, BaseAddress, 0); 3111 } 3112 3113 /* 3114 * @implemented 3115 */ 3116 NTSTATUS 3117 NTAPI 3118 MmUnmapViewInSystemSpace(IN PVOID MappedBase) 3119 { 3120 PMEMORY_AREA MemoryArea; 3121 PAGED_CODE(); 3122 3123 /* Was this mapped by RosMm? */ 3124 MmLockAddressSpace(MmGetKernelAddressSpace()); 3125 MemoryArea = MmLocateMemoryAreaByAddress(MmGetKernelAddressSpace(), MappedBase); 3126 if ((MemoryArea) && (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3)) 3127 { 3128 NTSTATUS Status = MiRosUnmapViewInSystemSpace(MappedBase); 3129 MmUnlockAddressSpace(MmGetKernelAddressSpace()); 3130 return Status; 3131 } 3132 MmUnlockAddressSpace(MmGetKernelAddressSpace()); 3133 3134 /* It was not, call the ARM3 routine */ 3135 return MiUnmapViewInSystemSpace(&MmSession, MappedBase); 3136 } 3137 3138 /* 3139 * @implemented 3140 */ 3141 NTSTATUS 3142 NTAPI 3143 MmCommitSessionMappedView(IN PVOID MappedBase, 3144 IN SIZE_T ViewSize) 3145 { 3146 ULONG_PTR StartAddress, EndingAddress, Base; 3147 ULONG Hash, Count = 0, Size, QuotaCharge; 3148 PMMSESSION Session; 3149 PMMPTE LastProtoPte, PointerPte, ProtoPte; 3150 PCONTROL_AREA ControlArea; 3151 PSEGMENT Segment; 3152 PSUBSECTION Subsection; 3153 MMPTE TempPte; 3154 PAGED_CODE(); 3155 3156 /* Make sure the base isn't past the session view range */ 3157 if ((MappedBase < MiSessionViewStart) || 3158 (MappedBase >= (PVOID)((ULONG_PTR)MiSessionViewStart + MmSessionViewSize))) 3159 { 3160 DPRINT1("Base outside of valid range\n"); 3161 return STATUS_INVALID_PARAMETER_1; 3162 } 3163 3164 /* Make sure the size isn't past the session view range */ 3165 if (((ULONG_PTR)MiSessionViewStart + MmSessionViewSize - 3166 (ULONG_PTR)MappedBase) < ViewSize) 3167 { 3168 DPRINT1("Size outside of valid range\n"); 3169 return STATUS_INVALID_PARAMETER_2; 3170 } 3171 3172 /* Sanity check */ 3173 ASSERT(ViewSize != 0); 3174 3175 /* Process must be in a session */ 3176 if (PsGetCurrentProcess()->ProcessInSession == FALSE) 3177 { 3178 DPRINT1("Process is not in session\n"); 3179 return STATUS_NOT_MAPPED_VIEW; 3180 } 3181 3182 /* Compute the correctly aligned base and end addresses */ 3183 StartAddress = (ULONG_PTR)PAGE_ALIGN(MappedBase); 3184 EndingAddress = ((ULONG_PTR)MappedBase + ViewSize - 1) | (PAGE_SIZE - 1); 3185 3186 /* Sanity check and grab the session */ 3187 ASSERT(MmIsAddressValid(MmSessionSpace) == TRUE); 3188 Session = &MmSessionSpace->Session; 3189 3190 /* Get the hash entry for this allocation */ 3191 Hash = (StartAddress >> 16) % Session->SystemSpaceHashKey; 3192 3193 /* Lock system space */ 3194 KeAcquireGuardedMutex(Session->SystemSpaceViewLockPointer); 3195 3196 /* Loop twice so we can try rolling over if needed */ 3197 while (TRUE) 3198 { 3199 /* Extract the size and base addresses from the entry */ 3200 Base = Session->SystemSpaceViewTable[Hash].Entry & ~0xFFFF; 3201 Size = Session->SystemSpaceViewTable[Hash].Entry & 0xFFFF; 3202 3203 /* Convert the size to bucket chunks */ 3204 Size *= MI_SYSTEM_VIEW_BUCKET_SIZE; 3205 3206 /* Bail out if this entry fits in here */ 3207 if ((StartAddress >= Base) && (EndingAddress < (Base + Size))) break; 3208 3209 /* Check if we overflew past the end of the hash table */ 3210 if (++Hash >= Session->SystemSpaceHashSize) 3211 { 3212 /* Reset the hash to zero and keep searching from the bottom */ 3213 Hash = 0; 3214 if (++Count == 2) 3215 { 3216 /* But if we overflew twice, then this is not a real mapping */ 3217 KeBugCheckEx(DRIVER_UNMAPPING_INVALID_VIEW, 3218 Base, 3219 2, 3220 0, 3221 0); 3222 } 3223 } 3224 } 3225 3226 /* Make sure the view being mapped is not file-based */ 3227 ControlArea = Session->SystemSpaceViewTable[Hash].ControlArea; 3228 if (ControlArea->FilePointer != NULL) 3229 { 3230 /* It is, so we have to bail out */ 3231 DPRINT1("Only page-filed backed sections can be commited\n"); 3232 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 3233 return STATUS_ALREADY_COMMITTED; 3234 } 3235 3236 /* Get the subsection. We don't support LARGE_CONTROL_AREA in ARM3 */ 3237 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 3238 ASSERT(ControlArea->u.Flags.Rom == 0); 3239 Subsection = (PSUBSECTION)(ControlArea + 1); 3240 3241 /* Get the start and end PTEs -- make sure the end PTE isn't past the end */ 3242 ProtoPte = Subsection->SubsectionBase + ((StartAddress - Base) >> PAGE_SHIFT); 3243 QuotaCharge = MiAddressToPte(EndingAddress) - MiAddressToPte(StartAddress) + 1; 3244 LastProtoPte = ProtoPte + QuotaCharge; 3245 if (LastProtoPte >= Subsection->SubsectionBase + Subsection->PtesInSubsection) 3246 { 3247 DPRINT1("PTE is out of bounds\n"); 3248 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 3249 return STATUS_INVALID_PARAMETER_2; 3250 } 3251 3252 /* Acquire the commit lock and count all the non-committed PTEs */ 3253 KeAcquireGuardedMutexUnsafe(&MmSectionCommitMutex); 3254 PointerPte = ProtoPte; 3255 while (PointerPte < LastProtoPte) 3256 { 3257 if (PointerPte->u.Long) QuotaCharge--; 3258 PointerPte++; 3259 } 3260 3261 /* Was everything committed already? */ 3262 if (!QuotaCharge) 3263 { 3264 /* Nothing to do! */ 3265 KeReleaseGuardedMutexUnsafe(&MmSectionCommitMutex); 3266 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 3267 return STATUS_SUCCESS; 3268 } 3269 3270 /* Pick the segment and template PTE */ 3271 Segment = ControlArea->Segment; 3272 TempPte = Segment->SegmentPteTemplate; 3273 ASSERT(TempPte.u.Long != 0); 3274 3275 /* Loop all prototype PTEs to be committed */ 3276 PointerPte = ProtoPte; 3277 while (PointerPte < LastProtoPte) 3278 { 3279 /* Make sure the PTE is already invalid */ 3280 if (PointerPte->u.Long == 0) 3281 { 3282 /* And write the invalid PTE */ 3283 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 3284 } 3285 3286 /* Move to the next PTE */ 3287 PointerPte++; 3288 } 3289 3290 /* Check if we had at least one page charged */ 3291 if (QuotaCharge) 3292 { 3293 /* Update the accounting data */ 3294 Segment->NumberOfCommittedPages += QuotaCharge; 3295 InterlockedExchangeAddSizeT(&MmSharedCommit, QuotaCharge); 3296 } 3297 3298 /* Release all */ 3299 KeReleaseGuardedMutexUnsafe(&MmSectionCommitMutex); 3300 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 3301 return STATUS_SUCCESS; 3302 } 3303 3304 VOID 3305 NTAPI 3306 MiDeleteARM3Section(PVOID ObjectBody) 3307 { 3308 PSECTION SectionObject; 3309 PCONTROL_AREA ControlArea; 3310 KIRQL OldIrql; 3311 3312 SectionObject = (PSECTION)ObjectBody; 3313 3314 if (SectionObject->u.Flags.Based == 1) 3315 { 3316 /* Remove the node from the global section address tree */ 3317 KeAcquireGuardedMutex(&MmSectionBasedMutex); 3318 MiRemoveNode(&SectionObject->Address, &MmSectionBasedRoot); 3319 KeReleaseGuardedMutex(&MmSectionBasedMutex); 3320 } 3321 3322 /* Lock the PFN database */ 3323 OldIrql = MiAcquirePfnLock(); 3324 3325 ASSERT(SectionObject->Segment); 3326 ASSERT(SectionObject->Segment->ControlArea); 3327 3328 ControlArea = SectionObject->Segment->ControlArea; 3329 3330 /* Dereference */ 3331 ControlArea->NumberOfSectionReferences--; 3332 ControlArea->NumberOfUserReferences--; 3333 3334 ASSERT(ControlArea->u.Flags.BeingDeleted == 0); 3335 3336 /* Check it. It will delete it if there is no more reference to it */ 3337 MiCheckControlArea(ControlArea, OldIrql); 3338 } 3339 3340 ULONG 3341 NTAPI 3342 MmDoesFileHaveUserWritableReferences(IN PSECTION_OBJECT_POINTERS SectionPointer) 3343 { 3344 UNIMPLEMENTED_ONCE; 3345 return 0; 3346 } 3347 3348 /* SYSTEM CALLS ***************************************************************/ 3349 3350 NTSTATUS 3351 NTAPI 3352 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage, 3353 IN PVOID File2MappedAsFile) 3354 { 3355 PVOID AddressSpace; 3356 PMMVAD Vad1, Vad2; 3357 PFILE_OBJECT FileObject1, FileObject2; 3358 NTSTATUS Status; 3359 3360 /* Lock address space */ 3361 AddressSpace = MmGetCurrentAddressSpace(); 3362 MmLockAddressSpace(AddressSpace); 3363 3364 /* Get the VAD for Address 1 */ 3365 Vad1 = MiLocateAddress(File1MappedAsAnImage); 3366 if (Vad1 == NULL) 3367 { 3368 /* Fail, the address does not exist */ 3369 DPRINT1("No VAD at address 1 %p\n", File1MappedAsAnImage); 3370 Status = STATUS_INVALID_ADDRESS; 3371 goto Exit; 3372 } 3373 3374 /* Get the VAD for Address 2 */ 3375 Vad2 = MiLocateAddress(File2MappedAsFile); 3376 if (Vad2 == NULL) 3377 { 3378 /* Fail, the address does not exist */ 3379 DPRINT1("No VAD at address 2 %p\n", File2MappedAsFile); 3380 Status = STATUS_INVALID_ADDRESS; 3381 goto Exit; 3382 } 3383 3384 /* Get the file object pointer for VAD 1 */ 3385 FileObject1 = MiGetFileObjectForVad(Vad1); 3386 if (FileObject1 == NULL) 3387 { 3388 DPRINT1("Failed to get file object for Address 1 %p\n", File1MappedAsAnImage); 3389 Status = STATUS_CONFLICTING_ADDRESSES; 3390 goto Exit; 3391 } 3392 3393 /* Get the file object pointer for VAD 2 */ 3394 FileObject2 = MiGetFileObjectForVad(Vad2); 3395 if (FileObject2 == NULL) 3396 { 3397 DPRINT1("Failed to get file object for Address 2 %p\n", File2MappedAsFile); 3398 Status = STATUS_CONFLICTING_ADDRESSES; 3399 goto Exit; 3400 } 3401 3402 /* Make sure Vad1 is an image mapping */ 3403 if (Vad1->u.VadFlags.VadType != VadImageMap) 3404 { 3405 DPRINT1("Address 1 (%p) is not an image mapping\n", File1MappedAsAnImage); 3406 Status = STATUS_NOT_SAME_DEVICE; 3407 goto Exit; 3408 } 3409 3410 /* SectionObjectPointer is equal if the files are equal */ 3411 if (FileObject1->SectionObjectPointer == FileObject2->SectionObjectPointer) 3412 { 3413 Status = STATUS_SUCCESS; 3414 } 3415 else 3416 { 3417 Status = STATUS_NOT_SAME_DEVICE; 3418 } 3419 3420 Exit: 3421 /* Unlock address space */ 3422 MmUnlockAddressSpace(AddressSpace); 3423 return Status; 3424 } 3425 3426 /* 3427 * @implemented 3428 */ 3429 NTSTATUS 3430 NTAPI 3431 NtCreateSection(OUT PHANDLE SectionHandle, 3432 IN ACCESS_MASK DesiredAccess, 3433 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 3434 IN PLARGE_INTEGER MaximumSize OPTIONAL, 3435 IN ULONG SectionPageProtection OPTIONAL, 3436 IN ULONG AllocationAttributes, 3437 IN HANDLE FileHandle OPTIONAL) 3438 { 3439 LARGE_INTEGER SafeMaximumSize; 3440 PVOID SectionObject; 3441 HANDLE Handle; 3442 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 3443 NTSTATUS Status; 3444 PAGED_CODE(); 3445 3446 /* Check for non-existing flags */ 3447 if ((AllocationAttributes & ~(SEC_COMMIT | SEC_RESERVE | SEC_BASED | 3448 SEC_LARGE_PAGES | SEC_IMAGE | SEC_NOCACHE | 3449 SEC_NO_CHANGE))) 3450 { 3451 if (!(AllocationAttributes & 1)) 3452 { 3453 DPRINT1("Bogus allocation attribute: %lx\n", AllocationAttributes); 3454 return STATUS_INVALID_PARAMETER_6; 3455 } 3456 } 3457 3458 /* Check for no allocation type */ 3459 if (!(AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_IMAGE))) 3460 { 3461 DPRINT1("Missing allocation type in allocation attributes\n"); 3462 return STATUS_INVALID_PARAMETER_6; 3463 } 3464 3465 /* Check for image allocation with invalid attributes */ 3466 if ((AllocationAttributes & SEC_IMAGE) && 3467 (AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_LARGE_PAGES | 3468 SEC_NOCACHE | SEC_NO_CHANGE))) 3469 { 3470 DPRINT1("Image allocation with invalid attributes\n"); 3471 return STATUS_INVALID_PARAMETER_6; 3472 } 3473 3474 /* Check for allocation type is both commit and reserve */ 3475 if ((AllocationAttributes & SEC_COMMIT) && (AllocationAttributes & SEC_RESERVE)) 3476 { 3477 DPRINT1("Commit and reserve in the same time\n"); 3478 return STATUS_INVALID_PARAMETER_6; 3479 } 3480 3481 /* Now check for valid protection */ 3482 if ((SectionPageProtection & PAGE_NOCACHE) || 3483 (SectionPageProtection & PAGE_WRITECOMBINE) || 3484 (SectionPageProtection & PAGE_GUARD) || 3485 (SectionPageProtection & PAGE_NOACCESS)) 3486 { 3487 DPRINT1("Sections don't support these protections\n"); 3488 return STATUS_INVALID_PAGE_PROTECTION; 3489 } 3490 3491 /* Use a maximum size of zero, if none was specified */ 3492 SafeMaximumSize.QuadPart = 0; 3493 3494 /* Check for user-mode caller */ 3495 if (PreviousMode != KernelMode) 3496 { 3497 /* Enter SEH */ 3498 _SEH2_TRY 3499 { 3500 /* Safely check user-mode parameters */ 3501 if (MaximumSize) SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize); 3502 MaximumSize = &SafeMaximumSize; 3503 ProbeForWriteHandle(SectionHandle); 3504 } 3505 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3506 { 3507 /* Return the exception code */ 3508 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3509 } 3510 _SEH2_END; 3511 } 3512 else if (!MaximumSize) MaximumSize = &SafeMaximumSize; 3513 3514 /* Check that MaximumSize is valid if backed by paging file */ 3515 if ((!FileHandle) && (!MaximumSize->QuadPart)) 3516 return STATUS_INVALID_PARAMETER_4; 3517 3518 /* Create the section */ 3519 Status = MmCreateSection(&SectionObject, 3520 DesiredAccess, 3521 ObjectAttributes, 3522 MaximumSize, 3523 SectionPageProtection, 3524 AllocationAttributes, 3525 FileHandle, 3526 NULL); 3527 if (!NT_SUCCESS(Status)) return Status; 3528 3529 /* FIXME: Should zero last page for a file mapping */ 3530 3531 /* Now insert the object */ 3532 Status = ObInsertObject(SectionObject, 3533 NULL, 3534 DesiredAccess, 3535 0, 3536 NULL, 3537 &Handle); 3538 if (NT_SUCCESS(Status)) 3539 { 3540 /* Enter SEH */ 3541 _SEH2_TRY 3542 { 3543 /* Return the handle safely */ 3544 *SectionHandle = Handle; 3545 } 3546 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3547 { 3548 /* Nothing here */ 3549 } 3550 _SEH2_END; 3551 } 3552 3553 /* Return the status */ 3554 return Status; 3555 } 3556 3557 NTSTATUS 3558 NTAPI 3559 NtOpenSection(OUT PHANDLE SectionHandle, 3560 IN ACCESS_MASK DesiredAccess, 3561 IN POBJECT_ATTRIBUTES ObjectAttributes) 3562 { 3563 HANDLE Handle; 3564 NTSTATUS Status; 3565 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 3566 PAGED_CODE(); 3567 3568 /* Check for user-mode caller */ 3569 if (PreviousMode != KernelMode) 3570 { 3571 /* Enter SEH */ 3572 _SEH2_TRY 3573 { 3574 /* Safely check user-mode parameters */ 3575 ProbeForWriteHandle(SectionHandle); 3576 } 3577 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3578 { 3579 /* Return the exception code */ 3580 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3581 } 3582 _SEH2_END; 3583 } 3584 3585 /* Try opening the object */ 3586 Status = ObOpenObjectByName(ObjectAttributes, 3587 MmSectionObjectType, 3588 PreviousMode, 3589 NULL, 3590 DesiredAccess, 3591 NULL, 3592 &Handle); 3593 3594 /* Enter SEH */ 3595 _SEH2_TRY 3596 { 3597 /* Return the handle safely */ 3598 *SectionHandle = Handle; 3599 } 3600 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3601 { 3602 /* Nothing here */ 3603 } 3604 _SEH2_END; 3605 3606 /* Return the status */ 3607 return Status; 3608 } 3609 3610 NTSTATUS 3611 NTAPI 3612 NtMapViewOfSection(IN HANDLE SectionHandle, 3613 IN HANDLE ProcessHandle, 3614 IN OUT PVOID* BaseAddress, 3615 IN ULONG_PTR ZeroBits, 3616 IN SIZE_T CommitSize, 3617 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, 3618 IN OUT PSIZE_T ViewSize, 3619 IN SECTION_INHERIT InheritDisposition, 3620 IN ULONG AllocationType, 3621 IN ULONG Protect) 3622 { 3623 PVOID SafeBaseAddress; 3624 LARGE_INTEGER SafeSectionOffset; 3625 SIZE_T SafeViewSize; 3626 PSECTION Section; 3627 PEPROCESS Process; 3628 NTSTATUS Status; 3629 ACCESS_MASK DesiredAccess; 3630 ULONG ProtectionMask; 3631 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 3632 #if defined(_M_IX86) || defined(_M_AMD64) 3633 static const ULONG ValidAllocationType = (MEM_TOP_DOWN | MEM_LARGE_PAGES | 3634 MEM_DOS_LIM | SEC_NO_CHANGE | MEM_RESERVE); 3635 #else 3636 static const ULONG ValidAllocationType = (MEM_TOP_DOWN | MEM_LARGE_PAGES | 3637 SEC_NO_CHANGE | MEM_RESERVE); 3638 #endif 3639 3640 /* Check for invalid inherit disposition */ 3641 if ((InheritDisposition > ViewUnmap) || (InheritDisposition < ViewShare)) 3642 { 3643 DPRINT1("Invalid inherit disposition\n"); 3644 return STATUS_INVALID_PARAMETER_8; 3645 } 3646 3647 /* Allow only valid allocation types */ 3648 if (AllocationType & ~ValidAllocationType) 3649 { 3650 DPRINT1("Invalid allocation type\n"); 3651 return STATUS_INVALID_PARAMETER_9; 3652 } 3653 3654 /* Convert the protection mask, and validate it */ 3655 ProtectionMask = MiMakeProtectionMask(Protect); 3656 if (ProtectionMask == MM_INVALID_PROTECTION) 3657 { 3658 DPRINT1("Invalid page protection\n"); 3659 return STATUS_INVALID_PAGE_PROTECTION; 3660 } 3661 3662 /* Now convert the protection mask into desired section access mask */ 3663 DesiredAccess = MmMakeSectionAccess[ProtectionMask & 0x7]; 3664 3665 /* Assume no section offset */ 3666 SafeSectionOffset.QuadPart = 0; 3667 3668 /* Enter SEH */ 3669 _SEH2_TRY 3670 { 3671 /* Check for unsafe parameters */ 3672 if (PreviousMode != KernelMode) 3673 { 3674 /* Probe the parameters */ 3675 ProbeForWritePointer(BaseAddress); 3676 ProbeForWriteSize_t(ViewSize); 3677 } 3678 3679 /* Check if a section offset was given */ 3680 if (SectionOffset) 3681 { 3682 /* Check for unsafe parameters and capture section offset */ 3683 if (PreviousMode != KernelMode) ProbeForWriteLargeInteger(SectionOffset); 3684 SafeSectionOffset = *SectionOffset; 3685 } 3686 3687 /* Capture the other parameters */ 3688 SafeBaseAddress = *BaseAddress; 3689 SafeViewSize = *ViewSize; 3690 } 3691 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3692 { 3693 /* Return the exception code */ 3694 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3695 } 3696 _SEH2_END; 3697 3698 /* Check for kernel-mode address */ 3699 if (SafeBaseAddress > MM_HIGHEST_VAD_ADDRESS) 3700 { 3701 DPRINT1("Kernel base not allowed\n"); 3702 return STATUS_INVALID_PARAMETER_3; 3703 } 3704 3705 /* Check for range entering kernel-mode */ 3706 if (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - (ULONG_PTR)SafeBaseAddress) < SafeViewSize) 3707 { 3708 DPRINT1("Overflowing into kernel base not allowed\n"); 3709 return STATUS_INVALID_PARAMETER_3; 3710 } 3711 3712 /* Check for invalid zero bits */ 3713 if (ZeroBits) 3714 { 3715 if (ZeroBits > MI_MAX_ZERO_BITS) 3716 { 3717 DPRINT1("Invalid zero bits\n"); 3718 return STATUS_INVALID_PARAMETER_4; 3719 } 3720 3721 if ((((ULONG_PTR)SafeBaseAddress << ZeroBits) >> ZeroBits) != (ULONG_PTR)SafeBaseAddress) 3722 { 3723 DPRINT1("Invalid zero bits\n"); 3724 return STATUS_INVALID_PARAMETER_4; 3725 } 3726 3727 if (((((ULONG_PTR)SafeBaseAddress + SafeViewSize) << ZeroBits) >> ZeroBits) != ((ULONG_PTR)SafeBaseAddress + SafeViewSize)) 3728 { 3729 DPRINT1("Invalid zero bits\n"); 3730 return STATUS_INVALID_PARAMETER_4; 3731 } 3732 } 3733 3734 /* Reference the process */ 3735 Status = ObReferenceObjectByHandle(ProcessHandle, 3736 PROCESS_VM_OPERATION, 3737 PsProcessType, 3738 PreviousMode, 3739 (PVOID*)&Process, 3740 NULL); 3741 if (!NT_SUCCESS(Status)) return Status; 3742 3743 /* Reference the section */ 3744 Status = ObReferenceObjectByHandle(SectionHandle, 3745 DesiredAccess, 3746 MmSectionObjectType, 3747 PreviousMode, 3748 (PVOID*)&Section, 3749 NULL); 3750 if (!NT_SUCCESS(Status)) 3751 { 3752 ObDereferenceObject(Process); 3753 return Status; 3754 } 3755 3756 if (Section->u.Flags.PhysicalMemory) 3757 { 3758 if (PreviousMode == UserMode && 3759 SafeSectionOffset.QuadPart + SafeViewSize > MmHighestPhysicalPage << PAGE_SHIFT) 3760 { 3761 DPRINT1("Denying map past highest physical page.\n"); 3762 ObDereferenceObject(Section); 3763 ObDereferenceObject(Process); 3764 return STATUS_INVALID_PARAMETER_6; 3765 } 3766 } 3767 else if (!(AllocationType & MEM_DOS_LIM)) 3768 { 3769 /* Check for non-allocation-granularity-aligned BaseAddress */ 3770 if (SafeBaseAddress != ALIGN_DOWN_POINTER_BY(SafeBaseAddress, MM_VIRTMEM_GRANULARITY)) 3771 { 3772 DPRINT("BaseAddress is not at 64-kilobyte address boundary.\n"); 3773 ObDereferenceObject(Section); 3774 ObDereferenceObject(Process); 3775 return STATUS_MAPPED_ALIGNMENT; 3776 } 3777 3778 /* Do the same for the section offset */ 3779 if (SafeSectionOffset.LowPart != ALIGN_DOWN_BY(SafeSectionOffset.LowPart, MM_VIRTMEM_GRANULARITY)) 3780 { 3781 DPRINT("SectionOffset is not at 64-kilobyte address boundary.\n"); 3782 ObDereferenceObject(Section); 3783 ObDereferenceObject(Process); 3784 return STATUS_MAPPED_ALIGNMENT; 3785 } 3786 } 3787 3788 /* Now do the actual mapping */ 3789 Status = MmMapViewOfSection(Section, 3790 Process, 3791 &SafeBaseAddress, 3792 ZeroBits, 3793 CommitSize, 3794 &SafeSectionOffset, 3795 &SafeViewSize, 3796 InheritDisposition, 3797 AllocationType, 3798 Protect); 3799 3800 /* Return data only on success */ 3801 if (NT_SUCCESS(Status)) 3802 { 3803 /* Check if this is an image for the current process */ 3804 if ((Section->u.Flags.Image) && 3805 (Process == PsGetCurrentProcess()) && 3806 (Status != STATUS_IMAGE_NOT_AT_BASE)) 3807 { 3808 /* Notify the debugger */ 3809 DbgkMapViewOfSection(Section, 3810 SafeBaseAddress, 3811 SafeSectionOffset.LowPart, 3812 SafeViewSize); 3813 } 3814 3815 /* Enter SEH */ 3816 _SEH2_TRY 3817 { 3818 /* Return parameters to user */ 3819 *BaseAddress = SafeBaseAddress; 3820 *ViewSize = SafeViewSize; 3821 if (SectionOffset) *SectionOffset = SafeSectionOffset; 3822 } 3823 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3824 { 3825 /* Nothing to do */ 3826 } 3827 _SEH2_END; 3828 } 3829 3830 /* Dereference all objects and return status */ 3831 ObDereferenceObject(Section); 3832 ObDereferenceObject(Process); 3833 return Status; 3834 } 3835 3836 NTSTATUS 3837 NTAPI 3838 NtUnmapViewOfSection(IN HANDLE ProcessHandle, 3839 IN PVOID BaseAddress) 3840 { 3841 PEPROCESS Process; 3842 NTSTATUS Status; 3843 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 3844 3845 /* Don't allowing mapping kernel views */ 3846 if ((PreviousMode == UserMode) && (BaseAddress > MM_HIGHEST_USER_ADDRESS)) 3847 { 3848 DPRINT1("Trying to unmap a kernel view\n"); 3849 return STATUS_NOT_MAPPED_VIEW; 3850 } 3851 3852 /* Reference the process */ 3853 Status = ObReferenceObjectByHandle(ProcessHandle, 3854 PROCESS_VM_OPERATION, 3855 PsProcessType, 3856 PreviousMode, 3857 (PVOID*)&Process, 3858 NULL); 3859 if (!NT_SUCCESS(Status)) return Status; 3860 3861 /* Unmap the view */ 3862 Status = MiUnmapViewOfSection(Process, BaseAddress, 0); 3863 3864 /* Dereference the process and return status */ 3865 ObDereferenceObject(Process); 3866 return Status; 3867 } 3868 3869 NTSTATUS 3870 NTAPI 3871 NtExtendSection(IN HANDLE SectionHandle, 3872 IN OUT PLARGE_INTEGER NewMaximumSize) 3873 { 3874 LARGE_INTEGER SafeNewMaximumSize; 3875 PSECTION Section; 3876 NTSTATUS Status; 3877 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 3878 3879 /* Check for user-mode parameters */ 3880 if (PreviousMode != KernelMode) 3881 { 3882 /* Enter SEH */ 3883 _SEH2_TRY 3884 { 3885 /* Probe and capture the maximum size, it's both read and write */ 3886 ProbeForWriteLargeInteger(NewMaximumSize); 3887 SafeNewMaximumSize = *NewMaximumSize; 3888 } 3889 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3890 { 3891 /* Return the exception code */ 3892 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3893 } 3894 _SEH2_END; 3895 } 3896 else 3897 { 3898 /* Just read the size directly */ 3899 SafeNewMaximumSize = *NewMaximumSize; 3900 } 3901 3902 /* Reference the section */ 3903 Status = ObReferenceObjectByHandle(SectionHandle, 3904 SECTION_EXTEND_SIZE, 3905 MmSectionObjectType, 3906 PreviousMode, 3907 (PVOID*)&Section, 3908 NULL); 3909 if (!NT_SUCCESS(Status)) return Status; 3910 3911 Status = MmExtendSection(Section, &SafeNewMaximumSize); 3912 3913 /* Dereference the section */ 3914 ObDereferenceObject(Section); 3915 3916 if (NT_SUCCESS(Status)) 3917 { 3918 _SEH2_TRY 3919 { 3920 /* Write back the new size */ 3921 *NewMaximumSize = SafeNewMaximumSize; 3922 } 3923 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3924 { 3925 Status = _SEH2_GetExceptionCode(); 3926 } 3927 _SEH2_END; 3928 } 3929 3930 /* Return the status */ 3931 return STATUS_NOT_IMPLEMENTED; 3932 } 3933 3934 /* EOF */ 3935