1 /* 2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section) 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 * 18 * 19 * PROJECT: ReactOS kernel 20 * FILE: ntoskrnl/mm/section.c 21 * PURPOSE: Implements section objects 22 * 23 * PROGRAMMERS: Rex Jolliff 24 * David Welch 25 * Eric Kohl 26 * Emanuele Aliberti 27 * Eugene Ingerman 28 * Casper Hornstrup 29 * KJK::Hyperion 30 * Guido de Jong 31 * Ge van Geldorp 32 * Royce Mitchell III 33 * Filip Navara 34 * Aleksey Bragin 35 * Jason Filby 36 * Thomas Weidenmueller 37 * Gunnar Andre' Dalsnes 38 * Mike Nordell 39 * Alex Ionescu 40 * Gregor Anich 41 * Steven Edwards 42 * Herve Poussineau 43 */ 44 45 /* INCLUDES *****************************************************************/ 46 47 #include <ntoskrnl.h> 48 #include <cache/newcc.h> 49 #include <cache/section/newmm.h> 50 #define NDEBUG 51 #include <debug.h> 52 #include <reactos/exeformat.h> 53 #include "ARM3/miarm.h" 54 55 #undef MmSetPageEntrySectionSegment 56 #define MmSetPageEntrySectionSegment(S,O,E) do { \ 57 DPRINT("SetPageEntrySectionSegment(old,%p,%x,%x)\n",(S),(O)->LowPart,E); \ 58 _MmSetPageEntrySectionSegment((S),(O),(E),__FILE__,__LINE__); \ 59 } while (0) 60 61 extern MMSESSION MmSession; 62 63 static LARGE_INTEGER TinyTime = {{-1L, -1L}}; 64 65 #ifndef NEWCC 66 KEVENT MmWaitPageEvent; 67 68 VOID 69 NTAPI 70 _MmLockSectionSegment(PMM_SECTION_SEGMENT Segment, const char *file, int line) 71 { 72 //DPRINT("MmLockSectionSegment(%p,%s:%d)\n", Segment, file, line); 73 ExAcquireFastMutex(&Segment->Lock); 74 Segment->Locked = TRUE; 75 } 76 77 VOID 78 NTAPI 79 _MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment, const char *file, int line) 80 { 81 ASSERT(Segment->Locked); 82 Segment->Locked = FALSE; 83 ExReleaseFastMutex(&Segment->Lock); 84 //DPRINT("MmUnlockSectionSegment(%p,%s:%d)\n", Segment, file, line); 85 } 86 #endif 87 88 static 89 PMM_SECTION_SEGMENT 90 MiGrabDataSection(PSECTION_OBJECT_POINTERS SectionObjectPointer) 91 { 92 KIRQL OldIrql = MiAcquirePfnLock(); 93 PMM_SECTION_SEGMENT Segment = NULL; 94 95 while (TRUE) 96 { 97 Segment = SectionObjectPointer->DataSectionObject; 98 if (!Segment) 99 break; 100 101 if (Segment->SegFlags & (MM_SEGMENT_INCREATE | MM_SEGMENT_INDELETE)) 102 { 103 MiReleasePfnLock(OldIrql); 104 KeDelayExecutionThread(KernelMode, FALSE, &TinyTime); 105 OldIrql = MiAcquirePfnLock(); 106 continue; 107 } 108 109 ASSERT(Segment->SegFlags & MM_DATAFILE_SEGMENT); 110 InterlockedIncrement64(&Segment->RefCount); 111 break; 112 } 113 114 MiReleasePfnLock(OldIrql); 115 116 return Segment; 117 } 118 119 /* Somewhat grotesque, but eh... */ 120 PMM_IMAGE_SECTION_OBJECT ImageSectionObjectFromSegment(PMM_SECTION_SEGMENT Segment) 121 { 122 ASSERT((Segment->SegFlags & MM_DATAFILE_SEGMENT) == 0); 123 124 return CONTAINING_RECORD(Segment->ReferenceCount, MM_IMAGE_SECTION_OBJECT, RefCount); 125 } 126 127 NTSTATUS 128 MiMapViewInSystemSpace(IN PVOID Section, 129 IN PVOID Session, 130 OUT PVOID *MappedBase, 131 IN OUT PSIZE_T ViewSize, 132 IN PLARGE_INTEGER SectionOffset); 133 134 NTSTATUS 135 NTAPI 136 MmCreateArm3Section(OUT PVOID *SectionObject, 137 IN ACCESS_MASK DesiredAccess, 138 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 139 IN PLARGE_INTEGER InputMaximumSize, 140 IN ULONG SectionPageProtection, 141 IN ULONG AllocationAttributes, 142 IN HANDLE FileHandle OPTIONAL, 143 IN PFILE_OBJECT FileObject OPTIONAL); 144 145 NTSTATUS 146 NTAPI 147 MmMapViewOfArm3Section(IN PVOID SectionObject, 148 IN PEPROCESS Process, 149 IN OUT PVOID *BaseAddress, 150 IN ULONG_PTR ZeroBits, 151 IN SIZE_T CommitSize, 152 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, 153 IN OUT PSIZE_T ViewSize, 154 IN SECTION_INHERIT InheritDisposition, 155 IN ULONG AllocationType, 156 IN ULONG Protect); 157 158 // 159 // PeFmtCreateSection depends on the following: 160 // 161 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE >= sizeof(IMAGE_DOS_HEADER)); 162 C_ASSERT(sizeof(IMAGE_NT_HEADERS32) <= sizeof(IMAGE_NT_HEADERS64)); 163 164 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64)); 165 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64, FileHeader)); 166 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader) == FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader)); 167 168 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Magic)); 169 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SectionAlignment)); 170 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, FileAlignment)); 171 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Subsystem)); 172 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MinorSubsystemVersion)); 173 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MajorSubsystemVersion)); 174 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint)); 175 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode)); 176 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfHeaders)); 177 178 /* TYPES *********************************************************************/ 179 180 typedef struct 181 { 182 PMEMORY_AREA MemoryArea; 183 PMM_SECTION_SEGMENT Segment; 184 LARGE_INTEGER Offset; 185 BOOLEAN WasDirty; 186 BOOLEAN Private; 187 PEPROCESS CallingProcess; 188 ULONG_PTR SectionEntry; 189 } 190 MM_SECTION_PAGEOUT_CONTEXT; 191 192 /* GLOBALS *******************************************************************/ 193 194 POBJECT_TYPE MmSectionObjectType = NULL; 195 196 ULONG_PTR MmSubsectionBase; 197 198 static ULONG SectionCharacteristicsToProtect[16] = 199 { 200 PAGE_NOACCESS, /* 0 = NONE */ 201 PAGE_NOACCESS, /* 1 = SHARED */ 202 PAGE_EXECUTE, /* 2 = EXECUTABLE */ 203 PAGE_EXECUTE, /* 3 = EXECUTABLE, SHARED */ 204 PAGE_READONLY, /* 4 = READABLE */ 205 PAGE_READONLY, /* 5 = READABLE, SHARED */ 206 PAGE_EXECUTE_READ, /* 6 = READABLE, EXECUTABLE */ 207 PAGE_EXECUTE_READ, /* 7 = READABLE, EXECUTABLE, SHARED */ 208 /* 209 * FIXME? do we really need the WriteCopy field in segments? can't we use 210 * PAGE_WRITECOPY here? 211 */ 212 PAGE_READWRITE, /* 8 = WRITABLE */ 213 PAGE_READWRITE, /* 9 = WRITABLE, SHARED */ 214 PAGE_EXECUTE_READWRITE, /* 10 = WRITABLE, EXECUTABLE */ 215 PAGE_EXECUTE_READWRITE, /* 11 = WRITABLE, EXECUTABLE, SHARED */ 216 PAGE_READWRITE, /* 12 = WRITABLE, READABLE */ 217 PAGE_READWRITE, /* 13 = WRITABLE, READABLE, SHARED */ 218 PAGE_EXECUTE_READWRITE, /* 14 = WRITABLE, READABLE, EXECUTABLE */ 219 PAGE_EXECUTE_READWRITE, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */ 220 }; 221 222 extern ULONG MmMakeFileAccess []; 223 ACCESS_MASK NTAPI MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection); 224 static GENERIC_MAPPING MmpSectionMapping = 225 { 226 STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY, 227 STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE, 228 STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE, 229 SECTION_ALL_ACCESS 230 }; 231 232 233 /* FUNCTIONS *****************************************************************/ 234 235 236 237 NTSTATUS 238 NTAPI 239 MiWritePage(PMM_SECTION_SEGMENT Segment, 240 LONGLONG SegOffset, 241 PFN_NUMBER Page) 242 /* 243 * FUNCTION: write a page for a section backed memory area. 244 * PARAMETERS: 245 * MemoryArea - Memory area to write the page for. 246 * Offset - Offset of the page to write. 247 * Page - Page which contains the data to write. 248 */ 249 { 250 NTSTATUS Status; 251 IO_STATUS_BLOCK IoStatus; 252 KEVENT Event; 253 UCHAR MdlBase[sizeof(MDL) + sizeof(PFN_NUMBER)]; 254 PMDL Mdl = (PMDL)MdlBase; 255 PFILE_OBJECT FileObject = Segment->FileObject; 256 LARGE_INTEGER FileOffset; 257 258 FileOffset.QuadPart = Segment->Image.FileOffset + SegOffset; 259 260 RtlZeroMemory(MdlBase, sizeof(MdlBase)); 261 MmInitializeMdl(Mdl, NULL, PAGE_SIZE); 262 MmBuildMdlFromPages(Mdl, &Page); 263 Mdl->MdlFlags |= MDL_PAGES_LOCKED; 264 265 KeInitializeEvent(&Event, NotificationEvent, FALSE); 266 Status = IoSynchronousPageWrite(FileObject, Mdl, &FileOffset, &Event, &IoStatus); 267 if (Status == STATUS_PENDING) 268 { 269 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 270 Status = IoStatus.Status; 271 } 272 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) 273 { 274 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); 275 } 276 277 return Status; 278 } 279 280 281 /* 282 References: 283 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object 284 File Format Specification", revision 6.0 (February 1999) 285 */ 286 NTSTATUS NTAPI PeFmtCreateSection(IN CONST VOID * FileHeader, 287 IN SIZE_T FileHeaderSize, 288 IN PVOID File, 289 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, 290 OUT PULONG Flags, 291 IN PEXEFMT_CB_READ_FILE ReadFileCb, 292 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb) 293 { 294 NTSTATUS nStatus; 295 ULONG cbFileHeaderOffsetSize = 0; 296 ULONG cbSectionHeadersOffset = 0; 297 ULONG cbSectionHeadersSize; 298 ULONG cbSectionHeadersOffsetSize = 0; 299 ULONG cbOptHeaderSize; 300 ULONG cbHeadersSize = 0; 301 ULONG nSectionAlignment; 302 ULONG nFileAlignment; 303 ULONG_PTR ImageBase = 0; 304 const IMAGE_DOS_HEADER * pidhDosHeader; 305 const IMAGE_NT_HEADERS32 * pinhNtHeader; 306 const IMAGE_OPTIONAL_HEADER32 * piohOptHeader; 307 const IMAGE_SECTION_HEADER * pishSectionHeaders; 308 PMM_SECTION_SEGMENT pssSegments; 309 LARGE_INTEGER lnOffset; 310 PVOID pBuffer; 311 SIZE_T nPrevVirtualEndOfSegment = 0; 312 ULONG nFileSizeOfHeaders = 0; 313 ULONG i; 314 ULONG AlignedLength; 315 316 ASSERT(FileHeader); 317 ASSERT(FileHeaderSize > 0); 318 ASSERT(File); 319 ASSERT(ImageSectionObject); 320 ASSERT(ReadFileCb); 321 ASSERT(AllocateSegmentsCb); 322 323 ASSERT(Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize)); 324 325 ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_DOS_HEADER)) == 0); 326 327 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; } 328 329 pBuffer = NULL; 330 pidhDosHeader = FileHeader; 331 332 /* DOS HEADER */ 333 nStatus = STATUS_ROS_EXEFMT_UNKNOWN_FORMAT; 334 335 /* image too small to be an MZ executable */ 336 if(FileHeaderSize < sizeof(IMAGE_DOS_HEADER)) 337 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize)); 338 339 /* no MZ signature */ 340 if(pidhDosHeader->e_magic != IMAGE_DOS_SIGNATURE) 341 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader->e_magic)); 342 343 /* NT HEADER */ 344 nStatus = STATUS_INVALID_IMAGE_PROTECT; 345 346 /* not a Windows executable */ 347 if(pidhDosHeader->e_lfanew <= 0) 348 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew)); 349 350 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize, pidhDosHeader->e_lfanew, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader))) 351 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew)); 352 353 if(FileHeaderSize < cbFileHeaderOffsetSize) 354 pinhNtHeader = NULL; 355 else 356 { 357 /* 358 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize), 359 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too 360 */ 361 ASSERT(Intsafe_CanOffsetPointer(FileHeader, pidhDosHeader->e_lfanew)); 362 pinhNtHeader = (PVOID)((UINT_PTR)FileHeader + pidhDosHeader->e_lfanew); 363 } 364 365 /* 366 * the buffer doesn't contain the NT file header, or the alignment is wrong: we 367 * need to read the header from the file 368 */ 369 if(FileHeaderSize < cbFileHeaderOffsetSize || 370 (UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0) 371 { 372 ULONG cbNtHeaderSize; 373 ULONG cbReadSize; 374 PVOID pData; 375 376 l_ReadHeaderFromFile: 377 cbNtHeaderSize = 0; 378 lnOffset.QuadPart = pidhDosHeader->e_lfanew; 379 380 /* read the header from the file */ 381 nStatus = ReadFileCb(File, &lnOffset, sizeof(IMAGE_NT_HEADERS64), &pData, &pBuffer, &cbReadSize); 382 383 if(!NT_SUCCESS(nStatus)) 384 { 385 NTSTATUS ReturnedStatus = nStatus; 386 387 /* If it attempted to read past the end of the file, it means e_lfanew is invalid */ 388 if (ReturnedStatus == STATUS_END_OF_FILE) nStatus = STATUS_INVALID_IMAGE_PROTECT; 389 390 DIE(("ReadFile failed, status %08X\n", ReturnedStatus)); 391 } 392 393 ASSERT(pData); 394 ASSERT(pBuffer); 395 ASSERT(cbReadSize > 0); 396 397 nStatus = STATUS_INVALID_IMAGE_FORMAT; 398 399 /* the buffer doesn't contain the file header */ 400 if(cbReadSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader)) 401 DIE(("The file doesn't contain the PE file header\n")); 402 403 pinhNtHeader = pData; 404 405 /* object still not aligned: copy it to the beginning of the buffer */ 406 if((UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0) 407 { 408 ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == 0); 409 RtlMoveMemory(pBuffer, pData, cbReadSize); 410 pinhNtHeader = pBuffer; 411 } 412 413 /* invalid NT header */ 414 nStatus = STATUS_INVALID_IMAGE_PROTECT; 415 416 if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE) 417 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature)); 418 419 nStatus = STATUS_INVALID_IMAGE_FORMAT; 420 421 if(!Intsafe_AddULong32(&cbNtHeaderSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader))) 422 DIE(("The full NT header is too large\n")); 423 424 /* the buffer doesn't contain the whole NT header */ 425 if(cbReadSize < cbNtHeaderSize) 426 DIE(("The file doesn't contain the full NT header\n")); 427 } 428 else 429 { 430 ULONG cbOptHeaderOffsetSize = 0; 431 432 nStatus = STATUS_INVALID_IMAGE_PROTECT; 433 434 /* don't trust an invalid NT header */ 435 if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE) 436 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature)); 437 438 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader))) 439 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew)); 440 441 nStatus = STATUS_INVALID_IMAGE_FORMAT; 442 443 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, cbOptHeaderOffsetSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader)) 444 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader->FileHeader.SizeOfOptionalHeader)); 445 446 /* the buffer doesn't contain the whole NT header: read it from the file */ 447 if(cbOptHeaderOffsetSize > FileHeaderSize) 448 goto l_ReadHeaderFromFile; 449 } 450 451 /* read information from the NT header */ 452 piohOptHeader = &pinhNtHeader->OptionalHeader; 453 cbOptHeaderSize = pinhNtHeader->FileHeader.SizeOfOptionalHeader; 454 455 nStatus = STATUS_INVALID_IMAGE_FORMAT; 456 457 if(!RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Magic)) 458 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize)); 459 460 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */ 461 462 switch(piohOptHeader->Magic) 463 { 464 case IMAGE_NT_OPTIONAL_HDR64_MAGIC: 465 #ifndef _WIN64 466 nStatus = STATUS_INVALID_IMAGE_WIN_64; 467 DIE(("Win64 optional header, unsupported\n")); 468 #else 469 // Fall through. 470 #endif 471 case IMAGE_NT_OPTIONAL_HDR32_MAGIC: 472 break; 473 default: 474 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader->Magic)); 475 } 476 477 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SectionAlignment) && 478 RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, FileAlignment)) 479 { 480 /* See [1], section 3.4.2 */ 481 if(piohOptHeader->SectionAlignment < PAGE_SIZE) 482 { 483 if(piohOptHeader->FileAlignment != piohOptHeader->SectionAlignment) 484 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n")); 485 } 486 else if(piohOptHeader->SectionAlignment < piohOptHeader->FileAlignment) 487 DIE(("The section alignment is smaller than the file alignment\n")); 488 489 nSectionAlignment = piohOptHeader->SectionAlignment; 490 nFileAlignment = piohOptHeader->FileAlignment; 491 492 if(!IsPowerOf2(nSectionAlignment) || !IsPowerOf2(nFileAlignment)) 493 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment, nFileAlignment)); 494 } 495 else 496 { 497 nSectionAlignment = PAGE_SIZE; 498 nFileAlignment = PAGE_SIZE; 499 } 500 501 ASSERT(IsPowerOf2(nSectionAlignment)); 502 ASSERT(IsPowerOf2(nFileAlignment)); 503 504 switch(piohOptHeader->Magic) 505 { 506 /* PE32 */ 507 case IMAGE_NT_OPTIONAL_HDR32_MAGIC: 508 { 509 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, ImageBase)) 510 ImageBase = piohOptHeader->ImageBase; 511 512 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfImage)) 513 ImageSectionObject->ImageInformation.ImageFileSize = piohOptHeader->SizeOfImage; 514 515 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackReserve)) 516 ImageSectionObject->ImageInformation.MaximumStackSize = piohOptHeader->SizeOfStackReserve; 517 518 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackCommit)) 519 ImageSectionObject->ImageInformation.CommittedStackSize = piohOptHeader->SizeOfStackCommit; 520 521 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Subsystem)) 522 { 523 ImageSectionObject->ImageInformation.SubSystemType = piohOptHeader->Subsystem; 524 525 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MinorSubsystemVersion) && 526 RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MajorSubsystemVersion)) 527 { 528 ImageSectionObject->ImageInformation.SubSystemMinorVersion = piohOptHeader->MinorSubsystemVersion; 529 ImageSectionObject->ImageInformation.SubSystemMajorVersion = piohOptHeader->MajorSubsystemVersion; 530 } 531 } 532 533 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint)) 534 { 535 ImageSectionObject->ImageInformation.TransferAddress = (PVOID) (ImageBase + 536 piohOptHeader->AddressOfEntryPoint); 537 } 538 539 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfCode)) 540 ImageSectionObject->ImageInformation.ImageContainsCode = piohOptHeader->SizeOfCode != 0; 541 else 542 ImageSectionObject->ImageInformation.ImageContainsCode = TRUE; 543 544 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint)) 545 { 546 if (piohOptHeader->AddressOfEntryPoint == 0) 547 { 548 ImageSectionObject->ImageInformation.ImageContainsCode = FALSE; 549 } 550 } 551 552 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, LoaderFlags)) 553 ImageSectionObject->ImageInformation.LoaderFlags = piohOptHeader->LoaderFlags; 554 555 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, DllCharacteristics)) 556 { 557 ImageSectionObject->ImageInformation.DllCharacteristics = piohOptHeader->DllCharacteristics; 558 559 /* 560 * Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code 561 * this flag here, which will prevent the loader and other code from doing any .manifest or SxS 562 * magic to any binary. 563 * 564 * This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc 565 * but honestly that's not tested. It will also break them when running no ReactOS once we implement 566 * the SxS support -- at which point, duh, this should be removed. 567 * 568 * But right now, any app depending on SxS is already broken anyway, so this flag only helps. 569 */ 570 ImageSectionObject->ImageInformation.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION; 571 } 572 573 break; 574 } 575 #ifdef _WIN64 576 /* PE64 */ 577 case IMAGE_NT_OPTIONAL_HDR64_MAGIC: 578 { 579 const IMAGE_OPTIONAL_HEADER64 * pioh64OptHeader; 580 581 pioh64OptHeader = (const IMAGE_OPTIONAL_HEADER64 *)piohOptHeader; 582 583 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, ImageBase)) 584 { 585 ImageBase = pioh64OptHeader->ImageBase; 586 if(pioh64OptHeader->ImageBase > MAXULONG_PTR) 587 DIE(("ImageBase exceeds the address space\n")); 588 } 589 590 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfImage)) 591 { 592 if(pioh64OptHeader->SizeOfImage > MAXULONG_PTR) 593 DIE(("SizeOfImage exceeds the address space\n")); 594 595 ImageSectionObject->ImageInformation.ImageFileSize = pioh64OptHeader->SizeOfImage; 596 } 597 598 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackReserve)) 599 { 600 if(pioh64OptHeader->SizeOfStackReserve > MAXULONG_PTR) 601 DIE(("SizeOfStackReserve exceeds the address space\n")); 602 603 ImageSectionObject->ImageInformation.MaximumStackSize = (ULONG_PTR) pioh64OptHeader->SizeOfStackReserve; 604 } 605 606 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackCommit)) 607 { 608 if(pioh64OptHeader->SizeOfStackCommit > MAXULONG_PTR) 609 DIE(("SizeOfStackCommit exceeds the address space\n")); 610 611 ImageSectionObject->ImageInformation.CommittedStackSize = (ULONG_PTR) pioh64OptHeader->SizeOfStackCommit; 612 } 613 614 if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, Subsystem)) 615 { 616 ImageSectionObject->ImageInformation.SubSystemType = pioh64OptHeader->Subsystem; 617 618 if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, MinorSubsystemVersion) && 619 RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, MajorSubsystemVersion)) 620 { 621 ImageSectionObject->ImageInformation.SubSystemMinorVersion = pioh64OptHeader->MinorSubsystemVersion; 622 ImageSectionObject->ImageInformation.SubSystemMajorVersion = pioh64OptHeader->MajorSubsystemVersion; 623 } 624 } 625 626 if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, AddressOfEntryPoint)) 627 { 628 ImageSectionObject->ImageInformation.TransferAddress = (PVOID) (ImageBase + 629 pioh64OptHeader->AddressOfEntryPoint); 630 } 631 632 if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfCode)) 633 ImageSectionObject->ImageInformation.ImageContainsCode = pioh64OptHeader->SizeOfCode != 0; 634 else 635 ImageSectionObject->ImageInformation.ImageContainsCode = TRUE; 636 637 if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, AddressOfEntryPoint)) 638 { 639 if (pioh64OptHeader->AddressOfEntryPoint == 0) 640 { 641 ImageSectionObject->ImageInformation.ImageContainsCode = FALSE; 642 } 643 } 644 645 if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, LoaderFlags)) 646 ImageSectionObject->ImageInformation.LoaderFlags = pioh64OptHeader->LoaderFlags; 647 648 if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, DllCharacteristics)) 649 ImageSectionObject->ImageInformation.DllCharacteristics = pioh64OptHeader->DllCharacteristics; 650 651 break; 652 } 653 #endif // _WIN64 654 } 655 656 /* [1], section 3.4.2 */ 657 if((ULONG_PTR)ImageBase % 0x10000) 658 DIE(("ImageBase is not aligned on a 64KB boundary")); 659 660 ImageSectionObject->ImageInformation.ImageCharacteristics = pinhNtHeader->FileHeader.Characteristics; 661 ImageSectionObject->ImageInformation.Machine = pinhNtHeader->FileHeader.Machine; 662 ImageSectionObject->ImageInformation.GpValue = 0; 663 ImageSectionObject->ImageInformation.ZeroBits = 0; 664 ImageSectionObject->BasedAddress = (PVOID)ImageBase; 665 666 /* SECTION HEADERS */ 667 nStatus = STATUS_INVALID_IMAGE_FORMAT; 668 669 /* see [1], section 3.3 */ 670 if(pinhNtHeader->FileHeader.NumberOfSections > 96) 671 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader->FileHeader.NumberOfSections)); 672 673 /* 674 * the additional segment is for the file's headers. They need to be present for 675 * the benefit of the dynamic loader (to locate exports, defaults for thread 676 * parameters, resources, etc.) 677 */ 678 ImageSectionObject->NrSegments = pinhNtHeader->FileHeader.NumberOfSections + 1; 679 680 /* file offset for the section headers */ 681 if(!Intsafe_AddULong32(&cbSectionHeadersOffset, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader))) 682 DIE(("Offset overflow\n")); 683 684 if(!Intsafe_AddULong32(&cbSectionHeadersOffset, cbSectionHeadersOffset, pinhNtHeader->FileHeader.SizeOfOptionalHeader)) 685 DIE(("Offset overflow\n")); 686 687 /* size of the section headers */ 688 ASSERT(Intsafe_CanMulULong32(pinhNtHeader->FileHeader.NumberOfSections, sizeof(IMAGE_SECTION_HEADER))); 689 cbSectionHeadersSize = pinhNtHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER); 690 691 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize, cbSectionHeadersOffset, cbSectionHeadersSize)) 692 DIE(("Section headers too large\n")); 693 694 /* size of the executable's headers */ 695 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfHeaders)) 696 { 697 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment)) 698 // DIE(("SizeOfHeaders is not aligned\n")); 699 700 if(cbSectionHeadersSize > piohOptHeader->SizeOfHeaders) 701 DIE(("The section headers overflow SizeOfHeaders\n")); 702 703 cbHeadersSize = piohOptHeader->SizeOfHeaders; 704 } 705 else if(!AlignUp(&cbHeadersSize, cbSectionHeadersOffsetSize, nFileAlignment)) 706 DIE(("Overflow aligning the size of headers\n")); 707 708 if(pBuffer) 709 { 710 ExFreePool(pBuffer); 711 pBuffer = NULL; 712 } 713 /* WARNING: pinhNtHeader IS NO LONGER USABLE */ 714 /* WARNING: piohOptHeader IS NO LONGER USABLE */ 715 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */ 716 717 if(FileHeaderSize < cbSectionHeadersOffsetSize) 718 pishSectionHeaders = NULL; 719 else 720 { 721 /* 722 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize), 723 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too 724 */ 725 ASSERT(Intsafe_CanOffsetPointer(FileHeader, cbSectionHeadersOffset)); 726 pishSectionHeaders = (PVOID)((UINT_PTR)FileHeader + cbSectionHeadersOffset); 727 } 728 729 /* 730 * the buffer doesn't contain the section headers, or the alignment is wrong: 731 * read the headers from the file 732 */ 733 if(FileHeaderSize < cbSectionHeadersOffsetSize || 734 (UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0) 735 { 736 PVOID pData; 737 ULONG cbReadSize; 738 739 lnOffset.QuadPart = cbSectionHeadersOffset; 740 741 /* read the header from the file */ 742 nStatus = ReadFileCb(File, &lnOffset, cbSectionHeadersSize, &pData, &pBuffer, &cbReadSize); 743 744 if(!NT_SUCCESS(nStatus)) 745 DIE(("ReadFile failed with status %08X\n", nStatus)); 746 747 ASSERT(pData); 748 ASSERT(pBuffer); 749 ASSERT(cbReadSize > 0); 750 751 nStatus = STATUS_INVALID_IMAGE_FORMAT; 752 753 /* the buffer doesn't contain all the section headers */ 754 if(cbReadSize < cbSectionHeadersSize) 755 DIE(("The file doesn't contain all of the section headers\n")); 756 757 pishSectionHeaders = pData; 758 759 /* object still not aligned: copy it to the beginning of the buffer */ 760 if((UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0) 761 { 762 ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) == 0); 763 RtlMoveMemory(pBuffer, pData, cbReadSize); 764 pishSectionHeaders = pBuffer; 765 } 766 } 767 768 /* SEGMENTS */ 769 /* allocate the segments */ 770 nStatus = STATUS_INSUFFICIENT_RESOURCES; 771 ImageSectionObject->Segments = AllocateSegmentsCb(ImageSectionObject->NrSegments); 772 773 if(ImageSectionObject->Segments == NULL) 774 DIE(("AllocateSegments failed\n")); 775 776 /* initialize the headers segment */ 777 pssSegments = ImageSectionObject->Segments; 778 779 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment)); 780 781 if(!AlignUp(&nFileSizeOfHeaders, cbHeadersSize, nFileAlignment)) 782 DIE(("Cannot align the size of the section headers\n")); 783 784 nPrevVirtualEndOfSegment = ALIGN_UP_BY(cbHeadersSize, nSectionAlignment); 785 if (nPrevVirtualEndOfSegment < cbHeadersSize) 786 DIE(("Cannot align the size of the section headers\n")); 787 788 pssSegments[0].Image.FileOffset = 0; 789 pssSegments[0].Protection = PAGE_READONLY; 790 pssSegments[0].Length.QuadPart = nPrevVirtualEndOfSegment; 791 pssSegments[0].RawLength.QuadPart = nFileSizeOfHeaders; 792 pssSegments[0].Image.VirtualAddress = 0; 793 pssSegments[0].Image.Characteristics = 0; 794 pssSegments[0].WriteCopy = TRUE; 795 796 /* skip the headers segment */ 797 ++ pssSegments; 798 799 nStatus = STATUS_INVALID_IMAGE_FORMAT; 800 801 ASSERT(ImageSectionObject->RefCount > 0); 802 803 /* convert the executable sections into segments. See also [1], section 4 */ 804 for(i = 0; i < ImageSectionObject->NrSegments - 1; ++ i) 805 { 806 ULONG nCharacteristics; 807 808 /* validate the alignment */ 809 if(!IsAligned(pishSectionHeaders[i].VirtualAddress, nSectionAlignment)) 810 DIE(("Image.VirtualAddress[%u] is not aligned\n", i)); 811 812 /* sections must be contiguous, ordered by base address and non-overlapping */ 813 if(pishSectionHeaders[i].VirtualAddress != nPrevVirtualEndOfSegment) 814 DIE(("Memory gap between section %u and the previous\n", i)); 815 816 /* ignore explicit BSS sections */ 817 if(pishSectionHeaders[i].SizeOfRawData != 0) 818 { 819 /* validate the alignment */ 820 #if 0 821 /* Yes, this should be a multiple of FileAlignment, but there's 822 * stuff out there that isn't. We can cope with that 823 */ 824 if(!IsAligned(pishSectionHeaders[i].SizeOfRawData, nFileAlignment)) 825 DIE(("SizeOfRawData[%u] is not aligned\n", i)); 826 #endif 827 828 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment)) 829 // DIE(("PointerToRawData[%u] is not aligned\n", i)); 830 831 if(!Intsafe_CanAddULong32(pishSectionHeaders[i].PointerToRawData, pishSectionHeaders[i].SizeOfRawData)) 832 DIE(("SizeOfRawData[%u] too large\n", i)); 833 834 /* conversion */ 835 pssSegments[i].Image.FileOffset = pishSectionHeaders[i].PointerToRawData; 836 pssSegments[i].RawLength.QuadPart = pishSectionHeaders[i].SizeOfRawData; 837 } 838 else 839 { 840 /* FIXME: Should reset PointerToRawData to 0 in the image mapping */ 841 ASSERT(pssSegments[i].Image.FileOffset == 0); 842 ASSERT(pssSegments[i].RawLength.QuadPart == 0); 843 } 844 845 ASSERT(Intsafe_CanAddLong64(pssSegments[i].Image.FileOffset, pssSegments[i].RawLength.QuadPart)); 846 847 nCharacteristics = pishSectionHeaders[i].Characteristics; 848 849 /* no explicit protection */ 850 if((nCharacteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == 0) 851 { 852 if(nCharacteristics & IMAGE_SCN_CNT_CODE) 853 nCharacteristics |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ; 854 855 if(nCharacteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) 856 nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; 857 858 if(nCharacteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) 859 nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; 860 } 861 862 /* see table above */ 863 pssSegments[i].Protection = SectionCharacteristicsToProtect[nCharacteristics >> 28]; 864 pssSegments[i].WriteCopy = !(nCharacteristics & IMAGE_SCN_MEM_SHARED); 865 866 if(pishSectionHeaders[i].Misc.VirtualSize == 0) 867 pssSegments[i].Length.QuadPart = pishSectionHeaders[i].SizeOfRawData; 868 else 869 pssSegments[i].Length.QuadPart = pishSectionHeaders[i].Misc.VirtualSize; 870 871 AlignedLength = ALIGN_UP_BY(pssSegments[i].Length.LowPart, nSectionAlignment); 872 if(AlignedLength < pssSegments[i].Length.LowPart) 873 DIE(("Cannot align the virtual size of section %u\n", i)); 874 875 pssSegments[i].Length.LowPart = AlignedLength; 876 877 if(pssSegments[i].Length.QuadPart == 0) 878 DIE(("Virtual size of section %u is null\n", i)); 879 880 pssSegments[i].Image.VirtualAddress = pishSectionHeaders[i].VirtualAddress; 881 pssSegments[i].Image.Characteristics = pishSectionHeaders[i].Characteristics; 882 883 /* ensure the memory image is no larger than 4GB */ 884 nPrevVirtualEndOfSegment = (ULONG_PTR)(pssSegments[i].Image.VirtualAddress + pssSegments[i].Length.QuadPart); 885 if (nPrevVirtualEndOfSegment < pssSegments[i].Image.VirtualAddress) 886 DIE(("The image is too large\n")); 887 } 888 889 if(nSectionAlignment >= PAGE_SIZE) 890 *Flags |= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED; 891 892 /* Success */ 893 nStatus = STATUS_SUCCESS;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32; 894 895 l_Return: 896 if(pBuffer) 897 ExFreePool(pBuffer); 898 899 return nStatus; 900 } 901 902 /* 903 * FUNCTION: Waits in kernel mode indefinitely for a file object lock. 904 * ARGUMENTS: PFILE_OBJECT to wait for. 905 * RETURNS: Status of the wait. 906 */ 907 NTSTATUS 908 MmspWaitForFileLock(PFILE_OBJECT File) 909 { 910 return STATUS_SUCCESS; 911 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL); 912 } 913 914 915 916 VOID 917 NTAPI 918 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment) 919 { 920 ULONG Length; 921 LARGE_INTEGER Offset; 922 ULONG_PTR Entry; 923 SWAPENTRY SavedSwapEntry; 924 PFN_NUMBER Page; 925 926 Page = 0; 927 928 MmLockSectionSegment(Segment); 929 930 Length = PAGE_ROUND_UP(Segment->Length.QuadPart); 931 for (Offset.QuadPart = 0; Offset.QuadPart < Length; Offset.QuadPart += PAGE_SIZE) 932 { 933 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 934 if (Entry) 935 { 936 MmSetPageEntrySectionSegment(Segment, &Offset, 0); 937 if (IS_SWAP_FROM_SSE(Entry)) 938 { 939 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry)); 940 } 941 else 942 { 943 Page = PFN_FROM_SSE(Entry); 944 SavedSwapEntry = MmGetSavedSwapEntryPage(Page); 945 if (SavedSwapEntry != 0) 946 { 947 MmSetSavedSwapEntryPage(Page, 0); 948 MmFreeSwapPage(SavedSwapEntry); 949 } 950 MmReleasePageMemoryConsumer(MC_USER, Page); 951 } 952 } 953 } 954 955 MmUnlockSectionSegment(Segment); 956 } 957 958 static 959 VOID 960 NTAPI 961 FreeSegmentPage(PMM_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset) 962 { 963 ULONG_PTR Entry; 964 PFN_NUMBER Page; 965 966 MmLockSectionSegment(Segment); 967 968 Entry = MmGetPageEntrySectionSegment(Segment, Offset); 969 970 MmUnlockSectionSegment(Segment); 971 972 /* This must be either a valid entry or nothing */ 973 ASSERT(!IS_SWAP_FROM_SSE(Entry)); 974 975 /* There should be no reference anymore */ 976 ASSERT(SHARE_COUNT_FROM_SSE(Entry) == 0); 977 978 Page = PFN_FROM_SSE(Entry); 979 /* If there is a page, this must be because it's still dirty */ 980 ASSERT(Page != 0); 981 982 /* Write the page */ 983 if (IS_DIRTY_SSE(Entry)) 984 MiWritePage(Segment, Offset->QuadPart, Page); 985 986 MmReleasePageMemoryConsumer(MC_USER, Page); 987 } 988 989 VOID 990 NTAPI 991 MmDereferenceSegment(PMM_SECTION_SEGMENT Segment) 992 { 993 KIRQL OldIrql; 994 995 /* Lock the PFN lock because we mess around with SectionObjectPointers */ 996 OldIrql = MiAcquirePfnLock(); 997 998 if (InterlockedDecrement64(Segment->ReferenceCount) > 0) 999 { 1000 /* Nothing to do yet */ 1001 MiReleasePfnLock(OldIrql); 1002 return; 1003 } 1004 1005 *Segment->Flags |= MM_SEGMENT_INDELETE; 1006 1007 MiReleasePfnLock(OldIrql); 1008 1009 /* Flush the segment */ 1010 if (*Segment->Flags & MM_DATAFILE_SEGMENT) 1011 { 1012 /* Free the page table. This will flush any remaining dirty data */ 1013 MmFreePageTablesSectionSegment(Segment, FreeSegmentPage); 1014 1015 OldIrql = MiAcquirePfnLock(); 1016 /* Delete the pointer on the file */ 1017 ASSERT(Segment->FileObject->SectionObjectPointer->DataSectionObject == Segment); 1018 Segment->FileObject->SectionObjectPointer->DataSectionObject = NULL; 1019 MiReleasePfnLock(OldIrql); 1020 ObDereferenceObject(Segment->FileObject); 1021 1022 ExFreePoolWithTag(Segment, TAG_MM_SECTION_SEGMENT); 1023 } 1024 else 1025 { 1026 /* Most grotesque thing ever */ 1027 PMM_IMAGE_SECTION_OBJECT ImageSectionObject = CONTAINING_RECORD(Segment->ReferenceCount, MM_IMAGE_SECTION_OBJECT, RefCount); 1028 PMM_SECTION_SEGMENT SectionSegments; 1029 ULONG NrSegments; 1030 ULONG i; 1031 1032 OldIrql = MiAcquirePfnLock(); 1033 /* Delete the pointer on the file */ 1034 ASSERT(ImageSectionObject->FileObject->SectionObjectPointer->ImageSectionObject == ImageSectionObject); 1035 ImageSectionObject->FileObject->SectionObjectPointer->ImageSectionObject = NULL; 1036 MiReleasePfnLock(OldIrql); 1037 1038 ObDereferenceObject(ImageSectionObject->FileObject); 1039 1040 NrSegments = ImageSectionObject->NrSegments; 1041 SectionSegments = ImageSectionObject->Segments; 1042 for (i = 0; i < NrSegments; i++) 1043 { 1044 if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED) 1045 { 1046 MmpFreePageFileSegment(&SectionSegments[i]); 1047 } 1048 1049 MmFreePageTablesSectionSegment(&SectionSegments[i], NULL); 1050 } 1051 1052 ExFreePoolWithTag(ImageSectionObject->Segments, TAG_MM_SECTION_SEGMENT); 1053 ExFreePoolWithTag(ImageSectionObject, TAG_MM_SECTION_SEGMENT); 1054 } 1055 } 1056 1057 VOID 1058 NTAPI 1059 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment, 1060 PLARGE_INTEGER Offset) 1061 { 1062 ULONG_PTR Entry; 1063 1064 Entry = MmGetPageEntrySectionSegment(Segment, Offset); 1065 if (Entry == 0) 1066 { 1067 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n"); 1068 KeBugCheck(MEMORY_MANAGEMENT); 1069 } 1070 if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT) 1071 { 1072 DPRINT1("Maximum share count reached\n"); 1073 KeBugCheck(MEMORY_MANAGEMENT); 1074 } 1075 if (IS_SWAP_FROM_SSE(Entry)) 1076 { 1077 KeBugCheck(MEMORY_MANAGEMENT); 1078 } 1079 MmSetPageEntrySectionSegment(Segment, Offset, BUMPREF_SSE(Entry)); 1080 } 1081 1082 BOOLEAN 1083 NTAPI 1084 MmUnsharePageEntrySectionSegment(PMEMORY_AREA MemoryArea, 1085 PMM_SECTION_SEGMENT Segment, 1086 PLARGE_INTEGER Offset, 1087 BOOLEAN Dirty, 1088 BOOLEAN PageOut, 1089 ULONG_PTR *InEntry) 1090 { 1091 ULONG_PTR Entry = InEntry ? *InEntry : MmGetPageEntrySectionSegment(Segment, Offset); 1092 PFN_NUMBER Page = PFN_FROM_SSE(Entry); 1093 BOOLEAN IsDataMap = BooleanFlagOn(*Segment->Flags, MM_DATAFILE_SEGMENT); 1094 1095 if (Entry == 0) 1096 { 1097 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n"); 1098 KeBugCheck(MEMORY_MANAGEMENT); 1099 } 1100 if (SHARE_COUNT_FROM_SSE(Entry) == 0) 1101 { 1102 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment, Offset->LowPart, PFN_FROM_SSE(Entry)); 1103 KeBugCheck(MEMORY_MANAGEMENT); 1104 } 1105 if (IS_SWAP_FROM_SSE(Entry)) 1106 { 1107 KeBugCheck(MEMORY_MANAGEMENT); 1108 } 1109 Entry = DECREF_SSE(Entry); 1110 if (Dirty) Entry = DIRTY_SSE(Entry); 1111 1112 /* If we are paging-out, pruning the page for real will be taken care of in MmCheckDirtySegment */ 1113 if ((SHARE_COUNT_FROM_SSE(Entry) > 0) || PageOut) 1114 { 1115 /* Update the page mapping in the segment and we're done */ 1116 MmSetPageEntrySectionSegment(Segment, Offset, Entry); 1117 return FALSE; 1118 } 1119 1120 /* We are pruning the last mapping on this page. See if we can keep it a bit more. */ 1121 ASSERT(!PageOut); 1122 1123 if (IsDataMap) 1124 { 1125 /* We can always keep memory in for data maps */ 1126 MmSetPageEntrySectionSegment(Segment, Offset, Entry); 1127 return FALSE; 1128 } 1129 1130 if (!BooleanFlagOn(Segment->Image.Characteristics, IMAGE_SCN_MEM_SHARED)) 1131 { 1132 /* So this must have been a read-only page. Keep it ! */ 1133 ASSERT(Segment->WriteCopy); 1134 ASSERT(!IS_DIRTY_SSE(Entry)); 1135 ASSERT(MmGetSavedSwapEntryPage(Page) == 0); 1136 MmSetPageEntrySectionSegment(Segment, Offset, Entry); 1137 return FALSE; 1138 } 1139 1140 /* 1141 * So this is a page for a shared section of a DLL. 1142 * We can keep it if it is not dirty. 1143 */ 1144 SWAPENTRY SwapEntry = MmGetSavedSwapEntryPage(Page); 1145 if ((SwapEntry == 0) && !IS_DIRTY_SSE(Entry)) 1146 { 1147 MmSetPageEntrySectionSegment(Segment, Offset, Entry); 1148 return FALSE; 1149 } 1150 1151 /* No more processes are referencing this shared dirty page. Ditch it. */ 1152 if (SwapEntry) 1153 { 1154 MmSetSavedSwapEntryPage(Page, 0); 1155 MmFreeSwapPage(SwapEntry); 1156 } 1157 MmSetPageEntrySectionSegment(Segment, Offset, 0); 1158 MmReleasePageMemoryConsumer(MC_USER, Page); 1159 return TRUE; 1160 } 1161 1162 static 1163 NTSTATUS 1164 MiCopyFromUserPage(PFN_NUMBER DestPage, const VOID *SrcAddress) 1165 { 1166 PEPROCESS Process; 1167 KIRQL Irql; 1168 PVOID DestAddress; 1169 1170 Process = PsGetCurrentProcess(); 1171 DestAddress = MiMapPageInHyperSpace(Process, DestPage, &Irql); 1172 if (DestAddress == NULL) 1173 { 1174 return STATUS_NO_MEMORY; 1175 } 1176 ASSERT((ULONG_PTR)DestAddress % PAGE_SIZE == 0); 1177 ASSERT((ULONG_PTR)SrcAddress % PAGE_SIZE == 0); 1178 RtlCopyMemory(DestAddress, SrcAddress, PAGE_SIZE); 1179 MiUnmapPageInHyperSpace(Process, DestAddress, Irql); 1180 return STATUS_SUCCESS; 1181 } 1182 1183 static 1184 NTSTATUS 1185 NTAPI 1186 MmMakeSegmentResident( 1187 _In_ PMM_SECTION_SEGMENT Segment, 1188 _In_ LONGLONG Offset, 1189 _In_ ULONG Length, 1190 _In_opt_ PLARGE_INTEGER ValidDataLength) 1191 { 1192 /* Let's use a 64K granularity. */ 1193 LONGLONG RangeStart, RangeEnd; 1194 NTSTATUS Status; 1195 PFILE_OBJECT FileObject = Segment->FileObject; 1196 1197 /* Calculate our range, aligned on 64K if possible. */ 1198 Status = RtlLongLongAdd(Offset, Length, &RangeEnd); 1199 ASSERT(NT_SUCCESS(Status)); 1200 if (!NT_SUCCESS(Status)) 1201 return Status; 1202 1203 /* If the file is not random access and we are not the page out thread 1204 * read a 64K Chunk. */ 1205 if (((ULONG_PTR)IoGetTopLevelIrp() != FSRTL_MOD_WRITE_TOP_LEVEL_IRP) 1206 && !FlagOn(FileObject->Flags, FO_RANDOM_ACCESS)) 1207 { 1208 RangeStart = Offset - (Offset % _64K); 1209 if (RangeEnd % _64K) 1210 RangeEnd += _64K - (RangeEnd % _64K); 1211 } 1212 else 1213 { 1214 RangeStart = Offset - (Offset % PAGE_SIZE); 1215 if (RangeEnd % PAGE_SIZE) 1216 RangeEnd += PAGE_SIZE - (RangeEnd % PAGE_SIZE); 1217 } 1218 1219 /* Clamp if needed */ 1220 if (!FlagOn(*Segment->Flags, MM_DATAFILE_SEGMENT)) 1221 { 1222 if (RangeEnd > Segment->RawLength.QuadPart) 1223 RangeEnd = Segment->RawLength.QuadPart; 1224 } 1225 1226 /* Let's gooooooooo */ 1227 for ( ; RangeStart < RangeEnd; RangeStart += _64K) 1228 { 1229 /* First take a look at where we miss pages */ 1230 ULONG ToReadPageBits = 0; 1231 LONGLONG ChunkEnd = RangeStart + _64K; 1232 1233 if (ChunkEnd > RangeEnd) 1234 ChunkEnd = RangeEnd; 1235 1236 MmLockSectionSegment(Segment); 1237 for (LONGLONG ChunkOffset = RangeStart; ChunkOffset < ChunkEnd; ChunkOffset += PAGE_SIZE) 1238 { 1239 LARGE_INTEGER CurrentOffset; 1240 1241 CurrentOffset.QuadPart = ChunkOffset; 1242 ULONG_PTR Entry = MmGetPageEntrySectionSegment(Segment, &CurrentOffset); 1243 1244 /* Let any pending read proceed */ 1245 while (MM_IS_WAIT_PTE(Entry)) 1246 { 1247 MmUnlockSectionSegment(Segment); 1248 1249 KeDelayExecutionThread(KernelMode, FALSE, &TinyTime); 1250 1251 MmLockSectionSegment(Segment); 1252 Entry = MmGetPageEntrySectionSegment(Segment, &CurrentOffset); 1253 } 1254 1255 if (Entry != 0) 1256 { 1257 /* There is a page here. Or a swap entry. Or whatever... */ 1258 continue; 1259 } 1260 1261 ToReadPageBits |= 1UL << ((ChunkOffset - RangeStart) >> PAGE_SHIFT); 1262 1263 /* Put a wait entry here */ 1264 MmSetPageEntrySectionSegment(Segment, &CurrentOffset, MAKE_SWAP_SSE(MM_WAIT_ENTRY)); 1265 } 1266 MmUnlockSectionSegment(Segment); 1267 1268 if (ToReadPageBits == 0) 1269 { 1270 /* Nothing to do for this chunk */ 1271 continue; 1272 } 1273 1274 /* Now perform the actual read */ 1275 LONGLONG ChunkOffset = RangeStart; 1276 while (ChunkOffset < ChunkEnd) 1277 { 1278 /* Move forward if there is a hole */ 1279 ULONG BitSet; 1280 if (!_BitScanForward(&BitSet, ToReadPageBits)) 1281 { 1282 /* Nothing more to read */ 1283 break; 1284 } 1285 ToReadPageBits >>= BitSet; 1286 ChunkOffset += BitSet * PAGE_SIZE; 1287 ASSERT(ChunkOffset < ChunkEnd); 1288 1289 /* Get the range we have to read */ 1290 _BitScanForward(&BitSet, ~ToReadPageBits); 1291 ULONG ReadLength = BitSet * PAGE_SIZE; 1292 1293 ASSERT(ReadLength <= _64K); 1294 1295 /* Clamp (This is for image mappings */ 1296 if ((ChunkOffset + ReadLength) > ChunkEnd) 1297 ReadLength = ChunkEnd - ChunkOffset; 1298 1299 ASSERT(ReadLength != 0); 1300 1301 /* Allocate a MDL */ 1302 PMDL Mdl = IoAllocateMdl(NULL, ReadLength, FALSE, FALSE, NULL); 1303 if (!Mdl) 1304 { 1305 /* Damn. Roll-back. */ 1306 MmLockSectionSegment(Segment); 1307 while (ChunkOffset < ChunkEnd) 1308 { 1309 if (ToReadPageBits & 1) 1310 { 1311 LARGE_INTEGER CurrentOffset; 1312 CurrentOffset.QuadPart = ChunkOffset; 1313 ASSERT(MM_IS_WAIT_PTE(MmGetPageEntrySectionSegment(Segment, &CurrentOffset))); 1314 MmSetPageEntrySectionSegment(Segment, &CurrentOffset, 0); 1315 } 1316 ToReadPageBits >>= 1; 1317 ChunkOffset += PAGE_SIZE; 1318 } 1319 MmUnlockSectionSegment(Segment); 1320 return STATUS_INSUFFICIENT_RESOURCES; 1321 } 1322 1323 /* Get our pages */ 1324 PPFN_NUMBER Pages = MmGetMdlPfnArray(Mdl); 1325 RtlZeroMemory(Pages, BYTES_TO_PAGES(ReadLength) * sizeof(PFN_NUMBER)); 1326 for (UINT i = 0; i < BYTES_TO_PAGES(ReadLength); i++) 1327 { 1328 /* MmRequestPageMemoryConsumer succeeds or bugchecks */ 1329 (void)MmRequestPageMemoryConsumer(MC_USER, FALSE, &Pages[i]); 1330 } 1331 Mdl->MdlFlags |= MDL_PAGES_LOCKED | MDL_IO_PAGE_READ; 1332 1333 LARGE_INTEGER FileOffset; 1334 FileOffset.QuadPart = Segment->Image.FileOffset + ChunkOffset; 1335 1336 /* Clamp to VDL */ 1337 if (ValidDataLength && ((FileOffset.QuadPart + ReadLength) > ValidDataLength->QuadPart)) 1338 { 1339 if (FileOffset.QuadPart > ValidDataLength->QuadPart) 1340 { 1341 /* Great, nothing to read. */ 1342 goto AssignPagesToSegment; 1343 } 1344 1345 Mdl->Size = (FileOffset.QuadPart + ReadLength) - ValidDataLength->QuadPart; 1346 } 1347 1348 KEVENT Event; 1349 KeInitializeEvent(&Event, NotificationEvent, FALSE); 1350 1351 /* Disable APCs */ 1352 KIRQL OldIrql; 1353 KeRaiseIrql(APC_LEVEL, &OldIrql); 1354 1355 IO_STATUS_BLOCK Iosb; 1356 Status = IoPageRead(FileObject, Mdl, &FileOffset, &Event, &Iosb); 1357 if (Status == STATUS_PENDING) 1358 { 1359 KeWaitForSingleObject(&Event, WrPageIn, KernelMode, FALSE, NULL); 1360 Status = Iosb.Status; 1361 } 1362 1363 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) 1364 { 1365 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl); 1366 } 1367 1368 KeLowerIrql(OldIrql); 1369 1370 if (Status == STATUS_END_OF_FILE) 1371 { 1372 DPRINT1("Got STATUS_END_OF_FILE at offset %I64d for file %wZ.\n", FileOffset.QuadPart, &FileObject->FileName); 1373 Status = STATUS_SUCCESS; 1374 } 1375 1376 if (!NT_SUCCESS(Status)) 1377 { 1378 /* Damn. Roll back. */ 1379 for (UINT i = 0; i < BYTES_TO_PAGES(ReadLength); i++) 1380 MmReleasePageMemoryConsumer(MC_USER, Pages[i]); 1381 1382 MmLockSectionSegment(Segment); 1383 while (ChunkOffset < ChunkEnd) 1384 { 1385 if (ToReadPageBits & 1) 1386 { 1387 LARGE_INTEGER CurrentOffset; 1388 CurrentOffset.QuadPart = ChunkOffset; 1389 ASSERT(MM_IS_WAIT_PTE(MmGetPageEntrySectionSegment(Segment, &CurrentOffset))); 1390 MmSetPageEntrySectionSegment(Segment, &CurrentOffset, 0); 1391 } 1392 ToReadPageBits >>= 1; 1393 ChunkOffset += PAGE_SIZE; 1394 } 1395 MmUnlockSectionSegment(Segment); 1396 IoFreeMdl(Mdl);; 1397 return Status; 1398 } 1399 1400 AssignPagesToSegment: 1401 MmLockSectionSegment(Segment); 1402 1403 for (UINT i = 0; i < BYTES_TO_PAGES(ReadLength); i++) 1404 { 1405 LARGE_INTEGER CurrentOffset; 1406 CurrentOffset.QuadPart = ChunkOffset + (i * PAGE_SIZE); 1407 1408 ASSERT(MM_IS_WAIT_PTE(MmGetPageEntrySectionSegment(Segment, &CurrentOffset))); 1409 1410 MmSetPageEntrySectionSegment(Segment, &CurrentOffset, MAKE_SSE(Pages[i] << PAGE_SHIFT, 0)); 1411 } 1412 1413 MmUnlockSectionSegment(Segment); 1414 1415 IoFreeMdl(Mdl); 1416 ToReadPageBits >>= BitSet; 1417 ChunkOffset += BitSet * PAGE_SIZE; 1418 } 1419 } 1420 1421 return STATUS_SUCCESS; 1422 } 1423 1424 static VOID 1425 MmAlterViewAttributes(PMMSUPPORT AddressSpace, 1426 PVOID BaseAddress, 1427 SIZE_T RegionSize, 1428 ULONG OldType, 1429 ULONG OldProtect, 1430 ULONG NewType, 1431 ULONG NewProtect) 1432 { 1433 PMEMORY_AREA MemoryArea; 1434 PMM_SECTION_SEGMENT Segment; 1435 BOOLEAN DoCOW = FALSE; 1436 ULONG i; 1437 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); 1438 1439 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress); 1440 ASSERT(MemoryArea != NULL); 1441 Segment = MemoryArea->SectionData.Segment; 1442 MmLockSectionSegment(Segment); 1443 1444 if ((Segment->WriteCopy) && 1445 (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE)) 1446 { 1447 DoCOW = TRUE; 1448 } 1449 1450 if (OldProtect != NewProtect) 1451 { 1452 for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++) 1453 { 1454 SWAPENTRY SwapEntry; 1455 PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE); 1456 ULONG Protect = NewProtect; 1457 1458 /* Wait for a wait entry to disappear */ 1459 do 1460 { 1461 MmGetPageFileMapping(Process, Address, &SwapEntry); 1462 if (SwapEntry != MM_WAIT_ENTRY) 1463 break; 1464 MiWaitForPageEvent(Process, Address); 1465 } 1466 while (TRUE); 1467 1468 /* 1469 * If we doing COW for this segment then check if the page is 1470 * already private. 1471 */ 1472 if (DoCOW && MmIsPagePresent(Process, Address)) 1473 { 1474 LARGE_INTEGER Offset; 1475 ULONG_PTR Entry; 1476 PFN_NUMBER Page; 1477 1478 Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea) 1479 + MemoryArea->SectionData.ViewOffset; 1480 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 1481 /* 1482 * An MM_WAIT_ENTRY is ok in this case... It'll just count as 1483 * IS_SWAP_FROM_SSE and we'll do the right thing. 1484 */ 1485 Page = MmGetPfnForProcess(Process, Address); 1486 1487 Protect = PAGE_READONLY; 1488 if (IS_SWAP_FROM_SSE(Entry) || PFN_FROM_SSE(Entry) != Page) 1489 { 1490 Protect = NewProtect; 1491 } 1492 } 1493 1494 if (MmIsPagePresent(Process, Address) || MmIsDisabledPage(Process, Address)) 1495 { 1496 MmSetPageProtect(Process, Address, 1497 Protect); 1498 } 1499 } 1500 } 1501 1502 MmUnlockSectionSegment(Segment); 1503 } 1504 1505 NTSTATUS 1506 NTAPI 1507 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace, 1508 MEMORY_AREA* MemoryArea, 1509 PVOID Address, 1510 BOOLEAN Locked) 1511 { 1512 LARGE_INTEGER Offset; 1513 PFN_NUMBER Page; 1514 NTSTATUS Status; 1515 PMM_SECTION_SEGMENT Segment; 1516 ULONG_PTR Entry; 1517 ULONG_PTR Entry1; 1518 ULONG Attributes; 1519 PMM_REGION Region; 1520 BOOLEAN HasSwapEntry; 1521 PVOID PAddress; 1522 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); 1523 SWAPENTRY SwapEntry; 1524 1525 /* 1526 * There is a window between taking the page fault and locking the 1527 * address space when another thread could load the page so we check 1528 * that. 1529 */ 1530 if (MmIsPagePresent(Process, Address)) 1531 { 1532 return STATUS_SUCCESS; 1533 } 1534 1535 if (MmIsDisabledPage(Process, Address)) 1536 { 1537 return STATUS_ACCESS_VIOLATION; 1538 } 1539 1540 /* 1541 * Check for the virtual memory area being deleted. 1542 */ 1543 if (MemoryArea->DeleteInProgress) 1544 { 1545 return STATUS_UNSUCCESSFUL; 1546 } 1547 1548 PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE); 1549 Offset.QuadPart = (ULONG_PTR)PAddress - MA_GetStartingAddress(MemoryArea) 1550 + MemoryArea->SectionData.ViewOffset; 1551 1552 Segment = MemoryArea->SectionData.Segment; 1553 Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea), 1554 &MemoryArea->SectionData.RegionListHead, 1555 Address, NULL); 1556 ASSERT(Region != NULL); 1557 1558 /* Check for a NOACCESS mapping */ 1559 if (Region->Protect & PAGE_NOACCESS) 1560 { 1561 return STATUS_ACCESS_VIOLATION; 1562 } 1563 1564 if (Region->Protect & PAGE_GUARD) 1565 { 1566 /* Remove it */ 1567 Status = MmAlterRegion(AddressSpace, (PVOID)MA_GetStartingAddress(MemoryArea), 1568 &MemoryArea->SectionData.RegionListHead, 1569 Address, PAGE_SIZE, Region->Type, Region->Protect & ~PAGE_GUARD, 1570 MmAlterViewAttributes); 1571 1572 if (!NT_SUCCESS(Status)) 1573 { 1574 DPRINT1("Removing PAGE_GUARD protection failed : 0x%08x.\n", Status); 1575 } 1576 1577 return STATUS_GUARD_PAGE_VIOLATION; 1578 } 1579 1580 /* 1581 * Lock the segment 1582 */ 1583 MmLockSectionSegment(Segment); 1584 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 1585 /* 1586 * Check if this page needs to be mapped COW 1587 */ 1588 if ((Segment->WriteCopy) && 1589 (Region->Protect == PAGE_READWRITE || 1590 Region->Protect == PAGE_EXECUTE_READWRITE)) 1591 { 1592 Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ; 1593 } 1594 else 1595 { 1596 Attributes = Region->Protect; 1597 } 1598 1599 /* 1600 * Check if someone else is already handling this fault, if so wait 1601 * for them 1602 */ 1603 if (Entry && MM_IS_WAIT_PTE(Entry)) 1604 { 1605 MmUnlockSectionSegment(Segment); 1606 MmUnlockAddressSpace(AddressSpace); 1607 MiWaitForPageEvent(NULL, NULL); 1608 MmLockAddressSpace(AddressSpace); 1609 DPRINT("Address 0x%p\n", Address); 1610 return STATUS_MM_RESTART_OPERATION; 1611 } 1612 1613 HasSwapEntry = MmIsPageSwapEntry(Process, Address); 1614 1615 /* See if we should use a private page */ 1616 if (HasSwapEntry) 1617 { 1618 SWAPENTRY DummyEntry; 1619 1620 MmGetPageFileMapping(Process, Address, &SwapEntry); 1621 if (SwapEntry == MM_WAIT_ENTRY) 1622 { 1623 MmUnlockSectionSegment(Segment); 1624 MmUnlockAddressSpace(AddressSpace); 1625 MiWaitForPageEvent(NULL, NULL); 1626 MmLockAddressSpace(AddressSpace); 1627 return STATUS_MM_RESTART_OPERATION; 1628 } 1629 1630 /* 1631 * Must be private page we have swapped out. 1632 */ 1633 1634 /* 1635 * Sanity check 1636 */ 1637 MmDeletePageFileMapping(Process, Address, &SwapEntry); 1638 MmUnlockSectionSegment(Segment); 1639 1640 /* Tell everyone else we are serving the fault. */ 1641 MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY); 1642 1643 MmUnlockAddressSpace(AddressSpace); 1644 MI_SET_USAGE(MI_USAGE_SECTION); 1645 if (Process) MI_SET_PROCESS2(Process->ImageFileName); 1646 if (!Process) MI_SET_PROCESS2("Kernel Section"); 1647 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page); 1648 if (!NT_SUCCESS(Status)) 1649 { 1650 KeBugCheck(MEMORY_MANAGEMENT); 1651 } 1652 1653 if (HasSwapEntry) 1654 { 1655 Status = MmReadFromSwapPage(SwapEntry, Page); 1656 if (!NT_SUCCESS(Status)) 1657 { 1658 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status); 1659 KeBugCheck(MEMORY_MANAGEMENT); 1660 } 1661 } 1662 1663 MmLockAddressSpace(AddressSpace); 1664 MmDeletePageFileMapping(Process, PAddress, &DummyEntry); 1665 Status = MmCreateVirtualMapping(Process, 1666 PAddress, 1667 Region->Protect, 1668 &Page, 1669 1); 1670 if (!NT_SUCCESS(Status)) 1671 { 1672 DPRINT("MmCreateVirtualMapping failed, not out of memory\n"); 1673 KeBugCheck(MEMORY_MANAGEMENT); 1674 return Status; 1675 } 1676 1677 /* 1678 * Store the swap entry for later use. 1679 */ 1680 if (HasSwapEntry) 1681 MmSetSavedSwapEntryPage(Page, SwapEntry); 1682 1683 /* 1684 * Add the page to the process's working set 1685 */ 1686 if (Process) MmInsertRmap(Page, Process, Address); 1687 /* 1688 * Finish the operation 1689 */ 1690 MiSetPageEvent(Process, Address); 1691 DPRINT("Address 0x%p\n", Address); 1692 return STATUS_SUCCESS; 1693 } 1694 1695 /* 1696 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy 1697 */ 1698 if ((*Segment->Flags) & MM_PHYSICALMEMORY_SEGMENT) 1699 { 1700 MmUnlockSectionSegment(Segment); 1701 /* 1702 * Just map the desired physical page 1703 */ 1704 Page = (PFN_NUMBER)(Offset.QuadPart >> PAGE_SHIFT); 1705 Status = MmCreateVirtualMappingUnsafe(Process, 1706 PAddress, 1707 Region->Protect, 1708 &Page, 1709 1); 1710 if (!NT_SUCCESS(Status)) 1711 { 1712 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n"); 1713 KeBugCheck(MEMORY_MANAGEMENT); 1714 return Status; 1715 } 1716 1717 /* 1718 * Cleanup and release locks 1719 */ 1720 MiSetPageEvent(Process, Address); 1721 DPRINT("Address 0x%p\n", Address); 1722 return STATUS_SUCCESS; 1723 } 1724 1725 /* 1726 * Get the entry corresponding to the offset within the section 1727 */ 1728 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 1729 1730 if (Entry == 0) 1731 { 1732 /* 1733 * If the entry is zero, then we need to load the page. 1734 */ 1735 if ((Offset.QuadPart >= (LONGLONG)PAGE_ROUND_UP(Segment->RawLength.QuadPart)) && (MemoryArea->VadNode.u.VadFlags.VadType == VadImageMap)) 1736 { 1737 /* We are beyond the data which is on file. Just get a new page. */ 1738 MI_SET_USAGE(MI_USAGE_SECTION); 1739 if (Process) MI_SET_PROCESS2(Process->ImageFileName); 1740 if (!Process) MI_SET_PROCESS2("Kernel Section"); 1741 MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page); 1742 MmSetPageEntrySectionSegment(Segment, &Offset, MAKE_SSE(Page << PAGE_SHIFT, 1)); 1743 MmUnlockSectionSegment(Segment); 1744 1745 Status = MmCreateVirtualMapping(Process, PAddress, Attributes, &Page, 1); 1746 if (!NT_SUCCESS(Status)) 1747 { 1748 DPRINT1("Unable to create virtual mapping\n"); 1749 KeBugCheck(MEMORY_MANAGEMENT); 1750 } 1751 ASSERT(MmIsPagePresent(Process, PAddress)); 1752 if (Process) 1753 MmInsertRmap(Page, Process, Address); 1754 1755 MiSetPageEvent(Process, Address); 1756 DPRINT("Address 0x%p\n", Address); 1757 return STATUS_SUCCESS; 1758 } 1759 1760 MmUnlockSectionSegment(Segment); 1761 MmUnlockAddressSpace(AddressSpace); 1762 1763 /* The data must be paged in. Lock the file, so that the VDL doesn't get updated behind us. */ 1764 FsRtlAcquireFileExclusive(Segment->FileObject); 1765 1766 PFSRTL_COMMON_FCB_HEADER FcbHeader = Segment->FileObject->FsContext; 1767 1768 Status = MmMakeSegmentResident(Segment, Offset.QuadPart, PAGE_SIZE, &FcbHeader->ValidDataLength); 1769 1770 FsRtlReleaseFile(Segment->FileObject); 1771 1772 /* Lock address space again */ 1773 MmLockAddressSpace(AddressSpace); 1774 if (!NT_SUCCESS(Status)) 1775 { 1776 /* Damn */ 1777 DPRINT1("Failed to page data in!\n"); 1778 return STATUS_IN_PAGE_ERROR; 1779 } 1780 1781 /* Everything went fine. Restart the operation */ 1782 return STATUS_MM_RESTART_OPERATION; 1783 } 1784 else if (IS_SWAP_FROM_SSE(Entry)) 1785 { 1786 SWAPENTRY SwapEntry; 1787 1788 SwapEntry = SWAPENTRY_FROM_SSE(Entry); 1789 1790 /* See if a page op is running on this segment. */ 1791 if (SwapEntry == MM_WAIT_ENTRY) 1792 { 1793 MmUnlockSectionSegment(Segment); 1794 MmUnlockAddressSpace(AddressSpace); 1795 MiWaitForPageEvent(NULL, NULL); 1796 MmLockAddressSpace(AddressSpace); 1797 return STATUS_MM_RESTART_OPERATION; 1798 } 1799 1800 /* 1801 * Release all our locks and read in the page from disk 1802 */ 1803 MmUnlockSectionSegment(Segment); 1804 1805 MmUnlockAddressSpace(AddressSpace); 1806 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page); 1807 if (!NT_SUCCESS(Status)) 1808 { 1809 KeBugCheck(MEMORY_MANAGEMENT); 1810 } 1811 1812 Status = MmReadFromSwapPage(SwapEntry, Page); 1813 if (!NT_SUCCESS(Status)) 1814 { 1815 KeBugCheck(MEMORY_MANAGEMENT); 1816 } 1817 1818 /* 1819 * Relock the address space and segment 1820 */ 1821 MmLockAddressSpace(AddressSpace); 1822 MmLockSectionSegment(Segment); 1823 1824 /* 1825 * Check the entry. No one should change the status of a page 1826 * that has a pending page-in. 1827 */ 1828 Entry1 = MmGetPageEntrySectionSegment(Segment, &Offset); 1829 if (Entry != Entry1) 1830 { 1831 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry, Entry1); 1832 KeBugCheck(MEMORY_MANAGEMENT); 1833 } 1834 1835 /* 1836 * Save the swap entry. 1837 */ 1838 MmSetSavedSwapEntryPage(Page, SwapEntry); 1839 1840 /* Map the page into the process address space */ 1841 Status = MmCreateVirtualMapping(Process, 1842 PAddress, 1843 Attributes, 1844 &Page, 1845 1); 1846 if (!NT_SUCCESS(Status)) 1847 { 1848 DPRINT1("Unable to create virtual mapping\n"); 1849 KeBugCheck(MEMORY_MANAGEMENT); 1850 } 1851 if (Process) 1852 MmInsertRmap(Page, Process, Address); 1853 1854 /* 1855 * Mark the offset within the section as having valid, in-memory 1856 * data 1857 */ 1858 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1); 1859 MmSetPageEntrySectionSegment(Segment, &Offset, Entry); 1860 MmUnlockSectionSegment(Segment); 1861 1862 MiSetPageEvent(Process, Address); 1863 DPRINT("Address 0x%p\n", Address); 1864 return STATUS_SUCCESS; 1865 } 1866 else 1867 { 1868 /* We already have a page on this section offset. Map it into the process address space. */ 1869 Page = PFN_FROM_SSE(Entry); 1870 1871 Status = MmCreateVirtualMapping(Process, 1872 PAddress, 1873 Attributes, 1874 &Page, 1875 1); 1876 if (!NT_SUCCESS(Status)) 1877 { 1878 DPRINT1("Unable to create virtual mapping\n"); 1879 KeBugCheck(MEMORY_MANAGEMENT); 1880 } 1881 1882 if (Process) 1883 MmInsertRmap(Page, Process, Address); 1884 1885 /* Take a reference on it */ 1886 MmSharePageEntrySectionSegment(Segment, &Offset); 1887 MmUnlockSectionSegment(Segment); 1888 1889 MiSetPageEvent(Process, Address); 1890 DPRINT("Address 0x%p\n", Address); 1891 return STATUS_SUCCESS; 1892 } 1893 } 1894 1895 NTSTATUS 1896 NTAPI 1897 MmAccessFaultSectionView(PMMSUPPORT AddressSpace, 1898 MEMORY_AREA* MemoryArea, 1899 PVOID Address) 1900 { 1901 PMM_SECTION_SEGMENT Segment; 1902 PFN_NUMBER OldPage; 1903 PFN_NUMBER NewPage; 1904 NTSTATUS Status; 1905 PVOID PAddress; 1906 LARGE_INTEGER Offset; 1907 PMM_REGION Region; 1908 ULONG_PTR Entry; 1909 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); 1910 1911 DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace, MemoryArea, Address); 1912 1913 /* Make sure we have a page mapping for this address. */ 1914 Status = MmNotPresentFaultSectionView(AddressSpace, MemoryArea, Address, TRUE); 1915 if (!NT_SUCCESS(Status)) 1916 { 1917 /* This is invalid access ! */ 1918 return Status; 1919 } 1920 1921 /* 1922 * Check if the page has already been set readwrite 1923 */ 1924 if (MmGetPageProtect(Process, Address) & PAGE_READWRITE) 1925 { 1926 DPRINT("Address 0x%p\n", Address); 1927 return STATUS_SUCCESS; 1928 } 1929 1930 /* 1931 * Find the offset of the page 1932 */ 1933 PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE); 1934 Offset.QuadPart = (ULONG_PTR)PAddress - MA_GetStartingAddress(MemoryArea) 1935 + MemoryArea->SectionData.ViewOffset; 1936 1937 Segment = MemoryArea->SectionData.Segment; 1938 Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea), 1939 &MemoryArea->SectionData.RegionListHead, 1940 Address, NULL); 1941 ASSERT(Region != NULL); 1942 1943 /* 1944 * Check if we are doing COW 1945 */ 1946 if (!((Segment->WriteCopy) && 1947 (Region->Protect == PAGE_READWRITE || 1948 Region->Protect == PAGE_EXECUTE_READWRITE))) 1949 { 1950 DPRINT("Address 0x%p\n", Address); 1951 return STATUS_ACCESS_VIOLATION; 1952 } 1953 1954 /* Get the page mapping this section offset. */ 1955 MmLockSectionSegment(Segment); 1956 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 1957 1958 /* Get the current page mapping for the process */ 1959 ASSERT(MmIsPagePresent(Process, PAddress)); 1960 OldPage = MmGetPfnForProcess(Process, PAddress); 1961 ASSERT(OldPage != 0); 1962 1963 if (IS_SWAP_FROM_SSE(Entry) || 1964 PFN_FROM_SSE(Entry) != OldPage) 1965 { 1966 MmUnlockSectionSegment(Segment); 1967 /* This is a private page. We must only change the page protection. */ 1968 MmSetPageProtect(Process, PAddress, Region->Protect); 1969 return STATUS_SUCCESS; 1970 } 1971 1972 /* 1973 * Allocate a page 1974 */ 1975 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage); 1976 if (!NT_SUCCESS(Status)) 1977 { 1978 KeBugCheck(MEMORY_MANAGEMENT); 1979 } 1980 1981 /* 1982 * Copy the old page 1983 */ 1984 NT_VERIFY(NT_SUCCESS(MiCopyFromUserPage(NewPage, PAddress))); 1985 1986 /* 1987 * Unshare the old page. 1988 */ 1989 DPRINT("Swapping page (Old %x New %x)\n", OldPage, NewPage); 1990 MmDeleteVirtualMapping(Process, PAddress, NULL, NULL); 1991 if (Process) 1992 MmDeleteRmap(OldPage, Process, PAddress); 1993 MmUnsharePageEntrySectionSegment(MemoryArea, Segment, &Offset, FALSE, FALSE, NULL); 1994 MmUnlockSectionSegment(Segment); 1995 1996 /* 1997 * Set the PTE to point to the new page 1998 */ 1999 Status = MmCreateVirtualMapping(Process, 2000 PAddress, 2001 Region->Protect, 2002 &NewPage, 2003 1); 2004 if (!NT_SUCCESS(Status)) 2005 { 2006 DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n"); 2007 KeBugCheck(MEMORY_MANAGEMENT); 2008 return Status; 2009 } 2010 2011 if (Process) 2012 MmInsertRmap(NewPage, Process, PAddress); 2013 2014 MiSetPageEvent(Process, Address); 2015 DPRINT("Address 0x%p\n", Address); 2016 return STATUS_SUCCESS; 2017 } 2018 2019 NTSTATUS 2020 NTAPI 2021 MmProtectSectionView(PMMSUPPORT AddressSpace, 2022 PMEMORY_AREA MemoryArea, 2023 PVOID BaseAddress, 2024 SIZE_T Length, 2025 ULONG Protect, 2026 PULONG OldProtect) 2027 { 2028 PMM_REGION Region; 2029 NTSTATUS Status; 2030 ULONG_PTR MaxLength; 2031 2032 MaxLength = MA_GetEndingAddress(MemoryArea) - (ULONG_PTR)BaseAddress; 2033 if (Length > MaxLength) 2034 Length = (ULONG)MaxLength; 2035 2036 Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea), 2037 &MemoryArea->SectionData.RegionListHead, 2038 BaseAddress, NULL); 2039 ASSERT(Region != NULL); 2040 2041 if ((MemoryArea->Flags & SEC_NO_CHANGE) && 2042 Region->Protect != Protect) 2043 { 2044 return STATUS_INVALID_PAGE_PROTECTION; 2045 } 2046 2047 *OldProtect = Region->Protect; 2048 Status = MmAlterRegion(AddressSpace, (PVOID)MA_GetStartingAddress(MemoryArea), 2049 &MemoryArea->SectionData.RegionListHead, 2050 BaseAddress, Length, Region->Type, Protect, 2051 MmAlterViewAttributes); 2052 2053 return Status; 2054 } 2055 2056 NTSTATUS NTAPI 2057 MmQuerySectionView(PMEMORY_AREA MemoryArea, 2058 PVOID Address, 2059 PMEMORY_BASIC_INFORMATION Info, 2060 PSIZE_T ResultLength) 2061 { 2062 PMM_REGION Region; 2063 PVOID RegionBaseAddress; 2064 PMM_SECTION_SEGMENT Segment; 2065 2066 Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea), 2067 &MemoryArea->SectionData.RegionListHead, 2068 Address, &RegionBaseAddress); 2069 if (Region == NULL) 2070 { 2071 return STATUS_UNSUCCESSFUL; 2072 } 2073 2074 if (MemoryArea->VadNode.u.VadFlags.VadType == VadImageMap) 2075 { 2076 Segment = MemoryArea->SectionData.Segment; 2077 Info->AllocationBase = (PUCHAR)MA_GetStartingAddress(MemoryArea) - Segment->Image.VirtualAddress; 2078 Info->Type = MEM_IMAGE; 2079 } 2080 else 2081 { 2082 Info->AllocationBase = (PVOID)MA_GetStartingAddress(MemoryArea); 2083 Info->Type = MEM_MAPPED; 2084 } 2085 Info->BaseAddress = RegionBaseAddress; 2086 Info->AllocationProtect = MmProtectToValue[MemoryArea->VadNode.u.VadFlags.Protection]; 2087 Info->RegionSize = Region->Length; 2088 Info->State = MEM_COMMIT; 2089 Info->Protect = Region->Protect; 2090 2091 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION); 2092 return STATUS_SUCCESS; 2093 } 2094 2095 VOID NTAPI 2096 MmpDeleteSection(PVOID ObjectBody) 2097 { 2098 PSECTION Section = ObjectBody; 2099 2100 /* Check if it's an ARM3, or ReactOS section */ 2101 if (!MiIsRosSectionObject(Section)) 2102 { 2103 MiDeleteARM3Section(ObjectBody); 2104 return; 2105 } 2106 2107 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody); 2108 if (Section->u.Flags.Image) 2109 { 2110 PMM_IMAGE_SECTION_OBJECT ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)Section->Segment; 2111 2112 /* 2113 * NOTE: Section->ImageSection can be NULL for short time 2114 * during the section creating. If we fail for some reason 2115 * until the image section is properly initialized we shouldn't 2116 * process further here. 2117 */ 2118 if (Section->Segment == NULL) 2119 return; 2120 2121 /* We just dereference the first segment */ 2122 ASSERT(ImageSectionObject->RefCount > 0); 2123 MmDereferenceSegment(ImageSectionObject->Segments); 2124 } 2125 else 2126 { 2127 PMM_SECTION_SEGMENT Segment = (PMM_SECTION_SEGMENT)Section->Segment; 2128 2129 /* 2130 * NOTE: Section->Segment can be NULL for short time 2131 * during the section creating. 2132 */ 2133 if (Segment == NULL) 2134 return; 2135 2136 Segment->SectionCount--; 2137 MmDereferenceSegment(Segment); 2138 } 2139 } 2140 2141 VOID NTAPI 2142 MmpCloseSection(IN PEPROCESS Process OPTIONAL, 2143 IN PVOID Object, 2144 IN ACCESS_MASK GrantedAccess, 2145 IN ULONG ProcessHandleCount, 2146 IN ULONG SystemHandleCount) 2147 { 2148 DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object, ProcessHandleCount); 2149 } 2150 2151 CODE_SEG("INIT") 2152 NTSTATUS 2153 NTAPI 2154 MmCreatePhysicalMemorySection(VOID) 2155 { 2156 PSECTION PhysSection; 2157 NTSTATUS Status; 2158 OBJECT_ATTRIBUTES Obj; 2159 UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory"); 2160 LARGE_INTEGER SectionSize; 2161 HANDLE Handle; 2162 PMM_SECTION_SEGMENT Segment; 2163 2164 /* 2165 * Create the section mapping physical memory 2166 */ 2167 SectionSize.QuadPart = MmHighestPhysicalPage * PAGE_SIZE; 2168 InitializeObjectAttributes(&Obj, 2169 &Name, 2170 OBJ_PERMANENT | OBJ_KERNEL_EXCLUSIVE, 2171 NULL, 2172 NULL); 2173 /* 2174 * Create the Object 2175 */ 2176 Status = ObCreateObject(KernelMode, 2177 MmSectionObjectType, 2178 &Obj, 2179 ExGetPreviousMode(), 2180 NULL, 2181 sizeof(*PhysSection), 2182 0, 2183 0, 2184 (PVOID*)&PhysSection); 2185 if (!NT_SUCCESS(Status)) 2186 { 2187 DPRINT1("MmCreatePhysicalMemorySection: failed to create object (0x%lx)\n", Status); 2188 return Status; 2189 } 2190 2191 /* 2192 * Initialize it 2193 */ 2194 RtlZeroMemory(PhysSection, sizeof(*PhysSection)); 2195 2196 /* Mark this as a "ROS Section" */ 2197 PhysSection->u.Flags.filler = 1; 2198 PhysSection->InitialPageProtection = PAGE_EXECUTE_READWRITE; 2199 PhysSection->u.Flags.PhysicalMemory = 1; 2200 PhysSection->SizeOfSection = SectionSize; 2201 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT), 2202 TAG_MM_SECTION_SEGMENT); 2203 if (Segment == NULL) 2204 { 2205 ObDereferenceObject(PhysSection); 2206 return STATUS_NO_MEMORY; 2207 } 2208 RtlZeroMemory(Segment, sizeof(MM_SECTION_SEGMENT)); 2209 PhysSection->Segment = (PSEGMENT)Segment; 2210 Segment->RefCount = 1; 2211 2212 Segment->ReferenceCount = &Segment->RefCount; 2213 Segment->Flags = &Segment->SegFlags; 2214 2215 ExInitializeFastMutex(&Segment->Lock); 2216 Segment->Image.FileOffset = 0; 2217 Segment->Protection = PAGE_EXECUTE_READWRITE; 2218 Segment->RawLength = SectionSize; 2219 Segment->Length = SectionSize; 2220 Segment->SegFlags = MM_PHYSICALMEMORY_SEGMENT; 2221 Segment->WriteCopy = FALSE; 2222 Segment->Image.VirtualAddress = 0; 2223 Segment->Image.Characteristics = 0; 2224 MiInitializeSectionPageTable(Segment); 2225 2226 Status = ObInsertObject(PhysSection, 2227 NULL, 2228 SECTION_ALL_ACCESS, 2229 0, 2230 NULL, 2231 &Handle); 2232 if (!NT_SUCCESS(Status)) 2233 { 2234 ObDereferenceObject(PhysSection); 2235 return Status; 2236 } 2237 ObCloseHandle(Handle, KernelMode); 2238 2239 return STATUS_SUCCESS; 2240 } 2241 2242 CODE_SEG("INIT") 2243 NTSTATUS 2244 NTAPI 2245 MmInitSectionImplementation(VOID) 2246 { 2247 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 2248 UNICODE_STRING Name; 2249 2250 DPRINT("Creating Section Object Type\n"); 2251 2252 /* Initialize the section based root */ 2253 ASSERT(MmSectionBasedRoot.NumberGenericTableElements == 0); 2254 MmSectionBasedRoot.BalancedRoot.u1.Parent = &MmSectionBasedRoot.BalancedRoot; 2255 2256 /* Initialize the Section object type */ 2257 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 2258 RtlInitUnicodeString(&Name, L"Section"); 2259 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 2260 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(SECTION); 2261 ObjectTypeInitializer.PoolType = PagedPool; 2262 ObjectTypeInitializer.UseDefaultObject = TRUE; 2263 ObjectTypeInitializer.GenericMapping = MmpSectionMapping; 2264 ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection; 2265 ObjectTypeInitializer.CloseProcedure = MmpCloseSection; 2266 ObjectTypeInitializer.ValidAccessMask = SECTION_ALL_ACCESS; 2267 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; 2268 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &MmSectionObjectType); 2269 2270 MmCreatePhysicalMemorySection(); 2271 2272 return STATUS_SUCCESS; 2273 } 2274 2275 static 2276 NTSTATUS 2277 NTAPI 2278 MmCreateDataFileSection(PSECTION *SectionObject, 2279 ACCESS_MASK DesiredAccess, 2280 POBJECT_ATTRIBUTES ObjectAttributes, 2281 PLARGE_INTEGER UMaximumSize, 2282 ULONG SectionPageProtection, 2283 ULONG AllocationAttributes, 2284 PFILE_OBJECT FileObject, 2285 BOOLEAN GotFileHandle) 2286 /* 2287 * Create a section backed by a data file 2288 */ 2289 { 2290 PSECTION Section; 2291 NTSTATUS Status; 2292 LARGE_INTEGER MaximumSize; 2293 PMM_SECTION_SEGMENT Segment; 2294 KIRQL OldIrql; 2295 2296 /* 2297 * Create the section 2298 */ 2299 Status = ObCreateObject(ExGetPreviousMode(), 2300 MmSectionObjectType, 2301 ObjectAttributes, 2302 ExGetPreviousMode(), 2303 NULL, 2304 sizeof(*Section), 2305 0, 2306 0, 2307 (PVOID*)&Section); 2308 if (!NT_SUCCESS(Status)) 2309 { 2310 return Status; 2311 } 2312 /* 2313 * Initialize it 2314 */ 2315 RtlZeroMemory(Section, sizeof(*Section)); 2316 2317 /* Mark this as a "ROS" section */ 2318 Section->u.Flags.filler = 1; 2319 Section->InitialPageProtection = SectionPageProtection; 2320 Section->u.Flags.File = 1; 2321 2322 if (AllocationAttributes & SEC_NO_CHANGE) 2323 Section->u.Flags.NoChange = 1; 2324 if (AllocationAttributes & SEC_RESERVE) 2325 Section->u.Flags.Reserve = 1; 2326 2327 if (!GotFileHandle) 2328 { 2329 ASSERT(UMaximumSize != NULL); 2330 // ASSERT(UMaximumSize->QuadPart != 0); 2331 MaximumSize = *UMaximumSize; 2332 } 2333 else 2334 { 2335 LARGE_INTEGER FileSize; 2336 Status = FsRtlGetFileSize(FileObject, &FileSize); 2337 if (!NT_SUCCESS(Status)) 2338 { 2339 ObDereferenceObject(Section); 2340 return Status; 2341 } 2342 2343 /* 2344 * FIXME: Revise this once a locking order for file size changes is 2345 * decided 2346 */ 2347 if ((UMaximumSize != NULL) && (UMaximumSize->QuadPart != 0)) 2348 { 2349 MaximumSize = *UMaximumSize; 2350 } 2351 else 2352 { 2353 MaximumSize = FileSize; 2354 /* Mapping zero-sized files isn't allowed. */ 2355 if (MaximumSize.QuadPart == 0) 2356 { 2357 ObDereferenceObject(Section); 2358 return STATUS_MAPPED_FILE_SIZE_ZERO; 2359 } 2360 } 2361 2362 if (MaximumSize.QuadPart > FileSize.QuadPart) 2363 { 2364 Status = IoSetInformation(FileObject, 2365 FileEndOfFileInformation, 2366 sizeof(LARGE_INTEGER), 2367 &MaximumSize); 2368 if (!NT_SUCCESS(Status)) 2369 { 2370 ObDereferenceObject(Section); 2371 return STATUS_SECTION_NOT_EXTENDED; 2372 } 2373 } 2374 } 2375 2376 if (FileObject->SectionObjectPointer == NULL) 2377 { 2378 ObDereferenceObject(Section); 2379 return STATUS_INVALID_FILE_FOR_SECTION; 2380 } 2381 2382 /* 2383 * Lock the file 2384 */ 2385 Status = MmspWaitForFileLock(FileObject); 2386 if (Status != STATUS_SUCCESS) 2387 { 2388 ObDereferenceObject(Section); 2389 return Status; 2390 } 2391 2392 /* Lock the PFN lock while messing with Section Object pointers */ 2393 OldIrql = MiAcquirePfnLock(); 2394 Segment = FileObject->SectionObjectPointer->DataSectionObject; 2395 2396 while (Segment && (Segment->SegFlags & (MM_SEGMENT_INDELETE | MM_SEGMENT_INCREATE))) 2397 { 2398 MiReleasePfnLock(OldIrql); 2399 KeDelayExecutionThread(KernelMode, FALSE, &TinyTime); 2400 OldIrql = MiAcquirePfnLock(); 2401 Segment = FileObject->SectionObjectPointer->DataSectionObject; 2402 } 2403 2404 /* 2405 * If this file hasn't been mapped as a data file before then allocate a 2406 * section segment to describe the data file mapping 2407 */ 2408 if (Segment == NULL) 2409 { 2410 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT), 2411 TAG_MM_SECTION_SEGMENT); 2412 if (Segment == NULL) 2413 { 2414 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); 2415 MiReleasePfnLock(OldIrql); 2416 ObDereferenceObject(Section); 2417 return STATUS_NO_MEMORY; 2418 } 2419 2420 /* We are creating it */ 2421 RtlZeroMemory(Segment, sizeof(*Segment)); 2422 Segment->SegFlags = MM_DATAFILE_SEGMENT | MM_SEGMENT_INCREATE; 2423 Segment->RefCount = 1; 2424 2425 FileObject->SectionObjectPointer->DataSectionObject = Segment; 2426 2427 /* We're safe to release the lock now */ 2428 MiReleasePfnLock(OldIrql); 2429 2430 Section->Segment = (PSEGMENT)Segment; 2431 2432 /* Self-referencing segment */ 2433 Segment->Flags = &Segment->SegFlags; 2434 Segment->ReferenceCount = &Segment->RefCount; 2435 2436 Segment->SectionCount = 1; 2437 2438 ExInitializeFastMutex(&Segment->Lock); 2439 Segment->FileObject = FileObject; 2440 ObReferenceObject(FileObject); 2441 2442 Segment->Image.FileOffset = 0; 2443 Segment->Protection = SectionPageProtection; 2444 2445 Segment->Image.Characteristics = 0; 2446 Segment->WriteCopy = (SectionPageProtection & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY)); 2447 if (AllocationAttributes & SEC_RESERVE) 2448 { 2449 Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0; 2450 } 2451 else 2452 { 2453 Segment->RawLength.QuadPart = MaximumSize.QuadPart; 2454 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart); 2455 } 2456 Segment->Image.VirtualAddress = 0; 2457 MiInitializeSectionPageTable(Segment); 2458 2459 /* We're good to use it now */ 2460 OldIrql = MiAcquirePfnLock(); 2461 Segment->SegFlags &= ~MM_SEGMENT_INCREATE; 2462 MiReleasePfnLock(OldIrql); 2463 } 2464 else 2465 { 2466 Section->Segment = (PSEGMENT)Segment; 2467 Segment->RefCount++; 2468 InterlockedIncrementUL(&Segment->SectionCount); 2469 2470 MiReleasePfnLock(OldIrql); 2471 2472 MmLockSectionSegment(Segment); 2473 2474 if (MaximumSize.QuadPart > Segment->RawLength.QuadPart && 2475 !(AllocationAttributes & SEC_RESERVE)) 2476 { 2477 Segment->RawLength.QuadPart = MaximumSize.QuadPart; 2478 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart); 2479 } 2480 2481 MmUnlockSectionSegment(Segment); 2482 } 2483 Section->SizeOfSection = MaximumSize; 2484 2485 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); 2486 *SectionObject = Section; 2487 return STATUS_SUCCESS; 2488 } 2489 2490 /* 2491 TODO: not that great (declaring loaders statically, having to declare all of 2492 them, having to keep them extern, etc.), will fix in the future 2493 */ 2494 extern NTSTATUS NTAPI PeFmtCreateSection 2495 ( 2496 IN CONST VOID * FileHeader, 2497 IN SIZE_T FileHeaderSize, 2498 IN PVOID File, 2499 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, 2500 OUT PULONG Flags, 2501 IN PEXEFMT_CB_READ_FILE ReadFileCb, 2502 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb 2503 ); 2504 2505 extern NTSTATUS NTAPI ElfFmtCreateSection 2506 ( 2507 IN CONST VOID * FileHeader, 2508 IN SIZE_T FileHeaderSize, 2509 IN PVOID File, 2510 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, 2511 OUT PULONG Flags, 2512 IN PEXEFMT_CB_READ_FILE ReadFileCb, 2513 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb 2514 ); 2515 2516 static PEXEFMT_LOADER ExeFmtpLoaders[] = 2517 { 2518 PeFmtCreateSection, 2519 #ifdef __ELF 2520 ElfFmtCreateSection 2521 #endif 2522 }; 2523 2524 static 2525 PMM_SECTION_SEGMENT 2526 NTAPI 2527 ExeFmtpAllocateSegments(IN ULONG NrSegments) 2528 { 2529 SIZE_T SizeOfSegments; 2530 PMM_SECTION_SEGMENT Segments; 2531 2532 /* TODO: check for integer overflow */ 2533 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * NrSegments; 2534 2535 Segments = ExAllocatePoolWithTag(NonPagedPool, 2536 SizeOfSegments, 2537 TAG_MM_SECTION_SEGMENT); 2538 2539 if(Segments) 2540 RtlZeroMemory(Segments, SizeOfSegments); 2541 2542 return Segments; 2543 } 2544 static 2545 NTSTATUS 2546 NTAPI 2547 ExeFmtpReadFile(IN PVOID File, 2548 IN PLARGE_INTEGER Offset, 2549 IN ULONG Length, 2550 OUT PVOID * Data, 2551 OUT PVOID * AllocBase, 2552 OUT PULONG ReadSize) 2553 { 2554 NTSTATUS Status; 2555 LARGE_INTEGER FileOffset; 2556 ULONG AdjustOffset; 2557 ULONG OffsetAdjustment; 2558 ULONG BufferSize; 2559 ULONG UsedSize; 2560 PVOID Buffer; 2561 PFILE_OBJECT FileObject = File; 2562 IO_STATUS_BLOCK Iosb; 2563 2564 ASSERT_IRQL_LESS(DISPATCH_LEVEL); 2565 2566 if(Length == 0) 2567 { 2568 KeBugCheck(MEMORY_MANAGEMENT); 2569 } 2570 2571 FileOffset = *Offset; 2572 2573 /* Negative/special offset: it cannot be used in this context */ 2574 if(FileOffset.u.HighPart < 0) 2575 { 2576 KeBugCheck(MEMORY_MANAGEMENT); 2577 } 2578 2579 AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart); 2580 OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset; 2581 FileOffset.u.LowPart = AdjustOffset; 2582 2583 BufferSize = Length + OffsetAdjustment; 2584 BufferSize = PAGE_ROUND_UP(BufferSize); 2585 2586 /* 2587 * It's ok to use paged pool, because this is a temporary buffer only used in 2588 * the loading of executables. The assumption is that MmCreateSection is 2589 * always called at low IRQLs and that these buffers don't survive a brief 2590 * initialization phase 2591 */ 2592 Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, 'rXmM'); 2593 if (!Buffer) 2594 { 2595 return STATUS_INSUFFICIENT_RESOURCES; 2596 } 2597 2598 Status = MiSimpleRead(FileObject, &FileOffset, Buffer, BufferSize, TRUE, &Iosb); 2599 2600 UsedSize = (ULONG)Iosb.Information; 2601 2602 if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment) 2603 { 2604 Status = STATUS_IN_PAGE_ERROR; 2605 ASSERT(!NT_SUCCESS(Status)); 2606 } 2607 2608 if(NT_SUCCESS(Status)) 2609 { 2610 *Data = (PVOID)((ULONG_PTR)Buffer + OffsetAdjustment); 2611 *AllocBase = Buffer; 2612 *ReadSize = UsedSize - OffsetAdjustment; 2613 } 2614 else 2615 { 2616 ExFreePoolWithTag(Buffer, 'rXmM'); 2617 } 2618 2619 return Status; 2620 } 2621 2622 #ifdef NASSERT 2623 # define MmspAssertSegmentsSorted(OBJ_) ((void)0) 2624 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0) 2625 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0) 2626 #else 2627 static 2628 VOID 2629 NTAPI 2630 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject) 2631 { 2632 ULONG i; 2633 2634 for( i = 1; i < ImageSectionObject->NrSegments; ++ i ) 2635 { 2636 ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >= 2637 ImageSectionObject->Segments[i - 1].Image.VirtualAddress); 2638 } 2639 } 2640 2641 static 2642 VOID 2643 NTAPI 2644 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject) 2645 { 2646 ULONG i; 2647 2648 MmspAssertSegmentsSorted(ImageSectionObject); 2649 2650 for( i = 0; i < ImageSectionObject->NrSegments; ++ i ) 2651 { 2652 ASSERT(ImageSectionObject->Segments[i].Length.QuadPart > 0); 2653 2654 if(i > 0) 2655 { 2656 ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >= 2657 (ImageSectionObject->Segments[i - 1].Image.VirtualAddress + 2658 ImageSectionObject->Segments[i - 1].Length.QuadPart)); 2659 } 2660 } 2661 } 2662 2663 static 2664 VOID 2665 NTAPI 2666 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject) 2667 { 2668 ULONG i; 2669 2670 for( i = 0; i < ImageSectionObject->NrSegments; ++ i ) 2671 { 2672 ASSERT((ImageSectionObject->Segments[i].Image.VirtualAddress % PAGE_SIZE) == 0); 2673 ASSERT((ImageSectionObject->Segments[i].Length.QuadPart % PAGE_SIZE) == 0); 2674 } 2675 } 2676 #endif 2677 2678 static 2679 int 2680 __cdecl 2681 MmspCompareSegments(const void * x, 2682 const void * y) 2683 { 2684 const MM_SECTION_SEGMENT *Segment1 = (const MM_SECTION_SEGMENT *)x; 2685 const MM_SECTION_SEGMENT *Segment2 = (const MM_SECTION_SEGMENT *)y; 2686 2687 if (Segment1->Image.VirtualAddress > Segment2->Image.VirtualAddress) 2688 return 1; 2689 else if (Segment1->Image.VirtualAddress < Segment2->Image.VirtualAddress) 2690 return -1; 2691 else 2692 return 0; 2693 } 2694 2695 /* 2696 * Ensures an image section's segments are sorted in memory 2697 */ 2698 static 2699 VOID 2700 NTAPI 2701 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, 2702 IN ULONG Flags) 2703 { 2704 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED) 2705 { 2706 MmspAssertSegmentsSorted(ImageSectionObject); 2707 } 2708 else 2709 { 2710 qsort(ImageSectionObject->Segments, 2711 ImageSectionObject->NrSegments, 2712 sizeof(ImageSectionObject->Segments[0]), 2713 MmspCompareSegments); 2714 } 2715 } 2716 2717 2718 /* 2719 * Ensures an image section's segments don't overlap in memory and don't have 2720 * gaps and don't have a null size. We let them map to overlapping file regions, 2721 * though - that's not necessarily an error 2722 */ 2723 static 2724 BOOLEAN 2725 NTAPI 2726 MmspCheckSegmentBounds 2727 ( 2728 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, 2729 IN ULONG Flags 2730 ) 2731 { 2732 ULONG i; 2733 2734 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP) 2735 { 2736 MmspAssertSegmentsNoOverlap(ImageSectionObject); 2737 return TRUE; 2738 } 2739 2740 ASSERT(ImageSectionObject->NrSegments >= 1); 2741 2742 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i ) 2743 { 2744 if(ImageSectionObject->Segments[i].Length.QuadPart == 0) 2745 { 2746 return FALSE; 2747 } 2748 2749 if(i > 0) 2750 { 2751 /* 2752 * TODO: relax the limitation on gaps. For example, gaps smaller than a 2753 * page could be OK (Windows seems to be OK with them), and larger gaps 2754 * could lead to image sections spanning several discontiguous regions 2755 * (NtMapViewOfSection could then refuse to map them, and they could 2756 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX) 2757 */ 2758 if ((ImageSectionObject->Segments[i - 1].Image.VirtualAddress + 2759 ImageSectionObject->Segments[i - 1].Length.QuadPart) != 2760 ImageSectionObject->Segments[i].Image.VirtualAddress) 2761 { 2762 return FALSE; 2763 } 2764 } 2765 } 2766 2767 return TRUE; 2768 } 2769 2770 /* 2771 * Merges and pads an image section's segments until they all are page-aligned 2772 * and have a size that is a multiple of the page size 2773 */ 2774 static 2775 BOOLEAN 2776 NTAPI 2777 MmspPageAlignSegments 2778 ( 2779 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, 2780 IN ULONG Flags 2781 ) 2782 { 2783 ULONG i; 2784 ULONG LastSegment; 2785 PMM_SECTION_SEGMENT EffectiveSegment; 2786 2787 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED) 2788 { 2789 MmspAssertSegmentsPageAligned(ImageSectionObject); 2790 return TRUE; 2791 } 2792 2793 LastSegment = 0; 2794 EffectiveSegment = &ImageSectionObject->Segments[LastSegment]; 2795 2796 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i ) 2797 { 2798 /* 2799 * The first segment requires special handling 2800 */ 2801 if (i == 0) 2802 { 2803 ULONG_PTR VirtualAddress; 2804 ULONG_PTR VirtualOffset; 2805 2806 VirtualAddress = EffectiveSegment->Image.VirtualAddress; 2807 2808 /* Round down the virtual address to the nearest page */ 2809 EffectiveSegment->Image.VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress); 2810 2811 /* Round up the virtual size to the nearest page */ 2812 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length.QuadPart) - 2813 EffectiveSegment->Image.VirtualAddress; 2814 2815 /* Adjust the raw address and size */ 2816 VirtualOffset = VirtualAddress - EffectiveSegment->Image.VirtualAddress; 2817 2818 if (EffectiveSegment->Image.FileOffset < VirtualOffset) 2819 { 2820 return FALSE; 2821 } 2822 2823 /* 2824 * Garbage in, garbage out: unaligned base addresses make the file 2825 * offset point in curious and odd places, but that's what we were 2826 * asked for 2827 */ 2828 EffectiveSegment->Image.FileOffset -= VirtualOffset; 2829 EffectiveSegment->RawLength.QuadPart += VirtualOffset; 2830 } 2831 else 2832 { 2833 PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i]; 2834 ULONG_PTR EndOfEffectiveSegment; 2835 2836 EndOfEffectiveSegment = (ULONG_PTR)(EffectiveSegment->Image.VirtualAddress + EffectiveSegment->Length.QuadPart); 2837 ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0); 2838 2839 /* 2840 * The current segment begins exactly where the current effective 2841 * segment ended, therefore beginning a new effective segment 2842 */ 2843 if (EndOfEffectiveSegment == Segment->Image.VirtualAddress) 2844 { 2845 LastSegment ++; 2846 ASSERT(LastSegment <= i); 2847 ASSERT(LastSegment < ImageSectionObject->NrSegments); 2848 2849 EffectiveSegment = &ImageSectionObject->Segments[LastSegment]; 2850 2851 if (LastSegment != i) 2852 { 2853 /* 2854 * Copy the current segment. If necessary, the effective segment 2855 * will be expanded later 2856 */ 2857 *EffectiveSegment = *Segment; 2858 } 2859 2860 /* 2861 * Page-align the virtual size. We know for sure the virtual address 2862 * already is 2863 */ 2864 ASSERT((EffectiveSegment->Image.VirtualAddress % PAGE_SIZE) == 0); 2865 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(EffectiveSegment->Length.QuadPart); 2866 } 2867 /* 2868 * The current segment is still part of the current effective segment: 2869 * extend the effective segment to reflect this 2870 */ 2871 else if (EndOfEffectiveSegment > Segment->Image.VirtualAddress) 2872 { 2873 static const ULONG FlagsToProtection[16] = 2874 { 2875 PAGE_NOACCESS, 2876 PAGE_READONLY, 2877 PAGE_READWRITE, 2878 PAGE_READWRITE, 2879 PAGE_EXECUTE_READ, 2880 PAGE_EXECUTE_READ, 2881 PAGE_EXECUTE_READWRITE, 2882 PAGE_EXECUTE_READWRITE, 2883 PAGE_WRITECOPY, 2884 PAGE_WRITECOPY, 2885 PAGE_WRITECOPY, 2886 PAGE_WRITECOPY, 2887 PAGE_EXECUTE_WRITECOPY, 2888 PAGE_EXECUTE_WRITECOPY, 2889 PAGE_EXECUTE_WRITECOPY, 2890 PAGE_EXECUTE_WRITECOPY 2891 }; 2892 2893 unsigned ProtectionFlags; 2894 2895 /* 2896 * Extend the file size 2897 */ 2898 2899 /* Unaligned segments must be contiguous within the file */ 2900 if (Segment->Image.FileOffset != (EffectiveSegment->Image.FileOffset + 2901 EffectiveSegment->RawLength.QuadPart)) 2902 { 2903 return FALSE; 2904 } 2905 2906 EffectiveSegment->RawLength.QuadPart += Segment->RawLength.QuadPart; 2907 2908 /* 2909 * Extend the virtual size 2910 */ 2911 ASSERT(PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) >= EndOfEffectiveSegment); 2912 2913 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) - 2914 EffectiveSegment->Image.VirtualAddress; 2915 2916 /* 2917 * Merge the protection 2918 */ 2919 EffectiveSegment->Protection |= Segment->Protection; 2920 2921 /* Clean up redundance */ 2922 ProtectionFlags = 0; 2923 2924 if(EffectiveSegment->Protection & PAGE_IS_READABLE) 2925 ProtectionFlags |= 1 << 0; 2926 2927 if(EffectiveSegment->Protection & PAGE_IS_WRITABLE) 2928 ProtectionFlags |= 1 << 1; 2929 2930 if(EffectiveSegment->Protection & PAGE_IS_EXECUTABLE) 2931 ProtectionFlags |= 1 << 2; 2932 2933 if(EffectiveSegment->Protection & PAGE_IS_WRITECOPY) 2934 ProtectionFlags |= 1 << 3; 2935 2936 ASSERT(ProtectionFlags < 16); 2937 EffectiveSegment->Protection = FlagsToProtection[ProtectionFlags]; 2938 2939 /* If a segment was required to be shared and cannot, fail */ 2940 if(!(Segment->Protection & PAGE_IS_WRITECOPY) && 2941 EffectiveSegment->Protection & PAGE_IS_WRITECOPY) 2942 { 2943 return FALSE; 2944 } 2945 } 2946 /* 2947 * We assume no holes between segments at this point 2948 */ 2949 else 2950 { 2951 KeBugCheck(MEMORY_MANAGEMENT); 2952 } 2953 } 2954 } 2955 ImageSectionObject->NrSegments = LastSegment + 1; 2956 2957 return TRUE; 2958 } 2959 2960 NTSTATUS 2961 ExeFmtpCreateImageSection(PFILE_OBJECT FileObject, 2962 PMM_IMAGE_SECTION_OBJECT ImageSectionObject) 2963 { 2964 LARGE_INTEGER Offset; 2965 PVOID FileHeader; 2966 PVOID FileHeaderBuffer; 2967 ULONG FileHeaderSize; 2968 ULONG Flags; 2969 ULONG OldNrSegments; 2970 NTSTATUS Status; 2971 ULONG i; 2972 2973 /* 2974 * Read the beginning of the file (2 pages). Should be enough to contain 2975 * all (or most) of the headers 2976 */ 2977 Offset.QuadPart = 0; 2978 2979 Status = ExeFmtpReadFile (FileObject, 2980 &Offset, 2981 PAGE_SIZE * 2, 2982 &FileHeader, 2983 &FileHeaderBuffer, 2984 &FileHeaderSize); 2985 2986 if (!NT_SUCCESS(Status)) 2987 return Status; 2988 2989 if (FileHeaderSize == 0) 2990 { 2991 ExFreePool(FileHeaderBuffer); 2992 return STATUS_UNSUCCESSFUL; 2993 } 2994 2995 /* 2996 * Look for a loader that can handle this executable 2997 */ 2998 for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i) 2999 { 3000 Flags = 0; 3001 3002 Status = ExeFmtpLoaders[i](FileHeader, 3003 FileHeaderSize, 3004 FileObject, 3005 ImageSectionObject, 3006 &Flags, 3007 ExeFmtpReadFile, 3008 ExeFmtpAllocateSegments); 3009 3010 if (!NT_SUCCESS(Status)) 3011 { 3012 if (ImageSectionObject->Segments) 3013 { 3014 ExFreePool(ImageSectionObject->Segments); 3015 ImageSectionObject->Segments = NULL; 3016 } 3017 } 3018 3019 if (Status != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT) 3020 break; 3021 } 3022 3023 ExFreePoolWithTag(FileHeaderBuffer, 'rXmM'); 3024 3025 /* 3026 * No loader handled the format 3027 */ 3028 if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT) 3029 { 3030 Status = STATUS_INVALID_IMAGE_NOT_MZ; 3031 ASSERT(!NT_SUCCESS(Status)); 3032 } 3033 3034 if (!NT_SUCCESS(Status)) 3035 return Status; 3036 3037 ASSERT(ImageSectionObject->Segments != NULL); 3038 ASSERT(ImageSectionObject->RefCount > 0); 3039 3040 /* 3041 * Some defaults 3042 */ 3043 /* FIXME? are these values platform-dependent? */ 3044 if (ImageSectionObject->ImageInformation.MaximumStackSize == 0) 3045 ImageSectionObject->ImageInformation.MaximumStackSize = 0x40000; 3046 3047 if(ImageSectionObject->ImageInformation.CommittedStackSize == 0) 3048 ImageSectionObject->ImageInformation.CommittedStackSize = 0x1000; 3049 3050 if(ImageSectionObject->BasedAddress == NULL) 3051 { 3052 if(ImageSectionObject->ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL) 3053 ImageSectionObject->BasedAddress = (PVOID)0x10000000; 3054 else 3055 ImageSectionObject->BasedAddress = (PVOID)0x00400000; 3056 } 3057 3058 /* 3059 * And now the fun part: fixing the segments 3060 */ 3061 3062 /* Sort them by virtual address */ 3063 MmspSortSegments(ImageSectionObject, Flags); 3064 3065 /* Ensure they don't overlap in memory */ 3066 if (!MmspCheckSegmentBounds(ImageSectionObject, Flags)) 3067 return STATUS_INVALID_IMAGE_FORMAT; 3068 3069 /* Ensure they are aligned */ 3070 OldNrSegments = ImageSectionObject->NrSegments; 3071 3072 if (!MmspPageAlignSegments(ImageSectionObject, Flags)) 3073 return STATUS_INVALID_IMAGE_FORMAT; 3074 3075 /* Trim them if the alignment phase merged some of them */ 3076 if (ImageSectionObject->NrSegments < OldNrSegments) 3077 { 3078 PMM_SECTION_SEGMENT Segments; 3079 SIZE_T SizeOfSegments; 3080 3081 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments; 3082 3083 Segments = ExAllocatePoolWithTag(PagedPool, 3084 SizeOfSegments, 3085 TAG_MM_SECTION_SEGMENT); 3086 3087 if (Segments == NULL) 3088 return STATUS_INSUFFICIENT_RESOURCES; 3089 3090 RtlCopyMemory(Segments, ImageSectionObject->Segments, SizeOfSegments); 3091 ExFreePool(ImageSectionObject->Segments); 3092 ImageSectionObject->Segments = Segments; 3093 } 3094 3095 /* And finish their initialization */ 3096 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i ) 3097 { 3098 ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock); 3099 ImageSectionObject->Segments[i].ReferenceCount = &ImageSectionObject->RefCount; 3100 ImageSectionObject->Segments[i].Flags = &ImageSectionObject->SegFlags; 3101 MiInitializeSectionPageTable(&ImageSectionObject->Segments[i]); 3102 ImageSectionObject->Segments[i].FileObject = FileObject; 3103 } 3104 3105 ASSERT(ImageSectionObject->RefCount > 0); 3106 3107 ImageSectionObject->FileObject = FileObject; 3108 3109 ASSERT(NT_SUCCESS(Status)); 3110 return Status; 3111 } 3112 3113 NTSTATUS 3114 MmCreateImageSection(PSECTION *SectionObject, 3115 ACCESS_MASK DesiredAccess, 3116 POBJECT_ATTRIBUTES ObjectAttributes, 3117 PLARGE_INTEGER UMaximumSize, 3118 ULONG SectionPageProtection, 3119 ULONG AllocationAttributes, 3120 PFILE_OBJECT FileObject) 3121 { 3122 PSECTION Section; 3123 NTSTATUS Status; 3124 PMM_IMAGE_SECTION_OBJECT ImageSectionObject; 3125 KIRQL OldIrql; 3126 3127 3128 if (FileObject == NULL) 3129 return STATUS_INVALID_FILE_FOR_SECTION; 3130 3131 if (FileObject->SectionObjectPointer == NULL) 3132 { 3133 DPRINT1("Denying section creation due to missing cache initialization\n"); 3134 return STATUS_INVALID_FILE_FOR_SECTION; 3135 } 3136 3137 /* 3138 * Create the section 3139 */ 3140 Status = ObCreateObject (ExGetPreviousMode(), 3141 MmSectionObjectType, 3142 ObjectAttributes, 3143 ExGetPreviousMode(), 3144 NULL, 3145 sizeof(*Section), 3146 0, 3147 0, 3148 (PVOID*)(PVOID)&Section); 3149 if (!NT_SUCCESS(Status)) 3150 { 3151 return Status; 3152 } 3153 3154 /* 3155 * Initialize it 3156 */ 3157 RtlZeroMemory(Section, sizeof(*Section)); 3158 3159 /* Mark this as a "ROS" Section */ 3160 Section->u.Flags.filler = 1; 3161 3162 Section->InitialPageProtection = SectionPageProtection; 3163 Section->u.Flags.File = 1; 3164 Section->u.Flags.Image = 1; 3165 if (AllocationAttributes & SEC_NO_CHANGE) 3166 Section->u.Flags.NoChange = 1; 3167 3168 OldIrql = MiAcquirePfnLock(); 3169 3170 /* Wait for it to be properly created or deleted */ 3171 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject; 3172 while(ImageSectionObject && (ImageSectionObject->SegFlags & (MM_SEGMENT_INDELETE | MM_SEGMENT_INCREATE))) 3173 { 3174 MiReleasePfnLock(OldIrql); 3175 3176 KeDelayExecutionThread(KernelMode, FALSE, &TinyTime); 3177 3178 OldIrql = MiAcquirePfnLock(); 3179 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject; 3180 } 3181 3182 if (ImageSectionObject == NULL) 3183 { 3184 NTSTATUS StatusExeFmt; 3185 3186 ImageSectionObject = ExAllocatePoolZero(NonPagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT); 3187 if (ImageSectionObject == NULL) 3188 { 3189 MiReleasePfnLock(OldIrql); 3190 ObDereferenceObject(Section); 3191 return STATUS_NO_MEMORY; 3192 } 3193 3194 ImageSectionObject->SegFlags = MM_SEGMENT_INCREATE; 3195 ImageSectionObject->RefCount = 1; 3196 FileObject->SectionObjectPointer->ImageSectionObject = ImageSectionObject; 3197 3198 MiReleasePfnLock(OldIrql); 3199 3200 /* Purge the cache */ 3201 CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, NULL); 3202 3203 StatusExeFmt = ExeFmtpCreateImageSection(FileObject, ImageSectionObject); 3204 3205 if (!NT_SUCCESS(StatusExeFmt)) 3206 { 3207 /* Unset */ 3208 OldIrql = MiAcquirePfnLock(); 3209 FileObject->SectionObjectPointer->ImageSectionObject = NULL; 3210 MiReleasePfnLock(OldIrql); 3211 3212 if(ImageSectionObject->Segments != NULL) 3213 ExFreePool(ImageSectionObject->Segments); 3214 3215 /* 3216 * If image file is empty, then return that the file is invalid for section 3217 */ 3218 Status = StatusExeFmt; 3219 if (StatusExeFmt == STATUS_END_OF_FILE) 3220 { 3221 Status = STATUS_INVALID_FILE_FOR_SECTION; 3222 } 3223 3224 ExFreePoolWithTag(ImageSectionObject, TAG_MM_SECTION_SEGMENT); 3225 ObDereferenceObject(Section); 3226 return Status; 3227 } 3228 3229 Section->Segment = (PSEGMENT)ImageSectionObject; 3230 ASSERT(ImageSectionObject->Segments); 3231 ASSERT(ImageSectionObject->RefCount > 0); 3232 3233 /* 3234 * Lock the file 3235 */ 3236 Status = MmspWaitForFileLock(FileObject); 3237 if (!NT_SUCCESS(Status)) 3238 { 3239 /* Unset */ 3240 OldIrql = MiAcquirePfnLock(); 3241 FileObject->SectionObjectPointer->ImageSectionObject = NULL; 3242 MiReleasePfnLock(OldIrql); 3243 3244 ExFreePool(ImageSectionObject->Segments); 3245 ExFreePool(ImageSectionObject); 3246 ObDereferenceObject(Section); 3247 return Status; 3248 } 3249 3250 OldIrql = MiAcquirePfnLock(); 3251 ImageSectionObject->SegFlags &= ~MM_SEGMENT_INCREATE; 3252 3253 /* Take a ref on the file on behalf of the newly created structure */ 3254 ObReferenceObject(FileObject); 3255 3256 MiReleasePfnLock(OldIrql); 3257 3258 Status = StatusExeFmt; 3259 } 3260 else 3261 { 3262 /* Take one ref */ 3263 ImageSectionObject->RefCount++; 3264 3265 MiReleasePfnLock(OldIrql); 3266 3267 Section->Segment = (PSEGMENT)ImageSectionObject; 3268 3269 Status = STATUS_SUCCESS; 3270 } 3271 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); 3272 *SectionObject = Section; 3273 ASSERT(ImageSectionObject->RefCount > 0); 3274 3275 return Status; 3276 } 3277 3278 3279 3280 static NTSTATUS 3281 MmMapViewOfSegment( 3282 PMMSUPPORT AddressSpace, 3283 BOOLEAN AsImage, 3284 PMM_SECTION_SEGMENT Segment, 3285 PVOID* BaseAddress, 3286 SIZE_T ViewSize, 3287 ULONG Protect, 3288 LONGLONG ViewOffset, 3289 ULONG AllocationType) 3290 { 3291 PMEMORY_AREA MArea; 3292 NTSTATUS Status; 3293 ULONG Granularity; 3294 3295 ASSERT(ViewSize != 0); 3296 3297 if (Segment->WriteCopy) 3298 { 3299 /* We have to do this because the not present fault 3300 * and access fault handlers depend on the protection 3301 * that should be granted AFTER the COW fault takes 3302 * place to be in Region->Protect. The not present fault 3303 * handler changes this to the correct protection for COW when 3304 * mapping the pages into the process's address space. If a COW 3305 * fault takes place, the access fault handler sets the page protection 3306 * to these values for the newly copied pages 3307 */ 3308 if (Protect == PAGE_WRITECOPY) 3309 Protect = PAGE_READWRITE; 3310 else if (Protect == PAGE_EXECUTE_WRITECOPY) 3311 Protect = PAGE_EXECUTE_READWRITE; 3312 } 3313 3314 if (*BaseAddress == NULL) 3315 Granularity = MM_ALLOCATION_GRANULARITY; 3316 else 3317 Granularity = PAGE_SIZE; 3318 3319 #ifdef NEWCC 3320 if (Segment->Flags & MM_DATAFILE_SEGMENT) 3321 { 3322 LARGE_INTEGER FileOffset; 3323 FileOffset.QuadPart = ViewOffset; 3324 ObReferenceObject(Section); 3325 return _MiMapViewOfSegment(AddressSpace, Segment, BaseAddress, ViewSize, Protect, &FileOffset, AllocationType, __FILE__, __LINE__); 3326 } 3327 #endif 3328 Status = MmCreateMemoryArea(AddressSpace, 3329 MEMORY_AREA_SECTION_VIEW, 3330 BaseAddress, 3331 ViewSize, 3332 Protect, 3333 &MArea, 3334 AllocationType, 3335 Granularity); 3336 if (!NT_SUCCESS(Status)) 3337 { 3338 DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n", 3339 (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status); 3340 return Status; 3341 } 3342 3343 InterlockedIncrement64(Segment->ReferenceCount); 3344 3345 MArea->SectionData.Segment = Segment; 3346 MArea->SectionData.ViewOffset = ViewOffset; 3347 if (AsImage) 3348 { 3349 MArea->VadNode.u.VadFlags.VadType = VadImageMap; 3350 } 3351 3352 MmInitializeRegion(&MArea->SectionData.RegionListHead, 3353 ViewSize, 0, Protect); 3354 3355 return STATUS_SUCCESS; 3356 } 3357 3358 3359 static VOID 3360 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, 3361 PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty) 3362 { 3363 ULONG_PTR Entry; 3364 LARGE_INTEGER Offset; 3365 SWAPENTRY SavedSwapEntry; 3366 PMM_SECTION_SEGMENT Segment; 3367 PMMSUPPORT AddressSpace; 3368 PEPROCESS Process; 3369 3370 AddressSpace = (PMMSUPPORT)Context; 3371 Process = MmGetAddressSpaceOwner(AddressSpace); 3372 3373 Address = (PVOID)PAGE_ROUND_DOWN(Address); 3374 3375 Offset.QuadPart = ((ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)) + 3376 MemoryArea->SectionData.ViewOffset; 3377 3378 Segment = MemoryArea->SectionData.Segment; 3379 3380 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 3381 while (Entry && MM_IS_WAIT_PTE(Entry)) 3382 { 3383 MmUnlockSectionSegment(Segment); 3384 MmUnlockAddressSpace(AddressSpace); 3385 3386 MiWaitForPageEvent(NULL, NULL); 3387 3388 MmLockAddressSpace(AddressSpace); 3389 MmLockSectionSegment(Segment); 3390 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 3391 } 3392 3393 /* 3394 * For a dirty, datafile, non-private page, there shoulkd be no swap entry 3395 */ 3396 if (*Segment->Flags & MM_DATAFILE_SEGMENT) 3397 { 3398 if (Page == PFN_FROM_SSE(Entry) && Dirty) 3399 { 3400 ASSERT(SwapEntry == 0); 3401 } 3402 } 3403 3404 if (SwapEntry != 0) 3405 { 3406 /* 3407 * Sanity check 3408 */ 3409 MmFreeSwapPage(SwapEntry); 3410 } 3411 else if (Page != 0) 3412 { 3413 if (IS_SWAP_FROM_SSE(Entry) || 3414 Page != PFN_FROM_SSE(Entry)) 3415 { 3416 ASSERT(Process != NULL); 3417 3418 /* 3419 * Just dereference private pages 3420 */ 3421 SavedSwapEntry = MmGetSavedSwapEntryPage(Page); 3422 if (SavedSwapEntry != 0) 3423 { 3424 MmFreeSwapPage(SavedSwapEntry); 3425 MmSetSavedSwapEntryPage(Page, 0); 3426 } 3427 MmDeleteRmap(Page, Process, Address); 3428 MmReleasePageMemoryConsumer(MC_USER, Page); 3429 } 3430 else 3431 { 3432 if (Process) 3433 { 3434 MmDeleteRmap(Page, Process, Address); 3435 } 3436 3437 /* We don't dirtify for System Space Maps. We let Cc manage that */ 3438 MmUnsharePageEntrySectionSegment(MemoryArea, Segment, &Offset, Process ? Dirty : FALSE, FALSE, NULL); 3439 } 3440 } 3441 } 3442 3443 static NTSTATUS 3444 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace, 3445 PVOID BaseAddress) 3446 { 3447 NTSTATUS Status; 3448 PMEMORY_AREA MemoryArea; 3449 PMM_SECTION_SEGMENT Segment; 3450 PLIST_ENTRY CurrentEntry; 3451 PMM_REGION CurrentRegion; 3452 PLIST_ENTRY RegionListHead; 3453 3454 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, 3455 BaseAddress); 3456 if (MemoryArea == NULL) 3457 { 3458 return STATUS_UNSUCCESSFUL; 3459 } 3460 3461 Segment = MemoryArea->SectionData.Segment; 3462 3463 #ifdef NEWCC 3464 if (Segment->Flags & MM_DATAFILE_SEGMENT) 3465 { 3466 MmUnlockAddressSpace(AddressSpace); 3467 Status = MmUnmapViewOfCacheSegment(AddressSpace, BaseAddress); 3468 MmLockAddressSpace(AddressSpace); 3469 3470 return Status; 3471 } 3472 #endif 3473 3474 MemoryArea->DeleteInProgress = TRUE; 3475 3476 MmLockSectionSegment(Segment); 3477 3478 RegionListHead = &MemoryArea->SectionData.RegionListHead; 3479 while (!IsListEmpty(RegionListHead)) 3480 { 3481 CurrentEntry = RemoveHeadList(RegionListHead); 3482 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry); 3483 ExFreePoolWithTag(CurrentRegion, TAG_MM_REGION); 3484 } 3485 3486 if ((*Segment->Flags) & MM_PHYSICALMEMORY_SEGMENT) 3487 { 3488 Status = MmFreeMemoryArea(AddressSpace, 3489 MemoryArea, 3490 NULL, 3491 NULL); 3492 } 3493 else 3494 { 3495 Status = MmFreeMemoryArea(AddressSpace, 3496 MemoryArea, 3497 MmFreeSectionPage, 3498 AddressSpace); 3499 } 3500 MmUnlockSectionSegment(Segment); 3501 MmDereferenceSegment(Segment); 3502 return Status; 3503 } 3504 3505 /* This functions must be called with a locked address space */ 3506 NTSTATUS 3507 NTAPI 3508 MiRosUnmapViewOfSection(IN PEPROCESS Process, 3509 IN PVOID BaseAddress, 3510 IN BOOLEAN SkipDebuggerNotify) 3511 { 3512 NTSTATUS Status; 3513 PMEMORY_AREA MemoryArea; 3514 PMMSUPPORT AddressSpace; 3515 PVOID ImageBaseAddress = 0; 3516 3517 DPRINT("Opening memory area Process %p BaseAddress %p\n", 3518 Process, BaseAddress); 3519 3520 ASSERT(Process); 3521 3522 AddressSpace = Process ? &Process->Vm : MmGetKernelAddressSpace(); 3523 3524 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, 3525 BaseAddress); 3526 if (MemoryArea == NULL || 3527 #ifdef NEWCC 3528 ((MemoryArea->Type != MEMORY_AREA_SECTION_VIEW) && (MemoryArea->Type != MEMORY_AREA_CACHE)) || 3529 #else 3530 (MemoryArea->Type != MEMORY_AREA_SECTION_VIEW) || 3531 #endif 3532 MemoryArea->DeleteInProgress) 3533 3534 { 3535 if (MemoryArea) ASSERT(MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3); 3536 3537 DPRINT1("Unable to find memory area at address %p.\n", BaseAddress); 3538 return STATUS_NOT_MAPPED_VIEW; 3539 } 3540 3541 if (MemoryArea->VadNode.u.VadFlags.VadType == VadImageMap) 3542 { 3543 ULONG i; 3544 ULONG NrSegments; 3545 PMM_IMAGE_SECTION_OBJECT ImageSectionObject; 3546 PMM_SECTION_SEGMENT SectionSegments; 3547 PMM_SECTION_SEGMENT Segment; 3548 3549 Segment = MemoryArea->SectionData.Segment; 3550 ImageSectionObject = ImageSectionObjectFromSegment(Segment); 3551 SectionSegments = ImageSectionObject->Segments; 3552 NrSegments = ImageSectionObject->NrSegments; 3553 3554 MemoryArea->DeleteInProgress = TRUE; 3555 3556 /* Search for the current segment within the section segments 3557 * and calculate the image base address */ 3558 for (i = 0; i < NrSegments; i++) 3559 { 3560 if (Segment == &SectionSegments[i]) 3561 { 3562 ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].Image.VirtualAddress; 3563 break; 3564 } 3565 } 3566 if (i >= NrSegments) 3567 { 3568 KeBugCheck(MEMORY_MANAGEMENT); 3569 } 3570 3571 for (i = 0; i < NrSegments; i++) 3572 { 3573 PVOID SBaseAddress = (PVOID) 3574 ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress); 3575 3576 Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress); 3577 if (!NT_SUCCESS(Status)) 3578 { 3579 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n", 3580 SBaseAddress, Process, Status); 3581 ASSERT(NT_SUCCESS(Status)); 3582 } 3583 } 3584 } 3585 else 3586 { 3587 Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress); 3588 if (!NT_SUCCESS(Status)) 3589 { 3590 DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n", 3591 BaseAddress, Process, Status); 3592 ASSERT(NT_SUCCESS(Status)); 3593 } 3594 } 3595 3596 /* Notify debugger */ 3597 if (ImageBaseAddress && !SkipDebuggerNotify) DbgkUnMapViewOfSection(ImageBaseAddress); 3598 3599 return STATUS_SUCCESS; 3600 } 3601 3602 3603 3604 3605 /** 3606 * Queries the information of a section object. 3607 * 3608 * @param SectionHandle 3609 * Handle to the section object. It must be opened with SECTION_QUERY 3610 * access. 3611 * @param SectionInformationClass 3612 * Index to a certain information structure. Can be either 3613 * SectionBasicInformation or SectionImageInformation. The latter 3614 * is valid only for sections that were created with the SEC_IMAGE 3615 * flag. 3616 * @param SectionInformation 3617 * Caller supplies storage for resulting information. 3618 * @param Length 3619 * Size of the supplied storage. 3620 * @param ResultLength 3621 * Data written. 3622 * 3623 * @return Status. 3624 * 3625 * @implemented 3626 */ 3627 NTSTATUS 3628 NTAPI 3629 NtQuerySection( 3630 _In_ HANDLE SectionHandle, 3631 _In_ SECTION_INFORMATION_CLASS SectionInformationClass, 3632 _Out_ PVOID SectionInformation, 3633 _In_ SIZE_T SectionInformationLength, 3634 _Out_opt_ PSIZE_T ResultLength) 3635 { 3636 PSECTION Section; 3637 KPROCESSOR_MODE PreviousMode; 3638 NTSTATUS Status; 3639 PAGED_CODE(); 3640 3641 PreviousMode = ExGetPreviousMode(); 3642 if (PreviousMode != KernelMode) 3643 { 3644 _SEH2_TRY 3645 { 3646 ProbeForWrite(SectionInformation, 3647 SectionInformationLength, 3648 __alignof(ULONG)); 3649 if (ResultLength != NULL) 3650 { 3651 ProbeForWrite(ResultLength, 3652 sizeof(*ResultLength), 3653 __alignof(SIZE_T)); 3654 } 3655 } 3656 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3657 { 3658 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3659 } 3660 _SEH2_END; 3661 } 3662 3663 if (SectionInformationClass == SectionBasicInformation) 3664 { 3665 if (SectionInformationLength < sizeof(SECTION_BASIC_INFORMATION)) 3666 { 3667 return STATUS_INFO_LENGTH_MISMATCH; 3668 } 3669 } 3670 else if (SectionInformationClass == SectionImageInformation) 3671 { 3672 if (SectionInformationLength < sizeof(SECTION_IMAGE_INFORMATION)) 3673 { 3674 return STATUS_INFO_LENGTH_MISMATCH; 3675 } 3676 } 3677 else 3678 { 3679 return STATUS_INVALID_INFO_CLASS; 3680 } 3681 3682 Status = ObReferenceObjectByHandle(SectionHandle, 3683 SECTION_QUERY, 3684 MmSectionObjectType, 3685 PreviousMode, 3686 (PVOID*)(PVOID)&Section, 3687 NULL); 3688 if (!NT_SUCCESS(Status)) 3689 { 3690 DPRINT1("Failed to reference section: 0x%lx\n", Status); 3691 return Status; 3692 } 3693 3694 switch(SectionInformationClass) 3695 { 3696 case SectionBasicInformation: 3697 { 3698 SECTION_BASIC_INFORMATION Sbi; 3699 3700 Sbi.Size = Section->SizeOfSection; 3701 Sbi.BaseAddress = (PVOID)Section->Address.StartingVpn; 3702 3703 Sbi.Attributes = 0; 3704 if (Section->u.Flags.File) 3705 Sbi.Attributes |= SEC_FILE; 3706 if (Section->u.Flags.Image) 3707 Sbi.Attributes |= SEC_IMAGE; 3708 3709 /* Those are not set ************* 3710 if (Section->u.Flags.Commit) 3711 Sbi.Attributes |= SEC_COMMIT; 3712 if (Section->u.Flags.Reserve) 3713 Sbi.Attributes |= SEC_RESERVE; 3714 **********************************/ 3715 3716 if (Section->u.Flags.Image) 3717 { 3718 if (MiIsRosSectionObject(Section)) 3719 { 3720 PMM_IMAGE_SECTION_OBJECT ImageSectionObject = ((PMM_IMAGE_SECTION_OBJECT)Section->Segment); 3721 Sbi.BaseAddress = 0; 3722 Sbi.Size.QuadPart = ImageSectionObject->ImageInformation.ImageFileSize; 3723 } 3724 else 3725 { 3726 /* Not supported yet */ 3727 ASSERT(FALSE); 3728 } 3729 } 3730 else if (MiIsRosSectionObject(Section)) 3731 { 3732 Sbi.BaseAddress = (PVOID)((PMM_SECTION_SEGMENT)Section->Segment)->Image.VirtualAddress; 3733 Sbi.Size.QuadPart = ((PMM_SECTION_SEGMENT)Section->Segment)->RawLength.QuadPart; 3734 } 3735 else 3736 { 3737 DPRINT1("Unimplemented code path!"); 3738 } 3739 3740 _SEH2_TRY 3741 { 3742 *((SECTION_BASIC_INFORMATION*)SectionInformation) = Sbi; 3743 if (ResultLength != NULL) 3744 { 3745 *ResultLength = sizeof(Sbi); 3746 } 3747 } 3748 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3749 { 3750 Status = _SEH2_GetExceptionCode(); 3751 } 3752 _SEH2_END; 3753 break; 3754 } 3755 case SectionImageInformation: 3756 { 3757 if (!Section->u.Flags.Image) 3758 { 3759 Status = STATUS_SECTION_NOT_IMAGE; 3760 } 3761 else if (MiIsRosSectionObject(Section)) 3762 { 3763 PMM_IMAGE_SECTION_OBJECT ImageSectionObject = ((PMM_IMAGE_SECTION_OBJECT)Section->Segment); 3764 3765 _SEH2_TRY 3766 { 3767 PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation; 3768 *Sii = ImageSectionObject->ImageInformation; 3769 if (ResultLength != NULL) 3770 { 3771 *ResultLength = sizeof(*Sii); 3772 } 3773 } 3774 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3775 { 3776 Status = _SEH2_GetExceptionCode(); 3777 } 3778 _SEH2_END; 3779 } 3780 else 3781 { 3782 _SEH2_TRY 3783 { 3784 PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation; 3785 *Sii = *Section->Segment->u2.ImageInformation; 3786 if (ResultLength != NULL) 3787 *ResultLength = sizeof(*Sii); 3788 } 3789 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3790 { 3791 Status = _SEH2_GetExceptionCode(); 3792 } 3793 _SEH2_END; 3794 } 3795 break; 3796 } 3797 default: 3798 DPRINT1("Unknown SectionInformationClass: %d\n", SectionInformationClass); 3799 Status = STATUS_NOT_SUPPORTED; 3800 } 3801 3802 ObDereferenceObject(Section); 3803 3804 return Status; 3805 } 3806 3807 /********************************************************************** 3808 * NAME EXPORTED 3809 * MmMapViewOfSection 3810 * 3811 * DESCRIPTION 3812 * Maps a view of a section into the virtual address space of a 3813 * process. 3814 * 3815 * ARGUMENTS 3816 * Section 3817 * Pointer to the section object. 3818 * 3819 * ProcessHandle 3820 * Pointer to the process. 3821 * 3822 * BaseAddress 3823 * Desired base address (or NULL) on entry; 3824 * Actual base address of the view on exit. 3825 * 3826 * ZeroBits 3827 * Number of high order address bits that must be zero. 3828 * 3829 * CommitSize 3830 * Size in bytes of the initially committed section of 3831 * the view. 3832 * 3833 * SectionOffset 3834 * Offset in bytes from the beginning of the section 3835 * to the beginning of the view. 3836 * 3837 * ViewSize 3838 * Desired length of map (or zero to map all) on entry 3839 * Actual length mapped on exit. 3840 * 3841 * InheritDisposition 3842 * Specified how the view is to be shared with 3843 * child processes. 3844 * 3845 * AllocationType 3846 * Type of allocation for the pages. 3847 * 3848 * Protect 3849 * Protection for the committed region of the view. 3850 * 3851 * RETURN VALUE 3852 * Status. 3853 * 3854 * @implemented 3855 */ 3856 NTSTATUS NTAPI 3857 MmMapViewOfSection(IN PVOID SectionObject, 3858 IN PEPROCESS Process, 3859 IN OUT PVOID *BaseAddress, 3860 IN ULONG_PTR ZeroBits, 3861 IN SIZE_T CommitSize, 3862 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, 3863 IN OUT PSIZE_T ViewSize, 3864 IN SECTION_INHERIT InheritDisposition, 3865 IN ULONG AllocationType, 3866 IN ULONG Protect) 3867 { 3868 PSECTION Section; 3869 PMMSUPPORT AddressSpace; 3870 NTSTATUS Status = STATUS_SUCCESS; 3871 BOOLEAN NotAtBase = FALSE; 3872 3873 if (MiIsRosSectionObject(SectionObject) == FALSE) 3874 { 3875 DPRINT("Mapping ARM3 section into %s\n", Process->ImageFileName); 3876 return MmMapViewOfArm3Section(SectionObject, 3877 Process, 3878 BaseAddress, 3879 ZeroBits, 3880 CommitSize, 3881 SectionOffset, 3882 ViewSize, 3883 InheritDisposition, 3884 AllocationType, 3885 Protect); 3886 } 3887 3888 ASSERT(Process); 3889 3890 if (!Protect || Protect & ~PAGE_FLAGS_VALID_FOR_SECTION) 3891 { 3892 return STATUS_INVALID_PAGE_PROTECTION; 3893 } 3894 3895 /* FIXME: We should keep this, but it would break code checking equality */ 3896 Protect &= ~PAGE_NOCACHE; 3897 3898 Section = SectionObject; 3899 AddressSpace = &Process->Vm; 3900 3901 if (Section->u.Flags.NoChange) 3902 AllocationType |= SEC_NO_CHANGE; 3903 3904 MmLockAddressSpace(AddressSpace); 3905 3906 if (Section->u.Flags.Image) 3907 { 3908 ULONG i; 3909 ULONG NrSegments; 3910 ULONG_PTR ImageBase; 3911 SIZE_T ImageSize; 3912 PMM_IMAGE_SECTION_OBJECT ImageSectionObject; 3913 PMM_SECTION_SEGMENT SectionSegments; 3914 3915 ImageSectionObject = ((PMM_IMAGE_SECTION_OBJECT)Section->Segment); 3916 SectionSegments = ImageSectionObject->Segments; 3917 NrSegments = ImageSectionObject->NrSegments; 3918 3919 ASSERT(ImageSectionObject->RefCount > 0); 3920 3921 ImageBase = (ULONG_PTR)*BaseAddress; 3922 if (ImageBase == 0) 3923 { 3924 ImageBase = (ULONG_PTR)ImageSectionObject->BasedAddress; 3925 } 3926 3927 ImageSize = 0; 3928 for (i = 0; i < NrSegments; i++) 3929 { 3930 ULONG_PTR MaxExtent; 3931 MaxExtent = (ULONG_PTR)(SectionSegments[i].Image.VirtualAddress + 3932 SectionSegments[i].Length.QuadPart); 3933 ImageSize = max(ImageSize, MaxExtent); 3934 } 3935 3936 ImageSectionObject->ImageInformation.ImageFileSize = (ULONG)ImageSize; 3937 3938 /* Check for an illegal base address */ 3939 if (((ImageBase + ImageSize) > (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS) || 3940 ((ImageBase + ImageSize) < ImageSize)) 3941 { 3942 ASSERT(*BaseAddress == NULL); 3943 ImageBase = ALIGN_DOWN_BY((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - ImageSize, 3944 MM_VIRTMEM_GRANULARITY); 3945 NotAtBase = TRUE; 3946 } 3947 else if (ImageBase != ALIGN_DOWN_BY(ImageBase, MM_VIRTMEM_GRANULARITY)) 3948 { 3949 ASSERT(*BaseAddress == NULL); 3950 ImageBase = ALIGN_DOWN_BY(ImageBase, MM_VIRTMEM_GRANULARITY); 3951 NotAtBase = TRUE; 3952 } 3953 3954 /* Check there is enough space to map the section at that point. */ 3955 if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase, 3956 PAGE_ROUND_UP(ImageSize)) != NULL) 3957 { 3958 /* Fail if the user requested a fixed base address. */ 3959 if ((*BaseAddress) != NULL) 3960 { 3961 MmUnlockAddressSpace(AddressSpace); 3962 return STATUS_CONFLICTING_ADDRESSES; 3963 } 3964 /* Otherwise find a gap to map the image. */ 3965 ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), MM_VIRTMEM_GRANULARITY, FALSE); 3966 if (ImageBase == 0) 3967 { 3968 MmUnlockAddressSpace(AddressSpace); 3969 return STATUS_CONFLICTING_ADDRESSES; 3970 } 3971 /* Remember that we loaded image at a different base address */ 3972 NotAtBase = TRUE; 3973 } 3974 3975 for (i = 0; i < NrSegments; i++) 3976 { 3977 PVOID SBaseAddress = (PVOID) 3978 ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress); 3979 MmLockSectionSegment(&SectionSegments[i]); 3980 Status = MmMapViewOfSegment(AddressSpace, 3981 TRUE, 3982 &SectionSegments[i], 3983 &SBaseAddress, 3984 SectionSegments[i].Length.QuadPart, 3985 SectionSegments[i].Protection, 3986 0, 3987 0); 3988 MmUnlockSectionSegment(&SectionSegments[i]); 3989 if (!NT_SUCCESS(Status)) 3990 { 3991 /* roll-back */ 3992 while (i--) 3993 { 3994 SBaseAddress = ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress); 3995 MmLockSectionSegment(&SectionSegments[i]); 3996 MmUnmapViewOfSegment(AddressSpace, SBaseAddress); 3997 MmUnlockSectionSegment(&SectionSegments[i]); 3998 } 3999 4000 MmUnlockAddressSpace(AddressSpace); 4001 return Status; 4002 } 4003 } 4004 4005 *BaseAddress = (PVOID)ImageBase; 4006 *ViewSize = ImageSize; 4007 } 4008 else 4009 { 4010 PMM_SECTION_SEGMENT Segment = (PMM_SECTION_SEGMENT)Section->Segment; 4011 LONGLONG ViewOffset; 4012 4013 ASSERT(Segment->RefCount > 0); 4014 4015 /* check for write access */ 4016 if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) && 4017 !(Section->InitialPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))) 4018 { 4019 MmUnlockAddressSpace(AddressSpace); 4020 return STATUS_SECTION_PROTECTION; 4021 } 4022 /* check for read access */ 4023 if ((Protect & (PAGE_READONLY|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_WRITECOPY)) && 4024 !(Section->InitialPageProtection & (PAGE_READONLY|PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY))) 4025 { 4026 MmUnlockAddressSpace(AddressSpace); 4027 return STATUS_SECTION_PROTECTION; 4028 } 4029 /* check for execute access */ 4030 if ((Protect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)) && 4031 !(Section->InitialPageProtection & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY))) 4032 { 4033 MmUnlockAddressSpace(AddressSpace); 4034 return STATUS_SECTION_PROTECTION; 4035 } 4036 4037 if (SectionOffset == NULL) 4038 { 4039 ViewOffset = 0; 4040 } 4041 else 4042 { 4043 ViewOffset = SectionOffset->QuadPart; 4044 } 4045 4046 if ((ViewOffset % PAGE_SIZE) != 0) 4047 { 4048 MmUnlockAddressSpace(AddressSpace); 4049 return STATUS_MAPPED_ALIGNMENT; 4050 } 4051 4052 if ((*ViewSize) == 0) 4053 { 4054 (*ViewSize) = Section->SizeOfSection.QuadPart - ViewOffset; 4055 } 4056 else if ((ExGetPreviousMode() == UserMode) && 4057 (((*ViewSize)+ViewOffset) > Section->SizeOfSection.QuadPart) && 4058 (!Section->u.Flags.Reserve)) 4059 { 4060 /* Dubious */ 4061 (*ViewSize) = MIN(Section->SizeOfSection.QuadPart - ViewOffset, SIZE_T_MAX - PAGE_SIZE); 4062 } 4063 4064 *ViewSize = PAGE_ROUND_UP(*ViewSize); 4065 4066 MmLockSectionSegment(Segment); 4067 Status = MmMapViewOfSegment(AddressSpace, 4068 FALSE, 4069 Segment, 4070 BaseAddress, 4071 *ViewSize, 4072 Protect, 4073 ViewOffset, 4074 AllocationType & (MEM_TOP_DOWN|SEC_NO_CHANGE)); 4075 MmUnlockSectionSegment(Segment); 4076 if (!NT_SUCCESS(Status)) 4077 { 4078 MmUnlockAddressSpace(AddressSpace); 4079 return Status; 4080 } 4081 } 4082 4083 MmUnlockAddressSpace(AddressSpace); 4084 4085 if (NotAtBase) 4086 Status = STATUS_IMAGE_NOT_AT_BASE; 4087 else 4088 Status = STATUS_SUCCESS; 4089 4090 return Status; 4091 } 4092 4093 /* 4094 * @unimplemented 4095 */ 4096 BOOLEAN NTAPI 4097 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer, 4098 IN PLARGE_INTEGER NewFileSize) 4099 { 4100 BOOLEAN Ret; 4101 PMM_SECTION_SEGMENT Segment; 4102 4103 /* Check whether an ImageSectionObject exists */ 4104 if (SectionObjectPointer->ImageSectionObject != NULL) 4105 { 4106 DPRINT1("ERROR: File can't be truncated because it has an image section\n"); 4107 return FALSE; 4108 } 4109 4110 Segment = MiGrabDataSection(SectionObjectPointer); 4111 if (!Segment) 4112 { 4113 /* There is no data section. It's fine to do anything. */ 4114 return TRUE; 4115 } 4116 4117 MmLockSectionSegment(Segment); 4118 if ((Segment->SectionCount == 0) || 4119 ((Segment->SectionCount == 1) && (SectionObjectPointer->SharedCacheMap != NULL))) 4120 { 4121 /* If the cache is the only one holding a reference to the segment, then it's fine to resize */ 4122 Ret = TRUE; 4123 } 4124 else 4125 { 4126 /* We can't shrink, but we can extend */ 4127 Ret = NewFileSize->QuadPart >= Segment->RawLength.QuadPart; 4128 #if DBG 4129 if (!Ret) 4130 { 4131 DPRINT1("Cannot truncate data: New Size %I64d, Segment Size %I64d\n", NewFileSize->QuadPart, Segment->RawLength.QuadPart); 4132 } 4133 #endif 4134 } 4135 MmUnlockSectionSegment(Segment); 4136 MmDereferenceSegment(Segment); 4137 4138 DPRINT("FIXME: didn't check for outstanding write probes\n"); 4139 4140 return Ret; 4141 } 4142 4143 /* 4144 * @implemented 4145 */ 4146 BOOLEAN NTAPI 4147 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer, 4148 IN MMFLUSH_TYPE FlushType) 4149 { 4150 switch(FlushType) 4151 { 4152 case MmFlushForDelete: 4153 case MmFlushForWrite: 4154 { 4155 BOOLEAN Ret = TRUE; 4156 KIRQL OldIrql = MiAcquirePfnLock(); 4157 4158 if (SectionObjectPointer->ImageSectionObject) 4159 { 4160 PMM_IMAGE_SECTION_OBJECT ImageSectionObject = SectionObjectPointer->ImageSectionObject; 4161 if (!(ImageSectionObject->SegFlags & MM_SEGMENT_INDELETE)) 4162 Ret = FALSE; 4163 } 4164 4165 MiReleasePfnLock(OldIrql); 4166 return Ret; 4167 } 4168 } 4169 return FALSE; 4170 } 4171 4172 /* 4173 * @implemented 4174 */ 4175 NTSTATUS 4176 NTAPI 4177 MmMapViewInSystemSpace (IN PVOID SectionObject, 4178 OUT PVOID * MappedBase, 4179 IN OUT PSIZE_T ViewSize) 4180 { 4181 LARGE_INTEGER SectionOffset; 4182 4183 SectionOffset.QuadPart = 0; 4184 4185 return MmMapViewInSystemSpaceEx(SectionObject, MappedBase, ViewSize, &SectionOffset, 0); 4186 } 4187 4188 NTSTATUS 4189 NTAPI 4190 MmMapViewInSystemSpaceEx ( 4191 _In_ PVOID SectionObject, 4192 _Outptr_result_bytebuffer_ (*ViewSize) PVOID *MappedBase, 4193 _Inout_ PSIZE_T ViewSize, 4194 _Inout_ PLARGE_INTEGER SectionOffset, 4195 _In_ ULONG_PTR Flags 4196 ) 4197 { 4198 PSECTION Section = SectionObject; 4199 PMM_SECTION_SEGMENT Segment; 4200 PMMSUPPORT AddressSpace; 4201 NTSTATUS Status; 4202 4203 UNREFERENCED_PARAMETER(Flags); 4204 4205 PAGED_CODE(); 4206 4207 if (MiIsRosSectionObject(SectionObject) == FALSE) 4208 { 4209 return MiMapViewInSystemSpace(SectionObject, 4210 &MmSession, 4211 MappedBase, 4212 ViewSize, 4213 SectionOffset); 4214 } 4215 4216 DPRINT("MmMapViewInSystemSpaceEx() called\n"); 4217 4218 Section = SectionObject; 4219 Segment = (PMM_SECTION_SEGMENT)Section->Segment; 4220 4221 if (*ViewSize == 0) 4222 { 4223 LONGLONG MapSizeLL; 4224 4225 /* Page-align the mapping */ 4226 SectionOffset->LowPart = PAGE_ROUND_DOWN(SectionOffset->LowPart); 4227 4228 if (!NT_SUCCESS(RtlLongLongSub(Section->SizeOfSection.QuadPart, SectionOffset->QuadPart, &MapSizeLL))) 4229 return STATUS_INVALID_VIEW_SIZE; 4230 4231 if (!NT_SUCCESS(RtlLongLongToSIZET(MapSizeLL, ViewSize))) 4232 return STATUS_INVALID_VIEW_SIZE; 4233 } 4234 else 4235 { 4236 LONGLONG HelperLL; 4237 4238 /* Get the map end */ 4239 if (!NT_SUCCESS(RtlLongLongAdd(SectionOffset->QuadPart, *ViewSize, &HelperLL))) 4240 return STATUS_INVALID_VIEW_SIZE; 4241 4242 /* Round it up, if needed */ 4243 if (HelperLL % PAGE_SIZE) 4244 { 4245 if (!NT_SUCCESS(RtlLongLongAdd(HelperLL, PAGE_SIZE - (HelperLL % PAGE_SIZE), &HelperLL))) 4246 return STATUS_INVALID_VIEW_SIZE; 4247 } 4248 4249 /* Now that we have the mapping end, we can align down its start */ 4250 SectionOffset->LowPart = PAGE_ROUND_DOWN(SectionOffset->LowPart); 4251 4252 /* Get the new size */ 4253 if (!NT_SUCCESS(RtlLongLongSub(HelperLL, SectionOffset->QuadPart, &HelperLL))) 4254 return STATUS_INVALID_VIEW_SIZE; 4255 4256 if (!NT_SUCCESS(RtlLongLongToSIZET(HelperLL, ViewSize))) 4257 return STATUS_INVALID_VIEW_SIZE; 4258 } 4259 4260 AddressSpace = MmGetKernelAddressSpace(); 4261 4262 MmLockAddressSpace(AddressSpace); 4263 4264 MmLockSectionSegment(Segment); 4265 4266 Status = MmMapViewOfSegment(AddressSpace, 4267 Section->u.Flags.Image, 4268 Segment, 4269 MappedBase, 4270 *ViewSize, 4271 PAGE_READWRITE, 4272 SectionOffset->QuadPart, 4273 SEC_RESERVE); 4274 4275 MmUnlockSectionSegment(Segment); 4276 MmUnlockAddressSpace(AddressSpace); 4277 4278 return Status; 4279 } 4280 4281 /* This function must be called with adress space lock held */ 4282 NTSTATUS 4283 NTAPI 4284 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase) 4285 { 4286 DPRINT("MmUnmapViewInSystemSpace() called\n"); 4287 4288 return MmUnmapViewOfSegment(MmGetKernelAddressSpace(), MappedBase); 4289 } 4290 4291 /********************************************************************** 4292 * NAME EXPORTED 4293 * MmCreateSection@ 4294 * 4295 * DESCRIPTION 4296 * Creates a section object. 4297 * 4298 * ARGUMENTS 4299 * SectionObject (OUT) 4300 * Caller supplied storage for the resulting pointer 4301 * to a SECTION_OBJECT instance; 4302 * 4303 * DesiredAccess 4304 * Specifies the desired access to the section can be a 4305 * combination of: 4306 * STANDARD_RIGHTS_REQUIRED | 4307 * SECTION_QUERY | 4308 * SECTION_MAP_WRITE | 4309 * SECTION_MAP_READ | 4310 * SECTION_MAP_EXECUTE 4311 * 4312 * ObjectAttributes [OPTIONAL] 4313 * Initialized attributes for the object can be used 4314 * to create a named section; 4315 * 4316 * MaximumSize 4317 * Maximizes the size of the memory section. Must be 4318 * non-NULL for a page-file backed section. 4319 * If value specified for a mapped file and the file is 4320 * not large enough, file will be extended. 4321 * 4322 * SectionPageProtection 4323 * Can be a combination of: 4324 * PAGE_READONLY | 4325 * PAGE_READWRITE | 4326 * PAGE_WRITEONLY | 4327 * PAGE_WRITECOPY 4328 * 4329 * AllocationAttributes 4330 * Can be a combination of: 4331 * SEC_IMAGE | 4332 * SEC_RESERVE 4333 * 4334 * FileHandle 4335 * Handle to a file to create a section mapped to a file 4336 * instead of a memory backed section; 4337 * 4338 * File 4339 * Unknown. 4340 * 4341 * RETURN VALUE 4342 * Status. 4343 * 4344 * @implemented 4345 */ 4346 NTSTATUS NTAPI 4347 MmCreateSection (OUT PVOID * Section, 4348 IN ACCESS_MASK DesiredAccess, 4349 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 4350 IN PLARGE_INTEGER MaximumSize, 4351 IN ULONG SectionPageProtection, 4352 IN ULONG AllocationAttributes, 4353 IN HANDLE FileHandle OPTIONAL, 4354 IN PFILE_OBJECT FileObject OPTIONAL) 4355 { 4356 NTSTATUS Status; 4357 ULONG Protection; 4358 PSECTION *SectionObject = (PSECTION *)Section; 4359 BOOLEAN FileLock = FALSE; 4360 4361 /* Check if an ARM3 section is being created instead */ 4362 if (!(AllocationAttributes & (SEC_IMAGE | SEC_PHYSICALMEMORY))) 4363 { 4364 if (!(FileObject) && !(FileHandle)) 4365 { 4366 return MmCreateArm3Section(Section, 4367 DesiredAccess, 4368 ObjectAttributes, 4369 MaximumSize, 4370 SectionPageProtection, 4371 AllocationAttributes &~ 1, 4372 FileHandle, 4373 FileObject); 4374 } 4375 } 4376 4377 /* Convert section flag to page flag */ 4378 if (AllocationAttributes & SEC_NOCACHE) SectionPageProtection |= PAGE_NOCACHE; 4379 4380 /* Check to make sure the protection is correct. Nt* does this already */ 4381 Protection = MiMakeProtectionMask(SectionPageProtection); 4382 if (Protection == MM_INVALID_PROTECTION) 4383 { 4384 DPRINT1("Page protection is invalid\n"); 4385 return STATUS_INVALID_PAGE_PROTECTION; 4386 } 4387 4388 /* Check if this is going to be a data or image backed file section */ 4389 if ((FileHandle) || (FileObject)) 4390 { 4391 /* These cannot be mapped with large pages */ 4392 if (AllocationAttributes & SEC_LARGE_PAGES) 4393 { 4394 DPRINT1("Large pages cannot be used with an image mapping\n"); 4395 return STATUS_INVALID_PARAMETER_6; 4396 } 4397 4398 /* Did the caller pass a file object ? */ 4399 if (FileObject) 4400 { 4401 /* Reference the object directly */ 4402 ObReferenceObject(FileObject); 4403 4404 /* We don't create image mappings with file objects */ 4405 AllocationAttributes &= ~SEC_IMAGE; 4406 } 4407 else 4408 { 4409 /* Reference the file handle to get the object */ 4410 Status = ObReferenceObjectByHandle(FileHandle, 4411 MmMakeFileAccess[Protection], 4412 IoFileObjectType, 4413 ExGetPreviousMode(), 4414 (PVOID*)&FileObject, 4415 NULL); 4416 if (!NT_SUCCESS(Status)) 4417 { 4418 DPRINT1("Failed to get a handle to the FO: %lx\n", Status); 4419 return Status; 4420 } 4421 4422 /* Lock the file */ 4423 Status = FsRtlAcquireToCreateMappedSection(FileObject, SectionPageProtection); 4424 if (!NT_SUCCESS(Status)) 4425 { 4426 ObDereferenceObject(FileObject); 4427 return Status; 4428 } 4429 4430 FileLock = TRUE; 4431 4432 /* Deny access if there are writes on the file */ 4433 #if 0 4434 if ((AllocationAttributes & SEC_IMAGE) && (Status == STATUS_FILE_LOCKED_WITH_WRITERS)) 4435 { 4436 DPRINT1("Cannot create image maps with writers open on the file!\n"); 4437 Status = STATUS_ACCESS_DENIED; 4438 goto Quit; 4439 } 4440 #else 4441 if ((AllocationAttributes & SEC_IMAGE) && (Status == STATUS_FILE_LOCKED_WITH_WRITERS)) 4442 DPRINT1("Creating image map with writers open on the file!\n"); 4443 #endif 4444 } 4445 } 4446 else 4447 { 4448 /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */ 4449 if (AllocationAttributes & SEC_IMAGE) return STATUS_INVALID_FILE_FOR_SECTION; 4450 } 4451 4452 if (AllocationAttributes & SEC_IMAGE) 4453 { 4454 Status = MmCreateImageSection(SectionObject, 4455 DesiredAccess, 4456 ObjectAttributes, 4457 MaximumSize, 4458 SectionPageProtection, 4459 AllocationAttributes, 4460 FileObject); 4461 } 4462 #ifndef NEWCC 4463 else if (FileObject != NULL) 4464 { 4465 Status = MmCreateDataFileSection(SectionObject, 4466 DesiredAccess, 4467 ObjectAttributes, 4468 MaximumSize, 4469 SectionPageProtection, 4470 AllocationAttributes, 4471 FileObject, 4472 FileHandle != NULL); 4473 } 4474 #else 4475 else if (FileHandle != NULL || FileObject != NULL) 4476 { 4477 Status = MmCreateCacheSection(SectionObject, 4478 DesiredAccess, 4479 ObjectAttributes, 4480 MaximumSize, 4481 SectionPageProtection, 4482 AllocationAttributes, 4483 FileObject); 4484 } 4485 #endif 4486 else 4487 { 4488 /* All cases should be handled above */ 4489 Status = STATUS_INVALID_PARAMETER; 4490 } 4491 4492 if (FileLock) 4493 FsRtlReleaseFile(FileObject); 4494 if (FileObject) 4495 ObDereferenceObject(FileObject); 4496 4497 return Status; 4498 } 4499 4500 BOOLEAN 4501 NTAPI 4502 MmArePagesResident( 4503 _In_ PEPROCESS Process, 4504 _In_ PVOID Address, 4505 _In_ ULONG Length) 4506 { 4507 PMEMORY_AREA MemoryArea; 4508 BOOLEAN Ret = TRUE; 4509 PMM_SECTION_SEGMENT Segment; 4510 LARGE_INTEGER SegmentOffset, RangeEnd; 4511 PMMSUPPORT AddressSpace = Process ? &Process->Vm : MmGetKernelAddressSpace(); 4512 4513 MmLockAddressSpace(AddressSpace); 4514 4515 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address); 4516 if (MemoryArea == NULL) 4517 { 4518 MmUnlockAddressSpace(AddressSpace); 4519 return FALSE; 4520 } 4521 4522 /* Only supported in old Mm for now */ 4523 ASSERT(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW); 4524 /* For file mappings */ 4525 ASSERT(MemoryArea->VadNode.u.VadFlags.VadType != VadImageMap); 4526 4527 Segment = MemoryArea->SectionData.Segment; 4528 MmLockSectionSegment(Segment); 4529 4530 SegmentOffset.QuadPart = PAGE_ROUND_DOWN(Address) - MA_GetStartingAddress(MemoryArea) 4531 + MemoryArea->SectionData.ViewOffset; 4532 RangeEnd.QuadPart = PAGE_ROUND_UP((ULONG_PTR)Address + Length) - MA_GetStartingAddress(MemoryArea) 4533 + MemoryArea->SectionData.ViewOffset; 4534 4535 while (SegmentOffset.QuadPart < RangeEnd.QuadPart) 4536 { 4537 ULONG_PTR Entry = MmGetPageEntrySectionSegment(Segment, &SegmentOffset); 4538 if ((Entry == 0) || IS_SWAP_FROM_SSE(Entry)) 4539 { 4540 Ret = FALSE; 4541 break; 4542 } 4543 SegmentOffset.QuadPart += PAGE_SIZE; 4544 } 4545 4546 MmUnlockSectionSegment(Segment); 4547 4548 MmUnlockAddressSpace(AddressSpace); 4549 return Ret; 4550 } 4551 4552 NTSTATUS 4553 NTAPI 4554 MmRosFlushVirtualMemory( 4555 _In_ PEPROCESS Process, 4556 _Inout_ PVOID* Address, 4557 _Inout_ PSIZE_T Length, 4558 _Out_ PIO_STATUS_BLOCK Iosb) 4559 { 4560 PMEMORY_AREA MemoryArea; 4561 PMM_SECTION_SEGMENT Segment; 4562 LARGE_INTEGER SegmentOffset, RangeEnd; 4563 PMMSUPPORT AddressSpace = Process ? &Process->Vm : MmGetKernelAddressSpace(); 4564 PVOID CurrentAddress; 4565 4566 PAGED_CODE(); 4567 4568 MmLockAddressSpace(AddressSpace); 4569 4570 DPRINT("Flushing Process %p at %p --> 0x%x", Process, *Address, *Length); 4571 4572 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *Address); 4573 if ((MemoryArea == NULL) || (MemoryArea->Type != MEMORY_AREA_SECTION_VIEW) || 4574 (MemoryArea->VadNode.u.VadFlags.VadType == VadImageMap)) 4575 { 4576 DPRINT1("Unable to find memory area at address %p.\n", Address); 4577 MmUnlockAddressSpace(AddressSpace); 4578 return STATUS_NOT_MAPPED_VIEW; 4579 } 4580 4581 Segment = MemoryArea->SectionData.Segment; 4582 4583 SegmentOffset.QuadPart = PAGE_ROUND_DOWN(*Address) - MA_GetStartingAddress(MemoryArea) 4584 + MemoryArea->SectionData.ViewOffset; 4585 RangeEnd.QuadPart = PAGE_ROUND_UP((ULONG_PTR)*Address + *Length) - MA_GetStartingAddress(MemoryArea) 4586 + MemoryArea->SectionData.ViewOffset; 4587 4588 CurrentAddress = *Address; 4589 4590 MmUnlockAddressSpace(AddressSpace); 4591 4592 MmLockSectionSegment(Segment); 4593 4594 Iosb->Information = 0; 4595 while (SegmentOffset.QuadPart < RangeEnd.QuadPart) 4596 { 4597 ULONG_PTR Entry = MmGetPageEntrySectionSegment(Segment, &SegmentOffset); 4598 4599 /* Let any pending read proceed */ 4600 while (MM_IS_WAIT_PTE(Entry)) 4601 { 4602 MmUnlockSectionSegment(Segment); 4603 MiWaitForPageEvent(NULL, NULL); 4604 MmLockSectionSegment(Segment); 4605 Entry = MmGetPageEntrySectionSegment(Segment, &SegmentOffset); 4606 } 4607 4608 /* We are called from Cc, this can't be backed by the page files */ 4609 ASSERT(!IS_SWAP_FROM_SSE(Entry)); 4610 4611 /* At this point, there may be a valid page there */ 4612 if (Entry != 0) 4613 { 4614 /* This will write the page to disk, if needed */ 4615 MmCheckDirtySegment(Segment, &SegmentOffset, Process ? MmIsDirtyPage(Process, CurrentAddress) : FALSE, FALSE); 4616 Iosb->Information += PAGE_SIZE; 4617 } 4618 SegmentOffset.QuadPart += PAGE_SIZE; 4619 CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + PAGE_SIZE); 4620 } 4621 4622 MmUnlockSectionSegment(Segment); 4623 4624 return STATUS_SUCCESS; 4625 } 4626 4627 /* Like CcPurgeCache but for the in-memory segment */ 4628 BOOLEAN 4629 NTAPI 4630 MmPurgeSegment( 4631 _In_ PSECTION_OBJECT_POINTERS SectionObjectPointer, 4632 _In_opt_ PLARGE_INTEGER Offset, 4633 _In_ ULONG Length) 4634 { 4635 LARGE_INTEGER PurgeStart, PurgeEnd; 4636 PMM_SECTION_SEGMENT Segment; 4637 4638 Segment = MiGrabDataSection(SectionObjectPointer); 4639 if (!Segment) 4640 { 4641 /* Nothing to purge */ 4642 return STATUS_SUCCESS; 4643 } 4644 4645 PurgeStart.QuadPart = Offset ? Offset->QuadPart : 0LL; 4646 if (Length && Offset) 4647 { 4648 if (!NT_SUCCESS(RtlLongLongAdd(PurgeStart.QuadPart, Length, &PurgeEnd.QuadPart))) 4649 return FALSE; 4650 } 4651 4652 MmLockSectionSegment(Segment); 4653 4654 if (!Length || !Offset) 4655 { 4656 /* We must calculate the length for ourselves */ 4657 /* FIXME: All of this is suboptimal */ 4658 ULONG ElemCount = RtlNumberGenericTableElements(&Segment->PageTable); 4659 /* No page. Nothing to purge */ 4660 if (!ElemCount) 4661 { 4662 MmUnlockSectionSegment(Segment); 4663 MmDereferenceSegment(Segment); 4664 return TRUE; 4665 } 4666 4667 PCACHE_SECTION_PAGE_TABLE PageTable = RtlGetElementGenericTable(&Segment->PageTable, ElemCount - 1); 4668 PurgeEnd.QuadPart = PageTable->FileOffset.QuadPart + _countof(PageTable->PageEntries) * PAGE_SIZE; 4669 } 4670 4671 while (PurgeStart.QuadPart < PurgeEnd.QuadPart) 4672 { 4673 ULONG_PTR Entry = MmGetPageEntrySectionSegment(Segment, &PurgeStart); 4674 4675 if (Entry == 0) 4676 { 4677 PurgeStart.QuadPart += PAGE_SIZE; 4678 continue; 4679 } 4680 4681 if (IS_SWAP_FROM_SSE(Entry)) 4682 { 4683 ASSERT(SWAPENTRY_FROM_SSE(Entry) == MM_WAIT_ENTRY); 4684 /* The page is currently being read. Meaning someone will need it soon. Bad luck */ 4685 MmUnlockSectionSegment(Segment); 4686 MmDereferenceSegment(Segment); 4687 return FALSE; 4688 } 4689 4690 if (IS_WRITE_SSE(Entry)) 4691 { 4692 /* We're trying to purge an entry which is being written. Restart this loop iteration */ 4693 MmUnlockSectionSegment(Segment); 4694 KeDelayExecutionThread(KernelMode, FALSE, &TinyTime); 4695 MmLockSectionSegment(Segment); 4696 continue; 4697 } 4698 4699 if (SHARE_COUNT_FROM_SSE(Entry) > 0) 4700 { 4701 /* This page is currently in use. Bad luck */ 4702 MmUnlockSectionSegment(Segment); 4703 MmDereferenceSegment(Segment); 4704 return FALSE; 4705 } 4706 4707 /* We can let this page go */ 4708 MmSetPageEntrySectionSegment(Segment, &PurgeStart, 0); 4709 MmReleasePageMemoryConsumer(MC_USER, PFN_FROM_SSE(Entry)); 4710 4711 PurgeStart.QuadPart += PAGE_SIZE; 4712 } 4713 4714 /* This page is currently in use. Bad luck */ 4715 MmUnlockSectionSegment(Segment); 4716 MmDereferenceSegment(Segment); 4717 return TRUE; 4718 } 4719 4720 NTSTATUS 4721 NTAPI 4722 MmMakeDataSectionResident( 4723 _In_ PSECTION_OBJECT_POINTERS SectionObjectPointer, 4724 _In_ LONGLONG Offset, 4725 _In_ ULONG Length, 4726 _In_ PLARGE_INTEGER ValidDataLength) 4727 { 4728 PMM_SECTION_SEGMENT Segment = MiGrabDataSection(SectionObjectPointer); 4729 4730 /* There must be a segment for this call */ 4731 ASSERT(Segment); 4732 4733 NTSTATUS Status = MmMakeSegmentResident(Segment, Offset, Length, ValidDataLength); 4734 4735 MmDereferenceSegment(Segment); 4736 4737 return Status; 4738 } 4739 4740 NTSTATUS 4741 NTAPI 4742 MmFlushSegment( 4743 _In_ PSECTION_OBJECT_POINTERS SectionObjectPointer, 4744 _In_opt_ PLARGE_INTEGER Offset, 4745 _In_ ULONG Length, 4746 _In_opt_ PIO_STATUS_BLOCK Iosb) 4747 { 4748 LARGE_INTEGER FlushStart, FlushEnd; 4749 NTSTATUS Status; 4750 4751 if (Offset) 4752 { 4753 FlushStart = *Offset; 4754 Status = RtlLongLongAdd(FlushStart.QuadPart, Length, &FlushEnd.QuadPart); 4755 if (!NT_SUCCESS(Status)) 4756 return Status; 4757 } 4758 4759 if (Iosb) 4760 Iosb->Information = 0; 4761 4762 PMM_SECTION_SEGMENT Segment = MiGrabDataSection(SectionObjectPointer); 4763 if (!Segment) 4764 { 4765 /* Nothing to flush */ 4766 if (Iosb) 4767 Iosb->Status = STATUS_SUCCESS; 4768 return STATUS_SUCCESS; 4769 } 4770 4771 ASSERT(*Segment->Flags & MM_DATAFILE_SEGMENT); 4772 4773 MmLockSectionSegment(Segment); 4774 4775 if (!Offset) 4776 { 4777 FlushStart.QuadPart = 0; 4778 4779 /* FIXME: All of this is suboptimal */ 4780 ULONG ElemCount = RtlNumberGenericTableElements(&Segment->PageTable); 4781 /* No page. Nothing to flush */ 4782 if (!ElemCount) 4783 { 4784 MmUnlockSectionSegment(Segment); 4785 MmDereferenceSegment(Segment); 4786 if (Iosb) 4787 { 4788 Iosb->Status = STATUS_SUCCESS; 4789 Iosb->Information = 0; 4790 } 4791 return STATUS_SUCCESS; 4792 } 4793 4794 PCACHE_SECTION_PAGE_TABLE PageTable = RtlGetElementGenericTable(&Segment->PageTable, ElemCount - 1); 4795 FlushEnd.QuadPart = PageTable->FileOffset.QuadPart + _countof(PageTable->PageEntries) * PAGE_SIZE; 4796 } 4797 4798 FlushStart.QuadPart >>= PAGE_SHIFT; 4799 FlushStart.QuadPart <<= PAGE_SHIFT; 4800 4801 while (FlushStart.QuadPart < FlushEnd.QuadPart) 4802 { 4803 ULONG_PTR Entry = MmGetPageEntrySectionSegment(Segment, &FlushStart); 4804 4805 if (IS_DIRTY_SSE(Entry)) 4806 { 4807 MmCheckDirtySegment(Segment, &FlushStart, FALSE, FALSE); 4808 4809 if (Iosb) 4810 Iosb->Information += PAGE_SIZE; 4811 } 4812 4813 FlushStart.QuadPart += PAGE_SIZE; 4814 } 4815 4816 MmUnlockSectionSegment(Segment); 4817 4818 MmDereferenceSegment(Segment); 4819 4820 if (Iosb) 4821 Iosb->Status = STATUS_SUCCESS; 4822 4823 return STATUS_SUCCESS; 4824 } 4825 4826 _Requires_exclusive_lock_held_(Segment->Lock) 4827 BOOLEAN 4828 NTAPI 4829 MmCheckDirtySegment( 4830 PMM_SECTION_SEGMENT Segment, 4831 PLARGE_INTEGER Offset, 4832 BOOLEAN ForceDirty, 4833 BOOLEAN PageOut) 4834 { 4835 ULONG_PTR Entry; 4836 NTSTATUS Status; 4837 PFN_NUMBER Page; 4838 4839 ASSERT(Segment->Locked); 4840 4841 ASSERT((Offset->QuadPart % PAGE_SIZE) == 0); 4842 4843 DPRINT("Checking segment for file %wZ at offset 0x%I64X.\n", &Segment->FileObject->FileName, Offset->QuadPart); 4844 4845 Entry = MmGetPageEntrySectionSegment(Segment, Offset); 4846 if (Entry == 0) 4847 return FALSE; 4848 4849 Page = PFN_FROM_SSE(Entry); 4850 if ((IS_DIRTY_SSE(Entry)) || ForceDirty) 4851 { 4852 BOOLEAN DirtyAgain; 4853 4854 /* 4855 * We got a dirty entry. This path is for the shared data, 4856 * be-it regular file maps or shared sections of DLLs 4857 */ 4858 ASSERT(!Segment->WriteCopy); 4859 ASSERT(FlagOn(*Segment->Flags, MM_DATAFILE_SEGMENT) || FlagOn(Segment->Image.Characteristics, IMAGE_SCN_MEM_SHARED)); 4860 4861 /* Insert the cleaned entry back. Mark it as write in progress, and clear the dirty bit. */ 4862 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1); 4863 Entry = WRITE_SSE(Entry); 4864 MmSetPageEntrySectionSegment(Segment, Offset, Entry); 4865 4866 /* Tell the other users that we are clean again */ 4867 MmSetCleanAllRmaps(Page); 4868 4869 MmUnlockSectionSegment(Segment); 4870 4871 if (FlagOn(*Segment->Flags, MM_DATAFILE_SEGMENT)) 4872 { 4873 /* We have to write it back to the file. Tell the FS driver who we are */ 4874 if (PageOut) 4875 IoSetTopLevelIrp((PIRP)FSRTL_MOD_WRITE_TOP_LEVEL_IRP); 4876 4877 /* Go ahead and write the page */ 4878 DPRINT("Writing page at offset %I64d for file %wZ, Pageout: %s\n", 4879 Offset->QuadPart, &Segment->FileObject->FileName, PageOut ? "TRUE" : "FALSE"); 4880 Status = MiWritePage(Segment, Offset->QuadPart, Page); 4881 4882 if (PageOut) 4883 IoSetTopLevelIrp(NULL); 4884 } 4885 else 4886 { 4887 /* This must only be called by the page-out path */ 4888 ASSERT(PageOut); 4889 4890 /* And this must be for a shared section in a DLL */ 4891 ASSERT(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED); 4892 4893 SWAPENTRY SwapEntry = MmGetSavedSwapEntryPage(Page); 4894 if (!SwapEntry) 4895 { 4896 SwapEntry = MmAllocSwapPage(); 4897 } 4898 4899 if (SwapEntry) 4900 { 4901 Status = MmWriteToSwapPage(SwapEntry, Page); 4902 if (NT_SUCCESS(Status)) 4903 { 4904 MmSetSavedSwapEntryPage(Page, SwapEntry); 4905 } 4906 else 4907 { 4908 MmFreeSwapPage(SwapEntry); 4909 } 4910 } 4911 else 4912 { 4913 DPRINT1("Failed to allocate a swap page!\n"); 4914 Status = STATUS_INSUFFICIENT_RESOURCES; 4915 } 4916 } 4917 4918 MmLockSectionSegment(Segment); 4919 4920 /* Get the entry again */ 4921 Entry = MmGetPageEntrySectionSegment(Segment, Offset); 4922 ASSERT(PFN_FROM_SSE(Entry) == Page); 4923 4924 if (!NT_SUCCESS(Status)) 4925 { 4926 /* Damn, this failed. Consider this page as still dirty */ 4927 DPRINT1("MiWritePage FAILED: Status 0x%08x!\n", Status); 4928 DirtyAgain = TRUE; 4929 } 4930 else 4931 { 4932 /* Check if someone dirtified this page while we were not looking */ 4933 DirtyAgain = IS_DIRTY_SSE(Entry) || MmIsDirtyPageRmap(Page); 4934 } 4935 4936 /* Drop the reference we got, deleting the write altogether. */ 4937 Entry = MAKE_SSE(Page << PAGE_SHIFT, SHARE_COUNT_FROM_SSE(Entry) - 1); 4938 if (DirtyAgain) 4939 { 4940 Entry = DIRTY_SSE(Entry); 4941 } 4942 MmSetPageEntrySectionSegment(Segment, Offset, Entry); 4943 } 4944 4945 /* Were this page hanging there just for the sake of being present ? */ 4946 if (!IS_DIRTY_SSE(Entry) && (SHARE_COUNT_FROM_SSE(Entry) == 0) && PageOut) 4947 { 4948 ULONG_PTR NewEntry = 0; 4949 /* Restore the swap entry here */ 4950 if (!FlagOn(*Segment->Flags, MM_DATAFILE_SEGMENT)) 4951 { 4952 SWAPENTRY SwapEntry = MmGetSavedSwapEntryPage(Page); 4953 if (SwapEntry) 4954 NewEntry = MAKE_SWAP_SSE(SwapEntry); 4955 } 4956 4957 /* Yes. Release it */ 4958 MmSetPageEntrySectionSegment(Segment, Offset, NewEntry); 4959 MmReleasePageMemoryConsumer(MC_USER, Page); 4960 /* Tell the caller we released the page */ 4961 return TRUE; 4962 } 4963 4964 return FALSE; 4965 } 4966 4967 NTSTATUS 4968 NTAPI 4969 MmMakePagesDirty( 4970 _In_ PEPROCESS Process, 4971 _In_ PVOID Address, 4972 _In_ ULONG Length) 4973 { 4974 PMEMORY_AREA MemoryArea; 4975 PMM_SECTION_SEGMENT Segment; 4976 LARGE_INTEGER SegmentOffset, RangeEnd; 4977 PMMSUPPORT AddressSpace = Process ? &Process->Vm : MmGetKernelAddressSpace(); 4978 4979 MmLockAddressSpace(AddressSpace); 4980 4981 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address); 4982 if (MemoryArea == NULL) 4983 { 4984 DPRINT1("Unable to find memory area at address %p.\n", Address); 4985 MmUnlockAddressSpace(AddressSpace); 4986 return STATUS_NOT_MAPPED_VIEW; 4987 } 4988 4989 /* Only supported in old Mm for now */ 4990 ASSERT(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW); 4991 /* For file mappings */ 4992 ASSERT(MemoryArea->VadNode.u.VadFlags.VadType != VadImageMap); 4993 4994 Segment = MemoryArea->SectionData.Segment; 4995 MmLockSectionSegment(Segment); 4996 4997 SegmentOffset.QuadPart = PAGE_ROUND_DOWN(Address) - MA_GetStartingAddress(MemoryArea) 4998 + MemoryArea->SectionData.ViewOffset; 4999 RangeEnd.QuadPart = PAGE_ROUND_UP((ULONG_PTR)Address + Length) - MA_GetStartingAddress(MemoryArea) 5000 + MemoryArea->SectionData.ViewOffset; 5001 5002 DPRINT("MmMakePagesResident: Segment %p, 0x%I64x -> 0x%I64x\n", Segment, SegmentOffset.QuadPart, RangeEnd.QuadPart); 5003 5004 while (SegmentOffset.QuadPart < RangeEnd.QuadPart) 5005 { 5006 ULONG_PTR Entry = MmGetPageEntrySectionSegment(Segment, &SegmentOffset); 5007 5008 /* Let any pending read proceed */ 5009 while (MM_IS_WAIT_PTE(Entry)) 5010 { 5011 MmUnlockSectionSegment(Segment); 5012 MmUnlockAddressSpace(AddressSpace); 5013 MiWaitForPageEvent(NULL, NULL); 5014 MmLockAddressSpace(AddressSpace); 5015 MmLockSectionSegment(Segment); 5016 Entry = MmGetPageEntrySectionSegment(Segment, &SegmentOffset); 5017 } 5018 5019 /* We are called from Cc, this can't be backed by the page files */ 5020 ASSERT(!IS_SWAP_FROM_SSE(Entry)); 5021 5022 /* If there is no page there, there is nothing to make dirty */ 5023 if (Entry != 0) 5024 { 5025 /* Dirtify the entry */ 5026 MmSetPageEntrySectionSegment(Segment, &SegmentOffset, DIRTY_SSE(Entry)); 5027 } 5028 5029 SegmentOffset.QuadPart += PAGE_SIZE; 5030 } 5031 5032 MmUnlockSectionSegment(Segment); 5033 5034 MmUnlockAddressSpace(AddressSpace); 5035 return STATUS_SUCCESS; 5036 } 5037 5038 NTSTATUS 5039 NTAPI 5040 MmExtendSection( 5041 _In_ PVOID _Section, 5042 _Inout_ PLARGE_INTEGER NewSize) 5043 { 5044 PSECTION Section = _Section; 5045 5046 /* It makes no sense to extend an image mapping */ 5047 if (Section->u.Flags.Image) 5048 return STATUS_SECTION_NOT_EXTENDED; 5049 5050 /* Nor is it possible to extend a page file mapping */ 5051 if (!Section->u.Flags.File) 5052 return STATUS_SECTION_NOT_EXTENDED; 5053 5054 if (!MiIsRosSectionObject(Section)) 5055 return STATUS_NOT_IMPLEMENTED; 5056 5057 /* We just extend the sizes. Shrinking is a no-op ? */ 5058 if (NewSize->QuadPart > Section->SizeOfSection.QuadPart) 5059 { 5060 PMM_SECTION_SEGMENT Segment = (PMM_SECTION_SEGMENT)Section->Segment; 5061 Section->SizeOfSection = *NewSize; 5062 5063 if (!Section->u.Flags.Reserve) 5064 { 5065 MmLockSectionSegment(Segment); 5066 if (Segment->RawLength.QuadPart < NewSize->QuadPart) 5067 { 5068 Segment->RawLength = *NewSize; 5069 Segment->Length.QuadPart = (NewSize->QuadPart + PAGE_SIZE - 1) & ~((LONGLONG)PAGE_SIZE); 5070 } 5071 MmUnlockSectionSegment(Segment); 5072 } 5073 } 5074 5075 return STATUS_SUCCESS; 5076 } 5077 5078 /* EOF */ 5079