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