ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

section.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.