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