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