Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygensection.c
Go to the documentation of this file.
00001 /* 00002 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section) 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * 00019 * PROJECT: ReactOS kernel 00020 * FILE: ntoskrnl/mm/section.c 00021 * PURPOSE: Implements section objects 00022 * 00023 * PROGRAMMERS: Rex Jolliff 00024 * David Welch 00025 * Eric Kohl 00026 * Emanuele Aliberti 00027 * Eugene Ingerman 00028 * Casper Hornstrup 00029 * KJK::Hyperion 00030 * Guido de Jong 00031 * Ge van Geldorp 00032 * Royce Mitchell III 00033 * Filip Navara 00034 * Aleksey Bragin 00035 * Jason Filby 00036 * Thomas Weidenmueller 00037 * Gunnar Andre' Dalsnes 00038 * Mike Nordell 00039 * Alex Ionescu 00040 * Gregor Anich 00041 * Steven Edwards 00042 * Herve Poussineau 00043 */ 00044 00045 /* INCLUDES *****************************************************************/ 00046 00047 #include <ntoskrnl.h> 00048 #include "../cache/newcc.h" 00049 #include "../cache/section/newmm.h" 00050 #define NDEBUG 00051 #include <debug.h> 00052 #include <reactos/exeformat.h> 00053 00054 #if defined (ALLOC_PRAGMA) 00055 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection) 00056 #pragma alloc_text(INIT, MmInitSectionImplementation) 00057 #endif 00058 00059 #include "ARM3/miarm.h" 00060 00061 #undef MmSetPageEntrySectionSegment 00062 #define MmSetPageEntrySectionSegment(S,O,E) do { \ 00063 DPRINT("SetPageEntrySectionSegment(old,%x,%x,%x)\n",(S),(O)->LowPart,E); \ 00064 _MmSetPageEntrySectionSegment((S),(O),(E),__FILE__,__LINE__); \ 00065 } while (0) 00066 00067 extern MMSESSION MmSession; 00068 00069 NTSTATUS 00070 NTAPI 00071 MiMapViewInSystemSpace(IN PVOID Section, 00072 IN PVOID Session, 00073 OUT PVOID *MappedBase, 00074 IN OUT PSIZE_T ViewSize); 00075 00076 NTSTATUS 00077 NTAPI 00078 MmCreateArm3Section(OUT PVOID *SectionObject, 00079 IN ACCESS_MASK DesiredAccess, 00080 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 00081 IN PLARGE_INTEGER InputMaximumSize, 00082 IN ULONG SectionPageProtection, 00083 IN ULONG AllocationAttributes, 00084 IN HANDLE FileHandle OPTIONAL, 00085 IN PFILE_OBJECT FileObject OPTIONAL); 00086 00087 NTSTATUS 00088 NTAPI 00089 MmMapViewOfArm3Section(IN PVOID SectionObject, 00090 IN PEPROCESS Process, 00091 IN OUT PVOID *BaseAddress, 00092 IN ULONG_PTR ZeroBits, 00093 IN SIZE_T CommitSize, 00094 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, 00095 IN OUT PSIZE_T ViewSize, 00096 IN SECTION_INHERIT InheritDisposition, 00097 IN ULONG AllocationType, 00098 IN ULONG Protect); 00099 00100 // 00101 // PeFmtCreateSection depends on the following: 00102 // 00103 C_ASSERT(EXEFMT_LOAD_HEADER_SIZE >= sizeof(IMAGE_DOS_HEADER)); 00104 C_ASSERT(sizeof(IMAGE_NT_HEADERS32) <= sizeof(IMAGE_NT_HEADERS64)); 00105 00106 C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64)); 00107 C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64, FileHeader)); 00108 C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader) == FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader)); 00109 00110 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Magic)); 00111 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SectionAlignment)); 00112 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, FileAlignment)); 00113 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Subsystem)); 00114 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MinorSubsystemVersion)); 00115 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MajorSubsystemVersion)); 00116 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint)); 00117 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode)); 00118 C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfHeaders)); 00119 00120 /* TYPES *********************************************************************/ 00121 00122 typedef struct 00123 { 00124 PROS_SECTION_OBJECT Section; 00125 PMM_SECTION_SEGMENT Segment; 00126 LARGE_INTEGER Offset; 00127 BOOLEAN WasDirty; 00128 BOOLEAN Private; 00129 PEPROCESS CallingProcess; 00130 ULONG_PTR SectionEntry; 00131 } 00132 MM_SECTION_PAGEOUT_CONTEXT; 00133 00134 /* GLOBALS *******************************************************************/ 00135 00136 POBJECT_TYPE MmSectionObjectType = NULL; 00137 00138 ULONG_PTR MmSubsectionBase; 00139 00140 static ULONG SectionCharacteristicsToProtect[16] = 00141 { 00142 PAGE_NOACCESS, /* 0 = NONE */ 00143 PAGE_NOACCESS, /* 1 = SHARED */ 00144 PAGE_EXECUTE, /* 2 = EXECUTABLE */ 00145 PAGE_EXECUTE, /* 3 = EXECUTABLE, SHARED */ 00146 PAGE_READONLY, /* 4 = READABLE */ 00147 PAGE_READONLY, /* 5 = READABLE, SHARED */ 00148 PAGE_EXECUTE_READ, /* 6 = READABLE, EXECUTABLE */ 00149 PAGE_EXECUTE_READ, /* 7 = READABLE, EXECUTABLE, SHARED */ 00150 /* 00151 * FIXME? do we really need the WriteCopy field in segments? can't we use 00152 * PAGE_WRITECOPY here? 00153 */ 00154 PAGE_READWRITE, /* 8 = WRITABLE */ 00155 PAGE_READWRITE, /* 9 = WRITABLE, SHARED */ 00156 PAGE_EXECUTE_READWRITE, /* 10 = WRITABLE, EXECUTABLE */ 00157 PAGE_EXECUTE_READWRITE, /* 11 = WRITABLE, EXECUTABLE, SHARED */ 00158 PAGE_READWRITE, /* 12 = WRITABLE, READABLE */ 00159 PAGE_READWRITE, /* 13 = WRITABLE, READABLE, SHARED */ 00160 PAGE_EXECUTE_READWRITE, /* 14 = WRITABLE, READABLE, EXECUTABLE */ 00161 PAGE_EXECUTE_READWRITE, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */ 00162 }; 00163 00164 ACCESS_MASK NTAPI MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection); 00165 static GENERIC_MAPPING MmpSectionMapping = { 00166 STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY, 00167 STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE, 00168 STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE, 00169 SECTION_ALL_ACCESS}; 00170 00171 static const INFORMATION_CLASS_INFO ExSectionInfoClass[] = 00172 { 00173 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */ 00174 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionImageInformation */ 00175 }; 00176 00177 /* FUNCTIONS *****************************************************************/ 00178 00179 00180 /* 00181 References: 00182 [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object 00183 File Format Specification", revision 6.0 (February 1999) 00184 */ 00185 NTSTATUS NTAPI PeFmtCreateSection(IN CONST VOID * FileHeader, 00186 IN SIZE_T FileHeaderSize, 00187 IN PVOID File, 00188 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, 00189 OUT PULONG Flags, 00190 IN PEXEFMT_CB_READ_FILE ReadFileCb, 00191 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb) 00192 { 00193 NTSTATUS nStatus; 00194 ULONG cbFileHeaderOffsetSize = 0; 00195 ULONG cbSectionHeadersOffset = 0; 00196 ULONG cbSectionHeadersSize; 00197 ULONG cbSectionHeadersOffsetSize = 0; 00198 ULONG cbOptHeaderSize; 00199 ULONG cbHeadersSize = 0; 00200 ULONG nSectionAlignment; 00201 ULONG nFileAlignment; 00202 const IMAGE_DOS_HEADER * pidhDosHeader; 00203 const IMAGE_NT_HEADERS32 * pinhNtHeader; 00204 const IMAGE_OPTIONAL_HEADER32 * piohOptHeader; 00205 const IMAGE_SECTION_HEADER * pishSectionHeaders; 00206 PMM_SECTION_SEGMENT pssSegments; 00207 LARGE_INTEGER lnOffset; 00208 PVOID pBuffer; 00209 SIZE_T nPrevVirtualEndOfSegment = 0; 00210 ULONG nFileSizeOfHeaders = 0; 00211 ULONG i; 00212 00213 ASSERT(FileHeader); 00214 ASSERT(FileHeaderSize > 0); 00215 ASSERT(File); 00216 ASSERT(ImageSectionObject); 00217 ASSERT(ReadFileCb); 00218 ASSERT(AllocateSegmentsCb); 00219 00220 ASSERT(Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize)); 00221 00222 ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_DOS_HEADER)) == 0); 00223 00224 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; } 00225 00226 pBuffer = NULL; 00227 pidhDosHeader = FileHeader; 00228 00229 /* DOS HEADER */ 00230 nStatus = STATUS_ROS_EXEFMT_UNKNOWN_FORMAT; 00231 00232 /* image too small to be an MZ executable */ 00233 if(FileHeaderSize < sizeof(IMAGE_DOS_HEADER)) 00234 DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize)); 00235 00236 /* no MZ signature */ 00237 if(pidhDosHeader->e_magic != IMAGE_DOS_SIGNATURE) 00238 DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader->e_magic)); 00239 00240 /* not a Windows executable */ 00241 if(pidhDosHeader->e_lfanew <= 0) 00242 DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew)); 00243 00244 /* NT HEADER */ 00245 nStatus = STATUS_INVALID_IMAGE_FORMAT; 00246 00247 if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize, pidhDosHeader->e_lfanew, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader))) 00248 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew)); 00249 00250 if(FileHeaderSize < cbFileHeaderOffsetSize) 00251 pinhNtHeader = NULL; 00252 else 00253 { 00254 /* 00255 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize), 00256 * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too 00257 */ 00258 ASSERT(Intsafe_CanOffsetPointer(FileHeader, pidhDosHeader->e_lfanew)); 00259 pinhNtHeader = (PVOID)((UINT_PTR)FileHeader + pidhDosHeader->e_lfanew); 00260 } 00261 00262 /* 00263 * the buffer doesn't contain the NT file header, or the alignment is wrong: we 00264 * need to read the header from the file 00265 */ 00266 if(FileHeaderSize < cbFileHeaderOffsetSize || 00267 (UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0) 00268 { 00269 ULONG cbNtHeaderSize; 00270 ULONG cbReadSize; 00271 PVOID pData; 00272 00273 l_ReadHeaderFromFile: 00274 cbNtHeaderSize = 0; 00275 lnOffset.QuadPart = pidhDosHeader->e_lfanew; 00276 00277 /* read the header from the file */ 00278 nStatus = ReadFileCb(File, &lnOffset, sizeof(IMAGE_NT_HEADERS64), &pData, &pBuffer, &cbReadSize); 00279 00280 if(!NT_SUCCESS(nStatus)) 00281 DIE(("ReadFile failed, status %08X\n", nStatus)); 00282 00283 ASSERT(pData); 00284 ASSERT(pBuffer); 00285 ASSERT(cbReadSize > 0); 00286 00287 nStatus = STATUS_INVALID_IMAGE_FORMAT; 00288 00289 /* the buffer doesn't contain the file header */ 00290 if(cbReadSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader)) 00291 DIE(("The file doesn't contain the PE file header\n")); 00292 00293 pinhNtHeader = pData; 00294 00295 /* object still not aligned: copy it to the beginning of the buffer */ 00296 if((UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0) 00297 { 00298 ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == 0); 00299 RtlMoveMemory(pBuffer, pData, cbReadSize); 00300 pinhNtHeader = pBuffer; 00301 } 00302 00303 /* invalid NT header */ 00304 nStatus = STATUS_INVALID_IMAGE_PROTECT; 00305 00306 if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE) 00307 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature)); 00308 00309 nStatus = STATUS_INVALID_IMAGE_FORMAT; 00310 00311 if(!Intsafe_AddULong32(&cbNtHeaderSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader))) 00312 DIE(("The full NT header is too large\n")); 00313 00314 /* the buffer doesn't contain the whole NT header */ 00315 if(cbReadSize < cbNtHeaderSize) 00316 DIE(("The file doesn't contain the full NT header\n")); 00317 } 00318 else 00319 { 00320 ULONG cbOptHeaderOffsetSize = 0; 00321 00322 nStatus = STATUS_INVALID_IMAGE_FORMAT; 00323 00324 /* don't trust an invalid NT header */ 00325 if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE) 00326 DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature)); 00327 00328 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader))) 00329 DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew)); 00330 00331 if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, cbOptHeaderOffsetSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader)) 00332 DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader->FileHeader.SizeOfOptionalHeader)); 00333 00334 /* the buffer doesn't contain the whole NT header: read it from the file */ 00335 if(cbOptHeaderOffsetSize > FileHeaderSize) 00336 goto l_ReadHeaderFromFile; 00337 } 00338 00339 /* read information from the NT header */ 00340 piohOptHeader = &pinhNtHeader->OptionalHeader; 00341 cbOptHeaderSize = pinhNtHeader->FileHeader.SizeOfOptionalHeader; 00342 00343 nStatus = STATUS_INVALID_IMAGE_FORMAT; 00344 00345 if(!RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Magic)) 00346 DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize)); 00347 00348 /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */ 00349 00350 switch(piohOptHeader->Magic) 00351 { 00352 case IMAGE_NT_OPTIONAL_HDR32_MAGIC: 00353 case IMAGE_NT_OPTIONAL_HDR64_MAGIC: 00354 break; 00355 00356 default: 00357 DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader->Magic)); 00358 } 00359 00360 if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SectionAlignment) && 00361 RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, FileAlignment)) 00362 { 00363 /* See [1], section 3.4.2 */ 00364 if(piohOptHeader->SectionAlignment < PAGE_SIZE) 00365 { 00366 if(piohOptHeader->FileAlignment != piohOptHeader->SectionAlignment) 00367 DIE(("Sections aren't page-aligned and the file alignment isn't the same\n")); 00368 } 00369 else if(piohOptHeader->SectionAlignment < piohOptHeader->FileAlignment) 00370 DIE(("The section alignment is smaller than the file alignment\n")); 00371 00372 nSectionAlignment = piohOptHeader->SectionAlignment; 00373 nFileAlignment = piohOptHeader->FileAlignment; 00374 00375 if(!IsPowerOf2(nSectionAlignment) || !IsPowerOf2(nFileAlignment)) 00376 DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment, nFileAlignment)); 00377 } 00378 else 00379 { 00380 nSectionAlignment = PAGE_SIZE; 00381 nFileAlignment = PAGE_SIZE; 00382 } 00383 00384 ASSERT(IsPowerOf2(nSectionAlignment)); 00385 ASSERT(IsPowerOf2(nFileAlignment)); 00386 00387 switch(piohOptHeader->Magic) 00388 { 00389 /* PE32 */ 00390 case IMAGE_NT_OPTIONAL_HDR32_MAGIC: 00391 { 00392 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, ImageBase)) 00393 ImageSectionObject->ImageBase = piohOptHeader->ImageBase; 00394 00395 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfImage)) 00396 ImageSectionObject->ImageSize = piohOptHeader->SizeOfImage; 00397 00398 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackReserve)) 00399 ImageSectionObject->StackReserve = piohOptHeader->SizeOfStackReserve; 00400 00401 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackCommit)) 00402 ImageSectionObject->StackCommit = piohOptHeader->SizeOfStackCommit; 00403 00404 break; 00405 } 00406 00407 /* PE64 */ 00408 case IMAGE_NT_OPTIONAL_HDR64_MAGIC: 00409 { 00410 const IMAGE_OPTIONAL_HEADER64 * pioh64OptHeader; 00411 00412 pioh64OptHeader = (const IMAGE_OPTIONAL_HEADER64 *)piohOptHeader; 00413 00414 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, ImageBase)) 00415 { 00416 if(pioh64OptHeader->ImageBase > MAXULONG_PTR) 00417 DIE(("ImageBase exceeds the address space\n")); 00418 00419 ImageSectionObject->ImageBase = (ULONG_PTR)pioh64OptHeader->ImageBase; 00420 } 00421 00422 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfImage)) 00423 { 00424 if(pioh64OptHeader->SizeOfImage > MAXULONG_PTR) 00425 DIE(("SizeOfImage exceeds the address space\n")); 00426 00427 ImageSectionObject->ImageSize = pioh64OptHeader->SizeOfImage; 00428 } 00429 00430 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackReserve)) 00431 { 00432 if(pioh64OptHeader->SizeOfStackReserve > MAXULONG_PTR) 00433 DIE(("SizeOfStackReserve exceeds the address space\n")); 00434 00435 ImageSectionObject->StackReserve = (ULONG_PTR)pioh64OptHeader->SizeOfStackReserve; 00436 } 00437 00438 if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackCommit)) 00439 { 00440 if(pioh64OptHeader->SizeOfStackCommit > MAXULONG_PTR) 00441 DIE(("SizeOfStackCommit exceeds the address space\n")); 00442 00443 ImageSectionObject->StackCommit = (ULONG_PTR)pioh64OptHeader->SizeOfStackCommit; 00444 } 00445 00446 break; 00447 } 00448 } 00449 00450 /* [1], section 3.4.2 */ 00451 if((ULONG_PTR)ImageSectionObject->ImageBase % 0x10000) 00452 DIE(("ImageBase is not aligned on a 64KB boundary")); 00453 00454 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Subsystem)) 00455 { 00456 ImageSectionObject->Subsystem = piohOptHeader->Subsystem; 00457 00458 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MinorSubsystemVersion) && 00459 RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MajorSubsystemVersion)) 00460 { 00461 ImageSectionObject->MinorSubsystemVersion = piohOptHeader->MinorSubsystemVersion; 00462 ImageSectionObject->MajorSubsystemVersion = piohOptHeader->MajorSubsystemVersion; 00463 } 00464 } 00465 00466 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint)) 00467 { 00468 ImageSectionObject->EntryPoint = ImageSectionObject->ImageBase + 00469 piohOptHeader->AddressOfEntryPoint; 00470 } 00471 00472 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfCode)) 00473 ImageSectionObject->Executable = piohOptHeader->SizeOfCode != 0; 00474 else 00475 ImageSectionObject->Executable = TRUE; 00476 00477 ImageSectionObject->ImageCharacteristics = pinhNtHeader->FileHeader.Characteristics; 00478 ImageSectionObject->Machine = pinhNtHeader->FileHeader.Machine; 00479 00480 /* SECTION HEADERS */ 00481 nStatus = STATUS_INVALID_IMAGE_FORMAT; 00482 00483 /* see [1], section 3.3 */ 00484 if(pinhNtHeader->FileHeader.NumberOfSections > 96) 00485 DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader->FileHeader.NumberOfSections)); 00486 00487 /* 00488 * the additional segment is for the file's headers. They need to be present for 00489 * the benefit of the dynamic loader (to locate exports, defaults for thread 00490 * parameters, resources, etc.) 00491 */ 00492 ImageSectionObject->NrSegments = pinhNtHeader->FileHeader.NumberOfSections + 1; 00493 00494 /* file offset for the section headers */ 00495 if(!Intsafe_AddULong32(&cbSectionHeadersOffset, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader))) 00496 DIE(("Offset overflow\n")); 00497 00498 if(!Intsafe_AddULong32(&cbSectionHeadersOffset, cbSectionHeadersOffset, pinhNtHeader->FileHeader.SizeOfOptionalHeader)) 00499 DIE(("Offset overflow\n")); 00500 00501 /* size of the section headers */ 00502 ASSERT(Intsafe_CanMulULong32(pinhNtHeader->FileHeader.NumberOfSections, sizeof(IMAGE_SECTION_HEADER))); 00503 cbSectionHeadersSize = pinhNtHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER); 00504 00505 if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize, cbSectionHeadersOffset, cbSectionHeadersSize)) 00506 DIE(("Section headers too large\n")); 00507 00508 /* size of the executable's headers */ 00509 if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfHeaders)) 00510 { 00511 // if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment)) 00512 // DIE(("SizeOfHeaders is not aligned\n")); 00513 00514 if(cbSectionHeadersSize > piohOptHeader->SizeOfHeaders) 00515 DIE(("The section headers overflow SizeOfHeaders\n")); 00516 00517 cbHeadersSize = piohOptHeader->SizeOfHeaders; 00518 } 00519 else if(!AlignUp(&cbHeadersSize, cbSectionHeadersOffsetSize, nFileAlignment)) 00520 DIE(("Overflow aligning the size of headers\n")); 00521 00522 if(pBuffer) 00523 { 00524 ExFreePool(pBuffer); 00525 pBuffer = NULL; 00526 } 00527 /* WARNING: pinhNtHeader IS NO LONGER USABLE */ 00528 /* WARNING: piohOptHeader IS NO LONGER USABLE */ 00529 /* WARNING: pioh64OptHeader IS NO LONGER USABLE */ 00530 00531 if(FileHeaderSize < cbSectionHeadersOffsetSize) 00532 pishSectionHeaders = NULL; 00533 else 00534 { 00535 /* 00536 * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize), 00537 * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too 00538 */ 00539 ASSERT(Intsafe_CanOffsetPointer(FileHeader, cbSectionHeadersOffset)); 00540 pishSectionHeaders = (PVOID)((UINT_PTR)FileHeader + cbSectionHeadersOffset); 00541 } 00542 00543 /* 00544 * the buffer doesn't contain the section headers, or the alignment is wrong: 00545 * read the headers from the file 00546 */ 00547 if(FileHeaderSize < cbSectionHeadersOffsetSize || 00548 (UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0) 00549 { 00550 PVOID pData; 00551 ULONG cbReadSize; 00552 00553 lnOffset.QuadPart = cbSectionHeadersOffset; 00554 00555 /* read the header from the file */ 00556 nStatus = ReadFileCb(File, &lnOffset, cbSectionHeadersSize, &pData, &pBuffer, &cbReadSize); 00557 00558 if(!NT_SUCCESS(nStatus)) 00559 DIE(("ReadFile failed with status %08X\n", nStatus)); 00560 00561 ASSERT(pData); 00562 ASSERT(pBuffer); 00563 ASSERT(cbReadSize > 0); 00564 00565 nStatus = STATUS_INVALID_IMAGE_FORMAT; 00566 00567 /* the buffer doesn't contain all the section headers */ 00568 if(cbReadSize < cbSectionHeadersSize) 00569 DIE(("The file doesn't contain all of the section headers\n")); 00570 00571 pishSectionHeaders = pData; 00572 00573 /* object still not aligned: copy it to the beginning of the buffer */ 00574 if((UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0) 00575 { 00576 ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) == 0); 00577 RtlMoveMemory(pBuffer, pData, cbReadSize); 00578 pishSectionHeaders = pBuffer; 00579 } 00580 } 00581 00582 /* SEGMENTS */ 00583 /* allocate the segments */ 00584 nStatus = STATUS_INSUFFICIENT_RESOURCES; 00585 ImageSectionObject->Segments = AllocateSegmentsCb(ImageSectionObject->NrSegments); 00586 00587 if(ImageSectionObject->Segments == NULL) 00588 DIE(("AllocateSegments failed\n")); 00589 00590 /* initialize the headers segment */ 00591 pssSegments = ImageSectionObject->Segments; 00592 00593 // ASSERT(IsAligned(cbHeadersSize, nFileAlignment)); 00594 00595 if(!AlignUp(&nFileSizeOfHeaders, cbHeadersSize, nFileAlignment)) 00596 DIE(("Cannot align the size of the section headers\n")); 00597 00598 nPrevVirtualEndOfSegment = ALIGN_UP_BY(cbHeadersSize, nSectionAlignment); 00599 if (nPrevVirtualEndOfSegment < cbHeadersSize) 00600 DIE(("Cannot align the size of the section headers\n")); 00601 00602 pssSegments[0].Image.FileOffset = 0; 00603 pssSegments[0].Protection = PAGE_READONLY; 00604 pssSegments[0].Length.QuadPart = nPrevVirtualEndOfSegment; 00605 pssSegments[0].RawLength.QuadPart = nFileSizeOfHeaders; 00606 pssSegments[0].Image.VirtualAddress = 0; 00607 pssSegments[0].Image.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA; 00608 pssSegments[0].WriteCopy = TRUE; 00609 00610 /* skip the headers segment */ 00611 ++ pssSegments; 00612 00613 nStatus = STATUS_INVALID_IMAGE_FORMAT; 00614 00615 /* convert the executable sections into segments. See also [1], section 4 */ 00616 for(i = 0; i < ImageSectionObject->NrSegments - 1; ++ i) 00617 { 00618 ULONG nCharacteristics; 00619 00620 /* validate the alignment */ 00621 if(!IsAligned(pishSectionHeaders[i].VirtualAddress, nSectionAlignment)) 00622 DIE(("Image.VirtualAddress[%u] is not aligned\n", i)); 00623 00624 /* sections must be contiguous, ordered by base address and non-overlapping */ 00625 if(pishSectionHeaders[i].VirtualAddress != nPrevVirtualEndOfSegment) 00626 DIE(("Memory gap between section %u and the previous\n", i)); 00627 00628 /* ignore explicit BSS sections */ 00629 if(pishSectionHeaders[i].SizeOfRawData != 0) 00630 { 00631 /* validate the alignment */ 00632 #if 0 00633 /* Yes, this should be a multiple of FileAlignment, but there's 00634 * stuff out there that isn't. We can cope with that 00635 */ 00636 if(!IsAligned(pishSectionHeaders[i].SizeOfRawData, nFileAlignment)) 00637 DIE(("SizeOfRawData[%u] is not aligned\n", i)); 00638 #endif 00639 00640 // if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment)) 00641 // DIE(("PointerToRawData[%u] is not aligned\n", i)); 00642 00643 /* conversion */ 00644 pssSegments[i].Image.FileOffset = pishSectionHeaders[i].PointerToRawData; 00645 pssSegments[i].RawLength.QuadPart = pishSectionHeaders[i].SizeOfRawData; 00646 } 00647 else 00648 { 00649 ASSERT(pssSegments[i].Image.FileOffset == 0); 00650 ASSERT(pssSegments[i].RawLength.QuadPart == 0); 00651 } 00652 00653 ASSERT(Intsafe_CanAddLong64(pssSegments[i].Image.FileOffset, pssSegments[i].RawLength.QuadPart)); 00654 00655 nCharacteristics = pishSectionHeaders[i].Characteristics; 00656 00657 /* no explicit protection */ 00658 if((nCharacteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == 0) 00659 { 00660 if(nCharacteristics & IMAGE_SCN_CNT_CODE) 00661 nCharacteristics |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ; 00662 00663 if(nCharacteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) 00664 nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; 00665 00666 if(nCharacteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) 00667 nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; 00668 } 00669 00670 /* see table above */ 00671 pssSegments[i].Protection = SectionCharacteristicsToProtect[nCharacteristics >> 28]; 00672 pssSegments[i].WriteCopy = !(nCharacteristics & IMAGE_SCN_MEM_SHARED); 00673 00674 if(pishSectionHeaders[i].Misc.VirtualSize == 0 || pishSectionHeaders[i].Misc.VirtualSize < pishSectionHeaders[i].SizeOfRawData) 00675 pssSegments[i].Length.QuadPart = pishSectionHeaders[i].SizeOfRawData; 00676 else 00677 pssSegments[i].Length.QuadPart = pishSectionHeaders[i].Misc.VirtualSize; 00678 00679 pssSegments[i].Length.LowPart = ALIGN_UP_BY(pssSegments[i].Length.LowPart, nSectionAlignment); 00680 if (pssSegments[i].Length.QuadPart < pssSegments[i].Length.QuadPart) 00681 DIE(("Cannot align the virtual size of section %u\n", i)); 00682 00683 if(pssSegments[i].Length.QuadPart == 0) 00684 DIE(("Virtual size of section %u is null\n", i)); 00685 00686 pssSegments[i].Image.VirtualAddress = pishSectionHeaders[i].VirtualAddress; 00687 pssSegments[i].Image.Characteristics = pishSectionHeaders[i].Characteristics; 00688 00689 /* ensure the memory image is no larger than 4GB */ 00690 nPrevVirtualEndOfSegment = (ULONG_PTR)(pssSegments[i].Image.VirtualAddress + pssSegments[i].Length.QuadPart); 00691 if (nPrevVirtualEndOfSegment < pssSegments[i].Image.VirtualAddress) 00692 DIE(("The image is too large\n")); 00693 } 00694 00695 if(nSectionAlignment >= PAGE_SIZE) 00696 *Flags |= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED; 00697 00698 /* Success */ 00699 nStatus = STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32; 00700 00701 l_Return: 00702 if(pBuffer) 00703 ExFreePool(pBuffer); 00704 00705 return nStatus; 00706 } 00707 00708 /* 00709 * FUNCTION: Waits in kernel mode indefinitely for a file object lock. 00710 * ARGUMENTS: PFILE_OBJECT to wait for. 00711 * RETURNS: Status of the wait. 00712 */ 00713 NTSTATUS 00714 MmspWaitForFileLock(PFILE_OBJECT File) 00715 { 00716 return STATUS_SUCCESS; 00717 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL); 00718 } 00719 00720 VOID 00721 NTAPI 00722 MmFreeSectionSegments(PFILE_OBJECT FileObject) 00723 { 00724 if (FileObject->SectionObjectPointer->ImageSectionObject != NULL) 00725 { 00726 PMM_IMAGE_SECTION_OBJECT ImageSectionObject; 00727 PMM_SECTION_SEGMENT SectionSegments; 00728 ULONG NrSegments; 00729 ULONG i; 00730 00731 ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject; 00732 NrSegments = ImageSectionObject->NrSegments; 00733 SectionSegments = ImageSectionObject->Segments; 00734 for (i = 0; i < NrSegments; i++) 00735 { 00736 if (SectionSegments[i].ReferenceCount != 0) 00737 { 00738 DPRINT1("Image segment %d still referenced (was %d)\n", i, 00739 SectionSegments[i].ReferenceCount); 00740 KeBugCheck(MEMORY_MANAGEMENT); 00741 } 00742 MmFreePageTablesSectionSegment(&SectionSegments[i], NULL); 00743 } 00744 ExFreePool(ImageSectionObject->Segments); 00745 ExFreePool(ImageSectionObject); 00746 FileObject->SectionObjectPointer->ImageSectionObject = NULL; 00747 } 00748 if (FileObject->SectionObjectPointer->DataSectionObject != NULL) 00749 { 00750 PMM_SECTION_SEGMENT Segment; 00751 00752 Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer-> 00753 DataSectionObject; 00754 00755 if (Segment->ReferenceCount != 0) 00756 { 00757 DPRINT1("Data segment still referenced\n"); 00758 KeBugCheck(MEMORY_MANAGEMENT); 00759 } 00760 MmFreePageTablesSectionSegment(Segment, NULL); 00761 ExFreePool(Segment); 00762 FileObject->SectionObjectPointer->DataSectionObject = NULL; 00763 } 00764 } 00765 00766 VOID 00767 NTAPI 00768 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment, 00769 PLARGE_INTEGER Offset) 00770 { 00771 ULONG_PTR Entry; 00772 00773 Entry = MmGetPageEntrySectionSegment(Segment, Offset); 00774 if (Entry == 0) 00775 { 00776 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n"); 00777 KeBugCheck(MEMORY_MANAGEMENT); 00778 } 00779 if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT) 00780 { 00781 DPRINT1("Maximum share count reached\n"); 00782 KeBugCheck(MEMORY_MANAGEMENT); 00783 } 00784 if (IS_SWAP_FROM_SSE(Entry)) 00785 { 00786 KeBugCheck(MEMORY_MANAGEMENT); 00787 } 00788 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1); 00789 MmSetPageEntrySectionSegment(Segment, Offset, Entry); 00790 } 00791 00792 BOOLEAN 00793 NTAPI 00794 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section, 00795 PMM_SECTION_SEGMENT Segment, 00796 PLARGE_INTEGER Offset, 00797 BOOLEAN Dirty, 00798 BOOLEAN PageOut, 00799 ULONG_PTR *InEntry) 00800 { 00801 ULONG_PTR Entry = InEntry ? *InEntry : MmGetPageEntrySectionSegment(Segment, Offset); 00802 BOOLEAN IsDirectMapped = FALSE; 00803 00804 if (Entry == 0) 00805 { 00806 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n"); 00807 KeBugCheck(MEMORY_MANAGEMENT); 00808 } 00809 if (SHARE_COUNT_FROM_SSE(Entry) == 0) 00810 { 00811 DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment, Offset->LowPart, PFN_FROM_SSE(Entry)); 00812 KeBugCheck(MEMORY_MANAGEMENT); 00813 } 00814 if (IS_SWAP_FROM_SSE(Entry)) 00815 { 00816 KeBugCheck(MEMORY_MANAGEMENT); 00817 } 00818 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1); 00819 /* 00820 * If we reducing the share count of this entry to zero then set the entry 00821 * to zero and tell the cache the page is no longer mapped. 00822 */ 00823 if (SHARE_COUNT_FROM_SSE(Entry) == 0) 00824 { 00825 PFILE_OBJECT FileObject; 00826 #ifndef NEWCC 00827 PBCB Bcb; 00828 #endif 00829 SWAPENTRY SavedSwapEntry; 00830 PFN_NUMBER Page; 00831 BOOLEAN IsImageSection; 00832 LARGE_INTEGER FileOffset; 00833 00834 FileOffset.QuadPart = Offset->QuadPart + Segment->Image.FileOffset; 00835 00836 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE; 00837 00838 Page = PFN_FROM_SSE(Entry); 00839 FileObject = Section->FileObject; 00840 if (FileObject != NULL && 00841 !(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)) 00842 { 00843 00844 #ifndef NEWCC 00845 if ((FileOffset.QuadPart % PAGE_SIZE) == 0 && 00846 (Offset->QuadPart + PAGE_SIZE <= Segment->RawLength.QuadPart || !IsImageSection)) 00847 { 00848 NTSTATUS Status; 00849 Bcb = FileObject->SectionObjectPointer->SharedCacheMap; 00850 IsDirectMapped = TRUE; 00851 #ifndef NEWCC 00852 Status = CcRosUnmapCacheSegment(Bcb, FileOffset.LowPart, Dirty); 00853 #else 00854 Status = STATUS_SUCCESS; 00855 #endif 00856 if (!NT_SUCCESS(Status)) 00857 { 00858 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status); 00859 KeBugCheck(MEMORY_MANAGEMENT); 00860 } 00861 } 00862 #endif 00863 } 00864 00865 SavedSwapEntry = MmGetSavedSwapEntryPage(Page); 00866 if (SavedSwapEntry == 0) 00867 { 00868 if (!PageOut && 00869 ((Segment->Flags & MM_PAGEFILE_SEGMENT) || 00870 (Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))) 00871 { 00872 /* 00873 * FIXME: 00874 * Try to page out this page and set the swap entry 00875 * within the section segment. There exist no rmap entry 00876 * for this page. The pager thread can't page out a 00877 * page without a rmap entry. 00878 */ 00879 MmSetPageEntrySectionSegment(Segment, Offset, Entry); 00880 if (InEntry) *InEntry = Entry; 00881 MiSetPageEvent(NULL, NULL); 00882 } 00883 else 00884 { 00885 MmSetPageEntrySectionSegment(Segment, Offset, 0); 00886 if (InEntry) *InEntry = 0; 00887 MiSetPageEvent(NULL, NULL); 00888 if (!IsDirectMapped) 00889 { 00890 MmReleasePageMemoryConsumer(MC_USER, Page); 00891 } 00892 } 00893 } 00894 else 00895 { 00896 if ((Segment->Flags & MM_PAGEFILE_SEGMENT) || 00897 (Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)) 00898 { 00899 if (!PageOut) 00900 { 00901 if (Dirty) 00902 { 00903 /* 00904 * FIXME: 00905 * We hold all locks. Nobody can do something with the current 00906 * process and the current segment (also not within an other process). 00907 */ 00908 NTSTATUS Status; 00909 Status = MmWriteToSwapPage(SavedSwapEntry, Page); 00910 if (!NT_SUCCESS(Status)) 00911 { 00912 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status); 00913 KeBugCheck(MEMORY_MANAGEMENT); 00914 } 00915 } 00916 MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry)); 00917 if (InEntry) *InEntry = MAKE_SWAP_SSE(SavedSwapEntry); 00918 MmSetSavedSwapEntryPage(Page, 0); 00919 MiSetPageEvent(NULL, NULL); 00920 } 00921 MmReleasePageMemoryConsumer(MC_USER, Page); 00922 } 00923 else 00924 { 00925 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n"); 00926 KeBugCheck(MEMORY_MANAGEMENT); 00927 } 00928 } 00929 } 00930 else 00931 { 00932 if (InEntry) 00933 *InEntry = Entry; 00934 else 00935 MmSetPageEntrySectionSegment(Segment, Offset, Entry); 00936 } 00937 return(SHARE_COUNT_FROM_SSE(Entry) > 0); 00938 } 00939 00940 BOOLEAN MiIsPageFromCache(PMEMORY_AREA MemoryArea, 00941 ULONG SegOffset) 00942 { 00943 #ifndef NEWCC 00944 if (!(MemoryArea->Data.SectionData.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)) 00945 { 00946 PBCB Bcb; 00947 PCACHE_SEGMENT CacheSeg; 00948 Bcb = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap; 00949 CacheSeg = CcRosLookupCacheSegment(Bcb, (ULONG)(SegOffset + MemoryArea->Data.SectionData.Segment->Image.FileOffset)); 00950 if (CacheSeg) 00951 { 00952 CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE); 00953 return TRUE; 00954 } 00955 } 00956 #endif 00957 return FALSE; 00958 } 00959 00960 NTSTATUS 00961 NTAPI 00962 MiCopyFromUserPage(PFN_NUMBER DestPage, PFN_NUMBER SrcPage) 00963 { 00964 PEPROCESS Process; 00965 KIRQL Irql, Irql2; 00966 PVOID DestAddress, SrcAddress; 00967 00968 Process = PsGetCurrentProcess(); 00969 DestAddress = MiMapPageInHyperSpace(Process, DestPage, &Irql); 00970 SrcAddress = MiMapPageInHyperSpace(Process, SrcPage, &Irql2); 00971 if (DestAddress == NULL || SrcAddress == NULL) 00972 { 00973 return(STATUS_NO_MEMORY); 00974 } 00975 ASSERT((ULONG_PTR)DestAddress % PAGE_SIZE == 0); 00976 ASSERT((ULONG_PTR)SrcAddress % PAGE_SIZE == 0); 00977 RtlCopyMemory(DestAddress, SrcAddress, PAGE_SIZE); 00978 MiUnmapPageInHyperSpace(Process, SrcAddress, Irql2); 00979 MiUnmapPageInHyperSpace(Process, DestAddress, Irql); 00980 return(STATUS_SUCCESS); 00981 } 00982 00983 #ifndef NEWCC 00984 NTSTATUS 00985 NTAPI 00986 MiReadPage(PMEMORY_AREA MemoryArea, 00987 ULONG_PTR SegOffset, 00988 PPFN_NUMBER Page) 00989 /* 00990 * FUNCTION: Read a page for a section backed memory area. 00991 * PARAMETERS: 00992 * MemoryArea - Memory area to read the page for. 00993 * Offset - Offset of the page to read. 00994 * Page - Variable that receives a page contains the read data. 00995 */ 00996 { 00997 ULONG BaseOffset; 00998 ULONGLONG FileOffset; 00999 PVOID BaseAddress; 01000 BOOLEAN UptoDate; 01001 PCACHE_SEGMENT CacheSeg; 01002 PFILE_OBJECT FileObject; 01003 NTSTATUS Status; 01004 ULONG_PTR RawLength; 01005 PBCB Bcb; 01006 BOOLEAN IsImageSection; 01007 ULONG_PTR Length; 01008 01009 FileObject = MemoryArea->Data.SectionData.Section->FileObject; 01010 Bcb = FileObject->SectionObjectPointer->SharedCacheMap; 01011 RawLength = (ULONG_PTR)(MemoryArea->Data.SectionData.Segment->RawLength.QuadPart); 01012 FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->Image.FileOffset; 01013 IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE; 01014 01015 ASSERT(Bcb); 01016 01017 DPRINT("%S %x\n", FileObject->FileName.Buffer, FileOffset); 01018 01019 /* 01020 * If the file system is letting us go directly to the cache and the 01021 * memory area was mapped at an offset in the file which is page aligned 01022 * then get the related cache segment. 01023 */ 01024 if (((FileOffset % PAGE_SIZE) == 0) && 01025 ((SegOffset + PAGE_SIZE <= RawLength) || !IsImageSection) && 01026 !(MemoryArea->Data.SectionData.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)) 01027 { 01028 01029 /* 01030 * Get the related cache segment; we use a lower level interface than 01031 * filesystems do because it is safe for us to use an offset with a 01032 * alignment less than the file system block size. 01033 */ 01034 Status = CcRosGetCacheSegment(Bcb, 01035 (ULONG)FileOffset, 01036 &BaseOffset, 01037 &BaseAddress, 01038 &UptoDate, 01039 &CacheSeg); 01040 if (!NT_SUCCESS(Status)) 01041 { 01042 return(Status); 01043 } 01044 if (!UptoDate) 01045 { 01046 /* 01047 * If the cache segment isn't up to date then call the file 01048 * system to read in the data. 01049 */ 01050 Status = ReadCacheSegment(CacheSeg); 01051 if (!NT_SUCCESS(Status)) 01052 { 01053 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE); 01054 return Status; 01055 } 01056 } 01057 /* 01058 * Retrieve the page from the cache segment that we actually want. 01059 */ 01060 (*Page) = MmGetPhysicalAddress((char*)BaseAddress + 01061 FileOffset - BaseOffset).LowPart >> PAGE_SHIFT; 01062 01063 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, TRUE); 01064 } 01065 else 01066 { 01067 PEPROCESS Process; 01068 KIRQL Irql; 01069 PVOID PageAddr; 01070 ULONG_PTR CacheSegOffset; 01071 01072 /* 01073 * Allocate a page, this is rather complicated by the possibility 01074 * we might have to move other things out of memory 01075 */ 01076 MI_SET_USAGE(MI_USAGE_SECTION); 01077 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName); 01078 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page); 01079 if (!NT_SUCCESS(Status)) 01080 { 01081 return(Status); 01082 } 01083 Status = CcRosGetCacheSegment(Bcb, 01084 (ULONG)FileOffset, 01085 &BaseOffset, 01086 &BaseAddress, 01087 &UptoDate, 01088 &CacheSeg); 01089 if (!NT_SUCCESS(Status)) 01090 { 01091 return(Status); 01092 } 01093 if (!UptoDate) 01094 { 01095 /* 01096 * If the cache segment isn't up to date then call the file 01097 * system to read in the data. 01098 */ 01099 Status = ReadCacheSegment(CacheSeg); 01100 if (!NT_SUCCESS(Status)) 01101 { 01102 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE); 01103 return Status; 01104 } 01105 } 01106 01107 Process = PsGetCurrentProcess(); 01108 PageAddr = MiMapPageInHyperSpace(Process, *Page, &Irql); 01109 CacheSegOffset = (ULONG_PTR)(BaseOffset + CacheSeg->Bcb->CacheSegmentSize - FileOffset); 01110 Length = RawLength - SegOffset; 01111 if (Length <= CacheSegOffset && Length <= PAGE_SIZE) 01112 { 01113 memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, Length); 01114 } 01115 else if (CacheSegOffset >= PAGE_SIZE) 01116 { 01117 memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, PAGE_SIZE); 01118 } 01119 else 01120 { 01121 memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, CacheSegOffset); 01122 MiUnmapPageInHyperSpace(Process, PageAddr, Irql); 01123 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE); 01124 Status = CcRosGetCacheSegment(Bcb, 01125 (ULONG)(FileOffset + CacheSegOffset), 01126 &BaseOffset, 01127 &BaseAddress, 01128 &UptoDate, 01129 &CacheSeg); 01130 if (!NT_SUCCESS(Status)) 01131 { 01132 return(Status); 01133 } 01134 if (!UptoDate) 01135 { 01136 /* 01137 * If the cache segment isn't up to date then call the file 01138 * system to read in the data. 01139 */ 01140 Status = ReadCacheSegment(CacheSeg); 01141 if (!NT_SUCCESS(Status)) 01142 { 01143 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE); 01144 return Status; 01145 } 01146 } 01147 PageAddr = MiMapPageInHyperSpace(Process, *Page, &Irql); 01148 if (Length < PAGE_SIZE) 01149 { 01150 memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, Length - CacheSegOffset); 01151 } 01152 else 01153 { 01154 memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, PAGE_SIZE - CacheSegOffset); 01155 } 01156 } 01157 MiUnmapPageInHyperSpace(Process, PageAddr, Irql); 01158 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE); 01159 } 01160 return(STATUS_SUCCESS); 01161 } 01162 #else 01163 NTSTATUS 01164 NTAPI 01165 MiReadPage(PMEMORY_AREA MemoryArea, 01166 ULONG_PTR SegOffset, 01167 PPFN_NUMBER Page) 01168 /* 01169 * FUNCTION: Read a page for a section backed memory area. 01170 * PARAMETERS: 01171 * MemoryArea - Memory area to read the page for. 01172 * Offset - Offset of the page to read. 01173 * Page - Variable that receives a page contains the read data. 01174 */ 01175 { 01176 MM_REQUIRED_RESOURCES Resources; 01177 NTSTATUS Status; 01178 01179 RtlZeroMemory(&Resources, sizeof(MM_REQUIRED_RESOURCES)); 01180 01181 Resources.Context = MemoryArea->Data.SectionData.Section->FileObject; 01182 Resources.FileOffset.QuadPart = SegOffset + 01183 MemoryArea->Data.SectionData.Segment->Image.FileOffset; 01184 Resources.Consumer = MC_USER; 01185 Resources.Amount = PAGE_SIZE; 01186 01187 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]); 01188 01189 Status = MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea, &Resources); 01190 *Page = Resources.Page[0]; 01191 return Status; 01192 } 01193 #endif 01194 01195 NTSTATUS 01196 NTAPI 01197 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace, 01198 MEMORY_AREA* MemoryArea, 01199 PVOID Address, 01200 BOOLEAN Locked) 01201 { 01202 LARGE_INTEGER Offset; 01203 PFN_NUMBER Page; 01204 NTSTATUS Status; 01205 PROS_SECTION_OBJECT Section; 01206 PMM_SECTION_SEGMENT Segment; 01207 ULONG_PTR Entry; 01208 ULONG_PTR Entry1; 01209 ULONG Attributes; 01210 PMM_REGION Region; 01211 BOOLEAN HasSwapEntry; 01212 PVOID PAddress; 01213 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); 01214 SWAPENTRY SwapEntry; 01215 01216 /* 01217 * There is a window between taking the page fault and locking the 01218 * address space when another thread could load the page so we check 01219 * that. 01220 */ 01221 if (MmIsPagePresent(Process, Address)) 01222 { 01223 return(STATUS_SUCCESS); 01224 } 01225 01226 /* 01227 * Check for the virtual memory area being deleted. 01228 */ 01229 if (MemoryArea->DeleteInProgress) 01230 { 01231 return(STATUS_UNSUCCESSFUL); 01232 } 01233 01234 PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE); 01235 Offset.QuadPart = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress 01236 + MemoryArea->Data.SectionData.ViewOffset.QuadPart; 01237 01238 Segment = MemoryArea->Data.SectionData.Segment; 01239 Section = MemoryArea->Data.SectionData.Section; 01240 Region = MmFindRegion(MemoryArea->StartingAddress, 01241 &MemoryArea->Data.SectionData.RegionListHead, 01242 Address, NULL); 01243 ASSERT(Region != NULL); 01244 /* 01245 * Lock the segment 01246 */ 01247 MmLockSectionSegment(Segment); 01248 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 01249 /* 01250 * Check if this page needs to be mapped COW 01251 */ 01252 if ((Segment->WriteCopy) && 01253 (Region->Protect == PAGE_READWRITE || 01254 Region->Protect == PAGE_EXECUTE_READWRITE)) 01255 { 01256 Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ; 01257 } 01258 else 01259 { 01260 Attributes = Region->Protect; 01261 } 01262 01263 /* 01264 * Check if someone else is already handling this fault, if so wait 01265 * for them 01266 */ 01267 if (Entry && IS_SWAP_FROM_SSE(Entry) && SWAPENTRY_FROM_SSE(Entry) == MM_WAIT_ENTRY) 01268 { 01269 MmUnlockSectionSegment(Segment); 01270 MmUnlockAddressSpace(AddressSpace); 01271 MiWaitForPageEvent(NULL, NULL); 01272 MmLockAddressSpace(AddressSpace); 01273 DPRINT("Address 0x%.8X\n", Address); 01274 return(STATUS_MM_RESTART_OPERATION); 01275 } 01276 01277 HasSwapEntry = MmIsPageSwapEntry(Process, Address); 01278 01279 if (HasSwapEntry) 01280 { 01281 /* 01282 * Is it a wait entry? 01283 */ 01284 MmGetPageFileMapping(Process, Address, &SwapEntry); 01285 01286 if (SwapEntry == MM_WAIT_ENTRY) 01287 { 01288 MmUnlockSectionSegment(Segment); 01289 MmUnlockAddressSpace(AddressSpace); 01290 MiWaitForPageEvent(NULL, NULL); 01291 MmLockAddressSpace(AddressSpace); 01292 return STATUS_MM_RESTART_OPERATION; 01293 } 01294 01295 /* 01296 * Must be private page we have swapped out. 01297 */ 01298 01299 /* 01300 * Sanity check 01301 */ 01302 if (Segment->Flags & MM_PAGEFILE_SEGMENT) 01303 { 01304 DPRINT1("Found a swaped out private page in a pagefile section.\n"); 01305 KeBugCheck(MEMORY_MANAGEMENT); 01306 } 01307 01308 MmUnlockSectionSegment(Segment); 01309 MmDeletePageFileMapping(Process, Address, &SwapEntry); 01310 MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY); 01311 01312 MmUnlockAddressSpace(AddressSpace); 01313 MI_SET_USAGE(MI_USAGE_SECTION); 01314 if (Process) MI_SET_PROCESS2(Process->ImageFileName); 01315 if (!Process) MI_SET_PROCESS2("Kernel Section"); 01316 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page); 01317 if (!NT_SUCCESS(Status)) 01318 { 01319 KeBugCheck(MEMORY_MANAGEMENT); 01320 } 01321 01322 Status = MmReadFromSwapPage(SwapEntry, Page); 01323 if (!NT_SUCCESS(Status)) 01324 { 01325 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status); 01326 KeBugCheck(MEMORY_MANAGEMENT); 01327 } 01328 MmLockAddressSpace(AddressSpace); 01329 Status = MmCreateVirtualMapping(Process, 01330 PAddress, 01331 Region->Protect, 01332 &Page, 01333 1); 01334 if (!NT_SUCCESS(Status)) 01335 { 01336 DPRINT("MmCreateVirtualMapping failed, not out of memory\n"); 01337 KeBugCheck(MEMORY_MANAGEMENT); 01338 return(Status); 01339 } 01340 01341 /* 01342 * Store the swap entry for later use. 01343 */ 01344 MmSetSavedSwapEntryPage(Page, SwapEntry); 01345 01346 /* 01347 * Add the page to the process's working set 01348 */ 01349 MmInsertRmap(Page, Process, Address); 01350 /* 01351 * Finish the operation 01352 */ 01353 MiSetPageEvent(Process, Address); 01354 DPRINT("Address 0x%.8X\n", Address); 01355 return(STATUS_SUCCESS); 01356 } 01357 01358 /* 01359 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy 01360 */ 01361 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY) 01362 { 01363 MmUnlockSectionSegment(Segment); 01364 /* 01365 * Just map the desired physical page 01366 */ 01367 Page = (PFN_NUMBER)(Offset.QuadPart >> PAGE_SHIFT); 01368 Status = MmCreateVirtualMappingUnsafe(Process, 01369 PAddress, 01370 Region->Protect, 01371 &Page, 01372 1); 01373 if (!NT_SUCCESS(Status)) 01374 { 01375 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n"); 01376 KeBugCheck(MEMORY_MANAGEMENT); 01377 return(Status); 01378 } 01379 01380 /* 01381 * Cleanup and release locks 01382 */ 01383 MiSetPageEvent(Process, Address); 01384 DPRINT("Address 0x%.8X\n", Address); 01385 return(STATUS_SUCCESS); 01386 } 01387 01388 /* 01389 * Map anonymous memory for BSS sections 01390 */ 01391 if (Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) 01392 { 01393 /* We'll be unlocking the address space below. Prevent us from being preempted 01394 * in faulting in the page. */ 01395 MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY); 01396 MmUnlockSectionSegment(Segment); 01397 MI_SET_USAGE(MI_USAGE_SECTION); 01398 if (Process) MI_SET_PROCESS2(Process->ImageFileName); 01399 if (!Process) MI_SET_PROCESS2("Kernel Section"); 01400 Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page); 01401 if (!NT_SUCCESS(Status)) 01402 { 01403 MmUnlockAddressSpace(AddressSpace); 01404 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page); 01405 MmLockAddressSpace(AddressSpace); 01406 } 01407 if (!NT_SUCCESS(Status)) 01408 { 01409 KeBugCheck(MEMORY_MANAGEMENT); 01410 } 01411 /* Remove the wait entry we placed, so that we can map the page */ 01412 MmDeletePageFileMapping(Process, PAddress, &SwapEntry); 01413 Status = MmCreateVirtualMapping(Process, 01414 PAddress, 01415 Region->Protect, 01416 &Page, 01417 1); 01418 if (!NT_SUCCESS(Status)) 01419 { 01420 DPRINT("MmCreateVirtualMapping failed, not out of memory\n"); 01421 KeBugCheck(MEMORY_MANAGEMENT); 01422 return(Status); 01423 } 01424 MmInsertRmap(Page, Process, Address); 01425 01426 /* 01427 * Cleanup and release locks 01428 */ 01429 MiSetPageEvent(Process, Address); 01430 DPRINT("Address 0x%.8X\n", Address); 01431 return(STATUS_SUCCESS); 01432 } 01433 01434 /* 01435 * Get the entry corresponding to the offset within the section 01436 */ 01437 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 01438 01439 if (Entry == 0) 01440 { 01441 /* 01442 * If the entry is zero (and it can't change because we have 01443 * locked the segment) then we need to load the page. 01444 */ 01445 01446 /* 01447 * Release all our locks and read in the page from disk 01448 */ 01449 MmSetPageEntrySectionSegment(Segment, &Offset, MAKE_SWAP_SSE(MM_WAIT_ENTRY)); 01450 MmUnlockSectionSegment(Segment); 01451 MmUnlockAddressSpace(AddressSpace); 01452 01453 if ((Segment->Flags & MM_PAGEFILE_SEGMENT) || 01454 ((Offset.QuadPart >= (LONGLONG)PAGE_ROUND_UP(Segment->RawLength.QuadPart) && 01455 (Section->AllocationAttributes & SEC_IMAGE)))) 01456 { 01457 MI_SET_USAGE(MI_USAGE_SECTION); 01458 if (Process) MI_SET_PROCESS2(Process->ImageFileName); 01459 if (!Process) MI_SET_PROCESS2("Kernel Section"); 01460 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page); 01461 if (!NT_SUCCESS(Status)) 01462 { 01463 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status); 01464 } 01465 01466 } 01467 else 01468 { 01469 Status = MiReadPage(MemoryArea, (ULONG_PTR)Offset.QuadPart, &Page); 01470 if (!NT_SUCCESS(Status)) 01471 { 01472 DPRINT1("MiReadPage failed (Status %x)\n", Status); 01473 } 01474 } 01475 if (!NT_SUCCESS(Status)) 01476 { 01477 /* 01478 * FIXME: What do we know in this case? 01479 */ 01480 /* 01481 * Cleanup and release locks 01482 */ 01483 MmLockAddressSpace(AddressSpace); 01484 MiSetPageEvent(Process, Address); 01485 DPRINT("Address 0x%.8X\n", Address); 01486 return(Status); 01487 } 01488 01489 /* 01490 * Mark the offset within the section as having valid, in-memory 01491 * data 01492 */ 01493 MmLockAddressSpace(AddressSpace); 01494 MmLockSectionSegment(Segment); 01495 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1); 01496 MmSetPageEntrySectionSegment(Segment, &Offset, Entry); 01497 MmUnlockSectionSegment(Segment); 01498 01499 Status = MmCreateVirtualMapping(Process, 01500 PAddress, 01501 Attributes, 01502 &Page, 01503 1); 01504 if (!NT_SUCCESS(Status)) 01505 { 01506 DPRINT1("Unable to create virtual mapping\n"); 01507 KeBugCheck(MEMORY_MANAGEMENT); 01508 } 01509 MmInsertRmap(Page, Process, Address); 01510 01511 MiSetPageEvent(Process, Address); 01512 DPRINT("Address 0x%.8X\n", Address); 01513 return(STATUS_SUCCESS); 01514 } 01515 else if (IS_SWAP_FROM_SSE(Entry)) 01516 { 01517 SWAPENTRY SwapEntry; 01518 01519 SwapEntry = SWAPENTRY_FROM_SSE(Entry); 01520 01521 /* 01522 * Release all our locks and read in the page from disk 01523 */ 01524 MmUnlockSectionSegment(Segment); 01525 01526 MmUnlockAddressSpace(AddressSpace); 01527 MI_SET_USAGE(MI_USAGE_SECTION); 01528 if (Process) MI_SET_PROCESS2(Process->ImageFileName); 01529 if (!Process) MI_SET_PROCESS2("Kernel Section"); 01530 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page); 01531 if (!NT_SUCCESS(Status)) 01532 { 01533 KeBugCheck(MEMORY_MANAGEMENT); 01534 } 01535 01536 Status = MmReadFromSwapPage(SwapEntry, Page); 01537 if (!NT_SUCCESS(Status)) 01538 { 01539 KeBugCheck(MEMORY_MANAGEMENT); 01540 } 01541 01542 /* 01543 * Relock the address space and segment 01544 */ 01545 MmLockAddressSpace(AddressSpace); 01546 MmLockSectionSegment(Segment); 01547 01548 /* 01549 * Check the entry. No one should change the status of a page 01550 * that has a pending page-in. 01551 */ 01552 Entry1 = MmGetPageEntrySectionSegment(Segment, &Offset); 01553 if (Entry != Entry1) 01554 { 01555 DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry, Entry1); 01556 KeBugCheck(MEMORY_MANAGEMENT); 01557 } 01558 01559 /* 01560 * Mark the offset within the section as having valid, in-memory 01561 * data 01562 */ 01563 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1); 01564 MmSetPageEntrySectionSegment(Segment, &Offset, Entry); 01565 MmUnlockSectionSegment(Segment); 01566 01567 /* 01568 * Save the swap entry. 01569 */ 01570 MmSetSavedSwapEntryPage(Page, SwapEntry); 01571 Status = MmCreateVirtualMapping(Process, 01572 PAddress, 01573 Region->Protect, 01574 &Page, 01575 1); 01576 if (!NT_SUCCESS(Status)) 01577 { 01578 DPRINT1("Unable to create virtual mapping\n"); 01579 KeBugCheck(MEMORY_MANAGEMENT); 01580 } 01581 MmInsertRmap(Page, Process, Address); 01582 MiSetPageEvent(Process, Address); 01583 DPRINT("Address 0x%.8X\n", Address); 01584 return(STATUS_SUCCESS); 01585 } 01586 else 01587 { 01588 /* 01589 * If the section offset is already in-memory and valid then just 01590 * take another reference to the page 01591 */ 01592 01593 Page = PFN_FROM_SSE(Entry); 01594 01595 MmSharePageEntrySectionSegment(Segment, &Offset); 01596 MmUnlockSectionSegment(Segment); 01597 01598 Status = MmCreateVirtualMapping(Process, 01599 PAddress, 01600 Attributes, 01601 &Page, 01602 1); 01603 if (!NT_SUCCESS(Status)) 01604 { 01605 DPRINT1("Unable to create virtual mapping\n"); 01606 KeBugCheck(MEMORY_MANAGEMENT); 01607 } 01608 MmInsertRmap(Page, Process, Address); 01609 MiSetPageEvent(Process, Address); 01610 DPRINT("Address 0x%.8X\n", Address); 01611 return(STATUS_SUCCESS); 01612 } 01613 } 01614 01615 NTSTATUS 01616 NTAPI 01617 MmAccessFaultSectionView(PMMSUPPORT AddressSpace, 01618 MEMORY_AREA* MemoryArea, 01619 PVOID Address) 01620 { 01621 PMM_SECTION_SEGMENT Segment; 01622 PROS_SECTION_OBJECT Section; 01623 PFN_NUMBER OldPage; 01624 PFN_NUMBER NewPage; 01625 NTSTATUS Status; 01626 PVOID PAddress; 01627 LARGE_INTEGER Offset; 01628 PMM_REGION Region; 01629 ULONG_PTR Entry; 01630 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); 01631 SWAPENTRY SwapEntry; 01632 01633 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace, MemoryArea, Address); 01634 01635 /* 01636 * Check if the page has already been set readwrite 01637 */ 01638 if (MmGetPageProtect(Process, Address) & PAGE_READWRITE) 01639 { 01640 DPRINT("Address 0x%.8X\n", Address); 01641 return(STATUS_SUCCESS); 01642 } 01643 01644 /* 01645 * Find the offset of the page 01646 */ 01647 PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE); 01648 Offset.QuadPart = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress 01649 + MemoryArea->Data.SectionData.ViewOffset.QuadPart; 01650 01651 Segment = MemoryArea->Data.SectionData.Segment; 01652 Section = MemoryArea->Data.SectionData.Section; 01653 Region = MmFindRegion(MemoryArea->StartingAddress, 01654 &MemoryArea->Data.SectionData.RegionListHead, 01655 Address, NULL); 01656 ASSERT(Region != NULL); 01657 /* 01658 * Lock the segment 01659 */ 01660 MmLockSectionSegment(Segment); 01661 01662 OldPage = MmGetPfnForProcess(Process, Address); 01663 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 01664 01665 MmUnlockSectionSegment(Segment); 01666 01667 /* 01668 * Check if we are doing COW 01669 */ 01670 if (!((Segment->WriteCopy) && 01671 (Region->Protect == PAGE_READWRITE || 01672 Region->Protect == PAGE_EXECUTE_READWRITE))) 01673 { 01674 DPRINT("Address 0x%.8X\n", Address); 01675 return(STATUS_ACCESS_VIOLATION); 01676 } 01677 01678 if (IS_SWAP_FROM_SSE(Entry) || 01679 PFN_FROM_SSE(Entry) != OldPage) 01680 { 01681 /* This is a private page. We must only change the page protection. */ 01682 MmSetPageProtect(Process, Address, Region->Protect); 01683 return(STATUS_SUCCESS); 01684 } 01685 01686 if(OldPage == 0) 01687 DPRINT("OldPage == 0!\n"); 01688 01689 /* 01690 * Get or create a pageop 01691 */ 01692 MmLockSectionSegment(Segment); 01693 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 01694 01695 /* 01696 * Wait for any other operations to complete 01697 */ 01698 if (Entry == SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY)) 01699 { 01700 MmUnlockSectionSegment(Segment); 01701 MmUnlockAddressSpace(AddressSpace); 01702 MiWaitForPageEvent(NULL, NULL); 01703 /* 01704 * Restart the operation 01705 */ 01706 MmLockAddressSpace(AddressSpace); 01707 DPRINT("Address 0x%.8X\n", Address); 01708 return(STATUS_MM_RESTART_OPERATION); 01709 } 01710 01711 MmDeleteRmap(OldPage, Process, PAddress); 01712 MmDeleteVirtualMapping(Process, PAddress, FALSE, NULL, NULL); 01713 MmCreatePageFileMapping(Process, PAddress, MM_WAIT_ENTRY); 01714 01715 /* 01716 * Release locks now we have the pageop 01717 */ 01718 MmUnlockSectionSegment(Segment); 01719 MmUnlockAddressSpace(AddressSpace); 01720 01721 /* 01722 * Allocate a page 01723 */ 01724 MI_SET_USAGE(MI_USAGE_SECTION); 01725 if (Process) MI_SET_PROCESS2(Process->ImageFileName); 01726 if (!Process) MI_SET_PROCESS2("Kernel Section"); 01727 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage); 01728 if (!NT_SUCCESS(Status)) 01729 { 01730 KeBugCheck(MEMORY_MANAGEMENT); 01731 } 01732 01733 /* 01734 * Copy the old page 01735 */ 01736 MiCopyFromUserPage(NewPage, OldPage); 01737 01738 MmLockAddressSpace(AddressSpace); 01739 01740 /* 01741 * Set the PTE to point to the new page 01742 */ 01743 MmDeletePageFileMapping(Process, PAddress, &SwapEntry); 01744 Status = MmCreateVirtualMapping(Process, 01745 PAddress, 01746 Region->Protect, 01747 &NewPage, 01748 1); 01749 if (!NT_SUCCESS(Status)) 01750 { 01751 DPRINT("MmCreateVirtualMapping failed, not out of memory\n"); 01752 KeBugCheck(MEMORY_MANAGEMENT); 01753 return(Status); 01754 } 01755 if (!NT_SUCCESS(Status)) 01756 { 01757 DPRINT1("Unable to create virtual mapping\n"); 01758 KeBugCheck(MEMORY_MANAGEMENT); 01759 } 01760 01761 /* 01762 * Unshare the old page. 01763 */ 01764 DPRINT("Swapping page (Old %x New %x)\n", OldPage, NewPage); 01765 MmInsertRmap(NewPage, Process, PAddress); 01766 MmLockSectionSegment(Segment); 01767 MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, FALSE, FALSE, NULL); 01768 MmUnlockSectionSegment(Segment); 01769 01770 MiSetPageEvent(Process, Address); 01771 DPRINT("Address 0x%.8X\n", Address); 01772 return(STATUS_SUCCESS); 01773 } 01774 01775 VOID 01776 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address) 01777 { 01778 MM_SECTION_PAGEOUT_CONTEXT* PageOutContext; 01779 BOOLEAN WasDirty; 01780 PFN_NUMBER Page = 0; 01781 01782 PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context; 01783 if (Process) 01784 { 01785 MmLockAddressSpace(&Process->Vm); 01786 } 01787 01788 MmDeleteVirtualMapping(Process, 01789 Address, 01790 FALSE, 01791 &WasDirty, 01792 &Page); 01793 if (WasDirty) 01794 { 01795 PageOutContext->WasDirty = TRUE; 01796 } 01797 if (!PageOutContext->Private) 01798 { 01799 MmLockSectionSegment(PageOutContext->Segment); 01800 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT)PageOutContext->Section, 01801 PageOutContext->Segment, 01802 &PageOutContext->Offset, 01803 PageOutContext->WasDirty, 01804 TRUE, 01805 &PageOutContext->SectionEntry); 01806 MmUnlockSectionSegment(PageOutContext->Segment); 01807 } 01808 if (Process) 01809 { 01810 MmUnlockAddressSpace(&Process->Vm); 01811 } 01812 01813 if (PageOutContext->Private) 01814 { 01815 MmReleasePageMemoryConsumer(MC_USER, Page); 01816 } 01817 } 01818 01819 NTSTATUS 01820 NTAPI 01821 MmPageOutSectionView(PMMSUPPORT AddressSpace, 01822 MEMORY_AREA* MemoryArea, 01823 PVOID Address, ULONG_PTR Entry) 01824 { 01825 PFN_NUMBER Page; 01826 MM_SECTION_PAGEOUT_CONTEXT Context; 01827 SWAPENTRY SwapEntry; 01828 ULONGLONG FileOffset; 01829 NTSTATUS Status; 01830 PFILE_OBJECT FileObject; 01831 #ifndef NEWCC 01832 PBCB Bcb = NULL; 01833 #endif 01834 BOOLEAN DirectMapped; 01835 BOOLEAN IsImageSection; 01836 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); 01837 KIRQL OldIrql; 01838 01839 Address = (PVOID)PAGE_ROUND_DOWN(Address); 01840 01841 /* 01842 * Get the segment and section. 01843 */ 01844 Context.Segment = MemoryArea->Data.SectionData.Segment; 01845 Context.Section = MemoryArea->Data.SectionData.Section; 01846 Context.SectionEntry = Entry; 01847 Context.CallingProcess = Process; 01848 01849 Context.Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress 01850 + MemoryArea->Data.SectionData.ViewOffset.QuadPart; 01851 FileOffset = Context.Offset.QuadPart + Context.Segment->Image.FileOffset; 01852 01853 IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE; 01854 01855 FileObject = Context.Section->FileObject; 01856 DirectMapped = FALSE; 01857 01858 MmLockSectionSegment(Context.Segment); 01859 01860 #ifndef NEWCC 01861 if (FileObject != NULL && 01862 !(Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)) 01863 { 01864 Bcb = FileObject->SectionObjectPointer->SharedCacheMap; 01865 01866 /* 01867 * If the file system is letting us go directly to the cache and the 01868 * memory area was mapped at an offset in the file which is page aligned 01869 * then note this is a direct mapped page. 01870 */ 01871 if ((FileOffset % PAGE_SIZE) == 0 && 01872 (Context.Offset.QuadPart + PAGE_SIZE <= Context.Segment->RawLength.QuadPart || !IsImageSection)) 01873 { 01874 DirectMapped = TRUE; 01875 } 01876 } 01877 #endif 01878 01879 01880 /* 01881 * This should never happen since mappings of physical memory are never 01882 * placed in the rmap lists. 01883 */ 01884 if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY) 01885 { 01886 DPRINT1("Trying to page out from physical memory section address 0x%X " 01887 "process %d\n", Address, 01888 Process ? Process->UniqueProcessId : 0); 01889 KeBugCheck(MEMORY_MANAGEMENT); 01890 } 01891 01892 /* 01893 * Get the section segment entry and the physical address. 01894 */ 01895 if (!MmIsPagePresent(Process, Address)) 01896 { 01897 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n", 01898 Process ? Process->UniqueProcessId : 0, Address); 01899 KeBugCheck(MEMORY_MANAGEMENT); 01900 } 01901 Page = MmGetPfnForProcess(Process, Address); 01902 SwapEntry = MmGetSavedSwapEntryPage(Page); 01903 01904 /* 01905 * Check the reference count to ensure this page can be paged out 01906 */ 01907 if (MmGetReferenceCountPage(Page) != 1) 01908 { 01909 DPRINT("Cannot page out locked section page: 0x%p (RefCount: %d)\n", 01910 Page, MmGetReferenceCountPage(Page)); 01911 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry); 01912 MmUnlockSectionSegment(Context.Segment); 01913 return STATUS_UNSUCCESSFUL; 01914 } 01915 01916 /* 01917 * Prepare the context structure for the rmap delete call. 01918 */ 01919 MmUnlockSectionSegment(Context.Segment); 01920 Context.WasDirty = FALSE; 01921 if (Context.Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA || 01922 IS_SWAP_FROM_SSE(Entry) || 01923 PFN_FROM_SSE(Entry) != Page) 01924 { 01925 Context.Private = TRUE; 01926 } 01927 else 01928 { 01929 Context.Private = FALSE; 01930 } 01931 01932 /* 01933 * Take an additional reference to the page or the cache segment. 01934 */ 01935 if (DirectMapped && !Context.Private) 01936 { 01937 if(!MiIsPageFromCache(MemoryArea, Context.Offset.LowPart)) 01938 { 01939 DPRINT1("Direct mapped non private page is not associated with the cache.\n"); 01940 KeBugCheck(MEMORY_MANAGEMENT); 01941 } 01942 } 01943 else 01944 { 01945 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 01946 MmReferencePage(Page); 01947 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 01948 } 01949 01950 MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping); 01951 01952 /* Since we passed in a surrogate, we'll get back the page entry 01953 * state in our context. This is intended to make intermediate 01954 * decrements of share count not release the wait entry. 01955 */ 01956 Entry = Context.SectionEntry; 01957 01958 /* 01959 * If this wasn't a private page then we should have reduced the entry to 01960 * zero by deleting all the rmaps. 01961 */ 01962 if (!Context.Private && Entry != 0) 01963 { 01964 if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) && 01965 !(Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)) 01966 { 01967 KeBugCheckEx(MEMORY_MANAGEMENT, Entry, (ULONG_PTR)Process, (ULONG_PTR)Address, 0); 01968 } 01969 } 01970 01971 /* 01972 * If the page wasn't dirty then we can just free it as for a readonly page. 01973 * Since we unmapped all the mappings above we know it will not suddenly 01974 * become dirty. 01975 * If the page is from a pagefile section and has no swap entry, 01976 * we can't free the page at this point. 01977 */ 01978 SwapEntry = MmGetSavedSwapEntryPage(Page); 01979 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT) 01980 { 01981 if (Context.Private) 01982 { 01983 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n", 01984 Context.WasDirty ? "dirty" : "clean", Address); 01985 KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address, 0); 01986 } 01987 if (!Context.WasDirty && SwapEntry != 0) 01988 { 01989 MmSetSavedSwapEntryPage(Page, 0); 01990 MmLockSectionSegment(Context.Segment); 01991 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry)); 01992 MmUnlockSectionSegment(Context.Segment); 01993 MmReleasePageMemoryConsumer(MC_USER, Page); 01994 MiSetPageEvent(NULL, NULL); 01995 return(STATUS_SUCCESS); 01996 } 01997 } 01998 else if (Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED) 01999 { 02000 if (Context.Private) 02001 { 02002 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n", 02003 Context.WasDirty ? "dirty" : "clean", Address); 02004 KeBugCheckEx(MEMORY_MANAGEMENT, Page, (ULONG_PTR)Process, (ULONG_PTR)Address, 0); 02005 } 02006 if (!Context.WasDirty || SwapEntry != 0) 02007 { 02008 MmSetSavedSwapEntryPage(Page, 0); 02009 if (SwapEntry != 0) 02010 { 02011 MmLockSectionSegment(Context.Segment); 02012 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry)); 02013 MmUnlockSectionSegment(Context.Segment); 02014 } 02015 MmReleasePageMemoryConsumer(MC_USER, Page); 02016 MiSetPageEvent(NULL, NULL); 02017 return(STATUS_SUCCESS); 02018 } 02019 } 02020 else if (!Context.Private && DirectMapped) 02021 { 02022 if (SwapEntry != 0) 02023 { 02024 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n", 02025 Address); 02026 KeBugCheckEx(MEMORY_MANAGEMENT, STATUS_UNSUCCESSFUL, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address); 02027 } 02028 #ifndef NEWCC 02029 Status = CcRosUnmapCacheSegment(Bcb, (ULONG)FileOffset, FALSE); 02030 #else 02031 Status = STATUS_SUCCESS; 02032 #endif 02033 #ifndef NEWCC 02034 if (!NT_SUCCESS(Status)) 02035 { 02036 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status); 02037 KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Bcb, (ULONG_PTR)FileOffset, (ULONG_PTR)Address); 02038 } 02039 #endif 02040 MiSetPageEvent(NULL, NULL); 02041 return(STATUS_SUCCESS); 02042 } 02043 else if (!Context.WasDirty && !DirectMapped && !Context.Private) 02044 { 02045 if (SwapEntry != 0) 02046 { 02047 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n", 02048 Address); 02049 KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, Page, (ULONG_PTR)Process, (ULONG_PTR)Address); 02050 } 02051 MmReleasePageMemoryConsumer(MC_USER, Page); 02052 MiSetPageEvent(NULL, NULL); 02053 return(STATUS_SUCCESS); 02054 } 02055 else if (!Context.WasDirty && Context.Private && SwapEntry != 0) 02056 { 02057 DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process, Address); 02058 MmSetSavedSwapEntryPage(Page, 0); 02059 MmLockAddressSpace(AddressSpace); 02060 Status = MmCreatePageFileMapping(Process, 02061 Address, 02062 SwapEntry); 02063 MmUnlockAddressSpace(AddressSpace); 02064 if (!NT_SUCCESS(Status)) 02065 { 02066 DPRINT1("Status %x Swapping out %p:%p\n", Status, Process, Address); 02067 KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Process, (ULONG_PTR)Address, SwapEntry); 02068 } 02069 MmReleasePageMemoryConsumer(MC_USER, Page); 02070 MiSetPageEvent(NULL, NULL); 02071 return(STATUS_SUCCESS); 02072 } 02073 02074 /* 02075 * If necessary, allocate an entry in the paging file for this page 02076 */ 02077 if (SwapEntry == 0) 02078 { 02079 SwapEntry = MmAllocSwapPage(); 02080 if (SwapEntry == 0) 02081 { 02082 MmShowOutOfSpaceMessagePagingFile(); 02083 MmLockAddressSpace(AddressSpace); 02084 /* 02085 * For private pages restore the old mappings. 02086 */ 02087 if (Context.Private) 02088 { 02089 Status = MmCreateVirtualMapping(Process, 02090 Address, 02091 MemoryArea->Protect, 02092 &Page, 02093 1); 02094 MmSetDirtyPage(Process, Address); 02095 MmInsertRmap(Page, 02096 Process, 02097 Address); 02098 } 02099 else 02100 { 02101 ULONG_PTR OldEntry; 02102 /* 02103 * For non-private pages if the page wasn't direct mapped then 02104 * set it back into the section segment entry so we don't loose 02105 * our copy. Otherwise it will be handled by the cache manager. 02106 */ 02107 Status = MmCreateVirtualMapping(Process, 02108 Address, 02109 MemoryArea->Protect, 02110 &Page, 02111 1); 02112 MmSetDirtyPage(Process, Address); 02113 MmInsertRmap(Page, 02114 Process, 02115 Address); 02116 // If we got here, the previous entry should have been a wait 02117 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1); 02118 MmLockSectionSegment(Context.Segment); 02119 OldEntry = MmGetPageEntrySectionSegment(Context.Segment, &Context.Offset); 02120 ASSERT(OldEntry == 0 || OldEntry == MAKE_SWAP_SSE(MM_WAIT_ENTRY)); 02121 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry); 02122 MmUnlockSectionSegment(Context.Segment); 02123 } 02124 MmUnlockAddressSpace(AddressSpace); 02125 MiSetPageEvent(NULL, NULL); 02126 return(STATUS_PAGEFILE_QUOTA); 02127 } 02128 } 02129 02130 /* 02131 * Write the page to the pagefile 02132 */ 02133 Status = MmWriteToSwapPage(SwapEntry, Page); 02134 if (!NT_SUCCESS(Status)) 02135 { 02136 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", 02137 Status); 02138 /* 02139 * As above: undo our actions. 02140 * FIXME: Also free the swap page. 02141 */ 02142 MmLockAddressSpace(AddressSpace); 02143 if (Context.Private) 02144 { 02145 Status = MmCreateVirtualMapping(Process, 02146 Address, 02147 MemoryArea->Protect, 02148 &Page, 02149 1); 02150 MmSetDirtyPage(Process, Address); 02151 MmInsertRmap(Page, 02152 Process, 02153 Address); 02154 } 02155 else 02156 { 02157 Status = MmCreateVirtualMapping(Process, 02158 Address, 02159 MemoryArea->Protect, 02160 &Page, 02161 1); 02162 MmSetDirtyPage(Process, Address); 02163 MmInsertRmap(Page, 02164 Process, 02165 Address); 02166 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1); 02167 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry); 02168 } 02169 MmUnlockAddressSpace(AddressSpace); 02170 MiSetPageEvent(NULL, NULL); 02171 return(STATUS_UNSUCCESSFUL); 02172 } 02173 02174 /* 02175 * Otherwise we have succeeded. 02176 */ 02177 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT); 02178 MmSetSavedSwapEntryPage(Page, 0); 02179 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT || 02180 Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED) 02181 { 02182 MmLockSectionSegment(Context.Segment); 02183 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry)); 02184 MmUnlockSectionSegment(Context.Segment); 02185 } 02186 else 02187 { 02188 MmReleasePageMemoryConsumer(MC_USER, Page); 02189 } 02190 02191 if (Context.Private) 02192 { 02193 MmLockAddressSpace(AddressSpace); 02194 MmLockSectionSegment(Context.Segment); 02195 Status = MmCreatePageFileMapping(Process, 02196 Address, 02197 SwapEntry); 02198 /* We had placed a wait entry upon entry ... replace it before leaving */ 02199 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry); 02200 MmUnlockSectionSegment(Context.Segment); 02201 MmUnlockAddressSpace(AddressSpace); 02202 if (!NT_SUCCESS(Status)) 02203 { 02204 DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status, Process, Address); 02205 KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Process, (ULONG_PTR)Address, SwapEntry); 02206 } 02207 } 02208 else 02209 { 02210 MmLockAddressSpace(AddressSpace); 02211 MmLockSectionSegment(Context.Segment); 02212 Entry = MAKE_SWAP_SSE(SwapEntry); 02213 /* We had placed a wait entry upon entry ... replace it before leaving */ 02214 MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry); 02215 MmUnlockSectionSegment(Context.Segment); 02216 MmUnlockAddressSpace(AddressSpace); 02217 } 02218 02219 MiSetPageEvent(NULL, NULL); 02220 return(STATUS_SUCCESS); 02221 } 02222 02223 NTSTATUS 02224 NTAPI 02225 MmWritePageSectionView(PMMSUPPORT AddressSpace, 02226 PMEMORY_AREA MemoryArea, 02227 PVOID Address, 02228 ULONG PageEntry) 02229 { 02230 LARGE_INTEGER Offset; 02231 PROS_SECTION_OBJECT Section; 02232 PMM_SECTION_SEGMENT Segment; 02233 PFN_NUMBER Page; 02234 SWAPENTRY SwapEntry; 02235 ULONG_PTR Entry; 02236 BOOLEAN Private; 02237 NTSTATUS Status; 02238 PFILE_OBJECT FileObject; 02239 PBCB Bcb = NULL; 02240 BOOLEAN DirectMapped; 02241 BOOLEAN IsImageSection; 02242 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); 02243 02244 Address = (PVOID)PAGE_ROUND_DOWN(Address); 02245 02246 Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress 02247 + MemoryArea->Data.SectionData.ViewOffset.QuadPart; 02248 02249 /* 02250 * Get the segment and section. 02251 */ 02252 Segment = MemoryArea->Data.SectionData.Segment; 02253 Section = MemoryArea->Data.SectionData.Section; 02254 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE; 02255 02256 FileObject = Section->FileObject; 02257 DirectMapped = FALSE; 02258 if (FileObject != NULL && 02259 !(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)) 02260 { 02261 Bcb = FileObject->SectionObjectPointer->SharedCacheMap; 02262 02263 /* 02264 * If the file system is letting us go directly to the cache and the 02265 * memory area was mapped at an offset in the file which is page aligned 02266 * then note this is a direct mapped page. 02267 */ 02268 if (((Offset.QuadPart + Segment->Image.FileOffset) % PAGE_SIZE) == 0 && 02269 (Offset.QuadPart + PAGE_SIZE <= Segment->RawLength.QuadPart || !IsImageSection)) 02270 { 02271 DirectMapped = TRUE; 02272 } 02273 } 02274 02275 /* 02276 * This should never happen since mappings of physical memory are never 02277 * placed in the rmap lists. 02278 */ 02279 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY) 02280 { 02281 DPRINT1("Trying to write back page from physical memory mapped at %X " 02282 "process %d\n", Address, 02283 Process ? Process->UniqueProcessId : 0); 02284 KeBugCheck(MEMORY_MANAGEMENT); 02285 } 02286 02287 /* 02288 * Get the section segment entry and the physical address. 02289 */ 02290 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 02291 if (!MmIsPagePresent(Process, Address)) 02292 { 02293 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n", 02294 Process ? Process->UniqueProcessId : 0, Address); 02295 KeBugCheck(MEMORY_MANAGEMENT); 02296 } 02297 Page = MmGetPfnForProcess(Process, Address); 02298 SwapEntry = MmGetSavedSwapEntryPage(Page); 02299 02300 /* 02301 * Check for a private (COWed) page. 02302 */ 02303 if (Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA || 02304 IS_SWAP_FROM_SSE(Entry) || 02305 PFN_FROM_SSE(Entry) != Page) 02306 { 02307 Private = TRUE; 02308 } 02309 else 02310 { 02311 Private = FALSE; 02312 } 02313 02314 /* 02315 * Speculatively set all mappings of the page to clean. 02316 */ 02317 MmSetCleanAllRmaps(Page); 02318 02319 /* 02320 * If this page was direct mapped from the cache then the cache manager 02321 * will take care of writing it back to disk. 02322 */ 02323 if (DirectMapped && !Private) 02324 { 02325 LARGE_INTEGER SOffset; 02326 ASSERT(SwapEntry == 0); 02327 SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset; 02328 #ifndef NEWCC 02329 CcRosMarkDirtyCacheSegment(Bcb, Offset.LowPart); 02330 #endif 02331 MmLockSectionSegment(Segment); 02332 MmSetPageEntrySectionSegment(Segment, &Offset, PageEntry); 02333 MmUnlockSectionSegment(Segment); 02334 MiSetPageEvent(NULL, NULL); 02335 return(STATUS_SUCCESS); 02336 } 02337 02338 /* 02339 * If necessary, allocate an entry in the paging file for this page 02340 */ 02341 if (SwapEntry == 0) 02342 { 02343 SwapEntry = MmAllocSwapPage(); 02344 if (SwapEntry == 0) 02345 { 02346 MmSetDirtyAllRmaps(Page); 02347 MiSetPageEvent(NULL, NULL); 02348 return(STATUS_PAGEFILE_QUOTA); 02349 } 02350 MmSetSavedSwapEntryPage(Page, SwapEntry); 02351 } 02352 02353 /* 02354 * Write the page to the pagefile 02355 */ 02356 Status = MmWriteToSwapPage(SwapEntry, Page); 02357 if (!NT_SUCCESS(Status)) 02358 { 02359 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", 02360 Status); 02361 MmSetDirtyAllRmaps(Page); 02362 MiSetPageEvent(NULL, NULL); 02363 return(STATUS_UNSUCCESSFUL); 02364 } 02365 02366 /* 02367 * Otherwise we have succeeded. 02368 */ 02369 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT); 02370 MiSetPageEvent(NULL, NULL); 02371 return(STATUS_SUCCESS); 02372 } 02373 02374 static VOID 02375 MmAlterViewAttributes(PMMSUPPORT AddressSpace, 02376 PVOID BaseAddress, 02377 SIZE_T RegionSize, 02378 ULONG OldType, 02379 ULONG OldProtect, 02380 ULONG NewType, 02381 ULONG NewProtect) 02382 { 02383 PMEMORY_AREA MemoryArea; 02384 PMM_SECTION_SEGMENT Segment; 02385 BOOLEAN DoCOW = FALSE; 02386 ULONG i; 02387 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); 02388 02389 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress); 02390 ASSERT(MemoryArea != NULL); 02391 Segment = MemoryArea->Data.SectionData.Segment; 02392 MmLockSectionSegment(Segment); 02393 02394 if ((Segment->WriteCopy) && 02395 (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE)) 02396 { 02397 DoCOW = TRUE; 02398 } 02399 02400 if (OldProtect != NewProtect) 02401 { 02402 for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++) 02403 { 02404 SWAPENTRY SwapEntry; 02405 PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE); 02406 ULONG Protect = NewProtect; 02407 02408 /* Wait for a wait entry to disappear */ 02409 do { 02410 MmGetPageFileMapping(Process, Address, &SwapEntry); 02411 if (SwapEntry != MM_WAIT_ENTRY) 02412 break; 02413 MiWaitForPageEvent(Process, Address); 02414 } while (TRUE); 02415 02416 /* 02417 * If we doing COW for this segment then check if the page is 02418 * already private. 02419 */ 02420 if (DoCOW && MmIsPagePresent(Process, Address)) 02421 { 02422 LARGE_INTEGER Offset; 02423 ULONG_PTR Entry; 02424 PFN_NUMBER Page; 02425 02426 Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress 02427 + MemoryArea->Data.SectionData.ViewOffset.QuadPart; 02428 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 02429 /* 02430 * An MM_WAIT_ENTRY is ok in this case... It'll just count as 02431 * IS_SWAP_FROM_SSE and we'll do the right thing. 02432 */ 02433 Page = MmGetPfnForProcess(Process, Address); 02434 02435 Protect = PAGE_READONLY; 02436 if (Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA || 02437 IS_SWAP_FROM_SSE(Entry) || 02438 PFN_FROM_SSE(Entry) != Page) 02439 { 02440 Protect = NewProtect; 02441 } 02442 } 02443 02444 if (MmIsPagePresent(Process, Address)) 02445 { 02446 MmSetPageProtect(Process, Address, 02447 Protect); 02448 } 02449 } 02450 } 02451 02452 MmUnlockSectionSegment(Segment); 02453 } 02454 02455 NTSTATUS 02456 NTAPI 02457 MmProtectSectionView(PMMSUPPORT AddressSpace, 02458 PMEMORY_AREA MemoryArea, 02459 PVOID BaseAddress, 02460 SIZE_T Length, 02461 ULONG Protect, 02462 PULONG OldProtect) 02463 { 02464 PMM_REGION Region; 02465 NTSTATUS Status; 02466 ULONG_PTR MaxLength; 02467 02468 MaxLength = (ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)BaseAddress; 02469 if (Length > MaxLength) 02470 Length = (ULONG)MaxLength; 02471 02472 Region = MmFindRegion(MemoryArea->StartingAddress, 02473 &MemoryArea->Data.SectionData.RegionListHead, 02474 BaseAddress, NULL); 02475 ASSERT(Region != NULL); 02476 02477 if ((MemoryArea->Flags & SEC_NO_CHANGE) && 02478 Region->Protect != Protect) 02479 { 02480 return STATUS_INVALID_PAGE_PROTECTION; 02481 } 02482 02483 *OldProtect = Region->Protect; 02484 Status = MmAlterRegion(AddressSpace, MemoryArea->StartingAddress, 02485 &MemoryArea->Data.SectionData.RegionListHead, 02486 BaseAddress, Length, Region->Type, Protect, 02487 MmAlterViewAttributes); 02488 02489 return(Status); 02490 } 02491 02492 NTSTATUS NTAPI 02493 MmQuerySectionView(PMEMORY_AREA MemoryArea, 02494 PVOID Address, 02495 PMEMORY_BASIC_INFORMATION Info, 02496 PSIZE_T ResultLength) 02497 { 02498 PMM_REGION Region; 02499 PVOID RegionBaseAddress; 02500 PROS_SECTION_OBJECT Section; 02501 PMM_SECTION_SEGMENT Segment; 02502 02503 Region = MmFindRegion((PVOID)MemoryArea->StartingAddress, 02504 &MemoryArea->Data.SectionData.RegionListHead, 02505 Address, &RegionBaseAddress); 02506 if (Region == NULL) 02507 { 02508 return STATUS_UNSUCCESSFUL; 02509 } 02510 02511 Section = MemoryArea->Data.SectionData.Section; 02512 if (Section->AllocationAttributes & SEC_IMAGE) 02513 { 02514 Segment = MemoryArea->Data.SectionData.Segment; 02515 Info->AllocationBase = (PUCHAR)MemoryArea->StartingAddress - Segment->Image.VirtualAddress; 02516 Info->Type = MEM_IMAGE; 02517 } 02518 else 02519 { 02520 Info->AllocationBase = MemoryArea->StartingAddress; 02521 Info->Type = MEM_MAPPED; 02522 } 02523 Info->BaseAddress = RegionBaseAddress; 02524 Info->AllocationProtect = MemoryArea->Protect; 02525 Info->RegionSize = Region->Length; 02526 Info->State = MEM_COMMIT; 02527 Info->Protect = Region->Protect; 02528 02529 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION); 02530 return(STATUS_SUCCESS); 02531 } 02532 02533 VOID 02534 NTAPI 02535 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment) 02536 { 02537 ULONG Length; 02538 LARGE_INTEGER Offset; 02539 ULONG_PTR Entry; 02540 SWAPENTRY SavedSwapEntry; 02541 PFN_NUMBER Page; 02542 02543 Page = 0; 02544 02545 MmLockSectionSegment(Segment); 02546 02547 Length = PAGE_ROUND_UP(Segment->Length.QuadPart); 02548 for (Offset.QuadPart = 0; Offset.QuadPart < Length; Offset.QuadPart += PAGE_SIZE) 02549 { 02550 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 02551 if (Entry) 02552 { 02553 MmSetPageEntrySectionSegment(Segment, &Offset, 0); 02554 if (IS_SWAP_FROM_SSE(Entry)) 02555 { 02556 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry)); 02557 } 02558 else 02559 { 02560 Page = PFN_FROM_SSE(Entry); 02561 SavedSwapEntry = MmGetSavedSwapEntryPage(Page); 02562 if (SavedSwapEntry != 0) 02563 { 02564 MmSetSavedSwapEntryPage(Page, 0); 02565 MmFreeSwapPage(SavedSwapEntry); 02566 } 02567 MmReleasePageMemoryConsumer(MC_USER, Page); 02568 } 02569 } 02570 } 02571 02572 MmUnlockSectionSegment(Segment); 02573 } 02574 02575 VOID NTAPI 02576 MmpDeleteSection(PVOID ObjectBody) 02577 { 02578 PROS_SECTION_OBJECT Section = (PROS_SECTION_OBJECT)ObjectBody; 02579 02580 DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody); 02581 if (Section->AllocationAttributes & SEC_IMAGE) 02582 { 02583 ULONG i; 02584 ULONG NrSegments; 02585 ULONG RefCount; 02586 PMM_SECTION_SEGMENT SectionSegments; 02587 02588 /* 02589 * NOTE: Section->ImageSection can be NULL for short time 02590 * during the section creating. If we fail for some reason 02591 * until the image section is properly initialized we shouldn't 02592 * process further here. 02593 */ 02594 if (Section->ImageSection == NULL) 02595 return; 02596 02597 SectionSegments = Section->ImageSection->Segments; 02598 NrSegments = Section->ImageSection->NrSegments; 02599 02600 for (i = 0; i < NrSegments; i++) 02601 { 02602 if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED) 02603 { 02604 MmLockSectionSegment(&SectionSegments[i]); 02605 } 02606 RefCount = InterlockedDecrementUL(&SectionSegments[i].ReferenceCount); 02607 if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED) 02608 { 02609 MmUnlockSectionSegment(&SectionSegments[i]); 02610 if (RefCount == 0) 02611 { 02612 MmpFreePageFileSegment(&SectionSegments[i]); 02613 } 02614 } 02615 } 02616 } 02617 #ifdef NEWCC 02618 else if (Section->Segment && Section->Segment->Flags & MM_DATAFILE_SEGMENT) 02619 { 02620 ULONG RefCount = 0; 02621 PMM_SECTION_SEGMENT Segment = Section->Segment; 02622 02623 if (Segment && 02624 (RefCount = InterlockedDecrementUL(&Segment->ReferenceCount)) == 0) 02625 { 02626 DPRINT("Freeing section segment\n"); 02627 Section->Segment = NULL; 02628 MmFinalizeSegment(Segment); 02629 } 02630 else 02631 { 02632 DPRINT("RefCount %d\n", RefCount); 02633 } 02634 } 02635 #endif 02636 else 02637 { 02638 /* 02639 * NOTE: Section->Segment can be NULL for short time 02640 * during the section creating. 02641 */ 02642 if (Section->Segment == NULL) 02643 return; 02644 02645 if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT) 02646 { 02647 MmpFreePageFileSegment(Section->Segment); 02648 MmFreePageTablesSectionSegment(Section->Segment, NULL); 02649 ExFreePool(Section->Segment); 02650 Section->Segment = NULL; 02651 } 02652 else 02653 { 02654 (void)InterlockedDecrementUL(&Section->Segment->ReferenceCount); 02655 } 02656 } 02657 if (Section->FileObject != NULL) 02658 { 02659 #ifndef NEWCC 02660 CcRosDereferenceCache(Section->FileObject); 02661 #endif 02662 ObDereferenceObject(Section->FileObject); 02663 Section->FileObject = NULL; 02664 } 02665 } 02666 02667 VOID NTAPI 02668 MmpCloseSection(IN PEPROCESS Process OPTIONAL, 02669 IN PVOID Object, 02670 IN ACCESS_MASK GrantedAccess, 02671 IN ULONG ProcessHandleCount, 02672 IN ULONG SystemHandleCount) 02673 { 02674 DPRINT("MmpCloseSection(OB %x, HC %d)\n", 02675 Object, ProcessHandleCount); 02676 } 02677 02678 NTSTATUS 02679 INIT_FUNCTION 02680 NTAPI 02681 MmCreatePhysicalMemorySection(VOID) 02682 { 02683 PROS_SECTION_OBJECT PhysSection; 02684 NTSTATUS Status; 02685 OBJECT_ATTRIBUTES Obj; 02686 UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory"); 02687 LARGE_INTEGER SectionSize; 02688 HANDLE Handle; 02689 02690 /* 02691 * Create the section mapping physical memory 02692 */ 02693 SectionSize.QuadPart = 0xFFFFFFFF; 02694 InitializeObjectAttributes(&Obj, 02695 &Name, 02696 OBJ_PERMANENT, 02697 NULL, 02698 NULL); 02699 Status = MmCreateSection((PVOID)&PhysSection, 02700 SECTION_ALL_ACCESS, 02701 &Obj, 02702 &SectionSize, 02703 PAGE_EXECUTE_READWRITE, 02704 0, 02705 NULL, 02706 NULL); 02707 if (!NT_SUCCESS(Status)) 02708 { 02709 DPRINT1("Failed to create PhysicalMemory section\n"); 02710 KeBugCheck(MEMORY_MANAGEMENT); 02711 } 02712 Status = ObInsertObject(PhysSection, 02713 NULL, 02714 SECTION_ALL_ACCESS, 02715 0, 02716 NULL, 02717 &Handle); 02718 if (!NT_SUCCESS(Status)) 02719 { 02720 ObDereferenceObject(PhysSection); 02721 } 02722 ObCloseHandle(Handle, KernelMode); 02723 PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY; 02724 PhysSection->Segment->Flags &= ~MM_PAGEFILE_SEGMENT; 02725 02726 return(STATUS_SUCCESS); 02727 } 02728 02729 NTSTATUS 02730 INIT_FUNCTION 02731 NTAPI 02732 MmInitSectionImplementation(VOID) 02733 { 02734 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 02735 UNICODE_STRING Name; 02736 02737 DPRINT("Creating Section Object Type\n"); 02738 02739 /* Initialize the section based root */ 02740 ASSERT(MmSectionBasedRoot.NumberGenericTableElements == 0); 02741 MmSectionBasedRoot.BalancedRoot.u1.Parent = &MmSectionBasedRoot.BalancedRoot; 02742 02743 /* Initialize the Section object type */ 02744 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 02745 RtlInitUnicodeString(&Name, L"Section"); 02746 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 02747 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(ROS_SECTION_OBJECT); 02748 ObjectTypeInitializer.PoolType = PagedPool; 02749 ObjectTypeInitializer.UseDefaultObject = TRUE; 02750 ObjectTypeInitializer.GenericMapping = MmpSectionMapping; 02751 ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection; 02752 ObjectTypeInitializer.CloseProcedure = MmpCloseSection; 02753 ObjectTypeInitializer.ValidAccessMask = SECTION_ALL_ACCESS; 02754 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &MmSectionObjectType); 02755 02756 MmCreatePhysicalMemorySection(); 02757 02758 return(STATUS_SUCCESS); 02759 } 02760 02761 NTSTATUS 02762 NTAPI 02763 MmCreatePageFileSection(PROS_SECTION_OBJECT *SectionObject, 02764 ACCESS_MASK DesiredAccess, 02765 POBJECT_ATTRIBUTES ObjectAttributes, 02766 PLARGE_INTEGER UMaximumSize, 02767 ULONG SectionPageProtection, 02768 ULONG AllocationAttributes) 02769 /* 02770 * Create a section which is backed by the pagefile 02771 */ 02772 { 02773 LARGE_INTEGER MaximumSize; 02774 PROS_SECTION_OBJECT Section; 02775 PMM_SECTION_SEGMENT Segment; 02776 NTSTATUS Status; 02777 02778 if (UMaximumSize == NULL) 02779 { 02780 return(STATUS_UNSUCCESSFUL); 02781 } 02782 MaximumSize = *UMaximumSize; 02783 02784 /* 02785 * Create the section 02786 */ 02787 Status = ObCreateObject(ExGetPreviousMode(), 02788 MmSectionObjectType, 02789 ObjectAttributes, 02790 ExGetPreviousMode(), 02791 NULL, 02792 sizeof(ROS_SECTION_OBJECT), 02793 0, 02794 0, 02795 (PVOID*)(PVOID)&Section); 02796 if (!NT_SUCCESS(Status)) 02797 { 02798 return(Status); 02799 } 02800 02801 /* 02802 * Initialize it 02803 */ 02804 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT)); 02805 Section->Type = 'SC'; 02806 Section->Size = 'TN'; 02807 Section->SectionPageProtection = SectionPageProtection; 02808 Section->AllocationAttributes = AllocationAttributes; 02809 Section->MaximumSize = MaximumSize; 02810 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT), 02811 TAG_MM_SECTION_SEGMENT); 02812 if (Segment == NULL) 02813 { 02814 ObDereferenceObject(Section); 02815 return(STATUS_NO_MEMORY); 02816 } 02817 RtlZeroMemory(Segment, sizeof(MM_SECTION_SEGMENT)); 02818 Section->Segment = Segment; 02819 Segment->ReferenceCount = 1; 02820 ExInitializeFastMutex(&Segment->Lock); 02821 Segment->Image.FileOffset = 0; 02822 Segment->Protection = SectionPageProtection; 02823 Segment->RawLength.QuadPart = MaximumSize.u.LowPart; 02824 Segment->Length.QuadPart = PAGE_ROUND_UP(MaximumSize.u.LowPart); 02825 Segment->Flags = MM_PAGEFILE_SEGMENT; 02826 Segment->WriteCopy = FALSE; 02827 Segment->Image.VirtualAddress = 0; 02828 Segment->Image.Characteristics = 0; 02829 *SectionObject = Section; 02830 MiInitializeSectionPageTable(Segment); 02831 return(STATUS_SUCCESS); 02832 } 02833 02834 NTSTATUS 02835 NTAPI 02836 MmCreateDataFileSection(PROS_SECTION_OBJECT *SectionObject, 02837 ACCESS_MASK DesiredAccess, 02838 POBJECT_ATTRIBUTES ObjectAttributes, 02839 PLARGE_INTEGER UMaximumSize, 02840 ULONG SectionPageProtection, 02841 ULONG AllocationAttributes, 02842 HANDLE FileHandle) 02843 /* 02844 * Create a section backed by a data file 02845 */ 02846 { 02847 PROS_SECTION_OBJECT Section; 02848 NTSTATUS Status; 02849 LARGE_INTEGER MaximumSize; 02850 PFILE_OBJECT FileObject; 02851 PMM_SECTION_SEGMENT Segment; 02852 ULONG FileAccess; 02853 IO_STATUS_BLOCK Iosb; 02854 LARGE_INTEGER Offset; 02855 CHAR Buffer; 02856 FILE_STANDARD_INFORMATION FileInfo; 02857 ULONG Length; 02858 02859 /* 02860 * Create the section 02861 */ 02862 Status = ObCreateObject(ExGetPreviousMode(), 02863 MmSectionObjectType, 02864 ObjectAttributes, 02865 ExGetPreviousMode(), 02866 NULL, 02867 sizeof(ROS_SECTION_OBJECT), 02868 0, 02869 0, 02870 (PVOID*)&Section); 02871 if (!NT_SUCCESS(Status)) 02872 { 02873 return(Status); 02874 } 02875 /* 02876 * Initialize it 02877 */ 02878 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT)); 02879 Section->Type = 'SC'; 02880 Section->Size = 'TN'; 02881 Section->SectionPageProtection = SectionPageProtection; 02882 Section->AllocationAttributes = AllocationAttributes; 02883 02884 /* 02885 * Reference the file handle 02886 */ 02887 FileAccess = MiArm3GetCorrectFileAccessMask(SectionPageProtection); 02888 Status = ObReferenceObjectByHandle(FileHandle, 02889 FileAccess, 02890 IoFileObjectType, 02891 ExGetPreviousMode(), 02892 (PVOID*)(PVOID)&FileObject, 02893 NULL); 02894 if (!NT_SUCCESS(Status)) 02895 { 02896 ObDereferenceObject(Section); 02897 return(Status); 02898 } 02899 02900 /* 02901 * FIXME: This is propably not entirely correct. We can't look into 02902 * the standard FCB header because it might not be initialized yet 02903 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the 02904 * standard file information is filled on first request). 02905 */ 02906 Status = IoQueryFileInformation(FileObject, 02907 FileStandardInformation, 02908 sizeof(FILE_STANDARD_INFORMATION), 02909 &FileInfo, 02910 &Length); 02911 Iosb.Information = Length; 02912 if (!NT_SUCCESS(Status)) 02913 { 02914 ObDereferenceObject(Section); 02915 ObDereferenceObject(FileObject); 02916 return Status; 02917 } 02918 02919 /* 02920 * FIXME: Revise this once a locking order for file size changes is 02921 * decided 02922 */ 02923 if ((UMaximumSize != NULL) && (UMaximumSize->QuadPart != 0)) 02924 { 02925 MaximumSize = *UMaximumSize; 02926 } 02927 else 02928 { 02929 MaximumSize = FileInfo.EndOfFile; 02930 /* Mapping zero-sized files isn't allowed. */ 02931 if (MaximumSize.QuadPart == 0) 02932 { 02933 ObDereferenceObject(Section); 02934 ObDereferenceObject(FileObject); 02935 return STATUS_FILE_INVALID; 02936 } 02937 } 02938 02939 if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart) 02940 { 02941 Status = IoSetInformation(FileObject, 02942 FileAllocationInformation, 02943 sizeof(LARGE_INTEGER), 02944 &MaximumSize); 02945 if (!NT_SUCCESS(Status)) 02946 { 02947 ObDereferenceObject(Section); 02948 ObDereferenceObject(FileObject); 02949 return(STATUS_SECTION_NOT_EXTENDED); 02950 } 02951 } 02952 02953 if (FileObject->SectionObjectPointer == NULL || 02954 FileObject->SectionObjectPointer->SharedCacheMap == NULL) 02955 { 02956 /* 02957 * Read a bit so caching is initiated for the file object. 02958 * This is only needed because MiReadPage currently cannot 02959 * handle non-cached streams. 02960 */ 02961 Offset.QuadPart = 0; 02962 Status = ZwReadFile(FileHandle, 02963 NULL, 02964 NULL, 02965 NULL, 02966 &Iosb, 02967 &Buffer, 02968 sizeof (Buffer), 02969 &Offset, 02970 0); 02971 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE)) 02972 { 02973 ObDereferenceObject(Section); 02974 ObDereferenceObject(FileObject); 02975 return(Status); 02976 } 02977 if (FileObject->SectionObjectPointer == NULL || 02978 FileObject->SectionObjectPointer->SharedCacheMap == NULL) 02979 { 02980 /* FIXME: handle this situation */ 02981 ObDereferenceObject(Section); 02982 ObDereferenceObject(FileObject); 02983 return STATUS_INVALID_PARAMETER; 02984 } 02985 } 02986 02987 /* 02988 * Lock the file 02989 */ 02990 Status = MmspWaitForFileLock(FileObject); 02991 if (Status != STATUS_SUCCESS) 02992 { 02993 ObDereferenceObject(Section); 02994 ObDereferenceObject(FileObject); 02995 return(Status); 02996 } 02997 02998 /* 02999 * If this file hasn't been mapped as a data file before then allocate a 03000 * section segment to describe the data file mapping 03001 */ 03002 if (FileObject->SectionObjectPointer->DataSectionObject == NULL) 03003 { 03004 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT), 03005 TAG_MM_SECTION_SEGMENT); 03006 if (Segment == NULL) 03007 { 03008 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); 03009 ObDereferenceObject(Section); 03010 ObDereferenceObject(FileObject); 03011 return(STATUS_NO_MEMORY); 03012 } 03013 Section->Segment = Segment; 03014 Segment->ReferenceCount = 1; 03015 ExInitializeFastMutex(&Segment->Lock); 03016 /* 03017 * Set the lock before assigning the segment to the file object 03018 */ 03019 ExAcquireFastMutex(&Segment->Lock); 03020 FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment; 03021 03022 Segment->Image.FileOffset = 0; 03023 Segment->Protection = SectionPageProtection; 03024 Segment->Flags = MM_DATAFILE_SEGMENT; 03025 Segment->Image.Characteristics = 0; 03026 Segment->WriteCopy = (SectionPageProtection & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY)); 03027 if (AllocationAttributes & SEC_RESERVE) 03028 { 03029 Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0; 03030 } 03031 else 03032 { 03033 Segment->RawLength.QuadPart = MaximumSize.QuadPart; 03034 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart); 03035 } 03036 Segment->Image.VirtualAddress = 0; 03037 Segment->Locked = TRUE; 03038 MiInitializeSectionPageTable(Segment); 03039 } 03040 else 03041 { 03042 /* 03043 * If the file is already mapped as a data file then we may need 03044 * to extend it 03045 */ 03046 Segment = 03047 (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer-> 03048 DataSectionObject; 03049 Section->Segment = Segment; 03050 (void)InterlockedIncrementUL(&Segment->ReferenceCount); 03051 MmLockSectionSegment(Segment); 03052 03053 if (MaximumSize.QuadPart > Segment->RawLength.QuadPart && 03054 !(AllocationAttributes & SEC_RESERVE)) 03055 { 03056 Segment->RawLength.QuadPart = MaximumSize.QuadPart; 03057 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart); 03058 } 03059 } 03060 MmUnlockSectionSegment(Segment); 03061 Section->FileObject = FileObject; 03062 Section->MaximumSize = MaximumSize; 03063 #ifndef NEWCC 03064 CcRosReferenceCache(FileObject); 03065 #endif 03066 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); 03067 *SectionObject = Section; 03068 return(STATUS_SUCCESS); 03069 } 03070 03071 /* 03072 TODO: not that great (declaring loaders statically, having to declare all of 03073 them, having to keep them extern, etc.), will fix in the future 03074 */ 03075 extern NTSTATUS NTAPI PeFmtCreateSection 03076 ( 03077 IN CONST VOID * FileHeader, 03078 IN SIZE_T FileHeaderSize, 03079 IN PVOID File, 03080 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, 03081 OUT PULONG Flags, 03082 IN PEXEFMT_CB_READ_FILE ReadFileCb, 03083 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb 03084 ); 03085 03086 extern NTSTATUS NTAPI ElfFmtCreateSection 03087 ( 03088 IN CONST VOID * FileHeader, 03089 IN SIZE_T FileHeaderSize, 03090 IN PVOID File, 03091 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, 03092 OUT PULONG Flags, 03093 IN PEXEFMT_CB_READ_FILE ReadFileCb, 03094 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb 03095 ); 03096 03097 /* TODO: this is a standard DDK/PSDK macro */ 03098 #ifndef RTL_NUMBER_OF 03099 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0])) 03100 #endif 03101 03102 static PEXEFMT_LOADER ExeFmtpLoaders[] = 03103 { 03104 PeFmtCreateSection, 03105 #ifdef __ELF 03106 ElfFmtCreateSection 03107 #endif 03108 }; 03109 03110 static 03111 PMM_SECTION_SEGMENT 03112 NTAPI 03113 ExeFmtpAllocateSegments(IN ULONG NrSegments) 03114 { 03115 SIZE_T SizeOfSegments; 03116 PMM_SECTION_SEGMENT Segments; 03117 03118 /* TODO: check for integer overflow */ 03119 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * NrSegments; 03120 03121 Segments = ExAllocatePoolWithTag(NonPagedPool, 03122 SizeOfSegments, 03123 TAG_MM_SECTION_SEGMENT); 03124 03125 if(Segments) 03126 RtlZeroMemory(Segments, SizeOfSegments); 03127 03128 return Segments; 03129 } 03130 03131 static 03132 NTSTATUS 03133 NTAPI 03134 ExeFmtpReadFile(IN PVOID File, 03135 IN PLARGE_INTEGER Offset, 03136 IN ULONG Length, 03137 OUT PVOID * Data, 03138 OUT PVOID * AllocBase, 03139 OUT PULONG ReadSize) 03140 { 03141 NTSTATUS Status; 03142 LARGE_INTEGER FileOffset; 03143 ULONG AdjustOffset; 03144 ULONG OffsetAdjustment; 03145 ULONG BufferSize; 03146 ULONG UsedSize; 03147 PVOID Buffer; 03148 PFILE_OBJECT FileObject = File; 03149 IO_STATUS_BLOCK Iosb; 03150 03151 ASSERT_IRQL_LESS(DISPATCH_LEVEL); 03152 03153 if(Length == 0) 03154 { 03155 KeBugCheck(MEMORY_MANAGEMENT); 03156 } 03157 03158 FileOffset = *Offset; 03159 03160 /* Negative/special offset: it cannot be used in this context */ 03161 if(FileOffset.u.HighPart < 0) 03162 { 03163 KeBugCheck(MEMORY_MANAGEMENT); 03164 } 03165 03166 AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart); 03167 OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset; 03168 FileOffset.u.LowPart = AdjustOffset; 03169 03170 BufferSize = Length + OffsetAdjustment; 03171 BufferSize = PAGE_ROUND_UP(BufferSize); 03172 03173 /* 03174 * It's ok to use paged pool, because this is a temporary buffer only used in 03175 * the loading of executables. The assumption is that MmCreateSection is 03176 * always called at low IRQLs and that these buffers don't survive a brief 03177 * initialization phase 03178 */ 03179 Buffer = ExAllocatePoolWithTag(PagedPool, 03180 BufferSize, 03181 'rXmM'); 03182 if (!Buffer) 03183 { 03184 KeBugCheck(MEMORY_MANAGEMENT); 03185 } 03186 03187 UsedSize = 0; 03188 03189 Status = MiSimpleRead(FileObject, &FileOffset, Buffer, BufferSize, TRUE, &Iosb); 03190 03191 UsedSize = (ULONG)Iosb.Information; 03192 03193 if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment) 03194 { 03195 Status = STATUS_IN_PAGE_ERROR; 03196 ASSERT(!NT_SUCCESS(Status)); 03197 } 03198 03199 if(NT_SUCCESS(Status)) 03200 { 03201 *Data = (PVOID)((ULONG_PTR)Buffer + OffsetAdjustment); 03202 *AllocBase = Buffer; 03203 *ReadSize = UsedSize - OffsetAdjustment; 03204 } 03205 else 03206 { 03207 ExFreePoolWithTag(Buffer, 'rXmM'); 03208 } 03209 03210 return Status; 03211 } 03212 03213 #ifdef NASSERT 03214 # define MmspAssertSegmentsSorted(OBJ_) ((void)0) 03215 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0) 03216 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0) 03217 #else 03218 static 03219 VOID 03220 NTAPI 03221 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject) 03222 { 03223 ULONG i; 03224 03225 for( i = 1; i < ImageSectionObject->NrSegments; ++ i ) 03226 { 03227 ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >= 03228 ImageSectionObject->Segments[i - 1].Image.VirtualAddress); 03229 } 03230 } 03231 03232 static 03233 VOID 03234 NTAPI 03235 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject) 03236 { 03237 ULONG i; 03238 03239 MmspAssertSegmentsSorted(ImageSectionObject); 03240 03241 for( i = 0; i < ImageSectionObject->NrSegments; ++ i ) 03242 { 03243 ASSERT(ImageSectionObject->Segments[i].Length.QuadPart > 0); 03244 03245 if(i > 0) 03246 { 03247 ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >= 03248 (ImageSectionObject->Segments[i - 1].Image.VirtualAddress + 03249 ImageSectionObject->Segments[i - 1].Length.QuadPart)); 03250 } 03251 } 03252 } 03253 03254 static 03255 VOID 03256 NTAPI 03257 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject) 03258 { 03259 ULONG i; 03260 03261 for( i = 0; i < ImageSectionObject->NrSegments; ++ i ) 03262 { 03263 ASSERT((ImageSectionObject->Segments[i].Image.VirtualAddress % PAGE_SIZE) == 0); 03264 ASSERT((ImageSectionObject->Segments[i].Length.QuadPart % PAGE_SIZE) == 0); 03265 } 03266 } 03267 #endif 03268 03269 static 03270 int 03271 __cdecl 03272 MmspCompareSegments(const void * x, 03273 const void * y) 03274 { 03275 const MM_SECTION_SEGMENT *Segment1 = (const MM_SECTION_SEGMENT *)x; 03276 const MM_SECTION_SEGMENT *Segment2 = (const MM_SECTION_SEGMENT *)y; 03277 03278 return 03279 (Segment1->Image.VirtualAddress - Segment2->Image.VirtualAddress) >> 03280 ((sizeof(ULONG_PTR) - sizeof(int)) * 8); 03281 } 03282 03283 /* 03284 * Ensures an image section's segments are sorted in memory 03285 */ 03286 static 03287 VOID 03288 NTAPI 03289 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, 03290 IN ULONG Flags) 03291 { 03292 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED) 03293 { 03294 MmspAssertSegmentsSorted(ImageSectionObject); 03295 } 03296 else 03297 { 03298 qsort(ImageSectionObject->Segments, 03299 ImageSectionObject->NrSegments, 03300 sizeof(ImageSectionObject->Segments[0]), 03301 MmspCompareSegments); 03302 } 03303 } 03304 03305 03306 /* 03307 * Ensures an image section's segments don't overlap in memory and don't have 03308 * gaps and don't have a null size. We let them map to overlapping file regions, 03309 * though - that's not necessarily an error 03310 */ 03311 static 03312 BOOLEAN 03313 NTAPI 03314 MmspCheckSegmentBounds 03315 ( 03316 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, 03317 IN ULONG Flags 03318 ) 03319 { 03320 ULONG i; 03321 03322 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP) 03323 { 03324 MmspAssertSegmentsNoOverlap(ImageSectionObject); 03325 return TRUE; 03326 } 03327 03328 ASSERT(ImageSectionObject->NrSegments >= 1); 03329 03330 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i ) 03331 { 03332 if(ImageSectionObject->Segments[i].Length.QuadPart == 0) 03333 { 03334 return FALSE; 03335 } 03336 03337 if(i > 0) 03338 { 03339 /* 03340 * TODO: relax the limitation on gaps. For example, gaps smaller than a 03341 * page could be OK (Windows seems to be OK with them), and larger gaps 03342 * could lead to image sections spanning several discontiguous regions 03343 * (NtMapViewOfSection could then refuse to map them, and they could 03344 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX) 03345 */ 03346 if ((ImageSectionObject->Segments[i - 1].Image.VirtualAddress + 03347 ImageSectionObject->Segments[i - 1].Length.QuadPart) != 03348 ImageSectionObject->Segments[i].Image.VirtualAddress) 03349 { 03350 return FALSE; 03351 } 03352 } 03353 } 03354 03355 return TRUE; 03356 } 03357 03358 /* 03359 * Merges and pads an image section's segments until they all are page-aligned 03360 * and have a size that is a multiple of the page size 03361 */ 03362 static 03363 BOOLEAN 03364 NTAPI 03365 MmspPageAlignSegments 03366 ( 03367 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, 03368 IN ULONG Flags 03369 ) 03370 { 03371 ULONG i; 03372 ULONG LastSegment; 03373 PMM_SECTION_SEGMENT EffectiveSegment; 03374 03375 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED) 03376 { 03377 MmspAssertSegmentsPageAligned(ImageSectionObject); 03378 return TRUE; 03379 } 03380 03381 LastSegment = 0; 03382 EffectiveSegment = &ImageSectionObject->Segments[LastSegment]; 03383 03384 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i ) 03385 { 03386 /* 03387 * The first segment requires special handling 03388 */ 03389 if (i == 0) 03390 { 03391 ULONG_PTR VirtualAddress; 03392 ULONG_PTR VirtualOffset; 03393 03394 VirtualAddress = EffectiveSegment->Image.VirtualAddress; 03395 03396 /* Round down the virtual address to the nearest page */ 03397 EffectiveSegment->Image.VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress); 03398 03399 /* Round up the virtual size to the nearest page */ 03400 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length.QuadPart) - 03401 EffectiveSegment->Image.VirtualAddress; 03402 03403 /* Adjust the raw address and size */ 03404 VirtualOffset = VirtualAddress - EffectiveSegment->Image.VirtualAddress; 03405 03406 if (EffectiveSegment->Image.FileOffset < VirtualOffset) 03407 { 03408 return FALSE; 03409 } 03410 03411 /* 03412 * Garbage in, garbage out: unaligned base addresses make the file 03413 * offset point in curious and odd places, but that's what we were 03414 * asked for 03415 */ 03416 EffectiveSegment->Image.FileOffset -= VirtualOffset; 03417 EffectiveSegment->RawLength.QuadPart += VirtualOffset; 03418 } 03419 else 03420 { 03421 PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i]; 03422 ULONG_PTR EndOfEffectiveSegment; 03423 03424 EndOfEffectiveSegment = (ULONG_PTR)(EffectiveSegment->Image.VirtualAddress + EffectiveSegment->Length.QuadPart); 03425 ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0); 03426 03427 /* 03428 * The current segment begins exactly where the current effective 03429 * segment ended, therefore beginning a new effective segment 03430 */ 03431 if (EndOfEffectiveSegment == Segment->Image.VirtualAddress) 03432 { 03433 LastSegment ++; 03434 ASSERT(LastSegment <= i); 03435 ASSERT(LastSegment < ImageSectionObject->NrSegments); 03436 03437 EffectiveSegment = &ImageSectionObject->Segments[LastSegment]; 03438 03439 if (LastSegment != i) 03440 { 03441 /* 03442 * Copy the current segment. If necessary, the effective segment 03443 * will be expanded later 03444 */ 03445 *EffectiveSegment = *Segment; 03446 } 03447 03448 /* 03449 * Page-align the virtual size. We know for sure the virtual address 03450 * already is 03451 */ 03452 ASSERT((EffectiveSegment->Image.VirtualAddress % PAGE_SIZE) == 0); 03453 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(EffectiveSegment->Length.QuadPart); 03454 } 03455 /* 03456 * The current segment is still part of the current effective segment: 03457 * extend the effective segment to reflect this 03458 */ 03459 else if (EndOfEffectiveSegment > Segment->Image.VirtualAddress) 03460 { 03461 static const ULONG FlagsToProtection[16] = 03462 { 03463 PAGE_NOACCESS, 03464 PAGE_READONLY, 03465 PAGE_READWRITE, 03466 PAGE_READWRITE, 03467 PAGE_EXECUTE_READ, 03468 PAGE_EXECUTE_READ, 03469 PAGE_EXECUTE_READWRITE, 03470 PAGE_EXECUTE_READWRITE, 03471 PAGE_WRITECOPY, 03472 PAGE_WRITECOPY, 03473 PAGE_WRITECOPY, 03474 PAGE_WRITECOPY, 03475 PAGE_EXECUTE_WRITECOPY, 03476 PAGE_EXECUTE_WRITECOPY, 03477 PAGE_EXECUTE_WRITECOPY, 03478 PAGE_EXECUTE_WRITECOPY 03479 }; 03480 03481 unsigned ProtectionFlags; 03482 03483 /* 03484 * Extend the file size 03485 */ 03486 03487 /* Unaligned segments must be contiguous within the file */ 03488 if (Segment->Image.FileOffset != (EffectiveSegment->Image.FileOffset + 03489 EffectiveSegment->RawLength.QuadPart)) 03490 { 03491 return FALSE; 03492 } 03493 03494 EffectiveSegment->RawLength.QuadPart += Segment->RawLength.QuadPart; 03495 03496 /* 03497 * Extend the virtual size 03498 */ 03499 ASSERT(PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) >= EndOfEffectiveSegment); 03500 03501 EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) - 03502 EffectiveSegment->Image.VirtualAddress; 03503 03504 /* 03505 * Merge the protection 03506 */ 03507 EffectiveSegment->Protection |= Segment->Protection; 03508 03509 /* Clean up redundance */ 03510 ProtectionFlags = 0; 03511 03512 if(EffectiveSegment->Protection & PAGE_IS_READABLE) 03513 ProtectionFlags |= 1 << 0; 03514 03515 if(EffectiveSegment->Protection & PAGE_IS_WRITABLE) 03516 ProtectionFlags |= 1 << 1; 03517 03518 if(EffectiveSegment->Protection & PAGE_IS_EXECUTABLE) 03519 ProtectionFlags |= 1 << 2; 03520 03521 if(EffectiveSegment->Protection & PAGE_IS_WRITECOPY) 03522 ProtectionFlags |= 1 << 3; 03523 03524 ASSERT(ProtectionFlags < 16); 03525 EffectiveSegment->Protection = FlagsToProtection[ProtectionFlags]; 03526 03527 /* If a segment was required to be shared and cannot, fail */ 03528 if(!(Segment->Protection & PAGE_IS_WRITECOPY) && 03529 EffectiveSegment->Protection & PAGE_IS_WRITECOPY) 03530 { 03531 return FALSE; 03532 } 03533 } 03534 /* 03535 * We assume no holes between segments at this point 03536 */ 03537 else 03538 { 03539 KeBugCheck(MEMORY_MANAGEMENT); 03540 } 03541 } 03542 } 03543 ImageSectionObject->NrSegments = LastSegment + 1; 03544 03545 return TRUE; 03546 } 03547 03548 NTSTATUS 03549 ExeFmtpCreateImageSection(HANDLE FileHandle, 03550 PMM_IMAGE_SECTION_OBJECT ImageSectionObject) 03551 { 03552 LARGE_INTEGER Offset; 03553 PVOID FileHeader; 03554 PVOID FileHeaderBuffer; 03555 ULONG FileHeaderSize; 03556 ULONG Flags; 03557 ULONG OldNrSegments; 03558 NTSTATUS Status; 03559 ULONG i; 03560 03561 /* 03562 * Read the beginning of the file (2 pages). Should be enough to contain 03563 * all (or most) of the headers 03564 */ 03565 Offset.QuadPart = 0; 03566 03567 /* FIXME: use FileObject instead of FileHandle */ 03568 Status = ExeFmtpReadFile (FileHandle, 03569 &Offset, 03570 PAGE_SIZE * 2, 03571 &FileHeader, 03572 &FileHeaderBuffer, 03573 &FileHeaderSize); 03574 03575 if (!NT_SUCCESS(Status)) 03576 return Status; 03577 03578 if (FileHeaderSize == 0) 03579 { 03580 ExFreePool(FileHeaderBuffer); 03581 return STATUS_UNSUCCESSFUL; 03582 } 03583 03584 /* 03585 * Look for a loader that can handle this executable 03586 */ 03587 for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i) 03588 { 03589 RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); 03590 Flags = 0; 03591 03592 /* FIXME: use FileObject instead of FileHandle */ 03593 Status = ExeFmtpLoaders[i](FileHeader, 03594 FileHeaderSize, 03595 FileHandle, 03596 ImageSectionObject, 03597 &Flags, 03598 ExeFmtpReadFile, 03599 ExeFmtpAllocateSegments); 03600 03601 if (!NT_SUCCESS(Status)) 03602 { 03603 if (ImageSectionObject->Segments) 03604 { 03605 ExFreePool(ImageSectionObject->Segments); 03606 ImageSectionObject->Segments = NULL; 03607 } 03608 } 03609 03610 if (Status != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT) 03611 break; 03612 } 03613 03614 ExFreePoolWithTag(FileHeaderBuffer, 'rXmM'); 03615 03616 /* 03617 * No loader handled the format 03618 */ 03619 if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT) 03620 { 03621 Status = STATUS_INVALID_IMAGE_NOT_MZ; 03622 ASSERT(!NT_SUCCESS(Status)); 03623 } 03624 03625 if (!NT_SUCCESS(Status)) 03626 return Status; 03627 03628 ASSERT(ImageSectionObject->Segments != NULL); 03629 03630 /* 03631 * Some defaults 03632 */ 03633 /* FIXME? are these values platform-dependent? */ 03634 if(ImageSectionObject->StackReserve == 0) 03635 ImageSectionObject->StackReserve = 0x40000; 03636 03637 if(ImageSectionObject->StackCommit == 0) 03638 ImageSectionObject->StackCommit = 0x1000; 03639 03640 if(ImageSectionObject->ImageBase == 0) 03641 { 03642 if(ImageSectionObject->ImageCharacteristics & IMAGE_FILE_DLL) 03643 ImageSectionObject->ImageBase = 0x10000000; 03644 else 03645 ImageSectionObject->ImageBase = 0x00400000; 03646 } 03647 03648 /* 03649 * And now the fun part: fixing the segments 03650 */ 03651 03652 /* Sort them by virtual address */ 03653 MmspSortSegments(ImageSectionObject, Flags); 03654 03655 /* Ensure they don't overlap in memory */ 03656 if (!MmspCheckSegmentBounds(ImageSectionObject, Flags)) 03657 return STATUS_INVALID_IMAGE_FORMAT; 03658 03659 /* Ensure they are aligned */ 03660 OldNrSegments = ImageSectionObject->NrSegments; 03661 03662 if (!MmspPageAlignSegments(ImageSectionObject, Flags)) 03663 return STATUS_INVALID_IMAGE_FORMAT; 03664 03665 /* Trim them if the alignment phase merged some of them */ 03666 if (ImageSectionObject->NrSegments < OldNrSegments) 03667 { 03668 PMM_SECTION_SEGMENT Segments; 03669 SIZE_T SizeOfSegments; 03670 03671 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments; 03672 03673 Segments = ExAllocatePoolWithTag(PagedPool, 03674 SizeOfSegments, 03675 TAG_MM_SECTION_SEGMENT); 03676 03677 if (Segments == NULL) 03678 return STATUS_INSUFFICIENT_RESOURCES; 03679 03680 RtlCopyMemory(Segments, ImageSectionObject->Segments, SizeOfSegments); 03681 ExFreePool(ImageSectionObject->Segments); 03682 ImageSectionObject->Segments = Segments; 03683 } 03684 03685 /* And finish their initialization */ 03686 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i ) 03687 { 03688 ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock); 03689 ImageSectionObject->Segments[i].ReferenceCount = 1; 03690 MiInitializeSectionPageTable(&ImageSectionObject->Segments[i]); 03691 } 03692 03693 ASSERT(NT_SUCCESS(Status)); 03694 return Status; 03695 } 03696 03697 NTSTATUS 03698 MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject, 03699 ACCESS_MASK DesiredAccess, 03700 POBJECT_ATTRIBUTES ObjectAttributes, 03701 PLARGE_INTEGER UMaximumSize, 03702 ULONG SectionPageProtection, 03703 ULONG AllocationAttributes, 03704 PFILE_OBJECT FileObject) 03705 { 03706 PROS_SECTION_OBJECT Section; 03707 NTSTATUS Status; 03708 PMM_SECTION_SEGMENT SectionSegments; 03709 PMM_IMAGE_SECTION_OBJECT ImageSectionObject; 03710 ULONG i; 03711 03712 if (FileObject == NULL) 03713 return STATUS_INVALID_FILE_FOR_SECTION; 03714 03715 /* 03716 * Create the section 03717 */ 03718 Status = ObCreateObject (ExGetPreviousMode(), 03719 MmSectionObjectType, 03720 ObjectAttributes, 03721 ExGetPreviousMode(), 03722 NULL, 03723 sizeof(ROS_SECTION_OBJECT), 03724 0, 03725 0, 03726 (PVOID*)(PVOID)&Section); 03727 if (!NT_SUCCESS(Status)) 03728 { 03729 ObDereferenceObject(FileObject); 03730 return(Status); 03731 } 03732 03733 /* 03734 * Initialize it 03735 */ 03736 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT)); 03737 Section->Type = 'SC'; 03738 Section->Size = 'TN'; 03739 Section->SectionPageProtection = SectionPageProtection; 03740 Section->AllocationAttributes = AllocationAttributes; 03741 03742 #ifndef NEWCC 03743 /* 03744 * Initialized caching for this file object if previously caching 03745 * was initialized for the same on disk file 03746 */ 03747 Status = CcTryToInitializeFileCache(FileObject); 03748 #else 03749 Status = STATUS_SUCCESS; 03750 #endif 03751 03752 if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL) 03753 { 03754 NTSTATUS StatusExeFmt; 03755 03756 ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT); 03757 if (ImageSectionObject == NULL) 03758 { 03759 ObDereferenceObject(FileObject); 03760 ObDereferenceObject(Section); 03761 return(STATUS_NO_MEMORY); 03762 } 03763 03764 RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT)); 03765 03766 StatusExeFmt = ExeFmtpCreateImageSection(FileObject, ImageSectionObject); 03767 03768 if (!NT_SUCCESS(StatusExeFmt)) 03769 { 03770 if(ImageSectionObject->Segments != NULL) 03771 ExFreePool(ImageSectionObject->Segments); 03772 03773 ExFreePool(ImageSectionObject); 03774 ObDereferenceObject(Section); 03775 ObDereferenceObject(FileObject); 03776 return(StatusExeFmt); 03777 } 03778 03779 Section->ImageSection = ImageSectionObject; 03780 ASSERT(ImageSectionObject->Segments); 03781 03782 /* 03783 * Lock the file 03784 */ 03785 Status = MmspWaitForFileLock(FileObject); 03786 if (!NT_SUCCESS(Status)) 03787 { 03788 ExFreePool(ImageSectionObject->Segments); 03789 ExFreePool(ImageSectionObject); 03790 ObDereferenceObject(Section); 03791 ObDereferenceObject(FileObject); 03792 return(Status); 03793 } 03794 03795 if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject, 03796 ImageSectionObject, NULL)) 03797 { 03798 /* 03799 * An other thread has initialized the same image in the background 03800 */ 03801 ExFreePool(ImageSectionObject->Segments); 03802 ExFreePool(ImageSectionObject); 03803 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject; 03804 Section->ImageSection = ImageSectionObject; 03805 SectionSegments = ImageSectionObject->Segments; 03806 03807 for (i = 0; i < ImageSectionObject->NrSegments; i++) 03808 { 03809 (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount); 03810 } 03811 } 03812 03813 Status = StatusExeFmt; 03814 } 03815 else 03816 { 03817 /* 03818 * Lock the file 03819 */ 03820 Status = MmspWaitForFileLock(FileObject); 03821 if (Status != STATUS_SUCCESS) 03822 { 03823 ObDereferenceObject(Section); 03824 ObDereferenceObject(FileObject); 03825 return(Status); 03826 } 03827 03828 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject; 03829 Section->ImageSection = ImageSectionObject; 03830 SectionSegments = ImageSectionObject->Segments; 03831 03832 /* 03833 * Otherwise just reference all the section segments 03834 */ 03835 for (i = 0; i < ImageSectionObject->NrSegments; i++) 03836 { 03837 (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount); 03838 } 03839 03840 Status = STATUS_SUCCESS; 03841 } 03842 Section->FileObject = FileObject; 03843 #ifndef NEWCC 03844 CcRosReferenceCache(FileObject); 03845 #endif 03846 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); 03847 *SectionObject = Section; 03848 return(Status); 03849 } 03850 03851 03852 03853 static NTSTATUS 03854 MmMapViewOfSegment(PMMSUPPORT AddressSpace, 03855 PROS_SECTION_OBJECT Section, 03856 PMM_SECTION_SEGMENT Segment, 03857 PVOID* BaseAddress, 03858 SIZE_T ViewSize, 03859 ULONG Protect, 03860 ULONG ViewOffset, 03861 ULONG AllocationType) 03862 { 03863 PMEMORY_AREA MArea; 03864 NTSTATUS Status; 03865 PHYSICAL_ADDRESS BoundaryAddressMultiple; 03866 03867 if (Segment->WriteCopy) 03868 { 03869 /* We have to do this because the not present fault 03870 * and access fault handlers depend on the protection 03871 * that should be granted AFTER the COW fault takes 03872 * place to be in Region->Protect. The not present fault 03873 * handler changes this to the correct protection for COW when 03874 * mapping the pages into the process's address space. If a COW 03875 * fault takes place, the access fault handler sets the page protection 03876 * to these values for the newly copied pages 03877 */ 03878 if (Protect == PAGE_WRITECOPY) 03879 Protect = PAGE_READWRITE; 03880 else if (Protect == PAGE_EXECUTE_WRITECOPY) 03881 Protect = PAGE_EXECUTE_READWRITE; 03882 } 03883 03884 BoundaryAddressMultiple.QuadPart = 0; 03885 03886 #ifdef NEWCC 03887 if (Segment->Flags & MM_DATAFILE_SEGMENT) { 03888 LARGE_INTEGER FileOffset; 03889 FileOffset.QuadPart = ViewOffset; 03890 ObReferenceObject(Section); 03891 return _MiMapViewOfSegment(AddressSpace, Segment, BaseAddress, ViewSize, Protect, &FileOffset, AllocationType, __FILE__, __LINE__); 03892 } 03893 #endif 03894 Status = MmCreateMemoryArea(AddressSpace, 03895 MEMORY_AREA_SECTION_VIEW, 03896 BaseAddress, 03897 ViewSize, 03898 Protect, 03899 &MArea, 03900 FALSE, 03901 AllocationType, 03902 BoundaryAddressMultiple); 03903 if (!NT_SUCCESS(Status)) 03904 { 03905 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n", 03906 (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status); 03907 return(Status); 03908 } 03909 03910 ObReferenceObject((PVOID)Section); 03911 03912 MArea->Data.SectionData.Segment = Segment; 03913 MArea->Data.SectionData.Section = Section; 03914 MArea->Data.SectionData.ViewOffset.QuadPart = ViewOffset; 03915 MmInitializeRegion(&MArea->Data.SectionData.RegionListHead, 03916 ViewSize, 0, Protect); 03917 03918 return(STATUS_SUCCESS); 03919 } 03920 03921 03922 static VOID 03923 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, 03924 PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty) 03925 { 03926 ULONG_PTR Entry; 03927 PFILE_OBJECT FileObject; 03928 PBCB Bcb; 03929 LARGE_INTEGER Offset; 03930 SWAPENTRY SavedSwapEntry; 03931 PROS_SECTION_OBJECT Section; 03932 PMM_SECTION_SEGMENT Segment; 03933 PMMSUPPORT AddressSpace; 03934 PEPROCESS Process; 03935 03936 AddressSpace = (PMMSUPPORT)Context; 03937 Process = MmGetAddressSpaceOwner(AddressSpace); 03938 03939 Address = (PVOID)PAGE_ROUND_DOWN(Address); 03940 03941 Offset.QuadPart = ((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress) + 03942 MemoryArea->Data.SectionData.ViewOffset.QuadPart; 03943 03944 Section = MemoryArea->Data.SectionData.Section; 03945 Segment = MemoryArea->Data.SectionData.Segment; 03946 03947 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 03948 while (Entry && IS_SWAP_FROM_SSE(Entry) && SWAPENTRY_FROM_SSE(Entry) == MM_WAIT_ENTRY) 03949 { 03950 MmUnlockSectionSegment(Segment); 03951 MmUnlockAddressSpace(AddressSpace); 03952 03953 MiWaitForPageEvent(NULL, NULL); 03954 03955 MmLockAddressSpace(AddressSpace); 03956 MmLockSectionSegment(Segment); 03957 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 03958 } 03959 03960 /* 03961 * For a dirty, datafile, non-private page mark it as dirty in the 03962 * cache manager. 03963 */ 03964 if (Segment->Flags & MM_DATAFILE_SEGMENT) 03965 { 03966 if (Page == PFN_FROM_SSE(Entry) && Dirty) 03967 { 03968 FileObject = MemoryArea->Data.SectionData.Section->FileObject; 03969 Bcb = FileObject->SectionObjectPointer->SharedCacheMap; 03970 #ifndef NEWCC 03971 CcRosMarkDirtyCacheSegment(Bcb, (ULONG)(Offset.QuadPart + Segment->Image.FileOffset)); 03972 #endif 03973 ASSERT(SwapEntry == 0); 03974 } 03975 } 03976 03977 if (SwapEntry != 0) 03978 { 03979 /* 03980 * Sanity check 03981 */ 03982 if (Segment->Flags & MM_PAGEFILE_SEGMENT) 03983 { 03984 DPRINT1("Found a swap entry for a page in a pagefile section.\n"); 03985 KeBugCheck(MEMORY_MANAGEMENT); 03986 } 03987 MmFreeSwapPage(SwapEntry); 03988 } 03989 else if (Page != 0) 03990 { 03991 if (IS_SWAP_FROM_SSE(Entry) || 03992 Page != PFN_FROM_SSE(Entry)) 03993 { 03994 /* 03995 * Sanity check 03996 */ 03997 if (Segment->Flags & MM_PAGEFILE_SEGMENT) 03998 { 03999 DPRINT1("Found a private page in a pagefile section.\n"); 04000 KeBugCheck(MEMORY_MANAGEMENT); 04001 } 04002 /* 04003 * Just dereference private pages 04004 */ 04005 SavedSwapEntry = MmGetSavedSwapEntryPage(Page); 04006 if (SavedSwapEntry != 0) 04007 { 04008 MmFreeSwapPage(SavedSwapEntry); 04009 MmSetSavedSwapEntryPage(Page, 0); 04010 } 04011 MmDeleteRmap(Page, Process, Address); 04012 MmReleasePageMemoryConsumer(MC_USER, Page); 04013 } 04014 else 04015 { 04016 MmDeleteRmap(Page, Process, Address); 04017 MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, Dirty, FALSE, NULL); 04018 } 04019 } 04020 } 04021 04022 static NTSTATUS 04023 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace, 04024 PVOID BaseAddress) 04025 { 04026 NTSTATUS Status; 04027 PMEMORY_AREA MemoryArea; 04028 PROS_SECTION_OBJECT Section; 04029 PMM_SECTION_SEGMENT Segment; 04030 PLIST_ENTRY CurrentEntry; 04031 PMM_REGION CurrentRegion; 04032 PLIST_ENTRY RegionListHead; 04033 04034 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, 04035 BaseAddress); 04036 if (MemoryArea == NULL) 04037 { 04038 return(STATUS_UNSUCCESSFUL); 04039 } 04040 04041 MemoryArea->DeleteInProgress = TRUE; 04042 Section = MemoryArea->Data.SectionData.Section; 04043 Segment = MemoryArea->Data.SectionData.Segment; 04044 04045 #ifdef NEWCC 04046 if (Segment->Flags & MM_DATAFILE_SEGMENT) 04047 return MmUnmapViewOfCacheSegment(AddressSpace, BaseAddress); 04048 #endif 04049 04050 MmLockSectionSegment(Segment); 04051 04052 RegionListHead = &MemoryArea->Data.SectionData.RegionListHead; 04053 while (!IsListEmpty(RegionListHead)) 04054 { 04055 CurrentEntry = RemoveHeadList(RegionListHead); 04056 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry); 04057 ExFreePoolWithTag(CurrentRegion, TAG_MM_REGION); 04058 } 04059 04060 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY) 04061 { 04062 Status = MmFreeMemoryArea(AddressSpace, 04063 MemoryArea, 04064 NULL, 04065 NULL); 04066 } 04067 else 04068 { 04069 Status = MmFreeMemoryArea(AddressSpace, 04070 MemoryArea, 04071 MmFreeSectionPage, 04072 AddressSpace); 04073 } 04074 MmUnlockSectionSegment(Segment); 04075 ObDereferenceObject(Section); 04076 return(Status); 04077 } 04078 04079 NTSTATUS 04080 NTAPI 04081 MiRosUnmapViewOfSection(IN PEPROCESS Process, 04082 IN PVOID BaseAddress, 04083 IN ULONG Flags) 04084 { 04085 NTSTATUS Status; 04086 PMEMORY_AREA MemoryArea; 04087 PMMSUPPORT AddressSpace; 04088 PROS_SECTION_OBJECT Section; 04089 PVOID ImageBaseAddress = 0; 04090 04091 DPRINT("Opening memory area Process %x BaseAddress %x\n", 04092 Process, BaseAddress); 04093 04094 ASSERT(Process); 04095 04096 AddressSpace = &Process->Vm; 04097 04098 MmLockAddressSpace(AddressSpace); 04099 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, 04100 BaseAddress); 04101 if (MemoryArea == NULL || 04102 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW || 04103 MemoryArea->DeleteInProgress) 04104 { 04105 ASSERT(MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3); 04106 MmUnlockAddressSpace(AddressSpace); 04107 return STATUS_NOT_MAPPED_VIEW; 04108 } 04109 04110 MemoryArea->DeleteInProgress = TRUE; 04111 04112 Section = MemoryArea->Data.SectionData.Section; 04113 04114 if (Section->AllocationAttributes & SEC_IMAGE) 04115 { 04116 ULONG i; 04117 ULONG NrSegments; 04118 PMM_IMAGE_SECTION_OBJECT ImageSectionObject; 04119 PMM_SECTION_SEGMENT SectionSegments; 04120 PMM_SECTION_SEGMENT Segment; 04121 04122 Segment = MemoryArea->Data.SectionData.Segment; 04123 ImageSectionObject = Section->ImageSection; 04124 SectionSegments = ImageSectionObject->Segments; 04125 NrSegments = ImageSectionObject->NrSegments; 04126 04127 /* Search for the current segment within the section segments 04128 * and calculate the image base address */ 04129 for (i = 0; i < NrSegments; i++) 04130 { 04131 if (!(SectionSegments[i].Image.Characteristics & IMAGE_SCN_TYPE_NOLOAD)) 04132 { 04133 if (Segment == &SectionSegments[i]) 04134 { 04135 ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].Image.VirtualAddress; 04136 break; 04137 } 04138 } 04139 } 04140 if (i >= NrSegments) 04141 { 04142 KeBugCheck(MEMORY_MANAGEMENT); 04143 } 04144 04145 for (i = 0; i < NrSegments; i++) 04146 { 04147 if (!(SectionSegments[i].Image.Characteristics & IMAGE_SCN_TYPE_NOLOAD)) 04148 { 04149 PVOID SBaseAddress = (PVOID) 04150 ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress); 04151 04152 Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress); 04153 } 04154 } 04155 } 04156 else 04157 { 04158 Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress); 04159 } 04160 04161 MmUnlockAddressSpace(AddressSpace); 04162 04163 /* Notify debugger */ 04164 if (ImageBaseAddress) DbgkUnMapViewOfSection(ImageBaseAddress); 04165 04166 return(STATUS_SUCCESS); 04167 } 04168 04169 04170 04171 04194 NTSTATUS NTAPI 04195 NtQuerySection(IN HANDLE SectionHandle, 04196 IN SECTION_INFORMATION_CLASS SectionInformationClass, 04197 OUT PVOID SectionInformation, 04198 IN SIZE_T SectionInformationLength, 04199 OUT PSIZE_T ResultLength OPTIONAL) 04200 { 04201 PROS_SECTION_OBJECT Section; 04202 KPROCESSOR_MODE PreviousMode; 04203 NTSTATUS Status; 04204 PAGED_CODE(); 04205 04206 PreviousMode = ExGetPreviousMode(); 04207 04208 Status = DefaultQueryInfoBufferCheck(SectionInformationClass, 04209 ExSectionInfoClass, 04210 sizeof(ExSectionInfoClass) / sizeof(ExSectionInfoClass[0]), 04211 SectionInformation, 04212 (ULONG)SectionInformationLength, 04213 NULL, 04214 ResultLength, 04215 PreviousMode); 04216 04217 if(!NT_SUCCESS(Status)) 04218 { 04219 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status); 04220 return Status; 04221 } 04222 04223 Status = ObReferenceObjectByHandle(SectionHandle, 04224 SECTION_QUERY, 04225 MmSectionObjectType, 04226 PreviousMode, 04227 (PVOID*)(PVOID)&Section, 04228 NULL); 04229 if (NT_SUCCESS(Status)) 04230 { 04231 switch (SectionInformationClass) 04232 { 04233 case SectionBasicInformation: 04234 { 04235 PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation; 04236 04237 _SEH2_TRY 04238 { 04239 Sbi->Attributes = Section->AllocationAttributes; 04240 if (Section->AllocationAttributes & SEC_IMAGE) 04241 { 04242 Sbi->BaseAddress = 0; 04243 Sbi->Size.QuadPart = 0; 04244 } 04245 else 04246 { 04247 Sbi->BaseAddress = (PVOID)Section->Segment->Image.VirtualAddress; 04248 Sbi->Size.QuadPart = Section->Segment->Length.QuadPart; 04249 } 04250 04251 if (ResultLength != NULL) 04252 { 04253 *ResultLength = sizeof(SECTION_BASIC_INFORMATION); 04254 } 04255 Status = STATUS_SUCCESS; 04256 } 04257 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 04258 { 04259 Status = _SEH2_GetExceptionCode(); 04260 } 04261 _SEH2_END; 04262 04263 break; 04264 } 04265 04266 case SectionImageInformation: 04267 { 04268 PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation; 04269 04270 _SEH2_TRY 04271 { 04272 memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION)); 04273 if (Section->AllocationAttributes & SEC_IMAGE) 04274 { 04275 PMM_IMAGE_SECTION_OBJECT ImageSectionObject; 04276 ImageSectionObject = Section->ImageSection; 04277 04278 Sii->TransferAddress = (PVOID)ImageSectionObject->EntryPoint; 04279 Sii->MaximumStackSize = ImageSectionObject->StackReserve; 04280 Sii->CommittedStackSize = ImageSectionObject->StackCommit; 04281 Sii->SubSystemType = ImageSectionObject->Subsystem; 04282 Sii->SubSystemMinorVersion = ImageSectionObject->MinorSubsystemVersion; 04283 Sii->SubSystemMajorVersion = ImageSectionObject->MajorSubsystemVersion; 04284 Sii->ImageCharacteristics = ImageSectionObject->ImageCharacteristics; 04285 Sii->Machine = ImageSectionObject->Machine; 04286 Sii->ImageContainsCode = ImageSectionObject->Executable; 04287 } 04288 04289 if (ResultLength != NULL) 04290 { 04291 *ResultLength = sizeof(SECTION_IMAGE_INFORMATION); 04292 } 04293 Status = STATUS_SUCCESS; 04294 } 04295 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 04296 { 04297 Status = _SEH2_GetExceptionCode(); 04298 } 04299 _SEH2_END; 04300 04301 break; 04302 } 04303 } 04304 04305 ObDereferenceObject(Section); 04306 } 04307 04308 return(Status); 04309 } 04310 04311 /********************************************************************** 04312 * NAME EXPORTED 04313 * MmMapViewOfSection 04314 * 04315 * DESCRIPTION 04316 * Maps a view of a section into the virtual address space of a 04317 * process. 04318 * 04319 * ARGUMENTS 04320 * Section 04321 * Pointer to the section object. 04322 * 04323 * ProcessHandle 04324 * Pointer to the process. 04325 * 04326 * BaseAddress 04327 * Desired base address (or NULL) on entry; 04328 * Actual base address of the view on exit. 04329 * 04330 * ZeroBits 04331 * Number of high order address bits that must be zero. 04332 * 04333 * CommitSize 04334 * Size in bytes of the initially committed section of 04335 * the view. 04336 * 04337 * SectionOffset 04338 * Offset in bytes from the beginning of the section 04339 * to the beginning of the view. 04340 * 04341 * ViewSize 04342 * Desired length of map (or zero to map all) on entry 04343 * Actual length mapped on exit. 04344 * 04345 * InheritDisposition 04346 * Specified how the view is to be shared with 04347 * child processes. 04348 * 04349 * AllocationType 04350 * Type of allocation for the pages. 04351 * 04352 * Protect 04353 * Protection for the committed region of the view. 04354 * 04355 * RETURN VALUE 04356 * Status. 04357 * 04358 * @implemented 04359 */ 04360 NTSTATUS NTAPI 04361 MmMapViewOfSection(IN PVOID SectionObject, 04362 IN PEPROCESS Process, 04363 IN OUT PVOID *BaseAddress, 04364 IN ULONG_PTR ZeroBits, 04365 IN SIZE_T CommitSize, 04366 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, 04367 IN OUT PSIZE_T ViewSize, 04368 IN SECTION_INHERIT InheritDisposition, 04369 IN ULONG AllocationType, 04370 IN ULONG Protect) 04371 { 04372 PROS_SECTION_OBJECT Section; 04373 PMMSUPPORT AddressSpace; 04374 ULONG ViewOffset; 04375 NTSTATUS Status = STATUS_SUCCESS; 04376 BOOLEAN NotAtBase = FALSE; 04377 04378 if (MiIsRosSectionObject(SectionObject) == FALSE) 04379 { 04380 DPRINT("Mapping ARM3 section into %s\n", Process->ImageFileName); 04381 return MmMapViewOfArm3Section(SectionObject, 04382 Process, 04383 BaseAddress, 04384 ZeroBits, 04385 CommitSize, 04386 SectionOffset, 04387 ViewSize, 04388 InheritDisposition, 04389 AllocationType, 04390 Protect); 04391 } 04392 04393 ASSERT(Process); 04394 04395 if (!Protect || Protect & ~PAGE_FLAGS_VALID_FOR_SECTION) 04396 { 04397 return STATUS_INVALID_PAGE_PROTECTION; 04398 } 04399 04400 04401 Section = (PROS_SECTION_OBJECT)SectionObject; 04402 AddressSpace = &Process->Vm; 04403 04404 AllocationType |= (Section->AllocationAttributes & SEC_NO_CHANGE); 04405 04406 MmLockAddressSpace(AddressSpace); 04407 04408 if (Section->AllocationAttributes & SEC_IMAGE) 04409 { 04410 ULONG i; 04411 ULONG NrSegments; 04412 ULONG_PTR ImageBase; 04413 SIZE_T ImageSize; 04414 PMM_IMAGE_SECTION_OBJECT ImageSectionObject; 04415 PMM_SECTION_SEGMENT SectionSegments; 04416 04417 ImageSectionObject = Section->ImageSection; 04418 SectionSegments = ImageSectionObject->Segments; 04419 NrSegments = ImageSectionObject->NrSegments; 04420 04421 04422 ImageBase = (ULONG_PTR)*BaseAddress; 04423 if (ImageBase == 0) 04424 { 04425 ImageBase = ImageSectionObject->ImageBase; 04426 } 04427 04428 ImageSize = 0; 04429 for (i = 0; i < NrSegments; i++) 04430 { 04431 if (!(SectionSegments[i].Image.Characteristics & IMAGE_SCN_TYPE_NOLOAD)) 04432 { 04433 ULONG_PTR MaxExtent; 04434 MaxExtent = (ULONG_PTR)(SectionSegments[i].Image.VirtualAddress + 04435 SectionSegments[i].Length.QuadPart); 04436 ImageSize = max(ImageSize, MaxExtent); 04437 } 04438 } 04439 04440 ImageSectionObject->ImageSize = (ULONG)ImageSize; 04441 04442 /* Check for an illegal base address */ 04443 if ((ImageBase + ImageSize) > (ULONG_PTR)MmHighestUserAddress) 04444 { 04445 ImageBase = PAGE_ROUND_DOWN((ULONG_PTR)MmHighestUserAddress - ImageSize); 04446 } 04447 04448 /* Check there is enough space to map the section at that point. */ 04449 if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase, 04450 PAGE_ROUND_UP(ImageSize)) != NULL) 04451 { 04452 /* Fail if the user requested a fixed base address. */ 04453 if ((*BaseAddress) != NULL) 04454 { 04455 MmUnlockAddressSpace(AddressSpace); 04456 return(STATUS_UNSUCCESSFUL); 04457 } 04458 /* Otherwise find a gap to map the image. */ 04459 ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), PAGE_SIZE, FALSE); 04460 if (ImageBase == 0) 04461 { 04462 MmUnlockAddressSpace(AddressSpace); 04463 return(STATUS_UNSUCCESSFUL); 04464 } 04465 /* Remember that we loaded image at a different base address */ 04466 NotAtBase = TRUE; 04467 } 04468 04469 for (i = 0; i < NrSegments; i++) 04470 { 04471 if (!(SectionSegments[i].Image.Characteristics & IMAGE_SCN_TYPE_NOLOAD)) 04472 { 04473 PVOID SBaseAddress = (PVOID) 04474 ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress); 04475 MmLockSectionSegment(&SectionSegments[i]); 04476 Status = MmMapViewOfSegment(AddressSpace, 04477 Section, 04478 &SectionSegments[i], 04479 &SBaseAddress, 04480 SectionSegments[i].Length.LowPart, 04481 SectionSegments[i].Protection, 04482 0, 04483 0); 04484 MmUnlockSectionSegment(&SectionSegments[i]); 04485 if (!NT_SUCCESS(Status)) 04486 { 04487 MmUnlockAddressSpace(AddressSpace); 04488 return(Status); 04489 } 04490 } 04491 } 04492 04493 *BaseAddress = (PVOID)ImageBase; 04494 *ViewSize = ImageSize; 04495 } 04496 else 04497 { 04498 /* check for write access */ 04499 if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) && 04500 !(Section->SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))) 04501 { 04502 MmUnlockAddressSpace(AddressSpace); 04503 return STATUS_SECTION_PROTECTION; 04504 } 04505 /* check for read access */ 04506 if ((Protect & (PAGE_READONLY|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_WRITECOPY)) && 04507 !(Section->SectionPageProtection & (PAGE_READONLY|PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY))) 04508 { 04509 MmUnlockAddressSpace(AddressSpace); 04510 return STATUS_SECTION_PROTECTION; 04511 } 04512 /* check for execute access */ 04513 if ((Protect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)) && 04514 !(Section->SectionPageProtection & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY))) 04515 { 04516 MmUnlockAddressSpace(AddressSpace); 04517 return STATUS_SECTION_PROTECTION; 04518 } 04519 04520 if (ViewSize == NULL) 04521 { 04522 /* Following this pointer would lead to us to the dark side */ 04523 /* What to do? Bugcheck? Return status? Do the mambo? */ 04524 KeBugCheck(MEMORY_MANAGEMENT); 04525 } 04526 04527 if (SectionOffset == NULL) 04528 { 04529 ViewOffset = 0; 04530 } 04531 else 04532 { 04533 ViewOffset = SectionOffset->u.LowPart; 04534 } 04535 04536 if ((ViewOffset % PAGE_SIZE) != 0) 04537 { 04538 MmUnlockAddressSpace(AddressSpace); 04539 return(STATUS_MAPPED_ALIGNMENT); 04540 } 04541 04542 if ((*ViewSize) == 0) 04543 { 04544 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset; 04545 } 04546 else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart) 04547 { 04548 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset; 04549 } 04550 04551 *ViewSize = PAGE_ROUND_UP(*ViewSize); 04552 04553 MmLockSectionSegment(Section->Segment); 04554 Status = MmMapViewOfSegment(AddressSpace, 04555 Section, 04556 Section->Segment, 04557 BaseAddress, 04558 *ViewSize, 04559 Protect, 04560 ViewOffset, 04561 AllocationType & (MEM_TOP_DOWN|SEC_NO_CHANGE)); 04562 MmUnlockSectionSegment(Section->Segment); 04563 if (!NT_SUCCESS(Status)) 04564 { 04565 MmUnlockAddressSpace(AddressSpace); 04566 return(Status); 04567 } 04568 } 04569 04570 MmUnlockAddressSpace(AddressSpace); 04571 04572 if (NotAtBase) 04573 Status = STATUS_IMAGE_NOT_AT_BASE; 04574 else 04575 Status = STATUS_SUCCESS; 04576 04577 return Status; 04578 } 04579 04580 /* 04581 * @unimplemented 04582 */ 04583 BOOLEAN NTAPI 04584 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer, 04585 IN PLARGE_INTEGER NewFileSize) 04586 { 04587 /* Check whether an ImageSectionObject exists */ 04588 if (SectionObjectPointer->ImageSectionObject != NULL) 04589 { 04590 DPRINT1("ERROR: File can't be truncated because it has an image section\n"); 04591 return FALSE; 04592 } 04593 04594 if (SectionObjectPointer->DataSectionObject != NULL) 04595 { 04596 PMM_SECTION_SEGMENT Segment; 04597 04598 Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer-> 04599 DataSectionObject; 04600 04601 if (Segment->ReferenceCount != 0) 04602 { 04603 #ifdef NEWCC 04604 CC_FILE_SIZES FileSizes; 04605 CcpLock(); 04606 if (SectionObjectPointer->SharedCacheMap && (Segment->ReferenceCount > CcpCountCacheSections((PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap))) 04607 { 04608 CcpUnlock(); 04609 /* Check size of file */ 04610 if (SectionObjectPointer->SharedCacheMap) 04611 { 04612 if (!CcGetFileSizes(Segment->FileObject, &FileSizes)) 04613 { 04614 return FALSE; 04615 } 04616 04617 if (NewFileSize->QuadPart <= FileSizes.FileSize.QuadPart) 04618 { 04619 return FALSE; 04620 } 04621 } 04622 } 04623 else 04624 CcpUnlock(); 04625 #else 04626 /* Check size of file */ 04627 if (SectionObjectPointer->SharedCacheMap) 04628 { 04629 PBCB Bcb = SectionObjectPointer->SharedCacheMap; 04630 if (NewFileSize->QuadPart <= Bcb->FileSize.QuadPart) 04631 { 04632 return FALSE; 04633 } 04634 } 04635 #endif 04636 } 04637 else 04638 { 04639 /* Something must gone wrong 04640 * how can we have a Section but no 04641 * reference? */ 04642 DPRINT("ERROR: DataSectionObject without reference!\n"); 04643 } 04644 } 04645 04646 DPRINT("FIXME: didn't check for outstanding write probes\n"); 04647 04648 return TRUE; 04649 } 04650 04651 04652 04653 04654 /* 04655 * @implemented 04656 */ 04657 BOOLEAN NTAPI 04658 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer, 04659 IN MMFLUSH_TYPE FlushType) 04660 { 04661 BOOLEAN Result = TRUE; 04662 #ifdef NEWCC 04663 PMM_SECTION_SEGMENT Segment; 04664 #endif 04665 04666 switch(FlushType) 04667 { 04668 case MmFlushForDelete: 04669 if (SectionObjectPointer->ImageSectionObject || 04670 SectionObjectPointer->DataSectionObject) 04671 { 04672 return FALSE; 04673 } 04674 #ifndef NEWCC 04675 CcRosSetRemoveOnClose(SectionObjectPointer); 04676 #endif 04677 return TRUE; 04678 case MmFlushForWrite: 04679 { 04680 DPRINT("MmFlushImageSection(%d)\n", FlushType); 04681 #ifdef NEWCC 04682 Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->DataSectionObject; 04683 #endif 04684 04685 if (SectionObjectPointer->ImageSectionObject) { 04686 DPRINT1("SectionObject has ImageSection\n"); 04687 return FALSE; 04688 } 04689 04690 #ifdef NEWCC 04691 CcpLock(); 04692 Result = !SectionObjectPointer->SharedCacheMap || (Segment->ReferenceCount == CcpCountCacheSections((PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap)); 04693 CcpUnlock(); 04694 DPRINT("Result %d\n", Result); 04695 #endif 04696 return Result; 04697 } 04698 } 04699 return FALSE; 04700 } 04701 04702 /* 04703 * @implemented 04704 */ 04705 NTSTATUS NTAPI 04706 MmMapViewInSystemSpace (IN PVOID SectionObject, 04707 OUT PVOID * MappedBase, 04708 IN OUT PSIZE_T ViewSize) 04709 { 04710 PROS_SECTION_OBJECT Section; 04711 PMMSUPPORT AddressSpace; 04712 NTSTATUS Status; 04713 PAGED_CODE(); 04714 04715 if (MiIsRosSectionObject(SectionObject) == FALSE) 04716 { 04717 return MiMapViewInSystemSpace(SectionObject, 04718 &MmSession, 04719 MappedBase, 04720 ViewSize); 04721 } 04722 04723 DPRINT("MmMapViewInSystemSpace() called\n"); 04724 04725 Section = (PROS_SECTION_OBJECT)SectionObject; 04726 AddressSpace = MmGetKernelAddressSpace(); 04727 04728 MmLockAddressSpace(AddressSpace); 04729 04730 04731 if ((*ViewSize) == 0) 04732 { 04733 (*ViewSize) = Section->MaximumSize.u.LowPart; 04734 } 04735 else if ((*ViewSize) > Section->MaximumSize.u.LowPart) 04736 { 04737 (*ViewSize) = Section->MaximumSize.u.LowPart; 04738 } 04739 04740 MmLockSectionSegment(Section->Segment); 04741 04742 04743 Status = MmMapViewOfSegment(AddressSpace, 04744 Section, 04745 Section->Segment, 04746 MappedBase, 04747 *ViewSize, 04748 PAGE_READWRITE, 04749 0, 04750 0); 04751 04752 MmUnlockSectionSegment(Section->Segment); 04753 MmUnlockAddressSpace(AddressSpace); 04754 04755 return Status; 04756 } 04757 04758 NTSTATUS 04759 NTAPI 04760 MiRosUnmapViewInSystemSpace(IN PVOID MappedBase) 04761 { 04762 PMMSUPPORT AddressSpace; 04763 NTSTATUS Status; 04764 04765 DPRINT("MmUnmapViewInSystemSpace() called\n"); 04766 04767 AddressSpace = MmGetKernelAddressSpace(); 04768 04769 MmLockAddressSpace(AddressSpace); 04770 04771 Status = MmUnmapViewOfSegment(AddressSpace, MappedBase); 04772 04773 MmUnlockAddressSpace(AddressSpace); 04774 04775 return Status; 04776 } 04777 04778 /********************************************************************** 04779 * NAME EXPORTED 04780 * MmCreateSection@ 04781 * 04782 * DESCRIPTION 04783 * Creates a section object. 04784 * 04785 * ARGUMENTS 04786 * SectionObject (OUT) 04787 * Caller supplied storage for the resulting pointer 04788 * to a SECTION_OBJECT instance; 04789 * 04790 * DesiredAccess 04791 * Specifies the desired access to the section can be a 04792 * combination of: 04793 * STANDARD_RIGHTS_REQUIRED | 04794 * SECTION_QUERY | 04795 * SECTION_MAP_WRITE | 04796 * SECTION_MAP_READ | 04797 * SECTION_MAP_EXECUTE 04798 * 04799 * ObjectAttributes [OPTIONAL] 04800 * Initialized attributes for the object can be used 04801 * to create a named section; 04802 * 04803 * MaximumSize 04804 * Maximizes the size of the memory section. Must be 04805 * non-NULL for a page-file backed section. 04806 * If value specified for a mapped file and the file is 04807 * not large enough, file will be extended. 04808 * 04809 * SectionPageProtection 04810 * Can be a combination of: 04811 * PAGE_READONLY | 04812 * PAGE_READWRITE | 04813 * PAGE_WRITEONLY | 04814 * PAGE_WRITECOPY 04815 * 04816 * AllocationAttributes 04817 * Can be a combination of: 04818 * SEC_IMAGE | 04819 * SEC_RESERVE 04820 * 04821 * FileHandle 04822 * Handle to a file to create a section mapped to a file 04823 * instead of a memory backed section; 04824 * 04825 * File 04826 * Unknown. 04827 * 04828 * RETURN VALUE 04829 * Status. 04830 * 04831 * @implemented 04832 */ 04833 NTSTATUS NTAPI 04834 MmCreateSection (OUT PVOID * Section, 04835 IN ACCESS_MASK DesiredAccess, 04836 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 04837 IN PLARGE_INTEGER MaximumSize, 04838 IN ULONG SectionPageProtection, 04839 IN ULONG AllocationAttributes, 04840 IN HANDLE FileHandle OPTIONAL, 04841 IN PFILE_OBJECT FileObject OPTIONAL) 04842 { 04843 NTSTATUS Status; 04844 ULONG Protection, FileAccess; 04845 PROS_SECTION_OBJECT *SectionObject = (PROS_SECTION_OBJECT *)Section; 04846 04847 /* Check if an ARM3 section is being created instead */ 04848 if (AllocationAttributes & 1) 04849 { 04850 DPRINT1("Creating ARM3 section\n"); 04851 return MmCreateArm3Section(Section, 04852 DesiredAccess, 04853 ObjectAttributes, 04854 MaximumSize, 04855 SectionPageProtection, 04856 AllocationAttributes &~ 1, 04857 FileHandle, 04858 FileObject); 04859 } 04860 04861 /* 04862 * Check the protection 04863 */ 04864 Protection = SectionPageProtection & ~(PAGE_GUARD | PAGE_NOCACHE); 04865 if (Protection != PAGE_READONLY && 04866 Protection != PAGE_READWRITE && 04867 Protection != PAGE_WRITECOPY && 04868 Protection != PAGE_EXECUTE && 04869 Protection != PAGE_EXECUTE_READ && 04870 Protection != PAGE_EXECUTE_READWRITE && 04871 Protection != PAGE_EXECUTE_WRITECOPY) 04872 { 04873 return STATUS_INVALID_PAGE_PROTECTION; 04874 } 04875 04876 if ((DesiredAccess & SECTION_MAP_WRITE) && 04877 (Protection == PAGE_READWRITE || 04878 Protection == PAGE_EXECUTE_READWRITE) && 04879 !(AllocationAttributes & SEC_IMAGE)) 04880 { 04881 DPRINT("Creating a section with WRITE access\n"); 04882 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE; 04883 } 04884 else 04885 { 04886 DPRINT("Creating a section with READ access\n"); 04887 FileAccess = FILE_READ_DATA | SYNCHRONIZE; 04888 } 04889 04890 /* FIXME: somehow combine this with the above checks */ 04891 if (AllocationAttributes & SEC_IMAGE) 04892 FileAccess = MiArm3GetCorrectFileAccessMask(SectionPageProtection); 04893 04894 if (!FileObject && FileHandle) 04895 { 04896 Status = ObReferenceObjectByHandle(FileHandle, 04897 FileAccess, 04898 IoFileObjectType, 04899 ExGetPreviousMode(), 04900 (PVOID *)&FileObject, 04901 NULL); 04902 if (!NT_SUCCESS(Status)) 04903 { 04904 DPRINT("Failed: 0x%08lx\n", Status); 04905 return Status; 04906 } 04907 } 04908 else if (FileObject) 04909 ObReferenceObject(FileObject); 04910 04911 #ifndef NEWCC // A hack for initializing caching. 04912 // This is needed only in the old case. 04913 if (FileHandle) 04914 { 04915 IO_STATUS_BLOCK Iosb; 04916 NTSTATUS Status; 04917 CHAR Buffer; 04918 LARGE_INTEGER ByteOffset; 04919 ByteOffset.QuadPart = 0; 04920 Status = ZwReadFile(FileHandle, 04921 NULL, 04922 NULL, 04923 NULL, 04924 &Iosb, 04925 &Buffer, 04926 sizeof(Buffer), 04927 &ByteOffset, 04928 NULL); 04929 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE) 04930 return Status; 04931 // Caching is initialized... 04932 } 04933 #endif 04934 04935 if (AllocationAttributes & SEC_IMAGE) 04936 { 04937 Status = MmCreateImageSection(SectionObject, 04938 DesiredAccess, 04939 ObjectAttributes, 04940 MaximumSize, 04941 SectionPageProtection, 04942 AllocationAttributes, 04943 FileObject); 04944 } 04945 #ifndef NEWCC 04946 else if (FileHandle != NULL) 04947 { 04948 Status = MmCreateDataFileSection(SectionObject, 04949 DesiredAccess, 04950 ObjectAttributes, 04951 MaximumSize, 04952 SectionPageProtection, 04953 AllocationAttributes, 04954 FileHandle); 04955 if (FileObject) 04956 ObDereferenceObject(FileObject); 04957 } 04958 #else 04959 else if (FileHandle != NULL || FileObject != NULL) 04960 { 04961 Status = MmCreateCacheSection(SectionObject, 04962 DesiredAccess, 04963 ObjectAttributes, 04964 MaximumSize, 04965 SectionPageProtection, 04966 AllocationAttributes, 04967 FileObject); 04968 } 04969 #endif 04970 else 04971 { 04972 Status = MmCreatePageFileSection(SectionObject, 04973 DesiredAccess, 04974 ObjectAttributes, 04975 MaximumSize, 04976 SectionPageProtection, 04977 AllocationAttributes); 04978 } 04979 04980 return Status; 04981 } 04982 04983 VOID 04984 MmModifyAttributes(IN PMMSUPPORT AddressSpace, 04985 IN PVOID BaseAddress, 04986 IN SIZE_T RegionSize, 04987 IN ULONG OldType, 04988 IN ULONG OldProtect, 04989 IN ULONG NewType, 04990 IN ULONG NewProtect) 04991 { 04992 // 04993 // This function is deprecated but remains in order to support VirtualAlloc 04994 // calls with MEM_COMMIT on top of MapViewOfFile calls with SEC_RESERVE. 04995 // 04996 // Win32k's shared user heap, for example, uses that mechanism. The two 04997 // conditions when this function needs to do something are ASSERTed for, 04998 // because they should not arise. 04999 // 05000 if (NewType == MEM_RESERVE && OldType == MEM_COMMIT) 05001 { 05002 ASSERT(FALSE); 05003 } 05004 05005 if ((NewType == MEM_COMMIT) && (OldType == MEM_COMMIT)) 05006 { 05007 ASSERT(OldProtect == NewProtect); 05008 } 05009 } 05010 05011 NTSTATUS 05012 NTAPI 05013 MiRosAllocateVirtualMemory(IN HANDLE ProcessHandle, 05014 IN PEPROCESS Process, 05015 IN PMEMORY_AREA MemoryArea, 05016 IN PMMSUPPORT AddressSpace, 05017 IN OUT PVOID* UBaseAddress, 05018 IN BOOLEAN Attached, 05019 IN OUT PSIZE_T URegionSize, 05020 IN ULONG AllocationType, 05021 IN ULONG Protect) 05022 { 05023 ULONG_PTR PRegionSize; 05024 ULONG Type, RegionSize; 05025 NTSTATUS Status; 05026 PVOID PBaseAddress, BaseAddress; 05027 KAPC_STATE ApcState; 05028 05029 PBaseAddress = *UBaseAddress; 05030 PRegionSize = *URegionSize; 05031 05032 BaseAddress = (PVOID)PAGE_ROUND_DOWN(PBaseAddress); 05033 RegionSize = PAGE_ROUND_UP((ULONG_PTR)PBaseAddress + PRegionSize) - 05034 PAGE_ROUND_DOWN(PBaseAddress); 05035 Type = (AllocationType & MEM_COMMIT) ? MEM_COMMIT : MEM_RESERVE; 05036 05037 ASSERT(PBaseAddress != 0); 05038 ASSERT(Type == MEM_COMMIT); 05039 ASSERT(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW); 05040 ASSERT(((ULONG_PTR)BaseAddress + RegionSize) <= (ULONG_PTR)MemoryArea->EndingAddress); 05041 ASSERT(((ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)MemoryArea->StartingAddress) >= RegionSize); 05042 ASSERT(MemoryArea->Data.SectionData.RegionListHead.Flink); 05043 05044 Status = MmAlterRegion(AddressSpace, 05045 MemoryArea->StartingAddress, 05046 &MemoryArea->Data.SectionData.RegionListHead, 05047 BaseAddress, 05048 RegionSize, 05049 Type, 05050 Protect, 05051 MmModifyAttributes); 05052 05053 MmUnlockAddressSpace(AddressSpace); 05054 if (Attached) KeUnstackDetachProcess(&ApcState); 05055 if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process); 05056 if (NT_SUCCESS(Status)) 05057 { 05058 *UBaseAddress = BaseAddress; 05059 *URegionSize = RegionSize; 05060 } 05061 05062 return Status; 05063 } 05064 05065 NTSTATUS 05066 NTAPI 05067 MiRosProtectVirtualMemory(IN PEPROCESS Process, 05068 IN OUT PVOID *BaseAddress, 05069 IN OUT PSIZE_T NumberOfBytesToProtect, 05070 IN ULONG NewAccessProtection, 05071 OUT PULONG OldAccessProtection OPTIONAL) 05072 { 05073 PMEMORY_AREA MemoryArea; 05074 PMMSUPPORT AddressSpace; 05075 ULONG OldAccessProtection_; 05076 NTSTATUS Status; 05077 05078 *NumberOfBytesToProtect = PAGE_ROUND_UP((ULONG_PTR)(*BaseAddress) + (*NumberOfBytesToProtect)) - PAGE_ROUND_DOWN(*BaseAddress); 05079 *BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress); 05080 05081 AddressSpace = &Process->Vm; 05082 MmLockAddressSpace(AddressSpace); 05083 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress); 05084 if (MemoryArea == NULL || MemoryArea->DeleteInProgress) 05085 { 05086 MmUnlockAddressSpace(AddressSpace); 05087 return STATUS_UNSUCCESSFUL; 05088 } 05089 05090 if (OldAccessProtection == NULL) OldAccessProtection = &OldAccessProtection_; 05091 05092 if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) 05093 { 05094 Status = MmProtectSectionView(AddressSpace, 05095 MemoryArea, 05096 *BaseAddress, 05097 *NumberOfBytesToProtect, 05098 NewAccessProtection, 05099 OldAccessProtection); 05100 } 05101 else 05102 { 05103 /* FIXME: Should we return failure or success in this case? */ 05104 Status = STATUS_CONFLICTING_ADDRESSES; 05105 } 05106 05107 MmUnlockAddressSpace(AddressSpace); 05108 05109 return Status; 05110 } 05111 05112 /* EOF */ Generated on Sun May 27 2012 04:37:36 for ReactOS by
1.7.6.1
|