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