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