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