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 1303 /* Make sure that we will not overflow */ 1304 if ((Section->SizeOfSection.QuadPart - SectionOffset->QuadPart) > MAXLONG_PTR) 1305 { 1306 MiDereferenceControlArea(ControlArea); 1307 return STATUS_INVALID_VIEW_SIZE; 1308 } 1309 1310 *ViewSize = (SIZE_T)(Section->SizeOfSection.QuadPart - SectionOffset->QuadPart); 1311 } 1312 else 1313 { 1314 /* A size was specified, align it to a 64K boundary */ 1315 *ViewSize += SectionOffset->LowPart & (_64K - 1); 1316 1317 /* Check for overflow or huge value */ 1318 if ((*ViewSize < (SectionOffset->LowPart & (_64K - 1))) || ((*ViewSize) > MAXLONG_PTR)) 1319 { 1320 MiDereferenceControlArea(ControlArea); 1321 return STATUS_INVALID_VIEW_SIZE; 1322 } 1323 1324 /* Align the offset as well to make this an aligned map */ 1325 SectionOffset->LowPart &= ~((ULONG)_64K - 1); 1326 } 1327 1328 /* We must be dealing with a 64KB aligned offset. This is a Windows ASSERT */ 1329 ASSERT((SectionOffset->LowPart & ((ULONG)_64K - 1)) == 0); 1330 1331 /* Windows ASSERTs for this flag */ 1332 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 1333 1334 /* Get the subsection. We don't support LARGE_CONTROL_AREA in ARM3 */ 1335 ASSERT(ControlArea->u.Flags.Rom == 0); 1336 Subsection = (PSUBSECTION)(ControlArea + 1); 1337 1338 /* Sections with extended segments are not supported in ARM3 */ 1339 ASSERT(Segment->SegmentFlags.TotalNumberOfPtes4132 == 0); 1340 1341 /* Within this section, figure out which PTEs will describe the view */ 1342 PteOffset = (PFN_NUMBER)(SectionOffset->QuadPart >> PAGE_SHIFT); 1343 1344 /* The offset must be in this segment's PTE chunk and it must be valid. Windows ASSERTs */ 1345 ASSERT(PteOffset < Segment->TotalNumberOfPtes); 1346 ASSERT(((SectionOffset->QuadPart + *ViewSize + PAGE_SIZE - 1) >> PAGE_SHIFT) >= PteOffset); 1347 1348 /* In ARM3, only one subsection is used for now. It must contain these PTEs */ 1349 ASSERT(PteOffset < Subsection->PtesInSubsection); 1350 1351 /* In ARM3, only page-file backed sections (shared memory) are supported now */ 1352 ASSERT(ControlArea->FilePointer == NULL); 1353 1354 /* Windows ASSERTs for this too -- there must be a subsection base address */ 1355 ASSERT(Subsection->SubsectionBase != NULL); 1356 1357 /* Compute how much commit space the segment will take */ 1358 if ((CommitSize) && (Segment->NumberOfCommittedPages < Segment->TotalNumberOfPtes)) 1359 { 1360 /* Charge for the maximum pages */ 1361 QuotaCharge = BYTES_TO_PAGES(CommitSize); 1362 } 1363 1364 /* ARM3 does not currently support large pages */ 1365 ASSERT(Segment->SegmentFlags.LargePages == 0); 1366 1367 /* Calculate how many pages the region spans */ 1368 ViewSizeInPages = BYTES_TO_PAGES(*ViewSize); 1369 1370 /* A VAD can now be allocated. Do so and zero it out */ 1371 /* FIXME: we are allocating a LONG VAD for ReactOS compatibility only */ 1372 ASSERT((AllocationType & MEM_RESERVE) == 0); /* ARM3 does not support this */ 1373 Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV'); 1374 if (!Vad) 1375 { 1376 MiDereferenceControlArea(ControlArea); 1377 return STATUS_INSUFFICIENT_RESOURCES; 1378 } 1379 1380 RtlZeroMemory(Vad, sizeof(MMVAD_LONG)); 1381 Vad->u4.Banked = (PVOID)(ULONG_PTR)0xDEADBABEDEADBABEULL; 1382 1383 /* Write all the data required in the VAD for handling a fault */ 1384 Vad->ControlArea = ControlArea; 1385 Vad->u.VadFlags.CommitCharge = 0; 1386 Vad->u.VadFlags.Protection = ProtectionMask; 1387 Vad->u2.VadFlags2.FileOffset = (ULONG)(SectionOffset->QuadPart >> 16); 1388 Vad->u2.VadFlags2.Inherit = (InheritDisposition == ViewShare); 1389 if ((AllocationType & SEC_NO_CHANGE) || (Section->u.Flags.NoChange)) 1390 { 1391 /* This isn't really implemented yet, but handle setting the flag */ 1392 Vad->u.VadFlags.NoChange = 1; 1393 Vad->u2.VadFlags2.SecNoChange = 1; 1394 } 1395 1396 /* Finally, write down the first and last prototype PTE */ 1397 Vad->FirstPrototypePte = &Subsection->SubsectionBase[PteOffset]; 1398 PteOffset += ViewSizeInPages - 1; 1399 ASSERT(PteOffset < Subsection->PtesInSubsection); 1400 Vad->LastContiguousPte = &Subsection->SubsectionBase[PteOffset]; 1401 1402 /* Make sure the prototype PTE ranges make sense, this is a Windows ASSERT */ 1403 ASSERT(Vad->FirstPrototypePte <= Vad->LastContiguousPte); 1404 1405 /* FIXME: Should setup VAD bitmap */ 1406 Status = STATUS_SUCCESS; 1407 1408 /* Check if anything was committed */ 1409 if (QuotaCharge) 1410 { 1411 /* Set the start and end PTE addresses, and pick the template PTE */ 1412 PointerPte = Vad->FirstPrototypePte; 1413 LastPte = PointerPte + BYTES_TO_PAGES(CommitSize); 1414 TempPte = Segment->SegmentPteTemplate; 1415 1416 /* Acquire the commit lock and loop all prototype PTEs to be committed */ 1417 KeAcquireGuardedMutex(&MmSectionCommitMutex); 1418 while (PointerPte < LastPte) 1419 { 1420 /* Make sure the PTE is already invalid */ 1421 if (PointerPte->u.Long == 0) 1422 { 1423 /* And write the invalid PTE */ 1424 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 1425 } 1426 else 1427 { 1428 /* The PTE is valid, so skip it */ 1429 QuotaExcess++; 1430 } 1431 1432 /* Move to the next PTE */ 1433 PointerPte++; 1434 } 1435 1436 /* Now check how many pages exactly we committed, and update accounting */ 1437 ASSERT(QuotaCharge >= QuotaExcess); 1438 QuotaCharge -= QuotaExcess; 1439 Segment->NumberOfCommittedPages += QuotaCharge; 1440 ASSERT(Segment->NumberOfCommittedPages <= Segment->TotalNumberOfPtes); 1441 1442 /* Now that we're done, release the lock */ 1443 KeReleaseGuardedMutex(&MmSectionCommitMutex); 1444 } 1445 1446 /* Is it SEC_BASED, or did the caller manually specify an address? */ 1447 if (*BaseAddress != NULL) 1448 { 1449 /* Just align what the caller gave us */ 1450 StartAddress = ALIGN_DOWN_BY((ULONG_PTR)*BaseAddress, Granularity); 1451 } 1452 else if (Section->Address.StartingVpn != 0) 1453 { 1454 /* It is a SEC_BASED mapping, use the address that was generated */ 1455 StartAddress = Section->Address.StartingVpn + SectionOffset->LowPart; 1456 } 1457 else 1458 { 1459 StartAddress = 0; 1460 } 1461 1462 /* Insert the VAD */ 1463 Status = MiInsertVadEx((PMMVAD)Vad, 1464 &StartAddress, 1465 ViewSizeInPages * PAGE_SIZE, 1466 MAXULONG_PTR >> ZeroBits, 1467 Granularity, 1468 AllocationType); 1469 if (!NT_SUCCESS(Status)) 1470 { 1471 return Status; 1472 } 1473 1474 /* Windows stores this for accounting purposes, do so as well */ 1475 if (!Segment->u2.FirstMappedVa) Segment->u2.FirstMappedVa = (PVOID)StartAddress; 1476 1477 /* Finally, let the caller know where, and for what size, the view was mapped */ 1478 *ViewSize = ViewSizeInPages * PAGE_SIZE; 1479 *BaseAddress = (PVOID)StartAddress; 1480 DPRINT("Start and region: 0x%p, 0x%p\n", *BaseAddress, *ViewSize); 1481 return STATUS_SUCCESS; 1482 } 1483 1484 VOID 1485 NTAPI 1486 MiSubsectionConsistent(IN PSUBSECTION Subsection) 1487 { 1488 /* ReactOS only supports systems with 4K pages and 4K sectors */ 1489 ASSERT(Subsection->u.SubsectionFlags.SectorEndOffset == 0); 1490 1491 /* Therefore, then number of PTEs should be equal to the number of sectors */ 1492 if (Subsection->NumberOfFullSectors != Subsection->PtesInSubsection) 1493 { 1494 /* Break and warn if this is inconsistent */ 1495 DPRINT1("Mm: Subsection inconsistent (%x vs %x)\n", 1496 Subsection->NumberOfFullSectors, Subsection->PtesInSubsection); 1497 DbgBreakPoint(); 1498 } 1499 } 1500 1501 NTSTATUS 1502 NTAPI 1503 MiCreateDataFileMap(IN PFILE_OBJECT File, 1504 OUT PSEGMENT *Segment, 1505 IN PSIZE_T MaximumSize, 1506 IN ULONG SectionPageProtection, 1507 IN ULONG AllocationAttributes, 1508 IN ULONG IgnoreFileSizing) 1509 { 1510 /* Not yet implemented */ 1511 ASSERT(FALSE); 1512 *Segment = NULL; 1513 return STATUS_NOT_IMPLEMENTED; 1514 } 1515 1516 static 1517 NTSTATUS 1518 NTAPI 1519 MiCreatePagingFileMap(OUT PSEGMENT *Segment, 1520 IN PLARGE_INTEGER MaximumSize, 1521 IN ULONG ProtectionMask, 1522 IN ULONG AllocationAttributes) 1523 { 1524 ULONGLONG SizeLimit; 1525 PFN_COUNT PteCount; 1526 PMMPTE PointerPte; 1527 MMPTE TempPte; 1528 PCONTROL_AREA ControlArea; 1529 PSEGMENT NewSegment; 1530 PSUBSECTION Subsection; 1531 PAGED_CODE(); 1532 1533 /* No large pages in ARM3 yet */ 1534 ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0); 1535 1536 /* Pagefile-backed sections need a known size */ 1537 if (!MaximumSize || !MaximumSize->QuadPart || MaximumSize->QuadPart < 0) 1538 return STATUS_INVALID_PARAMETER_4; 1539 1540 /* Calculate the maximum size possible, given the Prototype PTEs we'll need */ 1541 SizeLimit = MmSizeOfPagedPoolInBytes - sizeof(SEGMENT); 1542 SizeLimit /= sizeof(MMPTE); 1543 SizeLimit <<= PAGE_SHIFT; 1544 1545 /* Fail if this size is too big */ 1546 if (MaximumSize->QuadPart > SizeLimit) 1547 { 1548 return STATUS_SECTION_TOO_BIG; 1549 } 1550 1551 /* Calculate how many Prototype PTEs will be needed */ 1552 PteCount = (PFN_COUNT)((MaximumSize->QuadPart + PAGE_SIZE - 1) >> PAGE_SHIFT); 1553 1554 /* For commited memory, we must have a valid protection mask */ 1555 if (AllocationAttributes & SEC_COMMIT) ASSERT(ProtectionMask != 0); 1556 1557 /* The segment contains all the Prototype PTEs, allocate it in paged pool */ 1558 NewSegment = ExAllocatePoolWithTag(PagedPool, 1559 sizeof(SEGMENT) + 1560 sizeof(MMPTE) * (PteCount - 1), 1561 'tSmM'); 1562 if (!NewSegment) 1563 { 1564 return STATUS_INSUFFICIENT_RESOURCES; 1565 } 1566 *Segment = NewSegment; 1567 1568 /* Now allocate the control area, which has the subsection structure */ 1569 ControlArea = ExAllocatePoolWithTag(NonPagedPool, 1570 sizeof(CONTROL_AREA) + sizeof(SUBSECTION), 1571 'tCmM'); 1572 if (!ControlArea) 1573 { 1574 ExFreePoolWithTag(Segment, 'tSmM'); 1575 return STATUS_INSUFFICIENT_RESOURCES; 1576 } 1577 1578 /* And zero it out, filling the basic segmnet pointer and reference fields */ 1579 RtlZeroMemory(ControlArea, sizeof(CONTROL_AREA) + sizeof(SUBSECTION)); 1580 ControlArea->Segment = NewSegment; 1581 ControlArea->NumberOfSectionReferences = 1; 1582 ControlArea->NumberOfUserReferences = 1; 1583 1584 /* Convert allocation attributes to control area flags */ 1585 if (AllocationAttributes & SEC_BASED) ControlArea->u.Flags.Based = 1; 1586 if (AllocationAttributes & SEC_RESERVE) ControlArea->u.Flags.Reserve = 1; 1587 if (AllocationAttributes & SEC_COMMIT) ControlArea->u.Flags.Commit = 1; 1588 1589 /* We just allocated it */ 1590 ControlArea->u.Flags.BeingCreated = 1; 1591 1592 /* The subsection follows, write the mask, PTE count and point back to the CA */ 1593 Subsection = (PSUBSECTION)(ControlArea + 1); 1594 Subsection->ControlArea = ControlArea; 1595 Subsection->PtesInSubsection = PteCount; 1596 Subsection->u.SubsectionFlags.Protection = ProtectionMask; 1597 1598 /* Zero out the segment's prototype PTEs, and link it with the control area */ 1599 PointerPte = &NewSegment->ThePtes[0]; 1600 RtlZeroMemory(NewSegment, sizeof(SEGMENT)); 1601 NewSegment->PrototypePte = PointerPte; 1602 NewSegment->ControlArea = ControlArea; 1603 1604 /* Save some extra accounting data for the segment as well */ 1605 NewSegment->u1.CreatingProcess = PsGetCurrentProcess(); 1606 NewSegment->SizeOfSegment = ((ULONGLONG)PteCount) * PAGE_SIZE; 1607 NewSegment->TotalNumberOfPtes = PteCount; 1608 NewSegment->NonExtendedPtes = PteCount; 1609 1610 /* The subsection's base address is the first Prototype PTE in the segment */ 1611 Subsection->SubsectionBase = PointerPte; 1612 1613 /* Start with an empty PTE, unless this is a commit operation */ 1614 TempPte.u.Long = 0; 1615 if (AllocationAttributes & SEC_COMMIT) 1616 { 1617 /* In which case, write down the protection mask in the Prototype PTEs */ 1618 TempPte.u.Soft.Protection = ProtectionMask; 1619 1620 /* For accounting, also mark these pages as being committed */ 1621 NewSegment->NumberOfCommittedPages = PteCount; 1622 } 1623 1624 /* The template PTE itself for the segment should also have the mask set */ 1625 NewSegment->SegmentPteTemplate.u.Soft.Protection = ProtectionMask; 1626 1627 /* Write out the prototype PTEs, for now they're simply demand zero */ 1628 #ifdef _WIN64 1629 RtlFillMemoryUlonglong(PointerPte, PteCount * sizeof(MMPTE), TempPte.u.Long); 1630 #else 1631 RtlFillMemoryUlong(PointerPte, PteCount * sizeof(MMPTE), TempPte.u.Long); 1632 #endif 1633 return STATUS_SUCCESS; 1634 } 1635 1636 NTSTATUS 1637 NTAPI 1638 MiGetFileObjectForSectionAddress( 1639 IN PVOID Address, 1640 OUT PFILE_OBJECT *FileObject) 1641 { 1642 PMMVAD Vad; 1643 PCONTROL_AREA ControlArea; 1644 1645 /* Get the VAD */ 1646 Vad = MiLocateAddress(Address); 1647 if (Vad == NULL) 1648 { 1649 /* Fail, the address does not exist */ 1650 DPRINT1("Invalid address\n"); 1651 return STATUS_INVALID_ADDRESS; 1652 } 1653 1654 /* Check if this is a RosMm memory area */ 1655 if (Vad->u.VadFlags.Spare != 0) 1656 { 1657 PMEMORY_AREA MemoryArea = (PMEMORY_AREA)Vad; 1658 PROS_SECTION_OBJECT Section; 1659 1660 /* Check if it's a section view (RosMm section) */ 1661 if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) 1662 { 1663 /* Get the section pointer to the SECTION_OBJECT */ 1664 Section = MemoryArea->Data.SectionData.Section; 1665 *FileObject = Section->FileObject; 1666 } 1667 else 1668 { 1669 ASSERT(MemoryArea->Type == MEMORY_AREA_CACHE); 1670 DPRINT1("Address is a cache section!\n"); 1671 return STATUS_SECTION_NOT_IMAGE; 1672 } 1673 } 1674 else 1675 { 1676 /* Make sure it's not a VM VAD */ 1677 if (Vad->u.VadFlags.PrivateMemory == 1) 1678 { 1679 DPRINT1("Address is not a section\n"); 1680 return STATUS_SECTION_NOT_IMAGE; 1681 } 1682 1683 /* Get the control area */ 1684 ControlArea = Vad->ControlArea; 1685 if (!(ControlArea) || !(ControlArea->u.Flags.Image)) 1686 { 1687 DPRINT1("Address is not a section\n"); 1688 return STATUS_SECTION_NOT_IMAGE; 1689 } 1690 1691 /* Get the file object */ 1692 *FileObject = ControlArea->FilePointer; 1693 } 1694 1695 /* Return success */ 1696 return STATUS_SUCCESS; 1697 } 1698 1699 PFILE_OBJECT 1700 NTAPI 1701 MmGetFileObjectForSection(IN PVOID SectionObject) 1702 { 1703 PSECTION_OBJECT Section; 1704 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); 1705 ASSERT(SectionObject != NULL); 1706 1707 /* Check if it's an ARM3, or ReactOS section */ 1708 if (MiIsRosSectionObject(SectionObject) == FALSE) 1709 { 1710 /* Return the file pointer stored in the control area */ 1711 Section = SectionObject; 1712 return Section->Segment->ControlArea->FilePointer; 1713 } 1714 1715 /* Return the file object */ 1716 return ((PROS_SECTION_OBJECT)SectionObject)->FileObject; 1717 } 1718 1719 static 1720 PFILE_OBJECT 1721 MiGetFileObjectForVad( 1722 _In_ PMMVAD Vad) 1723 { 1724 PCONTROL_AREA ControlArea; 1725 PFILE_OBJECT FileObject; 1726 1727 /* Check if this is a RosMm memory area */ 1728 if (Vad->u.VadFlags.Spare != 0) 1729 { 1730 PMEMORY_AREA MemoryArea = (PMEMORY_AREA)Vad; 1731 PROS_SECTION_OBJECT Section; 1732 1733 /* Check if it's a section view (RosMm section) */ 1734 if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) 1735 { 1736 /* Get the section pointer to the SECTION_OBJECT */ 1737 Section = MemoryArea->Data.SectionData.Section; 1738 FileObject = Section->FileObject; 1739 } 1740 else 1741 { 1742 ASSERT(MemoryArea->Type == MEMORY_AREA_CACHE); 1743 DPRINT1("VAD is a cache section!\n"); 1744 return NULL; 1745 } 1746 } 1747 else 1748 { 1749 /* Make sure it's not a VM VAD */ 1750 if (Vad->u.VadFlags.PrivateMemory == 1) 1751 { 1752 DPRINT1("VAD is not a section\n"); 1753 return NULL; 1754 } 1755 1756 /* Get the control area */ 1757 ControlArea = Vad->ControlArea; 1758 if ((ControlArea == NULL) || !ControlArea->u.Flags.Image) 1759 { 1760 DPRINT1("Address is not a section\n"); 1761 return NULL; 1762 } 1763 1764 /* Get the file object */ 1765 FileObject = ControlArea->FilePointer; 1766 } 1767 1768 /* Return the file object */ 1769 return FileObject; 1770 } 1771 1772 VOID 1773 NTAPI 1774 MmGetImageInformation (OUT PSECTION_IMAGE_INFORMATION ImageInformation) 1775 { 1776 PSECTION_OBJECT SectionObject; 1777 1778 /* Get the section object of this process*/ 1779 SectionObject = PsGetCurrentProcess()->SectionObject; 1780 ASSERT(SectionObject != NULL); 1781 ASSERT(MiIsRosSectionObject(SectionObject) == TRUE); 1782 1783 /* Return the image information */ 1784 *ImageInformation = ((PROS_SECTION_OBJECT)SectionObject)->ImageSection->ImageInformation; 1785 } 1786 1787 NTSTATUS 1788 NTAPI 1789 MmGetFileNameForFileObject(IN PFILE_OBJECT FileObject, 1790 OUT POBJECT_NAME_INFORMATION *ModuleName) 1791 { 1792 POBJECT_NAME_INFORMATION ObjectNameInfo; 1793 NTSTATUS Status; 1794 ULONG ReturnLength; 1795 1796 /* Allocate memory for our structure */ 1797 ObjectNameInfo = ExAllocatePoolWithTag(PagedPool, 1024, TAG_MM); 1798 if (!ObjectNameInfo) return STATUS_NO_MEMORY; 1799 1800 /* Query the name */ 1801 Status = ObQueryNameString(FileObject, 1802 ObjectNameInfo, 1803 1024, 1804 &ReturnLength); 1805 if (!NT_SUCCESS(Status)) 1806 { 1807 /* Failed, free memory */ 1808 DPRINT1("Name query failed\n"); 1809 ExFreePoolWithTag(ObjectNameInfo, TAG_MM); 1810 *ModuleName = NULL; 1811 return Status; 1812 } 1813 1814 /* Success */ 1815 *ModuleName = ObjectNameInfo; 1816 return STATUS_SUCCESS; 1817 } 1818 1819 NTSTATUS 1820 NTAPI 1821 MmGetFileNameForSection(IN PVOID Section, 1822 OUT POBJECT_NAME_INFORMATION *ModuleName) 1823 { 1824 PFILE_OBJECT FileObject; 1825 1826 /* Make sure it's an image section */ 1827 if (MiIsRosSectionObject(Section) == FALSE) 1828 { 1829 /* Check ARM3 Section flag */ 1830 if (((PSECTION)Section)->u.Flags.Image == 0) 1831 { 1832 /* It's not, fail */ 1833 DPRINT1("Not an image section\n"); 1834 return STATUS_SECTION_NOT_IMAGE; 1835 } 1836 } 1837 else if (!(((PROS_SECTION_OBJECT)Section)->AllocationAttributes & SEC_IMAGE)) 1838 { 1839 /* It's not, fail */ 1840 DPRINT1("Not an image section\n"); 1841 return STATUS_SECTION_NOT_IMAGE; 1842 } 1843 1844 /* Get the file object */ 1845 FileObject = MmGetFileObjectForSection(Section); 1846 return MmGetFileNameForFileObject(FileObject, ModuleName); 1847 } 1848 1849 NTSTATUS 1850 NTAPI 1851 MmGetFileNameForAddress(IN PVOID Address, 1852 OUT PUNICODE_STRING ModuleName) 1853 { 1854 POBJECT_NAME_INFORMATION ModuleNameInformation; 1855 PVOID AddressSpace; 1856 NTSTATUS Status; 1857 PMMVAD Vad; 1858 PFILE_OBJECT FileObject = NULL; 1859 1860 /* Lock address space */ 1861 AddressSpace = MmGetCurrentAddressSpace(); 1862 MmLockAddressSpace(AddressSpace); 1863 1864 /* Get the VAD */ 1865 Vad = MiLocateAddress(Address); 1866 if (Vad == NULL) 1867 { 1868 /* Fail, the address does not exist */ 1869 DPRINT1("No VAD at address %p\n", Address); 1870 MmUnlockAddressSpace(AddressSpace); 1871 return STATUS_INVALID_ADDRESS; 1872 } 1873 1874 /* Get the file object pointer for the VAD */ 1875 FileObject = MiGetFileObjectForVad(Vad); 1876 if (FileObject == NULL) 1877 { 1878 DPRINT1("Failed to get file object for Address %p\n", Address); 1879 MmUnlockAddressSpace(AddressSpace); 1880 return STATUS_SECTION_NOT_IMAGE; 1881 } 1882 1883 /* Reference the file object */ 1884 ObReferenceObject(FileObject); 1885 1886 /* Unlock address space */ 1887 MmUnlockAddressSpace(AddressSpace); 1888 1889 /* Get the filename of the file object */ 1890 Status = MmGetFileNameForFileObject(FileObject, &ModuleNameInformation); 1891 1892 /* Dereference the file object */ 1893 ObDereferenceObject(FileObject); 1894 1895 /* Check if we were able to get the file object name */ 1896 if (NT_SUCCESS(Status)) 1897 { 1898 /* Init modulename */ 1899 RtlCreateUnicodeString(ModuleName, ModuleNameInformation->Name.Buffer); 1900 1901 /* Free temp taged buffer from MmGetFileNameForFileObject() */ 1902 ExFreePoolWithTag(ModuleNameInformation, TAG_MM); 1903 DPRINT("Found ModuleName %S by address %p\n", ModuleName->Buffer, Address); 1904 } 1905 1906 /* Return status */ 1907 return Status; 1908 } 1909 1910 NTSTATUS 1911 NTAPI 1912 MiQueryMemorySectionName(IN HANDLE ProcessHandle, 1913 IN PVOID BaseAddress, 1914 OUT PVOID MemoryInformation, 1915 IN SIZE_T MemoryInformationLength, 1916 OUT PSIZE_T ReturnLength) 1917 { 1918 PEPROCESS Process; 1919 NTSTATUS Status; 1920 UNICODE_STRING ModuleFileName; 1921 PMEMORY_SECTION_NAME SectionName = NULL; 1922 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1923 1924 Status = ObReferenceObjectByHandle(ProcessHandle, 1925 PROCESS_QUERY_INFORMATION, 1926 NULL, 1927 PreviousMode, 1928 (PVOID*)(&Process), 1929 NULL); 1930 1931 if (!NT_SUCCESS(Status)) 1932 { 1933 DPRINT("MiQueryMemorySectionName: ObReferenceObjectByHandle returned %x\n",Status); 1934 return Status; 1935 } 1936 1937 Status = MmGetFileNameForAddress(BaseAddress, &ModuleFileName); 1938 1939 if (NT_SUCCESS(Status)) 1940 { 1941 SectionName = MemoryInformation; 1942 if (PreviousMode != KernelMode) 1943 { 1944 _SEH2_TRY 1945 { 1946 RtlInitEmptyUnicodeString(&SectionName->SectionFileName, 1947 (PWSTR)(SectionName + 1), 1948 MemoryInformationLength - sizeof(MEMORY_SECTION_NAME)); 1949 RtlCopyUnicodeString(&SectionName->SectionFileName, &ModuleFileName); 1950 1951 if (ReturnLength) *ReturnLength = ModuleFileName.Length + sizeof(MEMORY_SECTION_NAME); 1952 1953 } 1954 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1955 { 1956 Status = _SEH2_GetExceptionCode(); 1957 } 1958 _SEH2_END; 1959 } 1960 else 1961 { 1962 RtlInitEmptyUnicodeString(&SectionName->SectionFileName, 1963 (PWSTR)(SectionName + 1), 1964 MemoryInformationLength - sizeof(MEMORY_SECTION_NAME)); 1965 RtlCopyUnicodeString(&SectionName->SectionFileName, &ModuleFileName); 1966 1967 if (ReturnLength) *ReturnLength = ModuleFileName.Length + sizeof(MEMORY_SECTION_NAME); 1968 1969 } 1970 1971 RtlFreeUnicodeString(&ModuleFileName); 1972 } 1973 ObDereferenceObject(Process); 1974 return Status; 1975 } 1976 1977 VOID 1978 NTAPI 1979 MiFlushTbAndCapture(IN PMMVAD FoundVad, 1980 IN PMMPTE PointerPte, 1981 IN ULONG ProtectionMask, 1982 IN PMMPFN Pfn1, 1983 IN BOOLEAN UpdateDirty) 1984 { 1985 MMPTE TempPte, PreviousPte; 1986 KIRQL OldIrql; 1987 BOOLEAN RebuildPte = FALSE; 1988 1989 // 1990 // User for sanity checking later on 1991 // 1992 PreviousPte = *PointerPte; 1993 1994 // 1995 // Build the PTE and acquire the PFN lock 1996 // 1997 MI_MAKE_HARDWARE_PTE_USER(&TempPte, 1998 PointerPte, 1999 ProtectionMask, 2000 PreviousPte.u.Hard.PageFrameNumber); 2001 OldIrql = MiAcquirePfnLock(); 2002 2003 // 2004 // We don't support I/O mappings in this path yet 2005 // 2006 ASSERT(Pfn1 != NULL); 2007 ASSERT(Pfn1->u3.e1.CacheAttribute != MiWriteCombined); 2008 2009 // 2010 // Make sure new protection mask doesn't get in conflict and fix it if it does 2011 // 2012 if (Pfn1->u3.e1.CacheAttribute == MiCached) 2013 { 2014 // 2015 // This is a cached PFN 2016 // 2017 if (ProtectionMask & (MM_NOCACHE | MM_NOACCESS)) 2018 { 2019 RebuildPte = TRUE; 2020 ProtectionMask &= ~(MM_NOCACHE | MM_NOACCESS); 2021 } 2022 } 2023 else if (Pfn1->u3.e1.CacheAttribute == MiNonCached) 2024 { 2025 // 2026 // This is a non-cached PFN 2027 // 2028 if ((ProtectionMask & (MM_NOCACHE | MM_NOACCESS)) != MM_NOCACHE) 2029 { 2030 RebuildPte = TRUE; 2031 ProtectionMask &= ~MM_NOACCESS; 2032 ProtectionMask |= MM_NOCACHE; 2033 } 2034 } 2035 2036 if (RebuildPte) 2037 { 2038 MI_MAKE_HARDWARE_PTE_USER(&TempPte, 2039 PointerPte, 2040 ProtectionMask, 2041 PreviousPte.u.Hard.PageFrameNumber); 2042 } 2043 2044 // 2045 // Write the new PTE, making sure we are only changing the bits 2046 // 2047 MI_UPDATE_VALID_PTE(PointerPte, TempPte); 2048 2049 // 2050 // Flush the TLB 2051 // 2052 ASSERT(PreviousPte.u.Hard.Valid == 1); 2053 KeFlushCurrentTb(); 2054 ASSERT(PreviousPte.u.Hard.Valid == 1); 2055 2056 // 2057 // Windows updates the relevant PFN1 information, we currently don't. 2058 // 2059 if (UpdateDirty && PreviousPte.u.Hard.Dirty) 2060 { 2061 if (!Pfn1->u3.e1.Modified) 2062 { 2063 DPRINT1("FIXME: Mark PFN as dirty\n"); 2064 } 2065 } 2066 2067 // 2068 // Not supported in ARM3 2069 // 2070 ASSERT(FoundVad->u.VadFlags.VadType != VadWriteWatch); 2071 2072 // 2073 // Release the PFN lock, we are done 2074 // 2075 MiReleasePfnLock(OldIrql); 2076 } 2077 2078 // 2079 // NOTE: This function gets a lot more complicated if we want Copy-on-Write support 2080 // 2081 NTSTATUS 2082 NTAPI 2083 MiSetProtectionOnSection(IN PEPROCESS Process, 2084 IN PMMVAD FoundVad, 2085 IN PVOID StartingAddress, 2086 IN PVOID EndingAddress, 2087 IN ULONG NewProtect, 2088 OUT PULONG CapturedOldProtect, 2089 IN ULONG DontCharge, 2090 OUT PULONG Locked) 2091 { 2092 PMMPTE PointerPte, LastPte; 2093 MMPTE TempPte, PteContents; 2094 PMMPDE PointerPde; 2095 PMMPFN Pfn1; 2096 ULONG ProtectionMask, QuotaCharge = 0; 2097 PETHREAD Thread = PsGetCurrentThread(); 2098 PAGED_CODE(); 2099 2100 // 2101 // Tell caller nothing is being locked 2102 // 2103 *Locked = FALSE; 2104 2105 // 2106 // This function should only be used for section VADs. Windows ASSERT */ 2107 // 2108 ASSERT(FoundVad->u.VadFlags.PrivateMemory == 0); 2109 2110 // 2111 // We don't support these features in ARM3 2112 // 2113 ASSERT(FoundVad->u.VadFlags.VadType != VadImageMap); 2114 ASSERT(FoundVad->u2.VadFlags2.CopyOnWrite == 0); 2115 2116 // 2117 // Convert and validate the protection mask 2118 // 2119 ProtectionMask = MiMakeProtectionMask(NewProtect); 2120 if (ProtectionMask == MM_INVALID_PROTECTION) 2121 { 2122 DPRINT1("Invalid section protect\n"); 2123 return STATUS_INVALID_PAGE_PROTECTION; 2124 } 2125 2126 // 2127 // Get the PTE and PDE for the address, as well as the final PTE 2128 // 2129 MiLockProcessWorkingSetUnsafe(Process, Thread); 2130 PointerPde = MiAddressToPde(StartingAddress); 2131 PointerPte = MiAddressToPte(StartingAddress); 2132 LastPte = MiAddressToPte(EndingAddress); 2133 2134 // 2135 // Make the PDE valid, and check the status of the first PTE 2136 // 2137 MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL); 2138 if (PointerPte->u.Long) 2139 { 2140 // 2141 // Not supported in ARM3 2142 // 2143 ASSERT(FoundVad->u.VadFlags.VadType != VadRotatePhysical); 2144 2145 // 2146 // Capture the page protection and make the PDE valid 2147 // 2148 *CapturedOldProtect = MiGetPageProtection(PointerPte); 2149 MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL); 2150 } 2151 else 2152 { 2153 // 2154 // Only pagefile-backed section VADs are supported for now 2155 // 2156 ASSERT(FoundVad->u.VadFlags.VadType != VadImageMap); 2157 2158 // 2159 // Grab the old protection from the VAD itself 2160 // 2161 *CapturedOldProtect = MmProtectToValue[FoundVad->u.VadFlags.Protection]; 2162 } 2163 2164 // 2165 // Loop all the PTEs now 2166 // 2167 MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL); 2168 while (PointerPte <= LastPte) 2169 { 2170 // 2171 // Check if we've crossed a PDE boundary and make the new PDE valid too 2172 // 2173 if (MiIsPteOnPdeBoundary(PointerPte)) 2174 { 2175 PointerPde = MiPteToPde(PointerPte); 2176 MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL); 2177 } 2178 2179 // 2180 // Capture the PTE and see what we're dealing with 2181 // 2182 PteContents = *PointerPte; 2183 if (PteContents.u.Long == 0) 2184 { 2185 // 2186 // This used to be a zero PTE and it no longer is, so we must add a 2187 // reference to the pagetable. 2188 // 2189 MiIncrementPageTableReferences(MiPteToAddress(PointerPte)); 2190 2191 // 2192 // Create the demand-zero prototype PTE 2193 // 2194 TempPte = PrototypePte; 2195 TempPte.u.Soft.Protection = ProtectionMask; 2196 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 2197 } 2198 else if (PteContents.u.Hard.Valid == 1) 2199 { 2200 // 2201 // Get the PFN entry 2202 // 2203 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents)); 2204 2205 // 2206 // We don't support these yet 2207 // 2208 ASSERT((NewProtect & (PAGE_NOACCESS | PAGE_GUARD)) == 0); 2209 ASSERT(Pfn1->u3.e1.PrototypePte == 0); 2210 2211 // 2212 // Write the protection mask and write it with a TLB flush 2213 // 2214 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask; 2215 MiFlushTbAndCapture(FoundVad, 2216 PointerPte, 2217 ProtectionMask, 2218 Pfn1, 2219 TRUE); 2220 } 2221 else 2222 { 2223 // 2224 // We don't support these cases yet 2225 // 2226 ASSERT(PteContents.u.Soft.Prototype == 0); 2227 ASSERT(PteContents.u.Soft.Transition == 0); 2228 2229 // 2230 // The PTE is already demand-zero, just update the protection mask 2231 // 2232 PointerPte->u.Soft.Protection = ProtectionMask; 2233 } 2234 2235 PointerPte++; 2236 } 2237 2238 // 2239 // Unlock the working set and update quota charges if needed, then return 2240 // 2241 MiUnlockProcessWorkingSetUnsafe(Process, Thread); 2242 if ((QuotaCharge > 0) && (!DontCharge)) 2243 { 2244 FoundVad->u.VadFlags.CommitCharge -= QuotaCharge; 2245 Process->CommitCharge -= QuotaCharge; 2246 } 2247 return STATUS_SUCCESS; 2248 } 2249 2250 VOID 2251 NTAPI 2252 MiRemoveMappedPtes(IN PVOID BaseAddress, 2253 IN ULONG NumberOfPtes, 2254 IN PCONTROL_AREA ControlArea, 2255 IN PMMSUPPORT Ws) 2256 { 2257 PMMPTE PointerPte, ProtoPte;//, FirstPte; 2258 PMMPDE PointerPde, SystemMapPde; 2259 PMMPFN Pfn1, Pfn2; 2260 MMPTE PteContents; 2261 KIRQL OldIrql; 2262 DPRINT("Removing mapped view at: 0x%p\n", BaseAddress); 2263 2264 ASSERT(Ws == NULL); 2265 2266 /* Get the PTE and loop each one */ 2267 PointerPte = MiAddressToPte(BaseAddress); 2268 //FirstPte = PointerPte; 2269 while (NumberOfPtes) 2270 { 2271 /* Check if the PTE is already valid */ 2272 PteContents = *PointerPte; 2273 if (PteContents.u.Hard.Valid == 1) 2274 { 2275 /* Get the PFN entry */ 2276 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents)); 2277 2278 /* Get the PTE */ 2279 PointerPde = MiPteToPde(PointerPte); 2280 2281 /* Lock the PFN database and make sure this isn't a mapped file */ 2282 OldIrql = MiAcquirePfnLock(); 2283 ASSERT(((Pfn1->u3.e1.PrototypePte) && (Pfn1->OriginalPte.u.Soft.Prototype)) == 0); 2284 2285 /* Mark the page as modified accordingly */ 2286 if (MI_IS_PAGE_DIRTY(&PteContents)) 2287 Pfn1->u3.e1.Modified = 1; 2288 2289 /* Was the PDE invalid */ 2290 if (PointerPde->u.Long == 0) 2291 { 2292 #if (_MI_PAGING_LEVELS == 2) 2293 /* Find the system double-mapped PDE that describes this mapping */ 2294 SystemMapPde = &MmSystemPagePtes[((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE)]; 2295 2296 /* Make it valid */ 2297 ASSERT(SystemMapPde->u.Hard.Valid == 1); 2298 MI_WRITE_VALID_PDE(PointerPde, *SystemMapPde); 2299 #else 2300 DBG_UNREFERENCED_LOCAL_VARIABLE(SystemMapPde); 2301 ASSERT(FALSE); 2302 #endif 2303 } 2304 2305 /* Dereference the PDE and the PTE */ 2306 Pfn2 = MiGetPfnEntry(PFN_FROM_PTE(PointerPde)); 2307 MiDecrementShareCount(Pfn2, PFN_FROM_PTE(PointerPde)); 2308 DBG_UNREFERENCED_LOCAL_VARIABLE(Pfn2); 2309 MiDecrementShareCount(Pfn1, PFN_FROM_PTE(&PteContents)); 2310 2311 /* Release the PFN lock */ 2312 MiReleasePfnLock(OldIrql); 2313 } 2314 else 2315 { 2316 /* Windows ASSERT */ 2317 ASSERT((PteContents.u.Long == 0) || (PteContents.u.Soft.Prototype == 1)); 2318 2319 /* Check if this is a prototype pointer PTE */ 2320 if (PteContents.u.Soft.Prototype == 1) 2321 { 2322 /* Get the prototype PTE */ 2323 ProtoPte = MiProtoPteToPte(&PteContents); 2324 2325 /* We don't support anything else atm */ 2326 ASSERT(ProtoPte->u.Long == 0); 2327 } 2328 } 2329 2330 /* Make the PTE into a zero PTE */ 2331 PointerPte->u.Long = 0; 2332 2333 /* Move to the next PTE */ 2334 PointerPte++; 2335 NumberOfPtes--; 2336 } 2337 2338 /* Flush the TLB */ 2339 KeFlushCurrentTb(); 2340 2341 /* Acquire the PFN lock */ 2342 OldIrql = MiAcquirePfnLock(); 2343 2344 /* Decrement the accounting counters */ 2345 ControlArea->NumberOfUserReferences--; 2346 ControlArea->NumberOfMappedViews--; 2347 2348 /* Check if we should destroy the CA and release the lock */ 2349 MiCheckControlArea(ControlArea, OldIrql); 2350 } 2351 2352 ULONG 2353 NTAPI 2354 MiRemoveFromSystemSpace(IN PMMSESSION Session, 2355 IN PVOID Base, 2356 OUT PCONTROL_AREA *ControlArea) 2357 { 2358 ULONG Hash, Size, Count = 0; 2359 ULONG_PTR Entry; 2360 PAGED_CODE(); 2361 2362 /* Compute the hash for this entry and loop trying to find it */ 2363 Entry = (ULONG_PTR)Base >> 16; 2364 Hash = Entry % Session->SystemSpaceHashKey; 2365 while ((Session->SystemSpaceViewTable[Hash].Entry >> 16) != Entry) 2366 { 2367 /* Check if we overflew past the end of the hash table */ 2368 if (++Hash >= Session->SystemSpaceHashSize) 2369 { 2370 /* Reset the hash to zero and keep searching from the bottom */ 2371 Hash = 0; 2372 if (++Count == 2) 2373 { 2374 /* But if we overflew twice, then this is not a real mapping */ 2375 KeBugCheckEx(DRIVER_UNMAPPING_INVALID_VIEW, 2376 (ULONG_PTR)Base, 2377 1, 2378 0, 2379 0); 2380 } 2381 } 2382 } 2383 2384 /* One less entry */ 2385 Session->SystemSpaceHashEntries--; 2386 2387 /* Extract the size and clear the entry */ 2388 Size = Session->SystemSpaceViewTable[Hash].Entry & 0xFFFF; 2389 Session->SystemSpaceViewTable[Hash].Entry = 0; 2390 2391 /* Return the control area and the size */ 2392 *ControlArea = Session->SystemSpaceViewTable[Hash].ControlArea; 2393 return Size; 2394 } 2395 2396 NTSTATUS 2397 NTAPI 2398 MiUnmapViewInSystemSpace(IN PMMSESSION Session, 2399 IN PVOID MappedBase) 2400 { 2401 ULONG Size; 2402 PCONTROL_AREA ControlArea; 2403 PAGED_CODE(); 2404 2405 /* Remove this mapping */ 2406 KeAcquireGuardedMutex(Session->SystemSpaceViewLockPointer); 2407 Size = MiRemoveFromSystemSpace(Session, MappedBase, &ControlArea); 2408 2409 /* Clear the bits for this mapping */ 2410 RtlClearBits(Session->SystemSpaceBitMap, 2411 (ULONG)(((ULONG_PTR)MappedBase - (ULONG_PTR)Session->SystemSpaceViewStart) >> 16), 2412 Size); 2413 2414 /* Convert the size from a bit size into the actual size */ 2415 Size = Size * (_64K >> PAGE_SHIFT); 2416 2417 /* Remove the PTEs now */ 2418 MiRemoveMappedPtes(MappedBase, Size, ControlArea, NULL); 2419 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 2420 2421 /* Return success */ 2422 return STATUS_SUCCESS; 2423 } 2424 2425 /* PUBLIC FUNCTIONS ***********************************************************/ 2426 2427 /* 2428 * @implemented 2429 */ 2430 NTSTATUS 2431 NTAPI 2432 MmCreateArm3Section(OUT PVOID *SectionObject, 2433 IN ACCESS_MASK DesiredAccess, 2434 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 2435 IN PLARGE_INTEGER InputMaximumSize, 2436 IN ULONG SectionPageProtection, 2437 IN ULONG AllocationAttributes, 2438 IN HANDLE FileHandle OPTIONAL, 2439 IN PFILE_OBJECT FileObject OPTIONAL) 2440 { 2441 SECTION Section; 2442 PSECTION NewSection; 2443 PSUBSECTION Subsection; 2444 PSEGMENT NewSegment, Segment; 2445 NTSTATUS Status; 2446 PCONTROL_AREA ControlArea; 2447 ULONG ProtectionMask, ControlAreaSize, Size, NonPagedCharge, PagedCharge; 2448 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 2449 BOOLEAN FileLock = FALSE, KernelCall = FALSE; 2450 KIRQL OldIrql; 2451 PFILE_OBJECT File; 2452 BOOLEAN UserRefIncremented = FALSE; 2453 PVOID PreviousSectionPointer; 2454 2455 /* Make the same sanity checks that the Nt interface should've validated */ 2456 ASSERT((AllocationAttributes & ~(SEC_COMMIT | SEC_RESERVE | SEC_BASED | 2457 SEC_LARGE_PAGES | SEC_IMAGE | SEC_NOCACHE | 2458 SEC_NO_CHANGE)) == 0); 2459 ASSERT((AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_IMAGE)) != 0); 2460 ASSERT(!((AllocationAttributes & SEC_IMAGE) && 2461 (AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | 2462 SEC_NOCACHE | SEC_NO_CHANGE)))); 2463 ASSERT(!((AllocationAttributes & SEC_COMMIT) && (AllocationAttributes & SEC_RESERVE))); 2464 ASSERT(!((SectionPageProtection & PAGE_NOCACHE) || 2465 (SectionPageProtection & PAGE_WRITECOMBINE) || 2466 (SectionPageProtection & PAGE_GUARD) || 2467 (SectionPageProtection & PAGE_NOACCESS))); 2468 2469 /* Convert section flag to page flag */ 2470 if (AllocationAttributes & SEC_NOCACHE) SectionPageProtection |= PAGE_NOCACHE; 2471 2472 /* Check to make sure the protection is correct. Nt* does this already */ 2473 ProtectionMask = MiMakeProtectionMask(SectionPageProtection); 2474 if (ProtectionMask == MM_INVALID_PROTECTION) return STATUS_INVALID_PAGE_PROTECTION; 2475 2476 /* Check if this is going to be a data or image backed file section */ 2477 if ((FileHandle) || (FileObject)) 2478 { 2479 /* These cannot be mapped with large pages */ 2480 if (AllocationAttributes & SEC_LARGE_PAGES) return STATUS_INVALID_PARAMETER_6; 2481 2482 /* For now, only support the mechanism through a file handle */ 2483 ASSERT(FileObject == NULL); 2484 2485 /* Reference the file handle to get the object */ 2486 Status = ObReferenceObjectByHandle(FileHandle, 2487 MmMakeFileAccess[ProtectionMask], 2488 IoFileObjectType, 2489 PreviousMode, 2490 (PVOID*)&File, 2491 NULL); 2492 if (!NT_SUCCESS(Status)) return Status; 2493 2494 /* Make sure Cc has been doing its job */ 2495 if (!File->SectionObjectPointer) 2496 { 2497 /* This is not a valid file system-based file, fail */ 2498 ObDereferenceObject(File); 2499 return STATUS_INVALID_FILE_FOR_SECTION; 2500 } 2501 2502 /* Image-file backed sections are not yet supported */ 2503 ASSERT((AllocationAttributes & SEC_IMAGE) == 0); 2504 2505 /* Compute the size of the control area, and allocate it */ 2506 ControlAreaSize = sizeof(CONTROL_AREA) + sizeof(MSUBSECTION); 2507 ControlArea = ExAllocatePoolWithTag(NonPagedPool, ControlAreaSize, 'aCmM'); 2508 if (!ControlArea) 2509 { 2510 ObDereferenceObject(File); 2511 return STATUS_INSUFFICIENT_RESOURCES; 2512 } 2513 2514 /* Zero it out */ 2515 RtlZeroMemory(ControlArea, ControlAreaSize); 2516 2517 /* Did we get a handle, or an object? */ 2518 if (FileHandle) 2519 { 2520 /* We got a file handle so we have to lock down the file */ 2521 #if 0 2522 Status = FsRtlAcquireToCreateMappedSection(File, SectionPageProtection); 2523 if (!NT_SUCCESS(Status)) 2524 { 2525 ExFreePool(ControlArea); 2526 ObDereferenceObject(File); 2527 return Status; 2528 } 2529 #else 2530 /* ReactOS doesn't support this API yet, so do nothing */ 2531 Status = STATUS_SUCCESS; 2532 #endif 2533 /* Update the top-level IRP so that drivers know what's happening */ 2534 IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP); 2535 FileLock = TRUE; 2536 } 2537 2538 /* Lock the PFN database while we play with the section pointers */ 2539 OldIrql = MiAcquirePfnLock(); 2540 2541 /* Image-file backed sections are not yet supported */ 2542 ASSERT((AllocationAttributes & SEC_IMAGE) == 0); 2543 2544 /* There should not already be a control area for this file */ 2545 ASSERT(File->SectionObjectPointer->DataSectionObject == NULL); 2546 NewSegment = NULL; 2547 2548 /* Write down that this CA is being created, and set it */ 2549 ControlArea->u.Flags.BeingCreated = TRUE; 2550 ASSERT((AllocationAttributes & SEC_IMAGE) == 0); 2551 PreviousSectionPointer = File->SectionObjectPointer; 2552 File->SectionObjectPointer->DataSectionObject = ControlArea; 2553 2554 /* We can release the PFN lock now */ 2555 MiReleasePfnLock(OldIrql); 2556 2557 /* We don't support previously-mapped file */ 2558 ASSERT(NewSegment == NULL); 2559 2560 /* Image-file backed sections are not yet supported */ 2561 ASSERT((AllocationAttributes & SEC_IMAGE) == 0); 2562 2563 /* So we always create a data file map */ 2564 Status = MiCreateDataFileMap(File, 2565 &Segment, 2566 (PSIZE_T)InputMaximumSize, 2567 SectionPageProtection, 2568 AllocationAttributes, 2569 KernelCall); 2570 if (!NT_SUCCESS(Status)) 2571 { 2572 /* Lock the PFN database while we play with the section pointers */ 2573 OldIrql = MiAcquirePfnLock(); 2574 2575 /* Reset the waiting-for-deletion event */ 2576 ASSERT(ControlArea->WaitingForDeletion == NULL); 2577 ControlArea->WaitingForDeletion = NULL; 2578 2579 /* Set the file pointer NULL flag */ 2580 ASSERT(ControlArea->u.Flags.FilePointerNull == 0); 2581 ControlArea->u.Flags.FilePointerNull = TRUE; 2582 2583 /* Delete the data section object */ 2584 ASSERT((AllocationAttributes & SEC_IMAGE) == 0); 2585 File->SectionObjectPointer->DataSectionObject = NULL; 2586 2587 /* No longer being created */ 2588 ControlArea->u.Flags.BeingCreated = FALSE; 2589 2590 /* We can release the PFN lock now */ 2591 MiReleasePfnLock(OldIrql); 2592 2593 /* Check if we locked and set the IRP */ 2594 if (FileLock) 2595 { 2596 /* Undo */ 2597 IoSetTopLevelIrp(NULL); 2598 //FsRtlReleaseFile(File); 2599 } 2600 2601 /* Free the control area and de-ref the file object */ 2602 ExFreePool(ControlArea); 2603 ObDereferenceObject(File); 2604 2605 /* All done */ 2606 return Status; 2607 } 2608 2609 /* On success, we expect this */ 2610 ASSERT(PreviousSectionPointer == File->SectionObjectPointer); 2611 2612 /* Check if a maximum size was specified */ 2613 if (!InputMaximumSize->QuadPart) 2614 { 2615 /* Nope, use the segment size */ 2616 Section.SizeOfSection.QuadPart = (LONGLONG)Segment->SizeOfSegment; 2617 } 2618 else 2619 { 2620 /* Yep, use the entered size */ 2621 Section.SizeOfSection.QuadPart = InputMaximumSize->QuadPart; 2622 } 2623 } 2624 else 2625 { 2626 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */ 2627 if (AllocationAttributes & SEC_IMAGE) return STATUS_INVALID_FILE_FOR_SECTION; 2628 2629 /* Not yet supported */ 2630 ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0); 2631 2632 /* So this must be a pagefile-backed section, create the mappings needed */ 2633 Status = MiCreatePagingFileMap(&NewSegment, 2634 InputMaximumSize, 2635 ProtectionMask, 2636 AllocationAttributes); 2637 if (!NT_SUCCESS(Status)) return Status; 2638 2639 /* Set the size here, and read the control area */ 2640 Section.SizeOfSection.QuadPart = NewSegment->SizeOfSegment; 2641 ControlArea = NewSegment->ControlArea; 2642 2643 /* MiCreatePagingFileMap increments user references */ 2644 UserRefIncremented = TRUE; 2645 } 2646 2647 /* Did we already have a segment? */ 2648 if (!NewSegment) 2649 { 2650 /* This must be the file path and we created a segment */ 2651 NewSegment = Segment; 2652 ASSERT(File != NULL); 2653 2654 /* Acquire the PFN lock while we set control area flags */ 2655 OldIrql = MiAcquirePfnLock(); 2656 2657 /* We don't support this race condition yet, so assume no waiters */ 2658 ASSERT(ControlArea->WaitingForDeletion == NULL); 2659 ControlArea->WaitingForDeletion = NULL; 2660 2661 /* Image-file backed sections are not yet supported, nor ROM images */ 2662 ASSERT((AllocationAttributes & SEC_IMAGE) == 0); 2663 ASSERT(Segment->ControlArea->u.Flags.Rom == 0); 2664 2665 /* Take off the being created flag, and then release the lock */ 2666 ControlArea->u.Flags.BeingCreated = FALSE; 2667 MiReleasePfnLock(OldIrql); 2668 } 2669 2670 /* Check if we locked the file earlier */ 2671 if (FileLock) 2672 { 2673 /* Reset the top-level IRP and release the lock */ 2674 IoSetTopLevelIrp(NULL); 2675 //FsRtlReleaseFile(File); 2676 FileLock = FALSE; 2677 } 2678 2679 /* Set the initial section object data */ 2680 Section.InitialPageProtection = SectionPageProtection; 2681 2682 /* The mapping created a control area and segment, save the flags */ 2683 Section.Segment = NewSegment; 2684 Section.u.LongFlags = ControlArea->u.LongFlags; 2685 2686 /* Check if this is a user-mode read-write non-image file mapping */ 2687 if (!(FileObject) && 2688 (SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)) && 2689 !(ControlArea->u.Flags.Image) && 2690 (ControlArea->FilePointer)) 2691 { 2692 /* Add a reference and set the flag */ 2693 Section.u.Flags.UserWritable = TRUE; 2694 InterlockedIncrement((volatile LONG*)&ControlArea->WritableUserReferences); 2695 } 2696 2697 /* Check for image mappings or page file mappings */ 2698 if ((ControlArea->u.Flags.Image) || !(ControlArea->FilePointer)) 2699 { 2700 /* Charge the segment size, and allocate a subsection */ 2701 PagedCharge = sizeof(SECTION) + NewSegment->TotalNumberOfPtes * sizeof(MMPTE); 2702 Size = sizeof(SUBSECTION); 2703 } 2704 else 2705 { 2706 /* Charge nothing, and allocate a mapped subsection */ 2707 PagedCharge = 0; 2708 Size = sizeof(MSUBSECTION); 2709 } 2710 2711 /* Check if this is a normal CA */ 2712 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 2713 ASSERT(ControlArea->u.Flags.Rom == 0); 2714 2715 /* Charge only a CA, and the subsection is right after */ 2716 NonPagedCharge = sizeof(CONTROL_AREA); 2717 Subsection = (PSUBSECTION)(ControlArea + 1); 2718 2719 /* We only support single-subsection mappings */ 2720 NonPagedCharge += Size; 2721 ASSERT(Subsection->NextSubsection == NULL); 2722 2723 /* Create the actual section object, with enough space for the prototype PTEs */ 2724 Status = ObCreateObject(PreviousMode, 2725 MmSectionObjectType, 2726 ObjectAttributes, 2727 PreviousMode, 2728 NULL, 2729 sizeof(SECTION), 2730 PagedCharge, 2731 NonPagedCharge, 2732 (PVOID*)&NewSection); 2733 if (!NT_SUCCESS(Status)) 2734 { 2735 /* Check if this is a user-mode read-write non-image file mapping */ 2736 if (!(FileObject) && 2737 (SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)) && 2738 !(ControlArea->u.Flags.Image) && 2739 (ControlArea->FilePointer)) 2740 { 2741 /* Remove a reference and check the flag */ 2742 ASSERT(Section.u.Flags.UserWritable == 1); 2743 InterlockedDecrement((volatile LONG*)&ControlArea->WritableUserReferences); 2744 } 2745 2746 /* Check if a user reference was added */ 2747 if (UserRefIncremented) 2748 { 2749 /* Acquire the PFN lock while we change counters */ 2750 OldIrql = MiAcquirePfnLock(); 2751 2752 /* Decrement the accounting counters */ 2753 ControlArea->NumberOfSectionReferences--; 2754 ASSERT((LONG)ControlArea->NumberOfUserReferences > 0); 2755 ControlArea->NumberOfUserReferences--; 2756 2757 /* Check if we should destroy the CA and release the lock */ 2758 MiCheckControlArea(ControlArea, OldIrql); 2759 } 2760 2761 /* Return the failure code */ 2762 return Status; 2763 } 2764 2765 /* NOTE: Past this point, all failures will be handled by Ob upon ref->0 */ 2766 2767 /* Now copy the local section object from the stack into this new object */ 2768 RtlCopyMemory(NewSection, &Section, sizeof(SECTION)); 2769 NewSection->Address.StartingVpn = 0; 2770 2771 /* For now, only user calls are supported */ 2772 ASSERT(KernelCall == FALSE); 2773 NewSection->u.Flags.UserReference = TRUE; 2774 2775 /* Is this a "based" allocation, in which all mappings are identical? */ 2776 if (AllocationAttributes & SEC_BASED) 2777 { 2778 /* Lock the VAD tree during the search */ 2779 KeAcquireGuardedMutex(&MmSectionBasedMutex); 2780 2781 /* Is it a brand new ControArea ? */ 2782 if (ControlArea->u.Flags.BeingCreated == 1) 2783 { 2784 ASSERT(ControlArea->u.Flags.Based == 1); 2785 /* Then we must find a global address, top-down */ 2786 Status = MiFindEmptyAddressRangeDownBasedTree((SIZE_T)ControlArea->Segment->SizeOfSegment, 2787 (ULONG_PTR)MmHighSectionBase, 2788 _64K, 2789 &MmSectionBasedRoot, 2790 (ULONG_PTR*)&ControlArea->Segment->BasedAddress); 2791 2792 if (!NT_SUCCESS(Status)) 2793 { 2794 /* No way to find a valid range. */ 2795 KeReleaseGuardedMutex(&MmSectionBasedMutex); 2796 ControlArea->u.Flags.Based = 0; 2797 NewSection->u.Flags.Based = 0; 2798 ObDereferenceObject(NewSection); 2799 return Status; 2800 } 2801 2802 /* Compute the ending address and insert it into the VAD tree */ 2803 NewSection->Address.StartingVpn = (ULONG_PTR)ControlArea->Segment->BasedAddress; 2804 NewSection->Address.EndingVpn = NewSection->Address.StartingVpn + NewSection->SizeOfSection.LowPart - 1; 2805 MiInsertBasedSection(NewSection); 2806 } 2807 else 2808 { 2809 /* 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 !*/ 2810 ASSERT(FALSE); 2811 } 2812 2813 KeReleaseGuardedMutex(&MmSectionBasedMutex); 2814 } 2815 2816 /* The control area is not being created anymore */ 2817 if (ControlArea->u.Flags.BeingCreated == 1) 2818 { 2819 /* Acquire the PFN lock while we set control area flags */ 2820 OldIrql = MiAcquirePfnLock(); 2821 2822 /* Take off the being created flag, and then release the lock */ 2823 ControlArea->u.Flags.BeingCreated = 0; 2824 NewSection->u.Flags.BeingCreated = 0; 2825 2826 MiReleasePfnLock(OldIrql); 2827 } 2828 2829 /* Migrate the attribute into a flag */ 2830 if (AllocationAttributes & SEC_NO_CHANGE) NewSection->u.Flags.NoChange = TRUE; 2831 2832 /* If R/W access is not requested, this might eventually become a CoW mapping */ 2833 if (!(SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE))) 2834 { 2835 NewSection->u.Flags.CopyOnWrite = TRUE; 2836 } 2837 2838 /* Write down if this was a kernel call */ 2839 ControlArea->u.Flags.WasPurged |= KernelCall; 2840 ASSERT(ControlArea->u.Flags.WasPurged == FALSE); 2841 2842 /* Make sure the segment and the section are the same size, or the section is smaller */ 2843 ASSERT((ULONG64)NewSection->SizeOfSection.QuadPart <= NewSection->Segment->SizeOfSegment); 2844 2845 /* Return the object and the creation status */ 2846 *SectionObject = (PVOID)NewSection; 2847 return Status; 2848 } 2849 2850 /* 2851 * @implemented 2852 */ 2853 NTSTATUS 2854 NTAPI 2855 MmMapViewOfArm3Section(IN PVOID SectionObject, 2856 IN PEPROCESS Process, 2857 IN OUT PVOID *BaseAddress, 2858 IN ULONG_PTR ZeroBits, 2859 IN SIZE_T CommitSize, 2860 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, 2861 IN OUT PSIZE_T ViewSize, 2862 IN SECTION_INHERIT InheritDisposition, 2863 IN ULONG AllocationType, 2864 IN ULONG Protect) 2865 { 2866 KAPC_STATE ApcState; 2867 BOOLEAN Attached = FALSE; 2868 PSECTION Section; 2869 PCONTROL_AREA ControlArea; 2870 ULONG ProtectionMask; 2871 NTSTATUS Status; 2872 ULONG64 CalculatedViewSize; 2873 PAGED_CODE(); 2874 2875 /* Get the segment and control area */ 2876 Section = (PSECTION)SectionObject; 2877 ControlArea = Section->Segment->ControlArea; 2878 2879 /* These flags/states are not yet supported by ARM3 */ 2880 ASSERT(Section->u.Flags.Image == 0); 2881 ASSERT(Section->u.Flags.NoCache == 0); 2882 ASSERT(Section->u.Flags.WriteCombined == 0); 2883 ASSERT(ControlArea->u.Flags.PhysicalMemory == 0); 2884 2885 /* FIXME */ 2886 if ((AllocationType & MEM_RESERVE) != 0) 2887 { 2888 DPRINT1("MmMapViewOfArm3Section called with MEM_RESERVE, this is not implemented yet!!!\n"); 2889 return STATUS_NOT_IMPLEMENTED; 2890 } 2891 2892 /* Check if the mapping protection is compatible with the create */ 2893 if (!MiIsProtectionCompatible(Section->InitialPageProtection, Protect)) 2894 { 2895 DPRINT1("Mapping protection is incompatible\n"); 2896 return STATUS_SECTION_PROTECTION; 2897 } 2898 2899 /* Check if the offset and size would cause an overflow */ 2900 if (((ULONG64)SectionOffset->QuadPart + *ViewSize) < 2901 (ULONG64)SectionOffset->QuadPart) 2902 { 2903 DPRINT1("Section offset overflows\n"); 2904 return STATUS_INVALID_VIEW_SIZE; 2905 } 2906 2907 /* Check if the offset and size are bigger than the section itself */ 2908 if (((ULONG64)SectionOffset->QuadPart + *ViewSize) > 2909 (ULONG64)Section->SizeOfSection.QuadPart) 2910 { 2911 DPRINT1("Section offset is larger than section\n"); 2912 return STATUS_INVALID_VIEW_SIZE; 2913 } 2914 2915 /* Check if the caller did not specify a view size */ 2916 if (!(*ViewSize)) 2917 { 2918 /* Compute it for the caller */ 2919 CalculatedViewSize = Section->SizeOfSection.QuadPart - 2920 SectionOffset->QuadPart; 2921 2922 /* Check if it's larger than 4GB or overflows into kernel-mode */ 2923 if (!NT_SUCCESS(RtlULongLongToSIZET(CalculatedViewSize, ViewSize)) || 2924 (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - (ULONG_PTR)*BaseAddress) < CalculatedViewSize)) 2925 { 2926 DPRINT1("Section view won't fit\n"); 2927 return STATUS_INVALID_VIEW_SIZE; 2928 } 2929 } 2930 2931 /* Check if the commit size is larger than the view size */ 2932 if (CommitSize > *ViewSize) 2933 { 2934 DPRINT1("Attempting to commit more than the view itself\n"); 2935 return STATUS_INVALID_PARAMETER_5; 2936 } 2937 2938 /* Check if the view size is larger than the section */ 2939 if (*ViewSize > (ULONG64)Section->SizeOfSection.QuadPart) 2940 { 2941 DPRINT1("The view is larger than the section\n"); 2942 return STATUS_INVALID_VIEW_SIZE; 2943 } 2944 2945 /* Compute and validate the protection mask */ 2946 ProtectionMask = MiMakeProtectionMask(Protect); 2947 if (ProtectionMask == MM_INVALID_PROTECTION) 2948 { 2949 DPRINT1("The protection is invalid\n"); 2950 return STATUS_INVALID_PAGE_PROTECTION; 2951 } 2952 2953 /* We only handle pagefile-backed sections, which cannot be writecombined */ 2954 if (Protect & PAGE_WRITECOMBINE) 2955 { 2956 DPRINT1("Cannot write combine a pagefile-backed section\n"); 2957 return STATUS_INVALID_PARAMETER_10; 2958 } 2959 2960 /* Start by attaching to the current process if needed */ 2961 if (PsGetCurrentProcess() != Process) 2962 { 2963 KeStackAttachProcess(&Process->Pcb, &ApcState); 2964 Attached = TRUE; 2965 } 2966 2967 /* Do the actual mapping */ 2968 Status = MiMapViewOfDataSection(ControlArea, 2969 Process, 2970 BaseAddress, 2971 SectionOffset, 2972 ViewSize, 2973 Section, 2974 InheritDisposition, 2975 ProtectionMask, 2976 CommitSize, 2977 ZeroBits, 2978 AllocationType); 2979 2980 /* Detach if needed, then return status */ 2981 if (Attached) KeUnstackDetachProcess(&ApcState); 2982 return Status; 2983 } 2984 2985 /* 2986 * @unimplemented 2987 */ 2988 BOOLEAN 2989 NTAPI 2990 MmDisableModifiedWriteOfSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer) 2991 { 2992 UNIMPLEMENTED; 2993 return FALSE; 2994 } 2995 2996 /* 2997 * @unimplemented 2998 */ 2999 BOOLEAN 3000 NTAPI 3001 MmForceSectionClosed(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, 3002 IN BOOLEAN DelayClose) 3003 { 3004 UNIMPLEMENTED; 3005 return FALSE; 3006 } 3007 3008 /* 3009 * @implemented 3010 */ 3011 NTSTATUS 3012 NTAPI 3013 MmMapViewInSessionSpace(IN PVOID Section, 3014 OUT PVOID *MappedBase, 3015 IN OUT PSIZE_T ViewSize) 3016 { 3017 PAGED_CODE(); 3018 3019 // HACK 3020 if (MiIsRosSectionObject(Section)) 3021 { 3022 return MmMapViewInSystemSpace(Section, MappedBase, ViewSize); 3023 } 3024 3025 /* Process must be in a session */ 3026 if (PsGetCurrentProcess()->ProcessInSession == FALSE) 3027 { 3028 DPRINT1("Process is not in session\n"); 3029 return STATUS_NOT_MAPPED_VIEW; 3030 } 3031 3032 /* Use the system space API, but with the session view instead */ 3033 ASSERT(MmIsAddressValid(MmSessionSpace) == TRUE); 3034 return MiMapViewInSystemSpace(Section, 3035 &MmSessionSpace->Session, 3036 MappedBase, 3037 ViewSize); 3038 } 3039 3040 /* 3041 * @implemented 3042 */ 3043 NTSTATUS 3044 NTAPI 3045 MmUnmapViewInSessionSpace(IN PVOID MappedBase) 3046 { 3047 PAGED_CODE(); 3048 3049 // HACK 3050 if (!MI_IS_SESSION_ADDRESS(MappedBase)) 3051 { 3052 return MmUnmapViewInSystemSpace(MappedBase); 3053 } 3054 3055 /* Process must be in a session */ 3056 if (PsGetCurrentProcess()->ProcessInSession == FALSE) 3057 { 3058 DPRINT1("Proess is not in session\n"); 3059 return STATUS_NOT_MAPPED_VIEW; 3060 } 3061 3062 /* Use the system space API, but with the session view instead */ 3063 ASSERT(MmIsAddressValid(MmSessionSpace) == TRUE); 3064 return MiUnmapViewInSystemSpace(&MmSessionSpace->Session, 3065 MappedBase); 3066 } 3067 3068 /* 3069 * @implemented 3070 */ 3071 NTSTATUS 3072 NTAPI 3073 MmUnmapViewOfSection(IN PEPROCESS Process, 3074 IN PVOID BaseAddress) 3075 { 3076 return MiUnmapViewOfSection(Process, BaseAddress, 0); 3077 } 3078 3079 /* 3080 * @implemented 3081 */ 3082 NTSTATUS 3083 NTAPI 3084 MmUnmapViewInSystemSpace(IN PVOID MappedBase) 3085 { 3086 PMEMORY_AREA MemoryArea; 3087 PAGED_CODE(); 3088 3089 /* Was this mapped by RosMm? */ 3090 MemoryArea = MmLocateMemoryAreaByAddress(MmGetKernelAddressSpace(), MappedBase); 3091 if ((MemoryArea) && (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3)) 3092 { 3093 return MiRosUnmapViewInSystemSpace(MappedBase); 3094 } 3095 3096 /* It was not, call the ARM3 routine */ 3097 return MiUnmapViewInSystemSpace(&MmSession, MappedBase); 3098 } 3099 3100 /* 3101 * @implemented 3102 */ 3103 NTSTATUS 3104 NTAPI 3105 MmCommitSessionMappedView(IN PVOID MappedBase, 3106 IN SIZE_T ViewSize) 3107 { 3108 ULONG_PTR StartAddress, EndingAddress, Base; 3109 ULONG Hash, Count = 0, Size, QuotaCharge; 3110 PMMSESSION Session; 3111 PMMPTE LastProtoPte, PointerPte, ProtoPte; 3112 PCONTROL_AREA ControlArea; 3113 PSEGMENT Segment; 3114 PSUBSECTION Subsection; 3115 MMPTE TempPte; 3116 PAGED_CODE(); 3117 3118 /* Make sure the base isn't past the session view range */ 3119 if ((MappedBase < MiSessionViewStart) || 3120 (MappedBase >= (PVOID)((ULONG_PTR)MiSessionViewStart + MmSessionViewSize))) 3121 { 3122 DPRINT1("Base outside of valid range\n"); 3123 return STATUS_INVALID_PARAMETER_1; 3124 } 3125 3126 /* Make sure the size isn't past the session view range */ 3127 if (((ULONG_PTR)MiSessionViewStart + MmSessionViewSize - 3128 (ULONG_PTR)MappedBase) < ViewSize) 3129 { 3130 DPRINT1("Size outside of valid range\n"); 3131 return STATUS_INVALID_PARAMETER_2; 3132 } 3133 3134 /* Sanity check */ 3135 ASSERT(ViewSize != 0); 3136 3137 /* Process must be in a session */ 3138 if (PsGetCurrentProcess()->ProcessInSession == FALSE) 3139 { 3140 DPRINT1("Process is not in session\n"); 3141 return STATUS_NOT_MAPPED_VIEW; 3142 } 3143 3144 /* Compute the correctly aligned base and end addresses */ 3145 StartAddress = (ULONG_PTR)PAGE_ALIGN(MappedBase); 3146 EndingAddress = ((ULONG_PTR)MappedBase + ViewSize - 1) | (PAGE_SIZE - 1); 3147 3148 /* Sanity check and grab the session */ 3149 ASSERT(MmIsAddressValid(MmSessionSpace) == TRUE); 3150 Session = &MmSessionSpace->Session; 3151 3152 /* Get the hash entry for this allocation */ 3153 Hash = (StartAddress >> 16) % Session->SystemSpaceHashKey; 3154 3155 /* Lock system space */ 3156 KeAcquireGuardedMutex(Session->SystemSpaceViewLockPointer); 3157 3158 /* Loop twice so we can try rolling over if needed */ 3159 while (TRUE) 3160 { 3161 /* Extract the size and base addresses from the entry */ 3162 Base = Session->SystemSpaceViewTable[Hash].Entry & ~0xFFFF; 3163 Size = Session->SystemSpaceViewTable[Hash].Entry & 0xFFFF; 3164 3165 /* Convert the size to bucket chunks */ 3166 Size *= MI_SYSTEM_VIEW_BUCKET_SIZE; 3167 3168 /* Bail out if this entry fits in here */ 3169 if ((StartAddress >= Base) && (EndingAddress < (Base + Size))) break; 3170 3171 /* Check if we overflew past the end of the hash table */ 3172 if (++Hash >= Session->SystemSpaceHashSize) 3173 { 3174 /* Reset the hash to zero and keep searching from the bottom */ 3175 Hash = 0; 3176 if (++Count == 2) 3177 { 3178 /* But if we overflew twice, then this is not a real mapping */ 3179 KeBugCheckEx(DRIVER_UNMAPPING_INVALID_VIEW, 3180 Base, 3181 2, 3182 0, 3183 0); 3184 } 3185 } 3186 } 3187 3188 /* Make sure the view being mapped is not file-based */ 3189 ControlArea = Session->SystemSpaceViewTable[Hash].ControlArea; 3190 if (ControlArea->FilePointer != NULL) 3191 { 3192 /* It is, so we have to bail out */ 3193 DPRINT1("Only page-filed backed sections can be commited\n"); 3194 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 3195 return STATUS_ALREADY_COMMITTED; 3196 } 3197 3198 /* Get the subsection. We don't support LARGE_CONTROL_AREA in ARM3 */ 3199 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 3200 ASSERT(ControlArea->u.Flags.Rom == 0); 3201 Subsection = (PSUBSECTION)(ControlArea + 1); 3202 3203 /* Get the start and end PTEs -- make sure the end PTE isn't past the end */ 3204 ProtoPte = Subsection->SubsectionBase + ((StartAddress - Base) >> PAGE_SHIFT); 3205 QuotaCharge = MiAddressToPte(EndingAddress) - MiAddressToPte(StartAddress) + 1; 3206 LastProtoPte = ProtoPte + QuotaCharge; 3207 if (LastProtoPte >= Subsection->SubsectionBase + Subsection->PtesInSubsection) 3208 { 3209 DPRINT1("PTE is out of bounds\n"); 3210 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 3211 return STATUS_INVALID_PARAMETER_2; 3212 } 3213 3214 /* Acquire the commit lock and count all the non-committed PTEs */ 3215 KeAcquireGuardedMutexUnsafe(&MmSectionCommitMutex); 3216 PointerPte = ProtoPte; 3217 while (PointerPte < LastProtoPte) 3218 { 3219 if (PointerPte->u.Long) QuotaCharge--; 3220 PointerPte++; 3221 } 3222 3223 /* Was everything committed already? */ 3224 if (!QuotaCharge) 3225 { 3226 /* Nothing to do! */ 3227 KeReleaseGuardedMutexUnsafe(&MmSectionCommitMutex); 3228 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 3229 return STATUS_SUCCESS; 3230 } 3231 3232 /* Pick the segment and template PTE */ 3233 Segment = ControlArea->Segment; 3234 TempPte = Segment->SegmentPteTemplate; 3235 ASSERT(TempPte.u.Long != 0); 3236 3237 /* Loop all prototype PTEs to be committed */ 3238 PointerPte = ProtoPte; 3239 while (PointerPte < LastProtoPte) 3240 { 3241 /* Make sure the PTE is already invalid */ 3242 if (PointerPte->u.Long == 0) 3243 { 3244 /* And write the invalid PTE */ 3245 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 3246 } 3247 3248 /* Move to the next PTE */ 3249 PointerPte++; 3250 } 3251 3252 /* Check if we had at least one page charged */ 3253 if (QuotaCharge) 3254 { 3255 /* Update the accounting data */ 3256 Segment->NumberOfCommittedPages += QuotaCharge; 3257 InterlockedExchangeAddSizeT(&MmSharedCommit, QuotaCharge); 3258 } 3259 3260 /* Release all */ 3261 KeReleaseGuardedMutexUnsafe(&MmSectionCommitMutex); 3262 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 3263 return STATUS_SUCCESS; 3264 } 3265 3266 VOID 3267 NTAPI 3268 MiDeleteARM3Section(PVOID ObjectBody) 3269 { 3270 PSECTION SectionObject; 3271 PCONTROL_AREA ControlArea; 3272 KIRQL OldIrql; 3273 3274 SectionObject = (PSECTION)ObjectBody; 3275 3276 if (SectionObject->u.Flags.Based == 1) 3277 { 3278 /* Remove the node from the global section address tree */ 3279 KeAcquireGuardedMutex(&MmSectionBasedMutex); 3280 MiRemoveNode(&SectionObject->Address, &MmSectionBasedRoot); 3281 KeReleaseGuardedMutex(&MmSectionBasedMutex); 3282 } 3283 3284 /* Lock the PFN database */ 3285 OldIrql = MiAcquirePfnLock(); 3286 3287 ASSERT(SectionObject->Segment); 3288 ASSERT(SectionObject->Segment->ControlArea); 3289 3290 ControlArea = SectionObject->Segment->ControlArea; 3291 3292 /* Dereference */ 3293 ControlArea->NumberOfSectionReferences--; 3294 ControlArea->NumberOfUserReferences--; 3295 3296 ASSERT(ControlArea->u.Flags.BeingDeleted == 0); 3297 3298 /* Check it. It will delete it if there is no more reference to it */ 3299 MiCheckControlArea(ControlArea, OldIrql); 3300 } 3301 3302 ULONG 3303 NTAPI 3304 MmDoesFileHaveUserWritableReferences(IN PSECTION_OBJECT_POINTERS SectionPointer) 3305 { 3306 UNIMPLEMENTED; 3307 return 0; 3308 } 3309 3310 /* SYSTEM CALLS ***************************************************************/ 3311 3312 NTSTATUS 3313 NTAPI 3314 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage, 3315 IN PVOID File2MappedAsFile) 3316 { 3317 PVOID AddressSpace; 3318 PMMVAD Vad1, Vad2; 3319 PFILE_OBJECT FileObject1, FileObject2; 3320 NTSTATUS Status; 3321 3322 /* Lock address space */ 3323 AddressSpace = MmGetCurrentAddressSpace(); 3324 MmLockAddressSpace(AddressSpace); 3325 3326 /* Get the VAD for Address 1 */ 3327 Vad1 = MiLocateAddress(File1MappedAsAnImage); 3328 if (Vad1 == NULL) 3329 { 3330 /* Fail, the address does not exist */ 3331 DPRINT1("No VAD at address 1 %p\n", File1MappedAsAnImage); 3332 Status = STATUS_INVALID_ADDRESS; 3333 goto Exit; 3334 } 3335 3336 /* Get the VAD for Address 2 */ 3337 Vad2 = MiLocateAddress(File2MappedAsFile); 3338 if (Vad2 == NULL) 3339 { 3340 /* Fail, the address does not exist */ 3341 DPRINT1("No VAD at address 2 %p\n", File2MappedAsFile); 3342 Status = STATUS_INVALID_ADDRESS; 3343 goto Exit; 3344 } 3345 3346 /* Get the file object pointer for VAD 1 */ 3347 FileObject1 = MiGetFileObjectForVad(Vad1); 3348 if (FileObject1 == NULL) 3349 { 3350 DPRINT1("Failed to get file object for Address 1 %p\n", File1MappedAsAnImage); 3351 Status = STATUS_CONFLICTING_ADDRESSES; 3352 goto Exit; 3353 } 3354 3355 /* Get the file object pointer for VAD 2 */ 3356 FileObject2 = MiGetFileObjectForVad(Vad2); 3357 if (FileObject2 == NULL) 3358 { 3359 DPRINT1("Failed to get file object for Address 2 %p\n", File2MappedAsFile); 3360 Status = STATUS_CONFLICTING_ADDRESSES; 3361 goto Exit; 3362 } 3363 3364 /* Make sure Vad1 is an image mapping */ 3365 if (Vad1->u.VadFlags.VadType != VadImageMap) 3366 { 3367 DPRINT1("Address 1 (%p) is not an image mapping\n", File1MappedAsAnImage); 3368 Status = STATUS_NOT_SAME_DEVICE; 3369 goto Exit; 3370 } 3371 3372 /* SectionObjectPointer is equal if the files are equal */ 3373 if (FileObject1->SectionObjectPointer == FileObject2->SectionObjectPointer) 3374 { 3375 Status = STATUS_SUCCESS; 3376 } 3377 else 3378 { 3379 Status = STATUS_NOT_SAME_DEVICE; 3380 } 3381 3382 Exit: 3383 /* Unlock address space */ 3384 MmUnlockAddressSpace(AddressSpace); 3385 return Status; 3386 } 3387 3388 /* 3389 * @implemented 3390 */ 3391 NTSTATUS 3392 NTAPI 3393 NtCreateSection(OUT PHANDLE SectionHandle, 3394 IN ACCESS_MASK DesiredAccess, 3395 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 3396 IN PLARGE_INTEGER MaximumSize OPTIONAL, 3397 IN ULONG SectionPageProtection OPTIONAL, 3398 IN ULONG AllocationAttributes, 3399 IN HANDLE FileHandle OPTIONAL) 3400 { 3401 LARGE_INTEGER SafeMaximumSize; 3402 PVOID SectionObject; 3403 HANDLE Handle; 3404 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 3405 NTSTATUS Status; 3406 PAGED_CODE(); 3407 3408 /* Check for non-existing flags */ 3409 if ((AllocationAttributes & ~(SEC_COMMIT | SEC_RESERVE | SEC_BASED | 3410 SEC_LARGE_PAGES | SEC_IMAGE | SEC_NOCACHE | 3411 SEC_NO_CHANGE))) 3412 { 3413 if (!(AllocationAttributes & 1)) 3414 { 3415 DPRINT1("Bogus allocation attribute: %lx\n", AllocationAttributes); 3416 return STATUS_INVALID_PARAMETER_6; 3417 } 3418 } 3419 3420 /* Check for no allocation type */ 3421 if (!(AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_IMAGE))) 3422 { 3423 DPRINT1("Missing allocation type in allocation attributes\n"); 3424 return STATUS_INVALID_PARAMETER_6; 3425 } 3426 3427 /* Check for image allocation with invalid attributes */ 3428 if ((AllocationAttributes & SEC_IMAGE) && 3429 (AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_LARGE_PAGES | 3430 SEC_NOCACHE | SEC_NO_CHANGE))) 3431 { 3432 DPRINT1("Image allocation with invalid attributes\n"); 3433 return STATUS_INVALID_PARAMETER_6; 3434 } 3435 3436 /* Check for allocation type is both commit and reserve */ 3437 if ((AllocationAttributes & SEC_COMMIT) && (AllocationAttributes & SEC_RESERVE)) 3438 { 3439 DPRINT1("Commit and reserve in the same time\n"); 3440 return STATUS_INVALID_PARAMETER_6; 3441 } 3442 3443 /* Now check for valid protection */ 3444 if ((SectionPageProtection & PAGE_NOCACHE) || 3445 (SectionPageProtection & PAGE_WRITECOMBINE) || 3446 (SectionPageProtection & PAGE_GUARD) || 3447 (SectionPageProtection & PAGE_NOACCESS)) 3448 { 3449 DPRINT1("Sections don't support these protections\n"); 3450 return STATUS_INVALID_PAGE_PROTECTION; 3451 } 3452 3453 /* Use a maximum size of zero, if none was specified */ 3454 SafeMaximumSize.QuadPart = 0; 3455 3456 /* Check for user-mode caller */ 3457 if (PreviousMode != KernelMode) 3458 { 3459 /* Enter SEH */ 3460 _SEH2_TRY 3461 { 3462 /* Safely check user-mode parameters */ 3463 if (MaximumSize) SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize); 3464 MaximumSize = &SafeMaximumSize; 3465 ProbeForWriteHandle(SectionHandle); 3466 } 3467 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3468 { 3469 /* Return the exception code */ 3470 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3471 } 3472 _SEH2_END; 3473 } 3474 else if (!MaximumSize) MaximumSize = &SafeMaximumSize; 3475 3476 /* Check that MaximumSize is valid if backed by paging file */ 3477 if ((!FileHandle) && (!MaximumSize->QuadPart)) 3478 return STATUS_INVALID_PARAMETER_4; 3479 3480 /* Create the section */ 3481 Status = MmCreateSection(&SectionObject, 3482 DesiredAccess, 3483 ObjectAttributes, 3484 MaximumSize, 3485 SectionPageProtection, 3486 AllocationAttributes, 3487 FileHandle, 3488 NULL); 3489 if (!NT_SUCCESS(Status)) return Status; 3490 3491 /* FIXME: Should zero last page for a file mapping */ 3492 3493 /* Now insert the object */ 3494 Status = ObInsertObject(SectionObject, 3495 NULL, 3496 DesiredAccess, 3497 0, 3498 NULL, 3499 &Handle); 3500 if (NT_SUCCESS(Status)) 3501 { 3502 /* Enter SEH */ 3503 _SEH2_TRY 3504 { 3505 /* Return the handle safely */ 3506 *SectionHandle = Handle; 3507 } 3508 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3509 { 3510 /* Nothing here */ 3511 } 3512 _SEH2_END; 3513 } 3514 3515 /* Return the status */ 3516 return Status; 3517 } 3518 3519 NTSTATUS 3520 NTAPI 3521 NtOpenSection(OUT PHANDLE SectionHandle, 3522 IN ACCESS_MASK DesiredAccess, 3523 IN POBJECT_ATTRIBUTES ObjectAttributes) 3524 { 3525 HANDLE Handle; 3526 NTSTATUS Status; 3527 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 3528 PAGED_CODE(); 3529 3530 /* Check for user-mode caller */ 3531 if (PreviousMode != KernelMode) 3532 { 3533 /* Enter SEH */ 3534 _SEH2_TRY 3535 { 3536 /* Safely check user-mode parameters */ 3537 ProbeForWriteHandle(SectionHandle); 3538 } 3539 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3540 { 3541 /* Return the exception code */ 3542 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3543 } 3544 _SEH2_END; 3545 } 3546 3547 /* Try opening the object */ 3548 Status = ObOpenObjectByName(ObjectAttributes, 3549 MmSectionObjectType, 3550 PreviousMode, 3551 NULL, 3552 DesiredAccess, 3553 NULL, 3554 &Handle); 3555 3556 /* Enter SEH */ 3557 _SEH2_TRY 3558 { 3559 /* Return the handle safely */ 3560 *SectionHandle = Handle; 3561 } 3562 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3563 { 3564 /* Nothing here */ 3565 } 3566 _SEH2_END; 3567 3568 /* Return the status */ 3569 return Status; 3570 } 3571 3572 NTSTATUS 3573 NTAPI 3574 NtMapViewOfSection(IN HANDLE SectionHandle, 3575 IN HANDLE ProcessHandle, 3576 IN OUT PVOID* BaseAddress, 3577 IN ULONG_PTR ZeroBits, 3578 IN SIZE_T CommitSize, 3579 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, 3580 IN OUT PSIZE_T ViewSize, 3581 IN SECTION_INHERIT InheritDisposition, 3582 IN ULONG AllocationType, 3583 IN ULONG Protect) 3584 { 3585 PVOID SafeBaseAddress; 3586 LARGE_INTEGER SafeSectionOffset; 3587 SIZE_T SafeViewSize; 3588 PROS_SECTION_OBJECT Section; 3589 PEPROCESS Process; 3590 NTSTATUS Status; 3591 ACCESS_MASK DesiredAccess; 3592 ULONG ProtectionMask; 3593 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 3594 #if defined(_M_IX86) || defined(_M_AMD64) 3595 static const ULONG ValidAllocationType = (MEM_TOP_DOWN | MEM_LARGE_PAGES | 3596 MEM_DOS_LIM | SEC_NO_CHANGE | MEM_RESERVE); 3597 #else 3598 static const ULONG ValidAllocationType = (MEM_TOP_DOWN | MEM_LARGE_PAGES | 3599 SEC_NO_CHANGE | MEM_RESERVE); 3600 #endif 3601 3602 /* Check for invalid inherit disposition */ 3603 if ((InheritDisposition > ViewUnmap) || (InheritDisposition < ViewShare)) 3604 { 3605 DPRINT1("Invalid inherit disposition\n"); 3606 return STATUS_INVALID_PARAMETER_8; 3607 } 3608 3609 /* Allow only valid allocation types */ 3610 if (AllocationType & ~ValidAllocationType) 3611 { 3612 DPRINT1("Invalid allocation type\n"); 3613 return STATUS_INVALID_PARAMETER_9; 3614 } 3615 3616 /* Convert the protection mask, and validate it */ 3617 ProtectionMask = MiMakeProtectionMask(Protect); 3618 if (ProtectionMask == MM_INVALID_PROTECTION) 3619 { 3620 DPRINT1("Invalid page protection\n"); 3621 return STATUS_INVALID_PAGE_PROTECTION; 3622 } 3623 3624 /* Now convert the protection mask into desired section access mask */ 3625 DesiredAccess = MmMakeSectionAccess[ProtectionMask & 0x7]; 3626 3627 /* Assume no section offset */ 3628 SafeSectionOffset.QuadPart = 0; 3629 3630 /* Enter SEH */ 3631 _SEH2_TRY 3632 { 3633 /* Check for unsafe parameters */ 3634 if (PreviousMode != KernelMode) 3635 { 3636 /* Probe the parameters */ 3637 ProbeForWritePointer(BaseAddress); 3638 ProbeForWriteSize_t(ViewSize); 3639 } 3640 3641 /* Check if a section offset was given */ 3642 if (SectionOffset) 3643 { 3644 /* Check for unsafe parameters and capture section offset */ 3645 if (PreviousMode != KernelMode) ProbeForWriteLargeInteger(SectionOffset); 3646 SafeSectionOffset = *SectionOffset; 3647 } 3648 3649 /* Capture the other parameters */ 3650 SafeBaseAddress = *BaseAddress; 3651 SafeViewSize = *ViewSize; 3652 } 3653 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3654 { 3655 /* Return the exception code */ 3656 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3657 } 3658 _SEH2_END; 3659 3660 /* Check for kernel-mode address */ 3661 if (SafeBaseAddress > MM_HIGHEST_VAD_ADDRESS) 3662 { 3663 DPRINT1("Kernel base not allowed\n"); 3664 return STATUS_INVALID_PARAMETER_3; 3665 } 3666 3667 /* Check for range entering kernel-mode */ 3668 if (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - (ULONG_PTR)SafeBaseAddress) < SafeViewSize) 3669 { 3670 DPRINT1("Overflowing into kernel base not allowed\n"); 3671 return STATUS_INVALID_PARAMETER_3; 3672 } 3673 3674 /* Check for invalid zero bits */ 3675 if (ZeroBits) 3676 { 3677 if (ZeroBits > MI_MAX_ZERO_BITS) 3678 { 3679 DPRINT1("Invalid zero bits\n"); 3680 return STATUS_INVALID_PARAMETER_4; 3681 } 3682 3683 if ((((ULONG_PTR)SafeBaseAddress << ZeroBits) >> ZeroBits) != (ULONG_PTR)SafeBaseAddress) 3684 { 3685 DPRINT1("Invalid zero bits\n"); 3686 return STATUS_INVALID_PARAMETER_4; 3687 } 3688 3689 if (((((ULONG_PTR)SafeBaseAddress + SafeViewSize) << ZeroBits) >> ZeroBits) != ((ULONG_PTR)SafeBaseAddress + SafeViewSize)) 3690 { 3691 DPRINT1("Invalid zero bits\n"); 3692 return STATUS_INVALID_PARAMETER_4; 3693 } 3694 } 3695 3696 /* Reference the process */ 3697 Status = ObReferenceObjectByHandle(ProcessHandle, 3698 PROCESS_VM_OPERATION, 3699 PsProcessType, 3700 PreviousMode, 3701 (PVOID*)&Process, 3702 NULL); 3703 if (!NT_SUCCESS(Status)) return Status; 3704 3705 /* Reference the section */ 3706 Status = ObReferenceObjectByHandle(SectionHandle, 3707 DesiredAccess, 3708 MmSectionObjectType, 3709 PreviousMode, 3710 (PVOID*)&Section, 3711 NULL); 3712 if (!NT_SUCCESS(Status)) 3713 { 3714 ObDereferenceObject(Process); 3715 return Status; 3716 } 3717 3718 if (MiIsRosSectionObject(Section) && 3719 (Section->AllocationAttributes & SEC_PHYSICALMEMORY)) 3720 { 3721 if (PreviousMode == UserMode && 3722 SafeSectionOffset.QuadPart + SafeViewSize > MmHighestPhysicalPage << PAGE_SHIFT) 3723 { 3724 DPRINT1("Denying map past highest physical page.\n"); 3725 ObDereferenceObject(Section); 3726 ObDereferenceObject(Process); 3727 return STATUS_INVALID_PARAMETER_6; 3728 } 3729 } 3730 else if (!(AllocationType & MEM_DOS_LIM)) 3731 { 3732 /* Check for non-allocation-granularity-aligned BaseAddress */ 3733 if (SafeBaseAddress != ALIGN_DOWN_POINTER_BY(SafeBaseAddress, MM_VIRTMEM_GRANULARITY)) 3734 { 3735 DPRINT("BaseAddress is not at 64-kilobyte address boundary.\n"); 3736 ObDereferenceObject(Section); 3737 ObDereferenceObject(Process); 3738 return STATUS_MAPPED_ALIGNMENT; 3739 } 3740 3741 /* Do the same for the section offset */ 3742 if (SafeSectionOffset.LowPart != ALIGN_DOWN_BY(SafeSectionOffset.LowPart, MM_VIRTMEM_GRANULARITY)) 3743 { 3744 DPRINT("SectionOffset is not at 64-kilobyte address boundary.\n"); 3745 ObDereferenceObject(Section); 3746 ObDereferenceObject(Process); 3747 return STATUS_MAPPED_ALIGNMENT; 3748 } 3749 } 3750 3751 /* Now do the actual mapping */ 3752 Status = MmMapViewOfSection(Section, 3753 Process, 3754 &SafeBaseAddress, 3755 ZeroBits, 3756 CommitSize, 3757 &SafeSectionOffset, 3758 &SafeViewSize, 3759 InheritDisposition, 3760 AllocationType, 3761 Protect); 3762 3763 /* Return data only on success */ 3764 if (NT_SUCCESS(Status)) 3765 { 3766 /* Check if this is an image for the current process */ 3767 if (MiIsRosSectionObject(Section) && 3768 (Section->AllocationAttributes & SEC_IMAGE) && 3769 (Process == PsGetCurrentProcess()) && 3770 (Status != STATUS_IMAGE_NOT_AT_BASE)) 3771 { 3772 /* Notify the debugger */ 3773 DbgkMapViewOfSection(Section, 3774 SafeBaseAddress, 3775 SafeSectionOffset.LowPart, 3776 SafeViewSize); 3777 } 3778 3779 /* Enter SEH */ 3780 _SEH2_TRY 3781 { 3782 /* Return parameters to user */ 3783 *BaseAddress = SafeBaseAddress; 3784 *ViewSize = SafeViewSize; 3785 if (SectionOffset) *SectionOffset = SafeSectionOffset; 3786 } 3787 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3788 { 3789 /* Nothing to do */ 3790 } 3791 _SEH2_END; 3792 } 3793 3794 /* Dereference all objects and return status */ 3795 ObDereferenceObject(Section); 3796 ObDereferenceObject(Process); 3797 return Status; 3798 } 3799 3800 NTSTATUS 3801 NTAPI 3802 NtUnmapViewOfSection(IN HANDLE ProcessHandle, 3803 IN PVOID BaseAddress) 3804 { 3805 PEPROCESS Process; 3806 NTSTATUS Status; 3807 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 3808 3809 /* Don't allowing mapping kernel views */ 3810 if ((PreviousMode == UserMode) && (BaseAddress > MM_HIGHEST_USER_ADDRESS)) 3811 { 3812 DPRINT1("Trying to unmap a kernel view\n"); 3813 return STATUS_NOT_MAPPED_VIEW; 3814 } 3815 3816 /* Reference the process */ 3817 Status = ObReferenceObjectByHandle(ProcessHandle, 3818 PROCESS_VM_OPERATION, 3819 PsProcessType, 3820 PreviousMode, 3821 (PVOID*)&Process, 3822 NULL); 3823 if (!NT_SUCCESS(Status)) return Status; 3824 3825 /* Unmap the view */ 3826 Status = MiUnmapViewOfSection(Process, BaseAddress, 0); 3827 3828 /* Dereference the process and return status */ 3829 ObDereferenceObject(Process); 3830 return Status; 3831 } 3832 3833 NTSTATUS 3834 NTAPI 3835 NtExtendSection(IN HANDLE SectionHandle, 3836 IN OUT PLARGE_INTEGER NewMaximumSize) 3837 { 3838 LARGE_INTEGER SafeNewMaximumSize; 3839 PROS_SECTION_OBJECT Section; 3840 NTSTATUS Status; 3841 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 3842 3843 /* Check for user-mode parameters */ 3844 if (PreviousMode != KernelMode) 3845 { 3846 /* Enter SEH */ 3847 _SEH2_TRY 3848 { 3849 /* Probe and capture the maximum size, it's both read and write */ 3850 ProbeForWriteLargeInteger(NewMaximumSize); 3851 SafeNewMaximumSize = *NewMaximumSize; 3852 } 3853 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3854 { 3855 /* Return the exception code */ 3856 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3857 } 3858 _SEH2_END; 3859 } 3860 else 3861 { 3862 /* Just read the size directly */ 3863 SafeNewMaximumSize = *NewMaximumSize; 3864 } 3865 3866 /* Reference the section */ 3867 Status = ObReferenceObjectByHandle(SectionHandle, 3868 SECTION_EXTEND_SIZE, 3869 MmSectionObjectType, 3870 PreviousMode, 3871 (PVOID*)&Section, 3872 NULL); 3873 if (!NT_SUCCESS(Status)) return Status; 3874 3875 /* Really this should go in MmExtendSection */ 3876 if (!(Section->AllocationAttributes & SEC_FILE)) 3877 { 3878 DPRINT1("Not extending a file\n"); 3879 ObDereferenceObject(Section); 3880 return STATUS_SECTION_NOT_EXTENDED; 3881 } 3882 3883 /* FIXME: Do the work */ 3884 3885 /* Dereference the section */ 3886 ObDereferenceObject(Section); 3887 3888 /* Enter SEH */ 3889 _SEH2_TRY 3890 { 3891 /* Write back the new size */ 3892 *NewMaximumSize = SafeNewMaximumSize; 3893 } 3894 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3895 { 3896 /* Nothing to do */ 3897 } 3898 _SEH2_END; 3899 3900 /* Return the status */ 3901 return STATUS_NOT_IMPLEMENTED; 3902 } 3903 3904 /* EOF */ 3905