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