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