reactos/ntoskrnl/mm/section.c
Jérôme Gardou df25e4e791 [NTOS/MM] Properly handle page faults in regions marked with
PAGE_NOACCESS or PAGE_GUARD

ROSTESTS-110
2018-11-03 12:50:16 +01:00

5157 lines
168 KiB
C

/*
* Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/section.c
* PURPOSE: Implements section objects
*
* PROGRAMMERS: Rex Jolliff
* David Welch
* Eric Kohl
* Emanuele Aliberti
* Eugene Ingerman
* Casper Hornstrup
* KJK::Hyperion
* Guido de Jong
* Ge van Geldorp
* Royce Mitchell III
* Filip Navara
* Aleksey Bragin
* Jason Filby
* Thomas Weidenmueller
* Gunnar Andre' Dalsnes
* Mike Nordell
* Alex Ionescu
* Gregor Anich
* Steven Edwards
* Herve Poussineau
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#include <cache/newcc.h>
#include <cache/section/newmm.h>
#define NDEBUG
#include <debug.h>
#include <reactos/exeformat.h>
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
#pragma alloc_text(INIT, MmInitSectionImplementation)
#endif
#include "ARM3/miarm.h"
#undef MmSetPageEntrySectionSegment
#define MmSetPageEntrySectionSegment(S,O,E) do { \
DPRINT("SetPageEntrySectionSegment(old,%p,%x,%x)\n",(S),(O)->LowPart,E); \
_MmSetPageEntrySectionSegment((S),(O),(E),__FILE__,__LINE__); \
} while (0)
extern MMSESSION MmSession;
NTSTATUS
NTAPI
MiMapViewInSystemSpace(IN PVOID Section,
IN PVOID Session,
OUT PVOID *MappedBase,
IN OUT PSIZE_T ViewSize);
NTSTATUS
NTAPI
MmCreateArm3Section(OUT PVOID *SectionObject,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN PLARGE_INTEGER InputMaximumSize,
IN ULONG SectionPageProtection,
IN ULONG AllocationAttributes,
IN HANDLE FileHandle OPTIONAL,
IN PFILE_OBJECT FileObject OPTIONAL);
NTSTATUS
NTAPI
MmMapViewOfArm3Section(IN PVOID SectionObject,
IN PEPROCESS Process,
IN OUT PVOID *BaseAddress,
IN ULONG_PTR ZeroBits,
IN SIZE_T CommitSize,
IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
IN OUT PSIZE_T ViewSize,
IN SECTION_INHERIT InheritDisposition,
IN ULONG AllocationType,
IN ULONG Protect);
//
// PeFmtCreateSection depends on the following:
//
C_ASSERT(EXEFMT_LOAD_HEADER_SIZE >= sizeof(IMAGE_DOS_HEADER));
C_ASSERT(sizeof(IMAGE_NT_HEADERS32) <= sizeof(IMAGE_NT_HEADERS64));
C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64));
C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64, FileHeader));
C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader) == FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Magic));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SectionAlignment));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, FileAlignment));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Subsystem));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MinorSubsystemVersion));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MajorSubsystemVersion));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfHeaders));
/* TYPES *********************************************************************/
typedef struct
{
PROS_SECTION_OBJECT Section;
PMM_SECTION_SEGMENT Segment;
LARGE_INTEGER Offset;
BOOLEAN WasDirty;
BOOLEAN Private;
PEPROCESS CallingProcess;
ULONG_PTR SectionEntry;
}
MM_SECTION_PAGEOUT_CONTEXT;
/* GLOBALS *******************************************************************/
POBJECT_TYPE MmSectionObjectType = NULL;
ULONG_PTR MmSubsectionBase;
static ULONG SectionCharacteristicsToProtect[16] =
{
PAGE_NOACCESS, /* 0 = NONE */
PAGE_NOACCESS, /* 1 = SHARED */
PAGE_EXECUTE, /* 2 = EXECUTABLE */
PAGE_EXECUTE, /* 3 = EXECUTABLE, SHARED */
PAGE_READONLY, /* 4 = READABLE */
PAGE_READONLY, /* 5 = READABLE, SHARED */
PAGE_EXECUTE_READ, /* 6 = READABLE, EXECUTABLE */
PAGE_EXECUTE_READ, /* 7 = READABLE, EXECUTABLE, SHARED */
/*
* FIXME? do we really need the WriteCopy field in segments? can't we use
* PAGE_WRITECOPY here?
*/
PAGE_READWRITE, /* 8 = WRITABLE */
PAGE_READWRITE, /* 9 = WRITABLE, SHARED */
PAGE_EXECUTE_READWRITE, /* 10 = WRITABLE, EXECUTABLE */
PAGE_EXECUTE_READWRITE, /* 11 = WRITABLE, EXECUTABLE, SHARED */
PAGE_READWRITE, /* 12 = WRITABLE, READABLE */
PAGE_READWRITE, /* 13 = WRITABLE, READABLE, SHARED */
PAGE_EXECUTE_READWRITE, /* 14 = WRITABLE, READABLE, EXECUTABLE */
PAGE_EXECUTE_READWRITE, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
};
extern ULONG MmMakeFileAccess [];
ACCESS_MASK NTAPI MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection);
static GENERIC_MAPPING MmpSectionMapping =
{
STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY,
STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE,
STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
SECTION_ALL_ACCESS
};
/* FUNCTIONS *****************************************************************/
/*
References:
[1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
File Format Specification", revision 6.0 (February 1999)
*/
NTSTATUS NTAPI PeFmtCreateSection(IN CONST VOID * FileHeader,
IN SIZE_T FileHeaderSize,
IN PVOID File,
OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
OUT PULONG Flags,
IN PEXEFMT_CB_READ_FILE ReadFileCb,
IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb)
{
NTSTATUS nStatus;
ULONG cbFileHeaderOffsetSize = 0;
ULONG cbSectionHeadersOffset = 0;
ULONG cbSectionHeadersSize;
ULONG cbSectionHeadersOffsetSize = 0;
ULONG cbOptHeaderSize;
ULONG cbHeadersSize = 0;
ULONG nSectionAlignment;
ULONG nFileAlignment;
ULONG_PTR ImageBase;
const IMAGE_DOS_HEADER * pidhDosHeader;
const IMAGE_NT_HEADERS32 * pinhNtHeader;
const IMAGE_OPTIONAL_HEADER32 * piohOptHeader;
const IMAGE_SECTION_HEADER * pishSectionHeaders;
PMM_SECTION_SEGMENT pssSegments;
LARGE_INTEGER lnOffset;
PVOID pBuffer;
SIZE_T nPrevVirtualEndOfSegment = 0;
ULONG nFileSizeOfHeaders = 0;
ULONG i;
ULONG AlignedLength;
ASSERT(FileHeader);
ASSERT(FileHeaderSize > 0);
ASSERT(File);
ASSERT(ImageSectionObject);
ASSERT(ReadFileCb);
ASSERT(AllocateSegmentsCb);
ASSERT(Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize));
ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_DOS_HEADER)) == 0);
#define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
pBuffer = NULL;
pidhDosHeader = FileHeader;
/* DOS HEADER */
nStatus = STATUS_ROS_EXEFMT_UNKNOWN_FORMAT;
/* image too small to be an MZ executable */
if(FileHeaderSize < sizeof(IMAGE_DOS_HEADER))
DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize));
/* no MZ signature */
if(pidhDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader->e_magic));
/* NT HEADER */
nStatus = STATUS_INVALID_IMAGE_PROTECT;
/* not a Windows executable */
if(pidhDosHeader->e_lfanew <= 0)
DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew));
if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize, pidhDosHeader->e_lfanew, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader)))
DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
if(FileHeaderSize < cbFileHeaderOffsetSize)
pinhNtHeader = NULL;
else
{
/*
* we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
* and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
*/
ASSERT(Intsafe_CanOffsetPointer(FileHeader, pidhDosHeader->e_lfanew));
pinhNtHeader = (PVOID)((UINT_PTR)FileHeader + pidhDosHeader->e_lfanew);
}
/*
* the buffer doesn't contain the NT file header, or the alignment is wrong: we
* need to read the header from the file
*/
if(FileHeaderSize < cbFileHeaderOffsetSize ||
(UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
{
ULONG cbNtHeaderSize;
ULONG cbReadSize;
PVOID pData;
l_ReadHeaderFromFile:
cbNtHeaderSize = 0;
lnOffset.QuadPart = pidhDosHeader->e_lfanew;
/* read the header from the file */
nStatus = ReadFileCb(File, &lnOffset, sizeof(IMAGE_NT_HEADERS64), &pData, &pBuffer, &cbReadSize);
if(!NT_SUCCESS(nStatus))
{
NTSTATUS ReturnedStatus = nStatus;
/* If it attempted to read past the end of the file, it means e_lfanew is invalid */
if (ReturnedStatus == STATUS_END_OF_FILE) nStatus = STATUS_INVALID_IMAGE_PROTECT;
DIE(("ReadFile failed, status %08X\n", ReturnedStatus));
}
ASSERT(pData);
ASSERT(pBuffer);
ASSERT(cbReadSize > 0);
nStatus = STATUS_INVALID_IMAGE_FORMAT;
/* the buffer doesn't contain the file header */
if(cbReadSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader))
DIE(("The file doesn't contain the PE file header\n"));
pinhNtHeader = pData;
/* object still not aligned: copy it to the beginning of the buffer */
if((UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
{
ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == 0);
RtlMoveMemory(pBuffer, pData, cbReadSize);
pinhNtHeader = pBuffer;
}
/* invalid NT header */
nStatus = STATUS_INVALID_IMAGE_PROTECT;
if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
nStatus = STATUS_INVALID_IMAGE_FORMAT;
if(!Intsafe_AddULong32(&cbNtHeaderSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
DIE(("The full NT header is too large\n"));
/* the buffer doesn't contain the whole NT header */
if(cbReadSize < cbNtHeaderSize)
DIE(("The file doesn't contain the full NT header\n"));
}
else
{
ULONG cbOptHeaderOffsetSize = 0;
nStatus = STATUS_INVALID_IMAGE_PROTECT;
/* don't trust an invalid NT header */
if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
nStatus = STATUS_INVALID_IMAGE_FORMAT;
if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, cbOptHeaderOffsetSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader->FileHeader.SizeOfOptionalHeader));
/* the buffer doesn't contain the whole NT header: read it from the file */
if(cbOptHeaderOffsetSize > FileHeaderSize)
goto l_ReadHeaderFromFile;
}
/* read information from the NT header */
piohOptHeader = &pinhNtHeader->OptionalHeader;
cbOptHeaderSize = pinhNtHeader->FileHeader.SizeOfOptionalHeader;
nStatus = STATUS_INVALID_IMAGE_FORMAT;
if(!RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Magic))
DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize));
/* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
switch(piohOptHeader->Magic)
{
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
#ifdef _WIN64
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
#endif // _WIN64
break;
default:
DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader->Magic));
}
if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SectionAlignment) &&
RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, FileAlignment))
{
/* See [1], section 3.4.2 */
if(piohOptHeader->SectionAlignment < PAGE_SIZE)
{
if(piohOptHeader->FileAlignment != piohOptHeader->SectionAlignment)
DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
}
else if(piohOptHeader->SectionAlignment < piohOptHeader->FileAlignment)
DIE(("The section alignment is smaller than the file alignment\n"));
nSectionAlignment = piohOptHeader->SectionAlignment;
nFileAlignment = piohOptHeader->FileAlignment;
if(!IsPowerOf2(nSectionAlignment) || !IsPowerOf2(nFileAlignment))
DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment, nFileAlignment));
}
else
{
nSectionAlignment = PAGE_SIZE;
nFileAlignment = PAGE_SIZE;
}
ASSERT(IsPowerOf2(nSectionAlignment));
ASSERT(IsPowerOf2(nFileAlignment));
switch(piohOptHeader->Magic)
{
/* PE32 */
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
{
if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, ImageBase))
ImageBase = piohOptHeader->ImageBase;
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfImage))
ImageSectionObject->ImageInformation.ImageFileSize = piohOptHeader->SizeOfImage;
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackReserve))
ImageSectionObject->ImageInformation.MaximumStackSize = piohOptHeader->SizeOfStackReserve;
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackCommit))
ImageSectionObject->ImageInformation.CommittedStackSize = piohOptHeader->SizeOfStackCommit;
if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Subsystem))
{
ImageSectionObject->ImageInformation.SubSystemType = piohOptHeader->Subsystem;
if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MinorSubsystemVersion) &&
RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MajorSubsystemVersion))
{
ImageSectionObject->ImageInformation.SubSystemMinorVersion = piohOptHeader->MinorSubsystemVersion;
ImageSectionObject->ImageInformation.SubSystemMajorVersion = piohOptHeader->MajorSubsystemVersion;
}
}
if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint))
{
ImageSectionObject->ImageInformation.TransferAddress = (PVOID) (ImageBase +
piohOptHeader->AddressOfEntryPoint);
}
if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfCode))
ImageSectionObject->ImageInformation.ImageContainsCode = piohOptHeader->SizeOfCode != 0;
else
ImageSectionObject->ImageInformation.ImageContainsCode = TRUE;
if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint))
{
if (piohOptHeader->AddressOfEntryPoint == 0)
{
ImageSectionObject->ImageInformation.ImageContainsCode = FALSE;
}
}
if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, LoaderFlags))
ImageSectionObject->ImageInformation.LoaderFlags = piohOptHeader->LoaderFlags;
if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, DllCharacteristics))
{
ImageSectionObject->ImageInformation.DllCharacteristics = piohOptHeader->DllCharacteristics;
/*
* Since we don't really implement SxS yet and LD doesn't supoprt /ALLOWISOLATION:NO, hard-code
* this flag here, which will prevent the loader and other code from doing any .manifest or SxS
* magic to any binary.
*
* This will break applications that depend on SxS when running with real Windows Kernel32/SxS/etc
* but honestly that's not tested. It will also break them when running no ReactOS once we implement
* the SxS support -- at which point, duh, this should be removed.
*
* But right now, any app depending on SxS is already broken anyway, so this flag only helps.
*/
ImageSectionObject->ImageInformation.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NO_ISOLATION;
}
break;
}
#ifdef _WIN64
/* PE64 */
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
{
const IMAGE_OPTIONAL_HEADER64 * pioh64OptHeader;
pioh64OptHeader = (const IMAGE_OPTIONAL_HEADER64 *)piohOptHeader;
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, ImageBase))
{
ImageBase = pioh64OptHeader->ImageBase;
if(pioh64OptHeader->ImageBase > MAXULONG_PTR)
DIE(("ImageBase exceeds the address space\n"));
}
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfImage))
{
if(pioh64OptHeader->SizeOfImage > MAXULONG_PTR)
DIE(("SizeOfImage exceeds the address space\n"));
ImageSectionObject->ImageInformation.ImageFileSize = pioh64OptHeader->SizeOfImage;
}
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackReserve))
{
if(pioh64OptHeader->SizeOfStackReserve > MAXULONG_PTR)
DIE(("SizeOfStackReserve exceeds the address space\n"));
ImageSectionObject->ImageInformation.MaximumStackSize = (ULONG_PTR) pioh64OptHeader->SizeOfStackReserve;
}
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackCommit))
{
if(pioh64OptHeader->SizeOfStackCommit > MAXULONG_PTR)
DIE(("SizeOfStackCommit exceeds the address space\n"));
ImageSectionObject->ImageInformation.CommittedStackSize = (ULONG_PTR) pioh64OptHeader->SizeOfStackCommit;
}
if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, Subsystem))
{
ImageSectionObject->ImageInformation.SubSystemType = pioh64OptHeader->Subsystem;
if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, MinorSubsystemVersion) &&
RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, MajorSubsystemVersion))
{
ImageSectionObject->ImageInformation.SubSystemMinorVersion = pioh64OptHeader->MinorSubsystemVersion;
ImageSectionObject->ImageInformation.SubSystemMajorVersion = pioh64OptHeader->MajorSubsystemVersion;
}
}
if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, AddressOfEntryPoint))
{
ImageSectionObject->ImageInformation.TransferAddress = (PVOID) (ImageBase +
pioh64OptHeader->AddressOfEntryPoint);
}
if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfCode))
ImageSectionObject->ImageInformation.ImageContainsCode = pioh64OptHeader->SizeOfCode != 0;
else
ImageSectionObject->ImageInformation.ImageContainsCode = TRUE;
if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, AddressOfEntryPoint))
{
if (pioh64OptHeader->AddressOfEntryPoint == 0)
{
ImageSectionObject->ImageInformation.ImageContainsCode = FALSE;
}
}
if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, LoaderFlags))
ImageSectionObject->ImageInformation.LoaderFlags = pioh64OptHeader->LoaderFlags;
if (RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, DllCharacteristics))
ImageSectionObject->ImageInformation.DllCharacteristics = pioh64OptHeader->DllCharacteristics;
break;
}
#endif // _WIN64
}
/* [1], section 3.4.2 */
if((ULONG_PTR)ImageBase % 0x10000)
DIE(("ImageBase is not aligned on a 64KB boundary"));
ImageSectionObject->ImageInformation.ImageCharacteristics = pinhNtHeader->FileHeader.Characteristics;
ImageSectionObject->ImageInformation.Machine = pinhNtHeader->FileHeader.Machine;
ImageSectionObject->ImageInformation.GpValue = 0;
ImageSectionObject->ImageInformation.ZeroBits = 0;
ImageSectionObject->BasedAddress = (PVOID)ImageBase;
/* SECTION HEADERS */
nStatus = STATUS_INVALID_IMAGE_FORMAT;
/* see [1], section 3.3 */
if(pinhNtHeader->FileHeader.NumberOfSections > 96)
DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader->FileHeader.NumberOfSections));
/*
* the additional segment is for the file's headers. They need to be present for
* the benefit of the dynamic loader (to locate exports, defaults for thread
* parameters, resources, etc.)
*/
ImageSectionObject->NrSegments = pinhNtHeader->FileHeader.NumberOfSections + 1;
/* file offset for the section headers */
if(!Intsafe_AddULong32(&cbSectionHeadersOffset, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
DIE(("Offset overflow\n"));
if(!Intsafe_AddULong32(&cbSectionHeadersOffset, cbSectionHeadersOffset, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
DIE(("Offset overflow\n"));
/* size of the section headers */
ASSERT(Intsafe_CanMulULong32(pinhNtHeader->FileHeader.NumberOfSections, sizeof(IMAGE_SECTION_HEADER)));
cbSectionHeadersSize = pinhNtHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize, cbSectionHeadersOffset, cbSectionHeadersSize))
DIE(("Section headers too large\n"));
/* size of the executable's headers */
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfHeaders))
{
// if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
// DIE(("SizeOfHeaders is not aligned\n"));
if(cbSectionHeadersSize > piohOptHeader->SizeOfHeaders)
DIE(("The section headers overflow SizeOfHeaders\n"));
cbHeadersSize = piohOptHeader->SizeOfHeaders;
}
else if(!AlignUp(&cbHeadersSize, cbSectionHeadersOffsetSize, nFileAlignment))
DIE(("Overflow aligning the size of headers\n"));
if(pBuffer)
{
ExFreePool(pBuffer);
pBuffer = NULL;
}
/* WARNING: pinhNtHeader IS NO LONGER USABLE */
/* WARNING: piohOptHeader IS NO LONGER USABLE */
/* WARNING: pioh64OptHeader IS NO LONGER USABLE */
if(FileHeaderSize < cbSectionHeadersOffsetSize)
pishSectionHeaders = NULL;
else
{
/*
* we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
* and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
*/
ASSERT(Intsafe_CanOffsetPointer(FileHeader, cbSectionHeadersOffset));
pishSectionHeaders = (PVOID)((UINT_PTR)FileHeader + cbSectionHeadersOffset);
}
/*
* the buffer doesn't contain the section headers, or the alignment is wrong:
* read the headers from the file
*/
if(FileHeaderSize < cbSectionHeadersOffsetSize ||
(UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
{
PVOID pData;
ULONG cbReadSize;
lnOffset.QuadPart = cbSectionHeadersOffset;
/* read the header from the file */
nStatus = ReadFileCb(File, &lnOffset, cbSectionHeadersSize, &pData, &pBuffer, &cbReadSize);
if(!NT_SUCCESS(nStatus))
DIE(("ReadFile failed with status %08X\n", nStatus));
ASSERT(pData);
ASSERT(pBuffer);
ASSERT(cbReadSize > 0);
nStatus = STATUS_INVALID_IMAGE_FORMAT;
/* the buffer doesn't contain all the section headers */
if(cbReadSize < cbSectionHeadersSize)
DIE(("The file doesn't contain all of the section headers\n"));
pishSectionHeaders = pData;
/* object still not aligned: copy it to the beginning of the buffer */
if((UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
{
ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) == 0);
RtlMoveMemory(pBuffer, pData, cbReadSize);
pishSectionHeaders = pBuffer;
}
}
/* SEGMENTS */
/* allocate the segments */
nStatus = STATUS_INSUFFICIENT_RESOURCES;
ImageSectionObject->Segments = AllocateSegmentsCb(ImageSectionObject->NrSegments);
if(ImageSectionObject->Segments == NULL)
DIE(("AllocateSegments failed\n"));
/* initialize the headers segment */
pssSegments = ImageSectionObject->Segments;
// ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
if(!AlignUp(&nFileSizeOfHeaders, cbHeadersSize, nFileAlignment))
DIE(("Cannot align the size of the section headers\n"));
nPrevVirtualEndOfSegment = ALIGN_UP_BY(cbHeadersSize, nSectionAlignment);
if (nPrevVirtualEndOfSegment < cbHeadersSize)
DIE(("Cannot align the size of the section headers\n"));
pssSegments[0].Image.FileOffset = 0;
pssSegments[0].Protection = PAGE_READONLY;
pssSegments[0].Length.QuadPart = nPrevVirtualEndOfSegment;
pssSegments[0].RawLength.QuadPart = nFileSizeOfHeaders;
pssSegments[0].Image.VirtualAddress = 0;
pssSegments[0].Image.Characteristics = 0;
pssSegments[0].WriteCopy = TRUE;
/* skip the headers segment */
++ pssSegments;
nStatus = STATUS_INVALID_IMAGE_FORMAT;
/* convert the executable sections into segments. See also [1], section 4 */
for(i = 0; i < ImageSectionObject->NrSegments - 1; ++ i)
{
ULONG nCharacteristics;
/* validate the alignment */
if(!IsAligned(pishSectionHeaders[i].VirtualAddress, nSectionAlignment))
DIE(("Image.VirtualAddress[%u] is not aligned\n", i));
/* sections must be contiguous, ordered by base address and non-overlapping */
if(pishSectionHeaders[i].VirtualAddress != nPrevVirtualEndOfSegment)
DIE(("Memory gap between section %u and the previous\n", i));
/* ignore explicit BSS sections */
if(pishSectionHeaders[i].SizeOfRawData != 0)
{
/* validate the alignment */
#if 0
/* Yes, this should be a multiple of FileAlignment, but there's
* stuff out there that isn't. We can cope with that
*/
if(!IsAligned(pishSectionHeaders[i].SizeOfRawData, nFileAlignment))
DIE(("SizeOfRawData[%u] is not aligned\n", i));
#endif
// if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
// DIE(("PointerToRawData[%u] is not aligned\n", i));
/* conversion */
pssSegments[i].Image.FileOffset = pishSectionHeaders[i].PointerToRawData;
pssSegments[i].RawLength.QuadPart = pishSectionHeaders[i].SizeOfRawData;
}
else
{
ASSERT(pssSegments[i].Image.FileOffset == 0);
ASSERT(pssSegments[i].RawLength.QuadPart == 0);
}
ASSERT(Intsafe_CanAddLong64(pssSegments[i].Image.FileOffset, pssSegments[i].RawLength.QuadPart));
nCharacteristics = pishSectionHeaders[i].Characteristics;
/* no explicit protection */
if((nCharacteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == 0)
{
if(nCharacteristics & IMAGE_SCN_CNT_CODE)
nCharacteristics |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
if(nCharacteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
if(nCharacteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
}
/* see table above */
pssSegments[i].Protection = SectionCharacteristicsToProtect[nCharacteristics >> 28];
pssSegments[i].WriteCopy = !(nCharacteristics & IMAGE_SCN_MEM_SHARED);
if(pishSectionHeaders[i].Misc.VirtualSize == 0 || pishSectionHeaders[i].Misc.VirtualSize < pishSectionHeaders[i].SizeOfRawData)
pssSegments[i].Length.QuadPart = pishSectionHeaders[i].SizeOfRawData;
else
pssSegments[i].Length.QuadPart = pishSectionHeaders[i].Misc.VirtualSize;
AlignedLength = ALIGN_UP_BY(pssSegments[i].Length.LowPart, nSectionAlignment);
if(AlignedLength < pssSegments[i].Length.LowPart)
DIE(("Cannot align the virtual size of section %u\n", i));
pssSegments[i].Length.LowPart = AlignedLength;
if(pssSegments[i].Length.QuadPart == 0)
DIE(("Virtual size of section %u is null\n", i));
pssSegments[i].Image.VirtualAddress = pishSectionHeaders[i].VirtualAddress;
pssSegments[i].Image.Characteristics = pishSectionHeaders[i].Characteristics;
/* ensure the memory image is no larger than 4GB */
nPrevVirtualEndOfSegment = (ULONG_PTR)(pssSegments[i].Image.VirtualAddress + pssSegments[i].Length.QuadPart);
if (nPrevVirtualEndOfSegment < pssSegments[i].Image.VirtualAddress)
DIE(("The image is too large\n"));
}
if(nSectionAlignment >= PAGE_SIZE)
*Flags |= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED;
/* Success */
nStatus = STATUS_SUCCESS;// STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
l_Return:
if(pBuffer)
ExFreePool(pBuffer);
return nStatus;
}
/*
* FUNCTION: Waits in kernel mode indefinitely for a file object lock.
* ARGUMENTS: PFILE_OBJECT to wait for.
* RETURNS: Status of the wait.
*/
NTSTATUS
MmspWaitForFileLock(PFILE_OBJECT File)
{
return STATUS_SUCCESS;
//return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
}
VOID
NTAPI
MmFreeSectionSegments(PFILE_OBJECT FileObject)
{
if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
{
PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
PMM_SECTION_SEGMENT SectionSegments;
ULONG NrSegments;
ULONG i;
ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject;
NrSegments = ImageSectionObject->NrSegments;
SectionSegments = ImageSectionObject->Segments;
for (i = 0; i < NrSegments; i++)
{
if (SectionSegments[i].ReferenceCount != 0)
{
DPRINT1("Image segment %lu still referenced (was %lu)\n", i,
SectionSegments[i].ReferenceCount);
KeBugCheck(MEMORY_MANAGEMENT);
}
MmFreePageTablesSectionSegment(&SectionSegments[i], NULL);
}
ExFreePool(ImageSectionObject->Segments);
ExFreePool(ImageSectionObject);
FileObject->SectionObjectPointer->ImageSectionObject = NULL;
}
if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
{
PMM_SECTION_SEGMENT Segment;
Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
DataSectionObject;
if (Segment->ReferenceCount != 0)
{
DPRINT1("Data segment still referenced\n");
KeBugCheck(MEMORY_MANAGEMENT);
}
MmFreePageTablesSectionSegment(Segment, NULL);
ExFreePool(Segment);
FileObject->SectionObjectPointer->DataSectionObject = NULL;
}
}
VOID
NTAPI
MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
PLARGE_INTEGER Offset)
{
ULONG_PTR Entry;
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
if (Entry == 0)
{
DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
KeBugCheck(MEMORY_MANAGEMENT);
}
if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
{
DPRINT1("Maximum share count reached\n");
KeBugCheck(MEMORY_MANAGEMENT);
}
if (IS_SWAP_FROM_SSE(Entry))
{
KeBugCheck(MEMORY_MANAGEMENT);
}
Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1);
MmSetPageEntrySectionSegment(Segment, Offset, Entry);
}
BOOLEAN
NTAPI
MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section,
PMM_SECTION_SEGMENT Segment,
PLARGE_INTEGER Offset,
BOOLEAN Dirty,
BOOLEAN PageOut,
ULONG_PTR *InEntry)
{
ULONG_PTR Entry = InEntry ? *InEntry : MmGetPageEntrySectionSegment(Segment, Offset);
BOOLEAN IsDirectMapped = FALSE;
if (Entry == 0)
{
DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
KeBugCheck(MEMORY_MANAGEMENT);
}
if (SHARE_COUNT_FROM_SSE(Entry) == 0)
{
DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment, Offset->LowPart, PFN_FROM_SSE(Entry));
KeBugCheck(MEMORY_MANAGEMENT);
}
if (IS_SWAP_FROM_SSE(Entry))
{
KeBugCheck(MEMORY_MANAGEMENT);
}
Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1);
/*
* If we reducing the share count of this entry to zero then set the entry
* to zero and tell the cache the page is no longer mapped.
*/
if (SHARE_COUNT_FROM_SSE(Entry) == 0)
{
PFILE_OBJECT FileObject;
SWAPENTRY SavedSwapEntry;
PFN_NUMBER Page;
#ifndef NEWCC
PROS_SHARED_CACHE_MAP SharedCacheMap;
BOOLEAN IsImageSection;
LARGE_INTEGER FileOffset;
FileOffset.QuadPart = Offset->QuadPart + Segment->Image.FileOffset;
IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
#endif
Page = PFN_FROM_SSE(Entry);
FileObject = Section->FileObject;
if (FileObject != NULL &&
!(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
{
#ifndef NEWCC
if ((FileOffset.QuadPart % PAGE_SIZE) == 0 &&
(Offset->QuadPart + PAGE_SIZE <= Segment->RawLength.QuadPart || !IsImageSection))
{
NTSTATUS Status;
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
IsDirectMapped = TRUE;
#ifndef NEWCC
Status = CcRosUnmapVacb(SharedCacheMap, FileOffset.QuadPart, Dirty);
#else
Status = STATUS_SUCCESS;
#endif
if (!NT_SUCCESS(Status))
{
DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status);
KeBugCheck(MEMORY_MANAGEMENT);
}
}
#endif
}
SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
if (SavedSwapEntry == 0)
{
if (!PageOut &&
((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)))
{
/*
* FIXME:
* Try to page out this page and set the swap entry
* within the section segment. There exist no rmap entry
* for this page. The pager thread can't page out a
* page without a rmap entry.
*/
MmSetPageEntrySectionSegment(Segment, Offset, Entry);
if (InEntry) *InEntry = Entry;
MiSetPageEvent(NULL, NULL);
}
else
{
MmSetPageEntrySectionSegment(Segment, Offset, 0);
if (InEntry) *InEntry = 0;
MiSetPageEvent(NULL, NULL);
if (!IsDirectMapped)
{
MmReleasePageMemoryConsumer(MC_USER, Page);
}
}
}
else
{
if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
{
if (!PageOut)
{
if (Dirty)
{
/*
* FIXME:
* We hold all locks. Nobody can do something with the current
* process and the current segment (also not within an other process).
*/
NTSTATUS Status;
Status = MmWriteToSwapPage(SavedSwapEntry, Page);
if (!NT_SUCCESS(Status))
{
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status);
KeBugCheck(MEMORY_MANAGEMENT);
}
}
MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry));
if (InEntry) *InEntry = MAKE_SWAP_SSE(SavedSwapEntry);
MmSetSavedSwapEntryPage(Page, 0);
MiSetPageEvent(NULL, NULL);
}
MmReleasePageMemoryConsumer(MC_USER, Page);
}
else
{
DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
KeBugCheck(MEMORY_MANAGEMENT);
}
}
}
else
{
if (InEntry)
*InEntry = Entry;
else
MmSetPageEntrySectionSegment(Segment, Offset, Entry);
}
return(SHARE_COUNT_FROM_SSE(Entry) > 0);
}
BOOLEAN MiIsPageFromCache(PMEMORY_AREA MemoryArea,
LONGLONG SegOffset)
{
#ifndef NEWCC
if (!(MemoryArea->Data.SectionData.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
{
PROS_SHARED_CACHE_MAP SharedCacheMap;
PROS_VACB Vacb;
SharedCacheMap = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap;
Vacb = CcRosLookupVacb(SharedCacheMap, SegOffset + MemoryArea->Data.SectionData.Segment->Image.FileOffset);
if (Vacb)
{
CcRosReleaseVacb(SharedCacheMap, Vacb, Vacb->Valid, FALSE, TRUE);
return TRUE;
}
}
#endif
return FALSE;
}
NTSTATUS
NTAPI
MiCopyFromUserPage(PFN_NUMBER DestPage, const VOID *SrcAddress)
{
PEPROCESS Process;
KIRQL Irql;
PVOID DestAddress;
Process = PsGetCurrentProcess();
DestAddress = MiMapPageInHyperSpace(Process, DestPage, &Irql);
if (DestAddress == NULL)
{
return(STATUS_NO_MEMORY);
}
ASSERT((ULONG_PTR)DestAddress % PAGE_SIZE == 0);
ASSERT((ULONG_PTR)SrcAddress % PAGE_SIZE == 0);
RtlCopyMemory(DestAddress, SrcAddress, PAGE_SIZE);
MiUnmapPageInHyperSpace(Process, DestAddress, Irql);
return(STATUS_SUCCESS);
}
#ifndef NEWCC
NTSTATUS
NTAPI
MiReadPage(PMEMORY_AREA MemoryArea,
LONGLONG SegOffset,
PPFN_NUMBER Page)
/*
* FUNCTION: Read a page for a section backed memory area.
* PARAMETERS:
* MemoryArea - Memory area to read the page for.
* Offset - Offset of the page to read.
* Page - Variable that receives a page contains the read data.
*/
{
LONGLONG BaseOffset;
LONGLONG FileOffset;
PVOID BaseAddress;
BOOLEAN UptoDate;
PROS_VACB Vacb;
PFILE_OBJECT FileObject;
NTSTATUS Status;
LONGLONG RawLength;
PROS_SHARED_CACHE_MAP SharedCacheMap;
BOOLEAN IsImageSection;
LONGLONG Length;
FileObject = MemoryArea->Data.SectionData.Section->FileObject;
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
RawLength = MemoryArea->Data.SectionData.Segment->RawLength.QuadPart;
FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->Image.FileOffset;
IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
ASSERT(SharedCacheMap);
DPRINT("%S %I64x\n", FileObject->FileName.Buffer, FileOffset);
/*
* If the file system is letting us go directly to the cache and the
* memory area was mapped at an offset in the file which is page aligned
* then get the related VACB.
*/
if (((FileOffset % PAGE_SIZE) == 0) &&
((SegOffset + PAGE_SIZE <= RawLength) || !IsImageSection) &&
!(MemoryArea->Data.SectionData.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
{
/*
* Get the related VACB; we use a lower level interface than
* filesystems do because it is safe for us to use an offset with an
* alignment less than the file system block size.
*/
Status = CcRosGetVacb(SharedCacheMap,
FileOffset,
&BaseOffset,
&BaseAddress,
&UptoDate,
&Vacb);
if (!NT_SUCCESS(Status))
{
return(Status);
}
if (!UptoDate)
{
/*
* If the VACB isn't up to date then call the file
* system to read in the data.
*/
Status = CcReadVirtualAddress(Vacb);
if (!NT_SUCCESS(Status))
{
CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
return Status;
}
}
/* Probe the page, since it's PDE might not be synced */
(void)*((volatile char*)BaseAddress + FileOffset - BaseOffset);
/*
* Retrieve the page from the view that we actually want.
*/
(*Page) = MmGetPhysicalAddress((char*)BaseAddress +
FileOffset - BaseOffset).LowPart >> PAGE_SHIFT;
CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, TRUE);
}
else
{
PEPROCESS Process;
KIRQL Irql;
PVOID PageAddr;
LONGLONG VacbOffset;
/*
* Allocate a page, this is rather complicated by the possibility
* we might have to move other things out of memory
*/
MI_SET_USAGE(MI_USAGE_SECTION);
MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page);
if (!NT_SUCCESS(Status))
{
return(Status);
}
Status = CcRosGetVacb(SharedCacheMap,
FileOffset,
&BaseOffset,
&BaseAddress,
&UptoDate,
&Vacb);
if (!NT_SUCCESS(Status))
{
return(Status);
}
if (!UptoDate)
{
/*
* If the VACB isn't up to date then call the file
* system to read in the data.
*/
Status = CcReadVirtualAddress(Vacb);
if (!NT_SUCCESS(Status))
{
CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
return Status;
}
}
Process = PsGetCurrentProcess();
PageAddr = MiMapPageInHyperSpace(Process, *Page, &Irql);
VacbOffset = BaseOffset + VACB_MAPPING_GRANULARITY - FileOffset;
Length = RawLength - SegOffset;
if (Length <= VacbOffset && Length <= PAGE_SIZE)
{
memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, Length);
}
else if (VacbOffset >= PAGE_SIZE)
{
memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, PAGE_SIZE);
}
else
{
memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, VacbOffset);
MiUnmapPageInHyperSpace(Process, PageAddr, Irql);
CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE);
Status = CcRosGetVacb(SharedCacheMap,
FileOffset + VacbOffset,
&BaseOffset,
&BaseAddress,
&UptoDate,
&Vacb);
if (!NT_SUCCESS(Status))
{
return(Status);
}
if (!UptoDate)
{
/*
* If the VACB isn't up to date then call the file
* system to read in the data.
*/
Status = CcReadVirtualAddress(Vacb);
if (!NT_SUCCESS(Status))
{
CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
return Status;
}
}
PageAddr = MiMapPageInHyperSpace(Process, *Page, &Irql);
if (Length < PAGE_SIZE)
{
memcpy((char*)PageAddr + VacbOffset, BaseAddress, Length - VacbOffset);
}
else
{
memcpy((char*)PageAddr + VacbOffset, BaseAddress, PAGE_SIZE - VacbOffset);
}
}
MiUnmapPageInHyperSpace(Process, PageAddr, Irql);
CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE);
}
return(STATUS_SUCCESS);
}
#else
NTSTATUS
NTAPI
MiReadPage(PMEMORY_AREA MemoryArea,
LONGLONG SegOffset,
PPFN_NUMBER Page)
/*
* FUNCTION: Read a page for a section backed memory area.
* PARAMETERS:
* MemoryArea - Memory area to read the page for.
* Offset - Offset of the page to read.
* Page - Variable that receives a page contains the read data.
*/
{
MM_REQUIRED_RESOURCES Resources;
NTSTATUS Status;
RtlZeroMemory(&Resources, sizeof(MM_REQUIRED_RESOURCES));
Resources.Context = MemoryArea->Data.SectionData.Section->FileObject;
Resources.FileOffset.QuadPart = SegOffset +
MemoryArea->Data.SectionData.Segment->Image.FileOffset;
Resources.Consumer = MC_USER;
Resources.Amount = PAGE_SIZE;
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]);
Status = MiReadFilePage(MmGetKernelAddressSpace(), MemoryArea, &Resources);
*Page = Resources.Page[0];
return Status;
}
#endif
static VOID
MmAlterViewAttributes(PMMSUPPORT AddressSpace,
PVOID BaseAddress,
SIZE_T RegionSize,
ULONG OldType,
ULONG OldProtect,
ULONG NewType,
ULONG NewProtect)
{
PMEMORY_AREA MemoryArea;
PMM_SECTION_SEGMENT Segment;
BOOLEAN DoCOW = FALSE;
ULONG i;
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
ASSERT(MemoryArea != NULL);
Segment = MemoryArea->Data.SectionData.Segment;
MmLockSectionSegment(Segment);
if ((Segment->WriteCopy) &&
(NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
{
DoCOW = TRUE;
}
if (OldProtect != NewProtect)
{
for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
{
SWAPENTRY SwapEntry;
PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
ULONG Protect = NewProtect;
/* Wait for a wait entry to disappear */
do
{
MmGetPageFileMapping(Process, Address, &SwapEntry);
if (SwapEntry != MM_WAIT_ENTRY)
break;
MiWaitForPageEvent(Process, Address);
}
while (TRUE);
/*
* If we doing COW for this segment then check if the page is
* already private.
*/
if (DoCOW && MmIsPagePresent(Process, Address))
{
LARGE_INTEGER Offset;
ULONG_PTR Entry;
PFN_NUMBER Page;
Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)
+ MemoryArea->Data.SectionData.ViewOffset.QuadPart;
Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
/*
* An MM_WAIT_ENTRY is ok in this case... It'll just count as
* IS_SWAP_FROM_SSE and we'll do the right thing.
*/
Page = MmGetPfnForProcess(Process, Address);
Protect = PAGE_READONLY;
if (IS_SWAP_FROM_SSE(Entry) || PFN_FROM_SSE(Entry) != Page)
{
Protect = NewProtect;
}
}
if (MmIsPagePresent(Process, Address) || MmIsDisabledPage(Process, Address))
{
MmSetPageProtect(Process, Address,
Protect);
}
}
}
MmUnlockSectionSegment(Segment);
}
NTSTATUS
NTAPI
MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
MEMORY_AREA* MemoryArea,
PVOID Address,
BOOLEAN Locked)
{
LARGE_INTEGER Offset;
PFN_NUMBER Page;
NTSTATUS Status;
PROS_SECTION_OBJECT Section;
PMM_SECTION_SEGMENT Segment;
ULONG_PTR Entry;
ULONG_PTR Entry1;
ULONG Attributes;
PMM_REGION Region;
BOOLEAN HasSwapEntry;
PVOID PAddress;
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
SWAPENTRY SwapEntry;
/*
* There is a window between taking the page fault and locking the
* address space when another thread could load the page so we check
* that.
*/
if (MmIsPagePresent(Process, Address))
{
return(STATUS_SUCCESS);
}
if (MmIsDisabledPage(Process, Address))
{
return(STATUS_ACCESS_VIOLATION);
}
/*
* Check for the virtual memory area being deleted.
*/
if (MemoryArea->DeleteInProgress)
{
return(STATUS_UNSUCCESSFUL);
}
PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
Offset.QuadPart = (ULONG_PTR)PAddress - MA_GetStartingAddress(MemoryArea)
+ MemoryArea->Data.SectionData.ViewOffset.QuadPart;
Segment = MemoryArea->Data.SectionData.Segment;
Section = MemoryArea->Data.SectionData.Section;
Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
&MemoryArea->Data.SectionData.RegionListHead,
Address, NULL);
ASSERT(Region != NULL);
/* Check for a NOACCESS mapping */
if (Region->Protect & PAGE_NOACCESS)
{
return STATUS_ACCESS_VIOLATION;
}
if (Region->Protect & PAGE_GUARD)
{
/* Remove it */
Status = MmAlterRegion(AddressSpace, (PVOID)MA_GetStartingAddress(MemoryArea),
&MemoryArea->Data.SectionData.RegionListHead,
Address, PAGE_SIZE, Region->Type, Region->Protect & ~PAGE_GUARD,
MmAlterViewAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("Removing PAGE_GUARD protection failed : 0x%08x.\n", Status);
}
return STATUS_GUARD_PAGE_VIOLATION;
}
/*
* Lock the segment
*/
MmLockSectionSegment(Segment);
Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
/*
* Check if this page needs to be mapped COW
*/
if ((Segment->WriteCopy) &&
(Region->Protect == PAGE_READWRITE ||
Region->Protect == PAGE_EXECUTE_READWRITE))
{
Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ;
}
else
{
Attributes = Region->Protect;
}
/*
* Check if someone else is already handling this fault, if so wait
* for them
*/
if (Entry && MM_IS_WAIT_PTE(Entry))
{
MmUnlockSectionSegment(Segment);
MmUnlockAddressSpace(AddressSpace);
MiWaitForPageEvent(NULL, NULL);
MmLockAddressSpace(AddressSpace);
DPRINT("Address 0x%p\n", Address);
return(STATUS_MM_RESTART_OPERATION);
}
HasSwapEntry = MmIsPageSwapEntry(Process, Address);
/* See if we should use a private page */
if (HasSwapEntry)
{
SWAPENTRY DummyEntry;
/*
* Is it a wait entry?
*/
if (HasSwapEntry)
{
MmGetPageFileMapping(Process, Address, &SwapEntry);
if (SwapEntry == MM_WAIT_ENTRY)
{
MmUnlockSectionSegment(Segment);
MmUnlockAddressSpace(AddressSpace);
MiWaitForPageEvent(NULL, NULL);
MmLockAddressSpace(AddressSpace);
return STATUS_MM_RESTART_OPERATION;
}
/*
* Must be private page we have swapped out.
*/
/*
* Sanity check
*/
if (Segment->Flags & MM_PAGEFILE_SEGMENT)
{
DPRINT1("Found a swaped out private page in a pagefile section.\n");
KeBugCheck(MEMORY_MANAGEMENT);
}
MmDeletePageFileMapping(Process, Address, &SwapEntry);
}
MmUnlockSectionSegment(Segment);
/* Tell everyone else we are serving the fault. */
MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY);
MmUnlockAddressSpace(AddressSpace);
MI_SET_USAGE(MI_USAGE_SECTION);
if (Process) MI_SET_PROCESS2(Process->ImageFileName);
if (!Process) MI_SET_PROCESS2("Kernel Section");
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
if (!NT_SUCCESS(Status))
{
KeBugCheck(MEMORY_MANAGEMENT);
}
if (HasSwapEntry)
{
Status = MmReadFromSwapPage(SwapEntry, Page);
if (!NT_SUCCESS(Status))
{
DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
KeBugCheck(MEMORY_MANAGEMENT);
}
}
MmLockAddressSpace(AddressSpace);
MmDeletePageFileMapping(Process, PAddress, &DummyEntry);
Status = MmCreateVirtualMapping(Process,
PAddress,
Region->Protect,
&Page,
1);
if (!NT_SUCCESS(Status))
{
DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
KeBugCheck(MEMORY_MANAGEMENT);
return(Status);
}
/*
* Store the swap entry for later use.
*/
if (HasSwapEntry)
MmSetSavedSwapEntryPage(Page, SwapEntry);
/*
* Add the page to the process's working set
*/
MmInsertRmap(Page, Process, Address);
/*
* Finish the operation
*/
MiSetPageEvent(Process, Address);
DPRINT("Address 0x%p\n", Address);
return(STATUS_SUCCESS);
}
/*
* Satisfying a page fault on a map of /Device/PhysicalMemory is easy
*/
if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
{
MmUnlockSectionSegment(Segment);
/*
* Just map the desired physical page
*/
Page = (PFN_NUMBER)(Offset.QuadPart >> PAGE_SHIFT);
Status = MmCreateVirtualMappingUnsafe(Process,
PAddress,
Region->Protect,
&Page,
1);
if (!NT_SUCCESS(Status))
{
DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
KeBugCheck(MEMORY_MANAGEMENT);
return(Status);
}
/*
* Cleanup and release locks
*/
MiSetPageEvent(Process, Address);
DPRINT("Address 0x%p\n", Address);
return(STATUS_SUCCESS);
}
/*
* Get the entry corresponding to the offset within the section
*/
Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
if (Entry == 0)
{
SWAPENTRY FakeSwapEntry;
/*
* If the entry is zero (and it can't change because we have
* locked the segment) then we need to load the page.
*/
/*
* Release all our locks and read in the page from disk
*/
MmSetPageEntrySectionSegment(Segment, &Offset, MAKE_SWAP_SSE(MM_WAIT_ENTRY));
MmUnlockSectionSegment(Segment);
MmCreatePageFileMapping(Process, PAddress, MM_WAIT_ENTRY);
MmUnlockAddressSpace(AddressSpace);
if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
((Offset.QuadPart >= (LONGLONG)PAGE_ROUND_UP(Segment->RawLength.QuadPart) &&
(Section->AllocationAttributes & SEC_IMAGE))))
{
MI_SET_USAGE(MI_USAGE_SECTION);
if (Process) MI_SET_PROCESS2(Process->ImageFileName);
if (!Process) MI_SET_PROCESS2("Kernel Section");
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
if (!NT_SUCCESS(Status))
{
DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
}
}
else
{
Status = MiReadPage(MemoryArea, Offset.QuadPart, &Page);
if (!NT_SUCCESS(Status))
{
DPRINT1("MiReadPage failed (Status %x)\n", Status);
}
}
if (!NT_SUCCESS(Status))
{
/*
* FIXME: What do we know in this case?
*/
/*
* Cleanup and release locks
*/
MmLockAddressSpace(AddressSpace);
MiSetPageEvent(Process, Address);
DPRINT("Address 0x%p\n", Address);
return(Status);
}
/* Lock both segment and process address space while we proceed. */
MmLockAddressSpace(AddressSpace);
MmLockSectionSegment(Segment);
MmDeletePageFileMapping(Process, PAddress, &FakeSwapEntry);
DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
Page, Process, PAddress, Attributes);
Status = MmCreateVirtualMapping(Process,
PAddress,
Attributes,
&Page,
1);
if (!NT_SUCCESS(Status))
{
DPRINT1("Unable to create virtual mapping\n");
KeBugCheck(MEMORY_MANAGEMENT);
}
ASSERT(MmIsPagePresent(Process, PAddress));
MmInsertRmap(Page, Process, Address);
/* Set this section offset has being backed by our new page. */
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
MmUnlockSectionSegment(Segment);
MiSetPageEvent(Process, Address);
DPRINT("Address 0x%p\n", Address);
return(STATUS_SUCCESS);
}
else if (IS_SWAP_FROM_SSE(Entry))
{
SWAPENTRY SwapEntry;
SwapEntry = SWAPENTRY_FROM_SSE(Entry);
/* See if a page op is running on this segment. */
if (SwapEntry == MM_WAIT_ENTRY)
{
MmUnlockSectionSegment(Segment);
MmUnlockAddressSpace(AddressSpace);
MiWaitForPageEvent(NULL, NULL);
MmLockAddressSpace(AddressSpace);
return STATUS_MM_RESTART_OPERATION;
}
/*
* Release all our locks and read in the page from disk
*/
MmUnlockSectionSegment(Segment);
MmUnlockAddressSpace(AddressSpace);
MI_SET_USAGE(MI_USAGE_SECTION);
if (Process) MI_SET_PROCESS2(Process->ImageFileName);
if (!Process) MI_SET_PROCESS2("Kernel Section");
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
if (!NT_SUCCESS(Status))
{
KeBugCheck(MEMORY_MANAGEMENT);
}
Status = MmReadFromSwapPage(SwapEntry, Page);
if (!NT_SUCCESS(Status))
{
KeBugCheck(MEMORY_MANAGEMENT);
}
/*
* Relock the address space and segment
*/
MmLockAddressSpace(AddressSpace);
MmLockSectionSegment(Segment);
/*
* Check the entry. No one should change the status of a page
* that has a pending page-in.
*/
Entry1 = MmGetPageEntrySectionSegment(Segment, &Offset);
if (Entry != Entry1)
{
DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry, Entry1);
KeBugCheck(MEMORY_MANAGEMENT);
}
/*
* Save the swap entry.
*/
MmSetSavedSwapEntryPage(Page, SwapEntry);
/* Map the page into the process address space */
Status = MmCreateVirtualMapping(Process,
PAddress,
Region->Protect,
&Page,
1);
if (!NT_SUCCESS(Status))
{
DPRINT1("Unable to create virtual mapping\n");
KeBugCheck(MEMORY_MANAGEMENT);
}
MmInsertRmap(Page, Process, Address);
/*
* Mark the offset within the section as having valid, in-memory
* data
*/
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
MmUnlockSectionSegment(Segment);
MiSetPageEvent(Process, Address);
DPRINT("Address 0x%p\n", Address);
return(STATUS_SUCCESS);
}
else
{
/* We already have a page on this section offset. Map it into the process address space. */
Page = PFN_FROM_SSE(Entry);
Status = MmCreateVirtualMapping(Process,
PAddress,
Attributes,
&Page,
1);
if (!NT_SUCCESS(Status))
{
DPRINT1("Unable to create virtual mapping\n");
KeBugCheck(MEMORY_MANAGEMENT);
}
MmInsertRmap(Page, Process, Address);
/* Take a reference on it */
MmSharePageEntrySectionSegment(Segment, &Offset);
MmUnlockSectionSegment(Segment);
MiSetPageEvent(Process, Address);
DPRINT("Address 0x%p\n", Address);
return(STATUS_SUCCESS);
}
}
NTSTATUS
NTAPI
MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
MEMORY_AREA* MemoryArea,
PVOID Address)
{
PMM_SECTION_SEGMENT Segment;
PROS_SECTION_OBJECT Section;
PFN_NUMBER OldPage;
PFN_NUMBER NewPage;
NTSTATUS Status;
PVOID PAddress;
LARGE_INTEGER Offset;
PMM_REGION Region;
ULONG_PTR Entry;
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace, MemoryArea, Address);
/* Make sure we have a page mapping for this address. */
Status = MmNotPresentFaultSectionView(AddressSpace, MemoryArea, Address, TRUE);
if (!NT_SUCCESS(Status))
{
/* This is invalid access ! */
return Status;
}
/*
* Check if the page has already been set readwrite
*/
if (MmGetPageProtect(Process, Address) & PAGE_READWRITE)
{
DPRINT("Address 0x%p\n", Address);
return(STATUS_SUCCESS);
}
/*
* Find the offset of the page
*/
PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
Offset.QuadPart = (ULONG_PTR)PAddress - MA_GetStartingAddress(MemoryArea)
+ MemoryArea->Data.SectionData.ViewOffset.QuadPart;
Segment = MemoryArea->Data.SectionData.Segment;
Section = MemoryArea->Data.SectionData.Section;
Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
&MemoryArea->Data.SectionData.RegionListHead,
Address, NULL);
ASSERT(Region != NULL);
/*
* Check if we are doing COW
*/
if (!((Segment->WriteCopy) &&
(Region->Protect == PAGE_READWRITE ||
Region->Protect == PAGE_EXECUTE_READWRITE)))
{
DPRINT("Address 0x%p\n", Address);
return(STATUS_ACCESS_VIOLATION);
}
/* Get the page mapping this section offset. */
MmLockSectionSegment(Segment);
Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
/* Get the current page mapping for the process */
ASSERT(MmIsPagePresent(Process, PAddress));
OldPage = MmGetPfnForProcess(Process, PAddress);
ASSERT(OldPage != 0);
if (IS_SWAP_FROM_SSE(Entry) ||
PFN_FROM_SSE(Entry) != OldPage)
{
MmUnlockSectionSegment(Segment);
/* This is a private page. We must only change the page protection. */
MmSetPageProtect(Process, PAddress, Region->Protect);
return(STATUS_SUCCESS);
}
/*
* Allocate a page
*/
MI_SET_USAGE(MI_USAGE_SECTION);
if (Process) MI_SET_PROCESS2(Process->ImageFileName);
if (!Process) MI_SET_PROCESS2("Kernel Section");
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
if (!NT_SUCCESS(Status))
{
KeBugCheck(MEMORY_MANAGEMENT);
}
/*
* Copy the old page
*/
NT_VERIFY(NT_SUCCESS(MiCopyFromUserPage(NewPage, PAddress)));
/*
* Unshare the old page.
*/
DPRINT("Swapping page (Old %x New %x)\n", OldPage, NewPage);
MmDeleteVirtualMapping(Process, PAddress, NULL, NULL);
MmDeleteRmap(OldPage, Process, PAddress);
MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, FALSE, FALSE, NULL);
MmUnlockSectionSegment(Segment);
/*
* Set the PTE to point to the new page
*/
Status = MmCreateVirtualMapping(Process,
PAddress,
Region->Protect,
&NewPage,
1);
if (!NT_SUCCESS(Status))
{
DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
KeBugCheck(MEMORY_MANAGEMENT);
return(Status);
}
MmInsertRmap(NewPage, Process, PAddress);
MiSetPageEvent(Process, Address);
DPRINT("Address 0x%p\n", Address);
return(STATUS_SUCCESS);
}
VOID
MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
{
MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
BOOLEAN WasDirty;
PFN_NUMBER Page = 0;
PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
if (Process)
{
MmLockAddressSpace(&Process->Vm);
}
MmDeleteVirtualMapping(Process,
Address,
&WasDirty,
&Page);
if (WasDirty)
{
PageOutContext->WasDirty = TRUE;
}
if (!PageOutContext->Private)
{
MmLockSectionSegment(PageOutContext->Segment);
MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT)PageOutContext->Section,
PageOutContext->Segment,
&PageOutContext->Offset,
PageOutContext->WasDirty,
TRUE,
&PageOutContext->SectionEntry);
MmUnlockSectionSegment(PageOutContext->Segment);
}
if (Process)
{
MmUnlockAddressSpace(&Process->Vm);
}
if (PageOutContext->Private)
{
MmReleasePageMemoryConsumer(MC_USER, Page);
}
}
NTSTATUS
NTAPI
MmPageOutSectionView(PMMSUPPORT AddressSpace,
MEMORY_AREA* MemoryArea,
PVOID Address, ULONG_PTR Entry)
{
PFN_NUMBER Page;
MM_SECTION_PAGEOUT_CONTEXT Context;
SWAPENTRY SwapEntry;
NTSTATUS Status;
#ifndef NEWCC
ULONGLONG FileOffset;
PFILE_OBJECT FileObject;
PROS_SHARED_CACHE_MAP SharedCacheMap = NULL;
BOOLEAN IsImageSection;
#endif
BOOLEAN DirectMapped;
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
KIRQL OldIrql;
Address = (PVOID)PAGE_ROUND_DOWN(Address);
/*
* Get the segment and section.
*/
Context.Segment = MemoryArea->Data.SectionData.Segment;
Context.Section = MemoryArea->Data.SectionData.Section;
Context.SectionEntry = Entry;
Context.CallingProcess = Process;
Context.Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)
+ MemoryArea->Data.SectionData.ViewOffset.QuadPart;
DirectMapped = FALSE;
MmLockSectionSegment(Context.Segment);
#ifndef NEWCC
FileOffset = Context.Offset.QuadPart + Context.Segment->Image.FileOffset;
IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
FileObject = Context.Section->FileObject;
if (FileObject != NULL &&
!(Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
{
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
/*
* If the file system is letting us go directly to the cache and the
* memory area was mapped at an offset in the file which is page aligned
* then note this is a direct mapped page.
*/
if ((FileOffset % PAGE_SIZE) == 0 &&
(Context.Offset.QuadPart + PAGE_SIZE <= Context.Segment->RawLength.QuadPart || !IsImageSection))
{
DirectMapped = TRUE;
}
}
#endif
/*
* This should never happen since mappings of physical memory are never
* placed in the rmap lists.
*/
if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY)
{
DPRINT1("Trying to page out from physical memory section address 0x%p "
"process %p\n", Address,
Process ? Process->UniqueProcessId : 0);
KeBugCheck(MEMORY_MANAGEMENT);
}
/*
* Get the section segment entry and the physical address.
*/
if (!MmIsPagePresent(Process, Address))
{
DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
Process ? Process->UniqueProcessId : 0, Address);
KeBugCheck(MEMORY_MANAGEMENT);
}
Page = MmGetPfnForProcess(Process, Address);
SwapEntry = MmGetSavedSwapEntryPage(Page);
/*
* Check the reference count to ensure this page can be paged out
*/
if (MmGetReferenceCountPage(Page) != 1)
{
DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n",
Page, MmGetReferenceCountPage(Page));
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
MmUnlockSectionSegment(Context.Segment);
return STATUS_UNSUCCESSFUL;
}
/*
* Prepare the context structure for the rmap delete call.
*/
MmUnlockSectionSegment(Context.Segment);
Context.WasDirty = FALSE;
if (IS_SWAP_FROM_SSE(Entry) || PFN_FROM_SSE(Entry) != Page)
{
Context.Private = TRUE;
}
else
{
Context.Private = FALSE;
}
/*
* Take an additional reference to the page or the VACB.
*/
if (DirectMapped && !Context.Private)
{
if(!MiIsPageFromCache(MemoryArea, Context.Offset.QuadPart))
{
DPRINT1("Direct mapped non private page is not associated with the cache.\n");
KeBugCheck(MEMORY_MANAGEMENT);
}
}
else
{
OldIrql = MiAcquirePfnLock();
MmReferencePage(Page);
MiReleasePfnLock(OldIrql);
}
MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping);
/* Since we passed in a surrogate, we'll get back the page entry
* state in our context. This is intended to make intermediate
* decrements of share count not release the wait entry.
*/
Entry = Context.SectionEntry;
/*
* If this wasn't a private page then we should have reduced the entry to
* zero by deleting all the rmaps.
*/
if (!Context.Private && Entry != 0)
{
if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) &&
!(Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
{
KeBugCheckEx(MEMORY_MANAGEMENT, Entry, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
}
}
/*
* If the page wasn't dirty then we can just free it as for a readonly page.
* Since we unmapped all the mappings above we know it will not suddenly
* become dirty.
* If the page is from a pagefile section and has no swap entry,
* we can't free the page at this point.
*/
SwapEntry = MmGetSavedSwapEntryPage(Page);
if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT)
{
if (Context.Private)
{
DPRINT1("Found a %s private page (address %p) in a pagefile segment.\n",
Context.WasDirty ? "dirty" : "clean", Address);
KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
}
if (!Context.WasDirty && SwapEntry != 0)
{
MmSetSavedSwapEntryPage(Page, 0);
MmLockSectionSegment(Context.Segment);
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
MmUnlockSectionSegment(Context.Segment);
MmReleasePageMemoryConsumer(MC_USER, Page);
MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
}
else if (Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)
{
if (Context.Private)
{
DPRINT1("Found a %s private page (address %p) in a shared section segment.\n",
Context.WasDirty ? "dirty" : "clean", Address);
KeBugCheckEx(MEMORY_MANAGEMENT, Page, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
}
if (!Context.WasDirty || SwapEntry != 0)
{
MmSetSavedSwapEntryPage(Page, 0);
if (SwapEntry != 0)
{
MmLockSectionSegment(Context.Segment);
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
MmUnlockSectionSegment(Context.Segment);
}
MmReleasePageMemoryConsumer(MC_USER, Page);
MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
}
else if (!Context.Private && DirectMapped)
{
if (SwapEntry != 0)
{
DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n",
Address);
KeBugCheckEx(MEMORY_MANAGEMENT, STATUS_UNSUCCESSFUL, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address);
}
#ifndef NEWCC
Status = CcRosUnmapVacb(SharedCacheMap, FileOffset, FALSE);
#else
Status = STATUS_SUCCESS;
#endif
#ifndef NEWCC
if (!NT_SUCCESS(Status))
{
DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status);
KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)SharedCacheMap, (ULONG_PTR)FileOffset, (ULONG_PTR)Address);
}
#endif
MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
else if (!Context.WasDirty && !DirectMapped && !Context.Private)
{
if (SwapEntry != 0)
{
DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n",
Address);
KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, Page, (ULONG_PTR)Process, (ULONG_PTR)Address);
}
MmReleasePageMemoryConsumer(MC_USER, Page);
MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
{
DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process, Address);
MmSetSavedSwapEntryPage(Page, 0);
MmLockAddressSpace(AddressSpace);
Status = MmCreatePageFileMapping(Process,
Address,
SwapEntry);
MmUnlockAddressSpace(AddressSpace);
if (!NT_SUCCESS(Status))
{
DPRINT1("Status %x Swapping out %p:%p\n", Status, Process, Address);
KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Process, (ULONG_PTR)Address, SwapEntry);
}
MmReleasePageMemoryConsumer(MC_USER, Page);
MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
/*
* If necessary, allocate an entry in the paging file for this page
*/
if (SwapEntry == 0)
{
SwapEntry = MmAllocSwapPage();
if (SwapEntry == 0)
{
MmShowOutOfSpaceMessagePagingFile();
MmLockAddressSpace(AddressSpace);
/*
* For private pages restore the old mappings.
*/
if (Context.Private)
{
Status = MmCreateVirtualMapping(Process,
Address,
MemoryArea->Protect,
&Page,
1);
MmSetDirtyPage(Process, Address);
MmInsertRmap(Page,
Process,
Address);
}
else
{
ULONG_PTR OldEntry;
MmLockSectionSegment(Context.Segment);
/*
* For non-private pages if the page wasn't direct mapped then
* set it back into the section segment entry so we don't loose
* our copy. Otherwise it will be handled by the cache manager.
*/
Status = MmCreateVirtualMapping(Process,
Address,
MemoryArea->Protect,
&Page,
1);
MmSetDirtyPage(Process, Address);
MmInsertRmap(Page,
Process,
Address);
// If we got here, the previous entry should have been a wait
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
OldEntry = MmGetPageEntrySectionSegment(Context.Segment, &Context.Offset);
ASSERT(OldEntry == 0 || OldEntry == MAKE_SWAP_SSE(MM_WAIT_ENTRY));
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
MmUnlockSectionSegment(Context.Segment);
}
MmUnlockAddressSpace(AddressSpace);
MiSetPageEvent(NULL, NULL);
return(STATUS_PAGEFILE_QUOTA);
}
}
/*
* Write the page to the pagefile
*/
Status = MmWriteToSwapPage(SwapEntry, Page);
if (!NT_SUCCESS(Status))
{
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
Status);
/*
* As above: undo our actions.
* FIXME: Also free the swap page.
*/
MmLockAddressSpace(AddressSpace);
if (Context.Private)
{
Status = MmCreateVirtualMapping(Process,
Address,
MemoryArea->Protect,
&Page,
1);
MmSetDirtyPage(Process, Address);
MmInsertRmap(Page,
Process,
Address);
}
else
{
MmLockSectionSegment(Context.Segment);
Status = MmCreateVirtualMapping(Process,
Address,
MemoryArea->Protect,
&Page,
1);
MmSetDirtyPage(Process, Address);
MmInsertRmap(Page,
Process,
Address);
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
MmUnlockSectionSegment(Context.Segment);
}
MmUnlockAddressSpace(AddressSpace);
MiSetPageEvent(NULL, NULL);
return(STATUS_UNSUCCESSFUL);
}
/*
* Otherwise we have succeeded.
*/
DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
MmSetSavedSwapEntryPage(Page, 0);
if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)
{
MmLockSectionSegment(Context.Segment);
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
MmUnlockSectionSegment(Context.Segment);
}
else
{
MmReleasePageMemoryConsumer(MC_USER, Page);
}
if (Context.Private)
{
MmLockAddressSpace(AddressSpace);
MmLockSectionSegment(Context.Segment);
Status = MmCreatePageFileMapping(Process,
Address,
SwapEntry);
/* We had placed a wait entry upon entry ... replace it before leaving */
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
MmUnlockSectionSegment(Context.Segment);
MmUnlockAddressSpace(AddressSpace);
if (!NT_SUCCESS(Status))
{
DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status, Process, Address);
KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Process, (ULONG_PTR)Address, SwapEntry);
}
}
else
{
MmLockAddressSpace(AddressSpace);
MmLockSectionSegment(Context.Segment);
Entry = MAKE_SWAP_SSE(SwapEntry);
/* We had placed a wait entry upon entry ... replace it before leaving */
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
MmUnlockSectionSegment(Context.Segment);
MmUnlockAddressSpace(AddressSpace);
}
MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
NTSTATUS
NTAPI
MmWritePageSectionView(PMMSUPPORT AddressSpace,
PMEMORY_AREA MemoryArea,
PVOID Address,
ULONG PageEntry)
{
LARGE_INTEGER Offset;
PROS_SECTION_OBJECT Section;
PMM_SECTION_SEGMENT Segment;
PFN_NUMBER Page;
SWAPENTRY SwapEntry;
ULONG_PTR Entry;
BOOLEAN Private;
NTSTATUS Status;
PFILE_OBJECT FileObject;
#ifndef NEWCC
PROS_SHARED_CACHE_MAP SharedCacheMap = NULL;
#endif
BOOLEAN DirectMapped;
BOOLEAN IsImageSection;
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
Address = (PVOID)PAGE_ROUND_DOWN(Address);
Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)
+ MemoryArea->Data.SectionData.ViewOffset.QuadPart;
/*
* Get the segment and section.
*/
Segment = MemoryArea->Data.SectionData.Segment;
Section = MemoryArea->Data.SectionData.Section;
IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
FileObject = Section->FileObject;
DirectMapped = FALSE;
if (FileObject != NULL &&
!(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
{
#ifndef NEWCC
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
#endif
/*
* If the file system is letting us go directly to the cache and the
* memory area was mapped at an offset in the file which is page aligned
* then note this is a direct mapped page.
*/
if (((Offset.QuadPart + Segment->Image.FileOffset) % PAGE_SIZE) == 0 &&
(Offset.QuadPart + PAGE_SIZE <= Segment->RawLength.QuadPart || !IsImageSection))
{
DirectMapped = TRUE;
}
}
/*
* This should never happen since mappings of physical memory are never
* placed in the rmap lists.
*/
if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
{
DPRINT1("Trying to write back page from physical memory mapped at %p "
"process %p\n", Address,
Process ? Process->UniqueProcessId : 0);
KeBugCheck(MEMORY_MANAGEMENT);
}
/*
* Get the section segment entry and the physical address.
*/
Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
if (!MmIsPagePresent(Process, Address))
{
DPRINT1("Trying to page out not-present page at (%p,0x%p).\n",
Process ? Process->UniqueProcessId : 0, Address);
KeBugCheck(MEMORY_MANAGEMENT);
}
Page = MmGetPfnForProcess(Process, Address);
SwapEntry = MmGetSavedSwapEntryPage(Page);
/*
* Check for a private (COWed) page.
*/
if (IS_SWAP_FROM_SSE(Entry) || PFN_FROM_SSE(Entry) != Page)
{
Private = TRUE;
}
else
{
Private = FALSE;
}
/*
* Speculatively set all mappings of the page to clean.
*/
MmSetCleanAllRmaps(Page);
/*
* If this page was direct mapped from the cache then the cache manager
* will take care of writing it back to disk.
*/
if (DirectMapped && !Private)
{
//LARGE_INTEGER SOffset;
ASSERT(SwapEntry == 0);
//SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
#ifndef NEWCC
CcRosMarkDirtyFile(SharedCacheMap, Offset.QuadPart);
#endif
MmLockSectionSegment(Segment);
MmSetPageEntrySectionSegment(Segment, &Offset, PageEntry);
MmUnlockSectionSegment(Segment);
MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
/*
* If necessary, allocate an entry in the paging file for this page
*/
if (SwapEntry == 0)
{
SwapEntry = MmAllocSwapPage();
if (SwapEntry == 0)
{
MmSetDirtyAllRmaps(Page);
MiSetPageEvent(NULL, NULL);
return(STATUS_PAGEFILE_QUOTA);
}
MmSetSavedSwapEntryPage(Page, SwapEntry);
}
/*
* Write the page to the pagefile
*/
Status = MmWriteToSwapPage(SwapEntry, Page);
if (!NT_SUCCESS(Status))
{
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
Status);
MmSetDirtyAllRmaps(Page);
MiSetPageEvent(NULL, NULL);
return(STATUS_UNSUCCESSFUL);
}
/*
* Otherwise we have succeeded.
*/
DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
NTSTATUS
NTAPI
MmProtectSectionView(PMMSUPPORT AddressSpace,
PMEMORY_AREA MemoryArea,
PVOID BaseAddress,
SIZE_T Length,
ULONG Protect,
PULONG OldProtect)
{
PMM_REGION Region;
NTSTATUS Status;
ULONG_PTR MaxLength;
MaxLength = MA_GetEndingAddress(MemoryArea) - (ULONG_PTR)BaseAddress;
if (Length > MaxLength)
Length = (ULONG)MaxLength;
Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
&MemoryArea->Data.SectionData.RegionListHead,
BaseAddress, NULL);
ASSERT(Region != NULL);
if ((MemoryArea->Flags & SEC_NO_CHANGE) &&
Region->Protect != Protect)
{
return STATUS_INVALID_PAGE_PROTECTION;
}
*OldProtect = Region->Protect;
Status = MmAlterRegion(AddressSpace, (PVOID)MA_GetStartingAddress(MemoryArea),
&MemoryArea->Data.SectionData.RegionListHead,
BaseAddress, Length, Region->Type, Protect,
MmAlterViewAttributes);
return(Status);
}
NTSTATUS NTAPI
MmQuerySectionView(PMEMORY_AREA MemoryArea,
PVOID Address,
PMEMORY_BASIC_INFORMATION Info,
PSIZE_T ResultLength)
{
PMM_REGION Region;
PVOID RegionBaseAddress;
PROS_SECTION_OBJECT Section;
PMM_SECTION_SEGMENT Segment;
Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
&MemoryArea->Data.SectionData.RegionListHead,
Address, &RegionBaseAddress);
if (Region == NULL)
{
return STATUS_UNSUCCESSFUL;
}
Section = MemoryArea->Data.SectionData.Section;
if (Section->AllocationAttributes & SEC_IMAGE)
{
Segment = MemoryArea->Data.SectionData.Segment;
Info->AllocationBase = (PUCHAR)MA_GetStartingAddress(MemoryArea) - Segment->Image.VirtualAddress;
Info->Type = MEM_IMAGE;
}
else
{
Info->AllocationBase = (PVOID)MA_GetStartingAddress(MemoryArea);
Info->Type = MEM_MAPPED;
}
Info->BaseAddress = RegionBaseAddress;
Info->AllocationProtect = MemoryArea->Protect;
Info->RegionSize = Region->Length;
Info->State = MEM_COMMIT;
Info->Protect = Region->Protect;
*ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
return(STATUS_SUCCESS);
}
VOID
NTAPI
MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment)
{
ULONG Length;
LARGE_INTEGER Offset;
ULONG_PTR Entry;
SWAPENTRY SavedSwapEntry;
PFN_NUMBER Page;
Page = 0;
MmLockSectionSegment(Segment);
Length = PAGE_ROUND_UP(Segment->Length.QuadPart);
for (Offset.QuadPart = 0; Offset.QuadPart < Length; Offset.QuadPart += PAGE_SIZE)
{
Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
if (Entry)
{
MmSetPageEntrySectionSegment(Segment, &Offset, 0);
if (IS_SWAP_FROM_SSE(Entry))
{
MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
}
else
{
Page = PFN_FROM_SSE(Entry);
SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
if (SavedSwapEntry != 0)
{
MmSetSavedSwapEntryPage(Page, 0);
MmFreeSwapPage(SavedSwapEntry);
}
MmReleasePageMemoryConsumer(MC_USER, Page);
}
}
}
MmUnlockSectionSegment(Segment);
}
VOID NTAPI
MmpDeleteSection(PVOID ObjectBody)
{
PROS_SECTION_OBJECT Section = (PROS_SECTION_OBJECT)ObjectBody;
/* Check if it's an ARM3, or ReactOS section */
if (!MiIsRosSectionObject(Section))
{
MiDeleteARM3Section(ObjectBody);
return;
}
DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody);
if (Section->AllocationAttributes & SEC_IMAGE)
{
ULONG i;
ULONG NrSegments;
ULONG RefCount;
PMM_SECTION_SEGMENT SectionSegments;
/*
* NOTE: Section->ImageSection can be NULL for short time
* during the section creating. If we fail for some reason
* until the image section is properly initialized we shouldn't
* process further here.
*/
if (Section->ImageSection == NULL)
return;
SectionSegments = Section->ImageSection->Segments;
NrSegments = Section->ImageSection->NrSegments;
for (i = 0; i < NrSegments; i++)
{
if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED)
{
MmLockSectionSegment(&SectionSegments[i]);
}
RefCount = InterlockedDecrementUL(&SectionSegments[i].ReferenceCount);
if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED)
{
MmUnlockSectionSegment(&SectionSegments[i]);
if (RefCount == 0)
{
MmpFreePageFileSegment(&SectionSegments[i]);
}
}
}
}
#ifdef NEWCC
else if (Section->Segment && Section->Segment->Flags & MM_DATAFILE_SEGMENT)
{
ULONG RefCount = 0;
PMM_SECTION_SEGMENT Segment = Section->Segment;
if (Segment &&
(RefCount = InterlockedDecrementUL(&Segment->ReferenceCount)) == 0)
{
DPRINT("Freeing section segment\n");
Section->Segment = NULL;
MmFinalizeSegment(Segment);
}
else
{
DPRINT("RefCount %d\n", RefCount);
}
}
#endif
else
{
/*
* NOTE: Section->Segment can be NULL for short time
* during the section creating.
*/
if (Section->Segment == NULL)
return;
if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
{
MmpFreePageFileSegment(Section->Segment);
MmFreePageTablesSectionSegment(Section->Segment, NULL);
ExFreePool(Section->Segment);
Section->Segment = NULL;
}
else
{
(void)InterlockedDecrementUL(&Section->Segment->ReferenceCount);
}
}
if (Section->FileObject != NULL)
{
#ifndef NEWCC
CcRosDereferenceCache(Section->FileObject);
#endif
ObDereferenceObject(Section->FileObject);
Section->FileObject = NULL;
}
}
VOID NTAPI
MmpCloseSection(IN PEPROCESS Process OPTIONAL,
IN PVOID Object,
IN ACCESS_MASK GrantedAccess,
IN ULONG ProcessHandleCount,
IN ULONG SystemHandleCount)
{
DPRINT("MmpCloseSection(OB %p, HC %lu)\n", Object, ProcessHandleCount);
}
NTSTATUS
INIT_FUNCTION
NTAPI
MmCreatePhysicalMemorySection(VOID)
{
PROS_SECTION_OBJECT PhysSection;
NTSTATUS Status;
OBJECT_ATTRIBUTES Obj;
UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
LARGE_INTEGER SectionSize;
HANDLE Handle;
/*
* Create the section mapping physical memory
*/
SectionSize.QuadPart = 0xFFFFFFFF;
InitializeObjectAttributes(&Obj,
&Name,
OBJ_PERMANENT | OBJ_KERNEL_EXCLUSIVE,
NULL,
NULL);
Status = MmCreateSection((PVOID)&PhysSection,
SECTION_ALL_ACCESS,
&Obj,
&SectionSize,
PAGE_EXECUTE_READWRITE,
SEC_PHYSICALMEMORY,
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create PhysicalMemory section\n");
KeBugCheck(MEMORY_MANAGEMENT);
}
Status = ObInsertObject(PhysSection,
NULL,
SECTION_ALL_ACCESS,
0,
NULL,
&Handle);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(PhysSection);
}
ObCloseHandle(Handle, KernelMode);
PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
PhysSection->Segment->Flags &= ~MM_PAGEFILE_SEGMENT;
return(STATUS_SUCCESS);
}
NTSTATUS
INIT_FUNCTION
NTAPI
MmInitSectionImplementation(VOID)
{
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
UNICODE_STRING Name;
DPRINT("Creating Section Object Type\n");
/* Initialize the section based root */
ASSERT(MmSectionBasedRoot.NumberGenericTableElements == 0);
MmSectionBasedRoot.BalancedRoot.u1.Parent = &MmSectionBasedRoot.BalancedRoot;
/* Initialize the Section object type */
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
RtlInitUnicodeString(&Name, L"Section");
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(ROS_SECTION_OBJECT);
ObjectTypeInitializer.PoolType = PagedPool;
ObjectTypeInitializer.UseDefaultObject = TRUE;
ObjectTypeInitializer.GenericMapping = MmpSectionMapping;
ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection;
ObjectTypeInitializer.CloseProcedure = MmpCloseSection;
ObjectTypeInitializer.ValidAccessMask = SECTION_ALL_ACCESS;
ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &MmSectionObjectType);
MmCreatePhysicalMemorySection();
return(STATUS_SUCCESS);
}
NTSTATUS
NTAPI
MmCreatePageFileSection(PROS_SECTION_OBJECT *SectionObject,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PLARGE_INTEGER UMaximumSize,
ULONG SectionPageProtection,
ULONG AllocationAttributes)
/*
* Create a section which is backed by the pagefile
*/
{
LARGE_INTEGER MaximumSize;
PROS_SECTION_OBJECT Section;
PMM_SECTION_SEGMENT Segment;
NTSTATUS Status;
if (UMaximumSize == NULL)
{
DPRINT1("MmCreatePageFileSection: (UMaximumSize == NULL)\n");
return(STATUS_INVALID_PARAMETER);
}
MaximumSize = *UMaximumSize;
/*
* Create the section
*/
Status = ObCreateObject(ExGetPreviousMode(),
MmSectionObjectType,
ObjectAttributes,
ExGetPreviousMode(),
NULL,
sizeof(ROS_SECTION_OBJECT),
0,
0,
(PVOID*)(PVOID)&Section);
if (!NT_SUCCESS(Status))
{
DPRINT1("MmCreatePageFileSection: failed to create object (0x%lx)\n", Status);
return(Status);
}
/*
* Initialize it
*/
RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
Section->Type = 'SC';
Section->Size = 'TN';
Section->SectionPageProtection = SectionPageProtection;
Section->AllocationAttributes = AllocationAttributes;
Section->MaximumSize = MaximumSize;
Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
TAG_MM_SECTION_SEGMENT);
if (Segment == NULL)
{
ObDereferenceObject(Section);
return(STATUS_NO_MEMORY);
}
RtlZeroMemory(Segment, sizeof(MM_SECTION_SEGMENT));
Section->Segment = Segment;
Segment->ReferenceCount = 1;
ExInitializeFastMutex(&Segment->Lock);
Segment->Image.FileOffset = 0;
Segment->Protection = SectionPageProtection;
Segment->RawLength.QuadPart = MaximumSize.u.LowPart;
Segment->Length.QuadPart = PAGE_ROUND_UP(MaximumSize.u.LowPart);
Segment->Flags = MM_PAGEFILE_SEGMENT;
Segment->WriteCopy = FALSE;
Segment->Image.VirtualAddress = 0;
Segment->Image.Characteristics = 0;
*SectionObject = Section;
MiInitializeSectionPageTable(Segment);
return(STATUS_SUCCESS);
}
NTSTATUS
NTAPI
MmCreateDataFileSection(PROS_SECTION_OBJECT *SectionObject,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PLARGE_INTEGER UMaximumSize,
ULONG SectionPageProtection,
ULONG AllocationAttributes,
PFILE_OBJECT FileObject)
/*
* Create a section backed by a data file
*/
{
PROS_SECTION_OBJECT Section;
NTSTATUS Status;
LARGE_INTEGER MaximumSize;
PMM_SECTION_SEGMENT Segment;
FILE_STANDARD_INFORMATION FileInfo;
ULONG Length;
/*
* Create the section
*/
Status = ObCreateObject(ExGetPreviousMode(),
MmSectionObjectType,
ObjectAttributes,
ExGetPreviousMode(),
NULL,
sizeof(ROS_SECTION_OBJECT),
0,
0,
(PVOID*)&Section);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(FileObject);
return(Status);
}
/*
* Initialize it
*/
RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
Section->Type = 'SC';
Section->Size = 'TN';
Section->SectionPageProtection = SectionPageProtection;
Section->AllocationAttributes = AllocationAttributes;
/*
* FIXME: This is propably not entirely correct. We can't look into
* the standard FCB header because it might not be initialized yet
* (as in case of the EXT2FS driver by Manoj Paul Joseph where the
* standard file information is filled on first request).
*/
Status = IoQueryFileInformation(FileObject,
FileStandardInformation,
sizeof(FILE_STANDARD_INFORMATION),
&FileInfo,
&Length);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Section);
ObDereferenceObject(FileObject);
return Status;
}
/*
* FIXME: Revise this once a locking order for file size changes is
* decided
*/
if ((UMaximumSize != NULL) && (UMaximumSize->QuadPart != 0))
{
MaximumSize = *UMaximumSize;
}
else
{
MaximumSize = FileInfo.EndOfFile;
/* Mapping zero-sized files isn't allowed. */
if (MaximumSize.QuadPart == 0)
{
ObDereferenceObject(Section);
ObDereferenceObject(FileObject);
return STATUS_MAPPED_FILE_SIZE_ZERO;
}
}
if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart)
{
Status = IoSetInformation(FileObject,
FileEndOfFileInformation,
sizeof(LARGE_INTEGER),
&MaximumSize);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Section);
ObDereferenceObject(FileObject);
return(STATUS_SECTION_NOT_EXTENDED);
}
}
if (FileObject->SectionObjectPointer == NULL ||
FileObject->SectionObjectPointer->SharedCacheMap == NULL)
{
ObDereferenceObject(Section);
ObDereferenceObject(FileObject);
return STATUS_INVALID_FILE_FOR_SECTION;
}
/*
* Lock the file
*/
Status = MmspWaitForFileLock(FileObject);
if (Status != STATUS_SUCCESS)
{
ObDereferenceObject(Section);
ObDereferenceObject(FileObject);
return(Status);
}
/*
* If this file hasn't been mapped as a data file before then allocate a
* section segment to describe the data file mapping
*/
if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
{
Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
TAG_MM_SECTION_SEGMENT);
if (Segment == NULL)
{
//KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
ObDereferenceObject(Section);
ObDereferenceObject(FileObject);
return(STATUS_NO_MEMORY);
}
Section->Segment = Segment;
Segment->ReferenceCount = 1;
ExInitializeFastMutex(&Segment->Lock);
/*
* Set the lock before assigning the segment to the file object
*/
ExAcquireFastMutex(&Segment->Lock);
FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
Segment->Image.FileOffset = 0;
Segment->Protection = SectionPageProtection;
Segment->Flags = MM_DATAFILE_SEGMENT;
Segment->Image.Characteristics = 0;
Segment->WriteCopy = (SectionPageProtection & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY));
if (AllocationAttributes & SEC_RESERVE)
{
Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0;
}
else
{
Segment->RawLength.QuadPart = MaximumSize.QuadPart;
Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
}
Segment->Image.VirtualAddress = 0;
Segment->Locked = TRUE;
MiInitializeSectionPageTable(Segment);
}
else
{
/*
* If the file is already mapped as a data file then we may need
* to extend it
*/
Segment =
(PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
DataSectionObject;
Section->Segment = Segment;
(void)InterlockedIncrementUL(&Segment->ReferenceCount);
MmLockSectionSegment(Segment);
if (MaximumSize.QuadPart > Segment->RawLength.QuadPart &&
!(AllocationAttributes & SEC_RESERVE))
{
Segment->RawLength.QuadPart = MaximumSize.QuadPart;
Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
}
}
MmUnlockSectionSegment(Segment);
Section->FileObject = FileObject;
Section->MaximumSize = MaximumSize;
#ifndef NEWCC
CcRosReferenceCache(FileObject);
#endif
//KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
*SectionObject = Section;
return(STATUS_SUCCESS);
}
/*
TODO: not that great (declaring loaders statically, having to declare all of
them, having to keep them extern, etc.), will fix in the future
*/
extern NTSTATUS NTAPI PeFmtCreateSection
(
IN CONST VOID * FileHeader,
IN SIZE_T FileHeaderSize,
IN PVOID File,
OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
OUT PULONG Flags,
IN PEXEFMT_CB_READ_FILE ReadFileCb,
IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
);
extern NTSTATUS NTAPI ElfFmtCreateSection
(
IN CONST VOID * FileHeader,
IN SIZE_T FileHeaderSize,
IN PVOID File,
OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
OUT PULONG Flags,
IN PEXEFMT_CB_READ_FILE ReadFileCb,
IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
);
static PEXEFMT_LOADER ExeFmtpLoaders[] =
{
PeFmtCreateSection,
#ifdef __ELF
ElfFmtCreateSection
#endif
};
static
PMM_SECTION_SEGMENT
NTAPI
ExeFmtpAllocateSegments(IN ULONG NrSegments)
{
SIZE_T SizeOfSegments;
PMM_SECTION_SEGMENT Segments;
/* TODO: check for integer overflow */
SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * NrSegments;
Segments = ExAllocatePoolWithTag(NonPagedPool,
SizeOfSegments,
TAG_MM_SECTION_SEGMENT);
if(Segments)
RtlZeroMemory(Segments, SizeOfSegments);
return Segments;
}
static
NTSTATUS
NTAPI
ExeFmtpReadFile(IN PVOID File,
IN PLARGE_INTEGER Offset,
IN ULONG Length,
OUT PVOID * Data,
OUT PVOID * AllocBase,
OUT PULONG ReadSize)
{
NTSTATUS Status;
LARGE_INTEGER FileOffset;
ULONG AdjustOffset;
ULONG OffsetAdjustment;
ULONG BufferSize;
ULONG UsedSize;
PVOID Buffer;
PFILE_OBJECT FileObject = File;
IO_STATUS_BLOCK Iosb;
ASSERT_IRQL_LESS(DISPATCH_LEVEL);
if(Length == 0)
{
KeBugCheck(MEMORY_MANAGEMENT);
}
FileOffset = *Offset;
/* Negative/special offset: it cannot be used in this context */
if(FileOffset.u.HighPart < 0)
{
KeBugCheck(MEMORY_MANAGEMENT);
}
AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart);
OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset;
FileOffset.u.LowPart = AdjustOffset;
BufferSize = Length + OffsetAdjustment;
BufferSize = PAGE_ROUND_UP(BufferSize);
/* Flush data since we're about to perform a non-cached read */
CcFlushCache(FileObject->SectionObjectPointer,
&FileOffset,
BufferSize,
&Iosb);
/*
* It's ok to use paged pool, because this is a temporary buffer only used in
* the loading of executables. The assumption is that MmCreateSection is
* always called at low IRQLs and that these buffers don't survive a brief
* initialization phase
*/
Buffer = ExAllocatePoolWithTag(PagedPool,
BufferSize,
'rXmM');
if (!Buffer)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
UsedSize = 0;
Status = MiSimpleRead(FileObject, &FileOffset, Buffer, BufferSize, TRUE, &Iosb);
UsedSize = (ULONG)Iosb.Information;
if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
{
Status = STATUS_IN_PAGE_ERROR;
ASSERT(!NT_SUCCESS(Status));
}
if(NT_SUCCESS(Status))
{
*Data = (PVOID)((ULONG_PTR)Buffer + OffsetAdjustment);
*AllocBase = Buffer;
*ReadSize = UsedSize - OffsetAdjustment;
}
else
{
ExFreePoolWithTag(Buffer, 'rXmM');
}
return Status;
}
#ifdef NASSERT
# define MmspAssertSegmentsSorted(OBJ_) ((void)0)
# define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
# define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
#else
static
VOID
NTAPI
MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
{
ULONG i;
for( i = 1; i < ImageSectionObject->NrSegments; ++ i )
{
ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >=
ImageSectionObject->Segments[i - 1].Image.VirtualAddress);
}
}
static
VOID
NTAPI
MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
{
ULONG i;
MmspAssertSegmentsSorted(ImageSectionObject);
for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
{
ASSERT(ImageSectionObject->Segments[i].Length.QuadPart > 0);
if(i > 0)
{
ASSERT(ImageSectionObject->Segments[i].Image.VirtualAddress >=
(ImageSectionObject->Segments[i - 1].Image.VirtualAddress +
ImageSectionObject->Segments[i - 1].Length.QuadPart));
}
}
}
static
VOID
NTAPI
MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
{
ULONG i;
for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
{
ASSERT((ImageSectionObject->Segments[i].Image.VirtualAddress % PAGE_SIZE) == 0);
ASSERT((ImageSectionObject->Segments[i].Length.QuadPart % PAGE_SIZE) == 0);
}
}
#endif
static
int
__cdecl
MmspCompareSegments(const void * x,
const void * y)
{
const MM_SECTION_SEGMENT *Segment1 = (const MM_SECTION_SEGMENT *)x;
const MM_SECTION_SEGMENT *Segment2 = (const MM_SECTION_SEGMENT *)y;
return
(Segment1->Image.VirtualAddress - Segment2->Image.VirtualAddress) >>
((sizeof(ULONG_PTR) - sizeof(int)) * 8);
}
/*
* Ensures an image section's segments are sorted in memory
*/
static
VOID
NTAPI
MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
IN ULONG Flags)
{
if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED)
{
MmspAssertSegmentsSorted(ImageSectionObject);
}
else
{
qsort(ImageSectionObject->Segments,
ImageSectionObject->NrSegments,
sizeof(ImageSectionObject->Segments[0]),
MmspCompareSegments);
}
}
/*
* Ensures an image section's segments don't overlap in memory and don't have
* gaps and don't have a null size. We let them map to overlapping file regions,
* though - that's not necessarily an error
*/
static
BOOLEAN
NTAPI
MmspCheckSegmentBounds
(
IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
IN ULONG Flags
)
{
ULONG i;
if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP)
{
MmspAssertSegmentsNoOverlap(ImageSectionObject);
return TRUE;
}
ASSERT(ImageSectionObject->NrSegments >= 1);
for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
{
if(ImageSectionObject->Segments[i].Length.QuadPart == 0)
{
return FALSE;
}
if(i > 0)
{
/*
* TODO: relax the limitation on gaps. For example, gaps smaller than a
* page could be OK (Windows seems to be OK with them), and larger gaps
* could lead to image sections spanning several discontiguous regions
* (NtMapViewOfSection could then refuse to map them, and they could
* e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
*/
if ((ImageSectionObject->Segments[i - 1].Image.VirtualAddress +
ImageSectionObject->Segments[i - 1].Length.QuadPart) !=
ImageSectionObject->Segments[i].Image.VirtualAddress)
{
return FALSE;
}
}
}
return TRUE;
}
/*
* Merges and pads an image section's segments until they all are page-aligned
* and have a size that is a multiple of the page size
*/
static
BOOLEAN
NTAPI
MmspPageAlignSegments
(
IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
IN ULONG Flags
)
{
ULONG i;
ULONG LastSegment;
PMM_SECTION_SEGMENT EffectiveSegment;
if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED)
{
MmspAssertSegmentsPageAligned(ImageSectionObject);
return TRUE;
}
LastSegment = 0;
EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
{
/*
* The first segment requires special handling
*/
if (i == 0)
{
ULONG_PTR VirtualAddress;
ULONG_PTR VirtualOffset;
VirtualAddress = EffectiveSegment->Image.VirtualAddress;
/* Round down the virtual address to the nearest page */
EffectiveSegment->Image.VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress);
/* Round up the virtual size to the nearest page */
EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length.QuadPart) -
EffectiveSegment->Image.VirtualAddress;
/* Adjust the raw address and size */
VirtualOffset = VirtualAddress - EffectiveSegment->Image.VirtualAddress;
if (EffectiveSegment->Image.FileOffset < VirtualOffset)
{
return FALSE;
}
/*
* Garbage in, garbage out: unaligned base addresses make the file
* offset point in curious and odd places, but that's what we were
* asked for
*/
EffectiveSegment->Image.FileOffset -= VirtualOffset;
EffectiveSegment->RawLength.QuadPart += VirtualOffset;
}
else
{
PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
ULONG_PTR EndOfEffectiveSegment;
EndOfEffectiveSegment = (ULONG_PTR)(EffectiveSegment->Image.VirtualAddress + EffectiveSegment->Length.QuadPart);
ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0);
/*
* The current segment begins exactly where the current effective
* segment ended, therefore beginning a new effective segment
*/
if (EndOfEffectiveSegment == Segment->Image.VirtualAddress)
{
LastSegment ++;
ASSERT(LastSegment <= i);
ASSERT(LastSegment < ImageSectionObject->NrSegments);
EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
if (LastSegment != i)
{
/*
* Copy the current segment. If necessary, the effective segment
* will be expanded later
*/
*EffectiveSegment = *Segment;
}
/*
* Page-align the virtual size. We know for sure the virtual address
* already is
*/
ASSERT((EffectiveSegment->Image.VirtualAddress % PAGE_SIZE) == 0);
EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(EffectiveSegment->Length.QuadPart);
}
/*
* The current segment is still part of the current effective segment:
* extend the effective segment to reflect this
*/
else if (EndOfEffectiveSegment > Segment->Image.VirtualAddress)
{
static const ULONG FlagsToProtection[16] =
{
PAGE_NOACCESS,
PAGE_READONLY,
PAGE_READWRITE,
PAGE_READWRITE,
PAGE_EXECUTE_READ,
PAGE_EXECUTE_READ,
PAGE_EXECUTE_READWRITE,
PAGE_EXECUTE_READWRITE,
PAGE_WRITECOPY,
PAGE_WRITECOPY,
PAGE_WRITECOPY,
PAGE_WRITECOPY,
PAGE_EXECUTE_WRITECOPY,
PAGE_EXECUTE_WRITECOPY,
PAGE_EXECUTE_WRITECOPY,
PAGE_EXECUTE_WRITECOPY
};
unsigned ProtectionFlags;
/*
* Extend the file size
*/
/* Unaligned segments must be contiguous within the file */
if (Segment->Image.FileOffset != (EffectiveSegment->Image.FileOffset +
EffectiveSegment->RawLength.QuadPart))
{
return FALSE;
}
EffectiveSegment->RawLength.QuadPart += Segment->RawLength.QuadPart;
/*
* Extend the virtual size
*/
ASSERT(PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) >= EndOfEffectiveSegment);
EffectiveSegment->Length.QuadPart = PAGE_ROUND_UP(Segment->Image.VirtualAddress + Segment->Length.QuadPart) -
EffectiveSegment->Image.VirtualAddress;
/*
* Merge the protection
*/
EffectiveSegment->Protection |= Segment->Protection;
/* Clean up redundance */
ProtectionFlags = 0;
if(EffectiveSegment->Protection & PAGE_IS_READABLE)
ProtectionFlags |= 1 << 0;
if(EffectiveSegment->Protection & PAGE_IS_WRITABLE)
ProtectionFlags |= 1 << 1;
if(EffectiveSegment->Protection & PAGE_IS_EXECUTABLE)
ProtectionFlags |= 1 << 2;
if(EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
ProtectionFlags |= 1 << 3;
ASSERT(ProtectionFlags < 16);
EffectiveSegment->Protection = FlagsToProtection[ProtectionFlags];
/* If a segment was required to be shared and cannot, fail */
if(!(Segment->Protection & PAGE_IS_WRITECOPY) &&
EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
{
return FALSE;
}
}
/*
* We assume no holes between segments at this point
*/
else
{
KeBugCheck(MEMORY_MANAGEMENT);
}
}
}
ImageSectionObject->NrSegments = LastSegment + 1;
return TRUE;
}
NTSTATUS
ExeFmtpCreateImageSection(PFILE_OBJECT FileObject,
PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
{
LARGE_INTEGER Offset;
PVOID FileHeader;
PVOID FileHeaderBuffer;
ULONG FileHeaderSize;
ULONG Flags;
ULONG OldNrSegments;
NTSTATUS Status;
ULONG i;
/*
* Read the beginning of the file (2 pages). Should be enough to contain
* all (or most) of the headers
*/
Offset.QuadPart = 0;
Status = ExeFmtpReadFile (FileObject,
&Offset,
PAGE_SIZE * 2,
&FileHeader,
&FileHeaderBuffer,
&FileHeaderSize);
if (!NT_SUCCESS(Status))
return Status;
if (FileHeaderSize == 0)
{
ExFreePool(FileHeaderBuffer);
return STATUS_UNSUCCESSFUL;
}
/*
* Look for a loader that can handle this executable
*/
for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i)
{
RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject));
Flags = 0;
Status = ExeFmtpLoaders[i](FileHeader,
FileHeaderSize,
FileObject,
ImageSectionObject,
&Flags,
ExeFmtpReadFile,
ExeFmtpAllocateSegments);
if (!NT_SUCCESS(Status))
{
if (ImageSectionObject->Segments)
{
ExFreePool(ImageSectionObject->Segments);
ImageSectionObject->Segments = NULL;
}
}
if (Status != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
break;
}
ExFreePoolWithTag(FileHeaderBuffer, 'rXmM');
/*
* No loader handled the format
*/
if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
{
Status = STATUS_INVALID_IMAGE_NOT_MZ;
ASSERT(!NT_SUCCESS(Status));
}
if (!NT_SUCCESS(Status))
return Status;
ASSERT(ImageSectionObject->Segments != NULL);
/*
* Some defaults
*/
/* FIXME? are these values platform-dependent? */
if (ImageSectionObject->ImageInformation.MaximumStackSize == 0)
ImageSectionObject->ImageInformation.MaximumStackSize = 0x40000;
if(ImageSectionObject->ImageInformation.CommittedStackSize == 0)
ImageSectionObject->ImageInformation.CommittedStackSize = 0x1000;
if(ImageSectionObject->BasedAddress == NULL)
{
if(ImageSectionObject->ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL)
ImageSectionObject->BasedAddress = (PVOID)0x10000000;
else
ImageSectionObject->BasedAddress = (PVOID)0x00400000;
}
/*
* And now the fun part: fixing the segments
*/
/* Sort them by virtual address */
MmspSortSegments(ImageSectionObject, Flags);
/* Ensure they don't overlap in memory */
if (!MmspCheckSegmentBounds(ImageSectionObject, Flags))
return STATUS_INVALID_IMAGE_FORMAT;
/* Ensure they are aligned */
OldNrSegments = ImageSectionObject->NrSegments;
if (!MmspPageAlignSegments(ImageSectionObject, Flags))
return STATUS_INVALID_IMAGE_FORMAT;
/* Trim them if the alignment phase merged some of them */
if (ImageSectionObject->NrSegments < OldNrSegments)
{
PMM_SECTION_SEGMENT Segments;
SIZE_T SizeOfSegments;
SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments;
Segments = ExAllocatePoolWithTag(PagedPool,
SizeOfSegments,
TAG_MM_SECTION_SEGMENT);
if (Segments == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
RtlCopyMemory(Segments, ImageSectionObject->Segments, SizeOfSegments);
ExFreePool(ImageSectionObject->Segments);
ImageSectionObject->Segments = Segments;
}
/* And finish their initialization */
for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
{
ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock);
ImageSectionObject->Segments[i].ReferenceCount = 1;
MiInitializeSectionPageTable(&ImageSectionObject->Segments[i]);
}
ASSERT(NT_SUCCESS(Status));
return Status;
}
NTSTATUS
MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PLARGE_INTEGER UMaximumSize,
ULONG SectionPageProtection,
ULONG AllocationAttributes,
PFILE_OBJECT FileObject)
{
PROS_SECTION_OBJECT Section;
NTSTATUS Status;
PMM_SECTION_SEGMENT SectionSegments;
PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
ULONG i;
if (FileObject == NULL)
return STATUS_INVALID_FILE_FOR_SECTION;
#ifndef NEWCC
if (FileObject->SectionObjectPointer->SharedCacheMap == NULL)
{
DPRINT1("Denying section creation due to missing cache initialization\n");
return STATUS_INVALID_FILE_FOR_SECTION;
}
#endif
/*
* Create the section
*/
Status = ObCreateObject (ExGetPreviousMode(),
MmSectionObjectType,
ObjectAttributes,
ExGetPreviousMode(),
NULL,
sizeof(ROS_SECTION_OBJECT),
0,
0,
(PVOID*)(PVOID)&Section);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(FileObject);
return(Status);
}
/*
* Initialize it
*/
RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
Section->Type = 'SC';
Section->Size = 'TN';
Section->SectionPageProtection = SectionPageProtection;
Section->AllocationAttributes = AllocationAttributes;
if (FileObject->SectionObjectPointer->ImageSectionObject == NULL)
{
NTSTATUS StatusExeFmt;
ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
if (ImageSectionObject == NULL)
{
ObDereferenceObject(FileObject);
ObDereferenceObject(Section);
return(STATUS_NO_MEMORY);
}
RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT));
StatusExeFmt = ExeFmtpCreateImageSection(FileObject, ImageSectionObject);
if (!NT_SUCCESS(StatusExeFmt))
{
if(ImageSectionObject->Segments != NULL)
ExFreePool(ImageSectionObject->Segments);
/*
* If image file is empty, then return that the file is invalid for section
*/
Status = StatusExeFmt;
if (StatusExeFmt == STATUS_END_OF_FILE)
{
Status = STATUS_INVALID_FILE_FOR_SECTION;
}
ExFreePoolWithTag(ImageSectionObject, TAG_MM_SECTION_SEGMENT);
ObDereferenceObject(Section);
ObDereferenceObject(FileObject);
return(Status);
}
Section->ImageSection = ImageSectionObject;
ASSERT(ImageSectionObject->Segments);
/*
* Lock the file
*/
Status = MmspWaitForFileLock(FileObject);
if (!NT_SUCCESS(Status))
{
ExFreePool(ImageSectionObject->Segments);
ExFreePool(ImageSectionObject);
ObDereferenceObject(Section);
ObDereferenceObject(FileObject);
return(Status);
}
if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject,
ImageSectionObject, NULL))
{
/*
* An other thread has initialized the same image in the background
*/
ExFreePool(ImageSectionObject->Segments);
ExFreePool(ImageSectionObject);
ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
Section->ImageSection = ImageSectionObject;
SectionSegments = ImageSectionObject->Segments;
for (i = 0; i < ImageSectionObject->NrSegments; i++)
{
(void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
}
}
Status = StatusExeFmt;
}
else
{
/*
* Lock the file
*/
Status = MmspWaitForFileLock(FileObject);
if (Status != STATUS_SUCCESS)
{
ObDereferenceObject(Section);
ObDereferenceObject(FileObject);
return(Status);
}
ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
Section->ImageSection = ImageSectionObject;
SectionSegments = ImageSectionObject->Segments;
/*
* Otherwise just reference all the section segments
*/
for (i = 0; i < ImageSectionObject->NrSegments; i++)
{
(void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
}
Status = STATUS_SUCCESS;
}
Section->FileObject = FileObject;
#ifndef NEWCC
CcRosReferenceCache(FileObject);
#endif
//KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
*SectionObject = Section;
return(Status);
}
static NTSTATUS
MmMapViewOfSegment(PMMSUPPORT AddressSpace,
PROS_SECTION_OBJECT Section,
PMM_SECTION_SEGMENT Segment,
PVOID* BaseAddress,
SIZE_T ViewSize,
ULONG Protect,
ULONG ViewOffset,
ULONG AllocationType)
{
PMEMORY_AREA MArea;
NTSTATUS Status;
ULONG Granularity;
if (Segment->WriteCopy)
{
/* We have to do this because the not present fault
* and access fault handlers depend on the protection
* that should be granted AFTER the COW fault takes
* place to be in Region->Protect. The not present fault
* handler changes this to the correct protection for COW when
* mapping the pages into the process's address space. If a COW
* fault takes place, the access fault handler sets the page protection
* to these values for the newly copied pages
*/
if (Protect == PAGE_WRITECOPY)
Protect = PAGE_READWRITE;
else if (Protect == PAGE_EXECUTE_WRITECOPY)
Protect = PAGE_EXECUTE_READWRITE;
}
if (*BaseAddress == NULL)
Granularity = MM_ALLOCATION_GRANULARITY;
else
Granularity = PAGE_SIZE;
#ifdef NEWCC
if (Segment->Flags & MM_DATAFILE_SEGMENT)
{
LARGE_INTEGER FileOffset;
FileOffset.QuadPart = ViewOffset;
ObReferenceObject(Section);
return _MiMapViewOfSegment(AddressSpace, Segment, BaseAddress, ViewSize, Protect, &FileOffset, AllocationType, __FILE__, __LINE__);
}
#endif
Status = MmCreateMemoryArea(AddressSpace,
MEMORY_AREA_SECTION_VIEW,
BaseAddress,
ViewSize,
Protect,
&MArea,
AllocationType,
Granularity);
if (!NT_SUCCESS(Status))
{
DPRINT1("Mapping between 0x%p and 0x%p failed (%X).\n",
(*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
return(Status);
}
ObReferenceObject((PVOID)Section);
MArea->Data.SectionData.Segment = Segment;
MArea->Data.SectionData.Section = Section;
MArea->Data.SectionData.ViewOffset.QuadPart = ViewOffset;
if (Section->AllocationAttributes & SEC_IMAGE)
{
MArea->VadNode.u.VadFlags.VadType = VadImageMap;
}
MmInitializeRegion(&MArea->Data.SectionData.RegionListHead,
ViewSize, 0, Protect);
return(STATUS_SUCCESS);
}
static VOID
MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
{
ULONG_PTR Entry;
#ifndef NEWCC
PFILE_OBJECT FileObject;
PROS_SHARED_CACHE_MAP SharedCacheMap;
#endif
LARGE_INTEGER Offset;
SWAPENTRY SavedSwapEntry;
PROS_SECTION_OBJECT Section;
PMM_SECTION_SEGMENT Segment;
PMMSUPPORT AddressSpace;
PEPROCESS Process;
AddressSpace = (PMMSUPPORT)Context;
Process = MmGetAddressSpaceOwner(AddressSpace);
Address = (PVOID)PAGE_ROUND_DOWN(Address);
Offset.QuadPart = ((ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)) +
MemoryArea->Data.SectionData.ViewOffset.QuadPart;
Section = MemoryArea->Data.SectionData.Section;
Segment = MemoryArea->Data.SectionData.Segment;
Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
while (Entry && MM_IS_WAIT_PTE(Entry))
{
MmUnlockSectionSegment(Segment);
MmUnlockAddressSpace(AddressSpace);
MiWaitForPageEvent(NULL, NULL);
MmLockAddressSpace(AddressSpace);
MmLockSectionSegment(Segment);
Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
}
/*
* For a dirty, datafile, non-private page mark it as dirty in the
* cache manager.
*/
if (Segment->Flags & MM_DATAFILE_SEGMENT)
{
if (Page == PFN_FROM_SSE(Entry) && Dirty)
{
#ifndef NEWCC
FileObject = MemoryArea->Data.SectionData.Section->FileObject;
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
CcRosMarkDirtyFile(SharedCacheMap, Offset.QuadPart + Segment->Image.FileOffset);
#endif
ASSERT(SwapEntry == 0);
}
}
if (SwapEntry != 0)
{
/*
* Sanity check
*/
if (Segment->Flags & MM_PAGEFILE_SEGMENT)
{
DPRINT1("Found a swap entry for a page in a pagefile section.\n");
KeBugCheck(MEMORY_MANAGEMENT);
}
MmFreeSwapPage(SwapEntry);
}
else if (Page != 0)
{
if (IS_SWAP_FROM_SSE(Entry) ||
Page != PFN_FROM_SSE(Entry))
{
/*
* Sanity check
*/
if (Segment->Flags & MM_PAGEFILE_SEGMENT)
{
DPRINT1("Found a private page in a pagefile section.\n");
KeBugCheck(MEMORY_MANAGEMENT);
}
/*
* Just dereference private pages
*/
SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
if (SavedSwapEntry != 0)
{
MmFreeSwapPage(SavedSwapEntry);
MmSetSavedSwapEntryPage(Page, 0);
}
MmDeleteRmap(Page, Process, Address);
MmReleasePageMemoryConsumer(MC_USER, Page);
}
else
{
MmDeleteRmap(Page, Process, Address);
MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, Dirty, FALSE, NULL);
}
}
}
static NTSTATUS
MmUnmapViewOfSegment(PMMSUPPORT AddressSpace,
PVOID BaseAddress)
{
NTSTATUS Status;
PMEMORY_AREA MemoryArea;
PROS_SECTION_OBJECT Section;
PMM_SECTION_SEGMENT Segment;
PLIST_ENTRY CurrentEntry;
PMM_REGION CurrentRegion;
PLIST_ENTRY RegionListHead;
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
BaseAddress);
if (MemoryArea == NULL)
{
return(STATUS_UNSUCCESSFUL);
}
Section = MemoryArea->Data.SectionData.Section;
Segment = MemoryArea->Data.SectionData.Segment;
#ifdef NEWCC
if (Segment->Flags & MM_DATAFILE_SEGMENT)
{
MmUnlockAddressSpace(AddressSpace);
Status = MmUnmapViewOfCacheSegment(AddressSpace, BaseAddress);
MmLockAddressSpace(AddressSpace);
return Status;
}
#endif
MemoryArea->DeleteInProgress = TRUE;
MmLockSectionSegment(Segment);
RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
while (!IsListEmpty(RegionListHead))
{
CurrentEntry = RemoveHeadList(RegionListHead);
CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
ExFreePoolWithTag(CurrentRegion, TAG_MM_REGION);
}
if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
{
Status = MmFreeMemoryArea(AddressSpace,
MemoryArea,
NULL,
NULL);
}
else
{
Status = MmFreeMemoryArea(AddressSpace,
MemoryArea,
MmFreeSectionPage,
AddressSpace);
}
MmUnlockSectionSegment(Segment);
ObDereferenceObject(Section);
return(Status);
}
NTSTATUS
NTAPI
MiRosUnmapViewOfSection(IN PEPROCESS Process,
IN PVOID BaseAddress,
IN BOOLEAN SkipDebuggerNotify)
{
NTSTATUS Status;
PMEMORY_AREA MemoryArea;
PMMSUPPORT AddressSpace;
PROS_SECTION_OBJECT Section;
PVOID ImageBaseAddress = 0;
DPRINT("Opening memory area Process %p BaseAddress %p\n",
Process, BaseAddress);
ASSERT(Process);
AddressSpace = Process ? &Process->Vm : MmGetKernelAddressSpace();
MmLockAddressSpace(AddressSpace);
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
BaseAddress);
if (MemoryArea == NULL ||
((MemoryArea->Type != MEMORY_AREA_SECTION_VIEW) &&
(MemoryArea->Type != MEMORY_AREA_CACHE)) ||
MemoryArea->DeleteInProgress)
{
if (MemoryArea) ASSERT(MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3);
MmUnlockAddressSpace(AddressSpace);
return STATUS_NOT_MAPPED_VIEW;
}
Section = MemoryArea->Data.SectionData.Section;
if ((Section != NULL) && (Section->AllocationAttributes & SEC_IMAGE))
{
ULONG i;
ULONG NrSegments;
PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
PMM_SECTION_SEGMENT SectionSegments;
PMM_SECTION_SEGMENT Segment;
Segment = MemoryArea->Data.SectionData.Segment;
ImageSectionObject = Section->ImageSection;
SectionSegments = ImageSectionObject->Segments;
NrSegments = ImageSectionObject->NrSegments;
MemoryArea->DeleteInProgress = TRUE;
/* Search for the current segment within the section segments
* and calculate the image base address */
for (i = 0; i < NrSegments; i++)
{
if (Segment == &SectionSegments[i])
{
ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].Image.VirtualAddress;
break;
}
}
if (i >= NrSegments)
{
KeBugCheck(MEMORY_MANAGEMENT);
}
for (i = 0; i < NrSegments; i++)
{
PVOID SBaseAddress = (PVOID)
((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress);
Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
if (!NT_SUCCESS(Status))
{
DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
SBaseAddress, Process, Status);
ASSERT(NT_SUCCESS(Status));
}
}
}
else
{
Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
if (!NT_SUCCESS(Status))
{
DPRINT1("MmUnmapViewOfSegment failed for %p (Process %p) with %lx\n",
BaseAddress, Process, Status);
ASSERT(NT_SUCCESS(Status));
}
}
MmUnlockAddressSpace(AddressSpace);
/* Notify debugger */
if (ImageBaseAddress && !SkipDebuggerNotify) DbgkUnMapViewOfSection(ImageBaseAddress);
return(STATUS_SUCCESS);
}
/**
* Queries the information of a section object.
*
* @param SectionHandle
* Handle to the section object. It must be opened with SECTION_QUERY
* access.
* @param SectionInformationClass
* Index to a certain information structure. Can be either
* SectionBasicInformation or SectionImageInformation. The latter
* is valid only for sections that were created with the SEC_IMAGE
* flag.
* @param SectionInformation
* Caller supplies storage for resulting information.
* @param Length
* Size of the supplied storage.
* @param ResultLength
* Data written.
*
* @return Status.
*
* @implemented
*/
NTSTATUS
NTAPI
NtQuerySection(
_In_ HANDLE SectionHandle,
_In_ SECTION_INFORMATION_CLASS SectionInformationClass,
_Out_ PVOID SectionInformation,
_In_ SIZE_T SectionInformationLength,
_Out_opt_ PSIZE_T ResultLength)
{
PSECTION Section;
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
ProbeForWrite(SectionInformation,
SectionInformationLength,
__alignof(ULONG));
if (ResultLength != NULL)
{
ProbeForWrite(ResultLength,
sizeof(*ResultLength),
__alignof(SIZE_T));
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
if (SectionInformationClass == SectionBasicInformation)
{
if (SectionInformationLength < sizeof(SECTION_BASIC_INFORMATION))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
}
else if (SectionInformationClass == SectionImageInformation)
{
if (SectionInformationLength < sizeof(SECTION_IMAGE_INFORMATION))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
}
else
{
return STATUS_INVALID_INFO_CLASS;
}
Status = ObReferenceObjectByHandle(SectionHandle,
SECTION_QUERY,
MmSectionObjectType,
PreviousMode,
(PVOID*)(PVOID)&Section,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to reference section: 0x%lx\n", Status);
return Status;
}
if (MiIsRosSectionObject(Section))
{
PROS_SECTION_OBJECT RosSection = (PROS_SECTION_OBJECT)Section;
switch (SectionInformationClass)
{
case SectionBasicInformation:
{
PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
_SEH2_TRY
{
Sbi->Attributes = RosSection->AllocationAttributes;
if (RosSection->AllocationAttributes & SEC_IMAGE)
{
Sbi->BaseAddress = 0;
Sbi->Size.QuadPart = 0;
}
else
{
Sbi->BaseAddress = (PVOID)RosSection->Segment->Image.VirtualAddress;
Sbi->Size.QuadPart = RosSection->Segment->Length.QuadPart;
}
if (ResultLength != NULL)
{
*ResultLength = sizeof(SECTION_BASIC_INFORMATION);
}
Status = STATUS_SUCCESS;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case SectionImageInformation:
{
PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
_SEH2_TRY
{
if (RosSection->AllocationAttributes & SEC_IMAGE)
{
PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
ImageSectionObject = RosSection->ImageSection;
*Sii = ImageSectionObject->ImageInformation;
}
if (ResultLength != NULL)
{
*ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
}
Status = STATUS_SUCCESS;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
}
}
else
{
switch(SectionInformationClass)
{
case SectionBasicInformation:
{
SECTION_BASIC_INFORMATION Sbi;
Sbi.Size = Section->SizeOfSection;
Sbi.BaseAddress = (PVOID)Section->Address.StartingVpn;
Sbi.Attributes = 0;
if (Section->u.Flags.Image)
Sbi.Attributes |= SEC_IMAGE;
if (Section->u.Flags.Commit)
Sbi.Attributes |= SEC_COMMIT;
if (Section->u.Flags.Reserve)
Sbi.Attributes |= SEC_RESERVE;
if (Section->u.Flags.File)
Sbi.Attributes |= SEC_FILE;
if (Section->u.Flags.Image)
Sbi.Attributes |= SEC_IMAGE;
/* FIXME : Complete/test the list of flags passed back from NtCreateSection */
_SEH2_TRY
{
*((SECTION_BASIC_INFORMATION*)SectionInformation) = Sbi;
if (ResultLength)
*ResultLength = sizeof(Sbi);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case SectionImageInformation:
{
if (!Section->u.Flags.Image)
{
Status = STATUS_SECTION_NOT_IMAGE;
}
else
{
/* Currently not supported */
ASSERT(FALSE);
}
break;
}
}
}
ObDereferenceObject(Section);
return(Status);
}
/**********************************************************************
* NAME EXPORTED
* MmMapViewOfSection
*
* DESCRIPTION
* Maps a view of a section into the virtual address space of a
* process.
*
* ARGUMENTS
* Section
* Pointer to the section object.
*
* ProcessHandle
* Pointer to the process.
*
* BaseAddress
* Desired base address (or NULL) on entry;
* Actual base address of the view on exit.
*
* ZeroBits
* Number of high order address bits that must be zero.
*
* CommitSize
* Size in bytes of the initially committed section of
* the view.
*
* SectionOffset
* Offset in bytes from the beginning of the section
* to the beginning of the view.
*
* ViewSize
* Desired length of map (or zero to map all) on entry
* Actual length mapped on exit.
*
* InheritDisposition
* Specified how the view is to be shared with
* child processes.
*
* AllocationType
* Type of allocation for the pages.
*
* Protect
* Protection for the committed region of the view.
*
* RETURN VALUE
* Status.
*
* @implemented
*/
NTSTATUS NTAPI
MmMapViewOfSection(IN PVOID SectionObject,
IN PEPROCESS Process,
IN OUT PVOID *BaseAddress,
IN ULONG_PTR ZeroBits,
IN SIZE_T CommitSize,
IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
IN OUT PSIZE_T ViewSize,
IN SECTION_INHERIT InheritDisposition,
IN ULONG AllocationType,
IN ULONG Protect)
{
PROS_SECTION_OBJECT Section;
PMMSUPPORT AddressSpace;
ULONG ViewOffset;
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN NotAtBase = FALSE;
if (MiIsRosSectionObject(SectionObject) == FALSE)
{
DPRINT("Mapping ARM3 section into %s\n", Process->ImageFileName);
return MmMapViewOfArm3Section(SectionObject,
Process,
BaseAddress,
ZeroBits,
CommitSize,
SectionOffset,
ViewSize,
InheritDisposition,
AllocationType,
Protect);
}
ASSERT(Process);
if (!Protect || Protect & ~PAGE_FLAGS_VALID_FOR_SECTION)
{
return STATUS_INVALID_PAGE_PROTECTION;
}
/* FIXME: We should keep this, but it would break code checking equality */
Protect &= ~PAGE_NOCACHE;
Section = (PROS_SECTION_OBJECT)SectionObject;
AddressSpace = &Process->Vm;
AllocationType |= (Section->AllocationAttributes & SEC_NO_CHANGE);
MmLockAddressSpace(AddressSpace);
if (Section->AllocationAttributes & SEC_IMAGE)
{
ULONG i;
ULONG NrSegments;
ULONG_PTR ImageBase;
SIZE_T ImageSize;
PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
PMM_SECTION_SEGMENT SectionSegments;
ImageSectionObject = Section->ImageSection;
SectionSegments = ImageSectionObject->Segments;
NrSegments = ImageSectionObject->NrSegments;
ImageBase = (ULONG_PTR)*BaseAddress;
if (ImageBase == 0)
{
ImageBase = (ULONG_PTR)ImageSectionObject->BasedAddress;
}
ImageSize = 0;
for (i = 0; i < NrSegments; i++)
{
ULONG_PTR MaxExtent;
MaxExtent = (ULONG_PTR)(SectionSegments[i].Image.VirtualAddress +
SectionSegments[i].Length.QuadPart);
ImageSize = max(ImageSize, MaxExtent);
}
ImageSectionObject->ImageInformation.ImageFileSize = (ULONG)ImageSize;
/* Check for an illegal base address */
if (((ImageBase + ImageSize) > (ULONG_PTR)MmHighestUserAddress) ||
((ImageBase + ImageSize) < ImageSize))
{
ASSERT(*BaseAddress == NULL);
ImageBase = ALIGN_DOWN_BY((ULONG_PTR)MmHighestUserAddress - ImageSize,
MM_VIRTMEM_GRANULARITY);
NotAtBase = TRUE;
}
else if (ImageBase != ALIGN_DOWN_BY(ImageBase, MM_VIRTMEM_GRANULARITY))
{
ASSERT(*BaseAddress == NULL);
ImageBase = ALIGN_DOWN_BY(ImageBase, MM_VIRTMEM_GRANULARITY);
NotAtBase = TRUE;
}
/* Check there is enough space to map the section at that point. */
if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase,
PAGE_ROUND_UP(ImageSize)) != NULL)
{
/* Fail if the user requested a fixed base address. */
if ((*BaseAddress) != NULL)
{
MmUnlockAddressSpace(AddressSpace);
return(STATUS_CONFLICTING_ADDRESSES);
}
/* Otherwise find a gap to map the image. */
ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), MM_VIRTMEM_GRANULARITY, FALSE);
if (ImageBase == 0)
{
MmUnlockAddressSpace(AddressSpace);
return(STATUS_CONFLICTING_ADDRESSES);
}
/* Remember that we loaded image at a different base address */
NotAtBase = TRUE;
}
for (i = 0; i < NrSegments; i++)
{
PVOID SBaseAddress = (PVOID)
((char*)ImageBase + (ULONG_PTR)SectionSegments[i].Image.VirtualAddress);
MmLockSectionSegment(&SectionSegments[i]);
Status = MmMapViewOfSegment(AddressSpace,
Section,
&SectionSegments[i],
&SBaseAddress,
SectionSegments[i].Length.LowPart,
SectionSegments[i].Protection,
0,
0);
MmUnlockSectionSegment(&SectionSegments[i]);
if (!NT_SUCCESS(Status))
{
MmUnlockAddressSpace(AddressSpace);
return(Status);
}
}
*BaseAddress = (PVOID)ImageBase;
*ViewSize = ImageSize;
}
else
{
/* check for write access */
if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) &&
!(Section->SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)))
{
MmUnlockAddressSpace(AddressSpace);
return STATUS_SECTION_PROTECTION;
}
/* check for read access */
if ((Protect & (PAGE_READONLY|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_WRITECOPY)) &&
!(Section->SectionPageProtection & (PAGE_READONLY|PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
{
MmUnlockAddressSpace(AddressSpace);
return STATUS_SECTION_PROTECTION;
}
/* check for execute access */
if ((Protect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)) &&
!(Section->SectionPageProtection & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
{
MmUnlockAddressSpace(AddressSpace);
return STATUS_SECTION_PROTECTION;
}
if (SectionOffset == NULL)
{
ViewOffset = 0;
}
else
{
ViewOffset = SectionOffset->u.LowPart;
}
if ((ViewOffset % PAGE_SIZE) != 0)
{
MmUnlockAddressSpace(AddressSpace);
return(STATUS_MAPPED_ALIGNMENT);
}
if ((*ViewSize) == 0)
{
(*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
}
else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
{
(*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
}
*ViewSize = PAGE_ROUND_UP(*ViewSize);
MmLockSectionSegment(Section->Segment);
Status = MmMapViewOfSegment(AddressSpace,
Section,
Section->Segment,
BaseAddress,
*ViewSize,
Protect,
ViewOffset,
AllocationType & (MEM_TOP_DOWN|SEC_NO_CHANGE));
MmUnlockSectionSegment(Section->Segment);
if (!NT_SUCCESS(Status))
{
MmUnlockAddressSpace(AddressSpace);
return(Status);
}
}
MmUnlockAddressSpace(AddressSpace);
ASSERT(*BaseAddress == ALIGN_DOWN_POINTER_BY(*BaseAddress, MM_VIRTMEM_GRANULARITY));
if (NotAtBase)
Status = STATUS_IMAGE_NOT_AT_BASE;
else
Status = STATUS_SUCCESS;
return Status;
}
/*
* @unimplemented
*/
BOOLEAN NTAPI
MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
IN PLARGE_INTEGER NewFileSize)
{
/* Check whether an ImageSectionObject exists */
if (SectionObjectPointer->ImageSectionObject != NULL)
{
DPRINT1("ERROR: File can't be truncated because it has an image section\n");
return FALSE;
}
if (SectionObjectPointer->DataSectionObject != NULL)
{
PMM_SECTION_SEGMENT Segment;
Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->
DataSectionObject;
if (Segment->ReferenceCount != 0)
{
#ifdef NEWCC
CC_FILE_SIZES FileSizes;
CcpLock();
if (SectionObjectPointer->SharedCacheMap && (Segment->ReferenceCount > CcpCountCacheSections((PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap)))
{
CcpUnlock();
/* Check size of file */
if (SectionObjectPointer->SharedCacheMap)
{
if (!CcGetFileSizes(Segment->FileObject, &FileSizes))
{
return FALSE;
}
if (NewFileSize->QuadPart <= FileSizes.FileSize.QuadPart)
{
return FALSE;
}
}
}
else
CcpUnlock();
#else
/* Check size of file */
if (SectionObjectPointer->SharedCacheMap)
{
PROS_SHARED_CACHE_MAP SharedCacheMap = SectionObjectPointer->SharedCacheMap;
if (NewFileSize->QuadPart <= SharedCacheMap->FileSize.QuadPart)
{
return FALSE;
}
}
#endif
}
else
{
/* Something must gone wrong
* how can we have a Section but no
* reference? */
DPRINT("ERROR: DataSectionObject without reference!\n");
}
}
DPRINT("FIXME: didn't check for outstanding write probes\n");
return TRUE;
}
/*
* @implemented
*/
BOOLEAN NTAPI
MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
IN MMFLUSH_TYPE FlushType)
{
BOOLEAN Result = TRUE;
#ifdef NEWCC
PMM_SECTION_SEGMENT Segment;
#endif
switch(FlushType)
{
case MmFlushForDelete:
if (SectionObjectPointer->ImageSectionObject ||
SectionObjectPointer->DataSectionObject)
{
return FALSE;
}
#ifndef NEWCC
CcRosRemoveIfClosed(SectionObjectPointer);
#endif
return TRUE;
case MmFlushForWrite:
{
DPRINT("MmFlushImageSection(%d)\n", FlushType);
#ifdef NEWCC
Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->DataSectionObject;
#endif
if (SectionObjectPointer->ImageSectionObject)
{
DPRINT1("SectionObject has ImageSection\n");
return FALSE;
}
#ifdef NEWCC
CcpLock();
Result = !SectionObjectPointer->SharedCacheMap || (Segment->ReferenceCount == CcpCountCacheSections((PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap));
CcpUnlock();
DPRINT("Result %d\n", Result);
#endif
return Result;
}
}
return FALSE;
}
/*
* @implemented
*/
NTSTATUS NTAPI
MmMapViewInSystemSpace (IN PVOID SectionObject,
OUT PVOID * MappedBase,
IN OUT PSIZE_T ViewSize)
{
PROS_SECTION_OBJECT Section;
PMMSUPPORT AddressSpace;
NTSTATUS Status;
PAGED_CODE();
if (MiIsRosSectionObject(SectionObject) == FALSE)
{
return MiMapViewInSystemSpace(SectionObject,
&MmSession,
MappedBase,
ViewSize);
}
DPRINT("MmMapViewInSystemSpace() called\n");
Section = (PROS_SECTION_OBJECT)SectionObject;
AddressSpace = MmGetKernelAddressSpace();
MmLockAddressSpace(AddressSpace);
if ((*ViewSize) == 0)
{
(*ViewSize) = Section->MaximumSize.u.LowPart;
}
else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
{
(*ViewSize) = Section->MaximumSize.u.LowPart;
}
MmLockSectionSegment(Section->Segment);
Status = MmMapViewOfSegment(AddressSpace,
Section,
Section->Segment,
MappedBase,
*ViewSize,
PAGE_READWRITE,
0,
0);
MmUnlockSectionSegment(Section->Segment);
MmUnlockAddressSpace(AddressSpace);
return Status;
}
NTSTATUS
NTAPI
MiRosUnmapViewInSystemSpace(IN PVOID MappedBase)
{
PMMSUPPORT AddressSpace;
NTSTATUS Status;
DPRINT("MmUnmapViewInSystemSpace() called\n");
AddressSpace = MmGetKernelAddressSpace();
MmLockAddressSpace(AddressSpace);
Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
MmUnlockAddressSpace(AddressSpace);
return Status;
}
/**********************************************************************
* NAME EXPORTED
* MmCreateSection@
*
* DESCRIPTION
* Creates a section object.
*
* ARGUMENTS
* SectionObject (OUT)
* Caller supplied storage for the resulting pointer
* to a SECTION_OBJECT instance;
*
* DesiredAccess
* Specifies the desired access to the section can be a
* combination of:
* STANDARD_RIGHTS_REQUIRED |
* SECTION_QUERY |
* SECTION_MAP_WRITE |
* SECTION_MAP_READ |
* SECTION_MAP_EXECUTE
*
* ObjectAttributes [OPTIONAL]
* Initialized attributes for the object can be used
* to create a named section;
*
* MaximumSize
* Maximizes the size of the memory section. Must be
* non-NULL for a page-file backed section.
* If value specified for a mapped file and the file is
* not large enough, file will be extended.
*
* SectionPageProtection
* Can be a combination of:
* PAGE_READONLY |
* PAGE_READWRITE |
* PAGE_WRITEONLY |
* PAGE_WRITECOPY
*
* AllocationAttributes
* Can be a combination of:
* SEC_IMAGE |
* SEC_RESERVE
*
* FileHandle
* Handle to a file to create a section mapped to a file
* instead of a memory backed section;
*
* File
* Unknown.
*
* RETURN VALUE
* Status.
*
* @implemented
*/
NTSTATUS NTAPI
MmCreateSection (OUT PVOID * Section,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN PLARGE_INTEGER MaximumSize,
IN ULONG SectionPageProtection,
IN ULONG AllocationAttributes,
IN HANDLE FileHandle OPTIONAL,
IN PFILE_OBJECT FileObject OPTIONAL)
{
NTSTATUS Status;
ULONG Protection;
PROS_SECTION_OBJECT *SectionObject = (PROS_SECTION_OBJECT *)Section;
/* Check if an ARM3 section is being created instead */
if (!(AllocationAttributes & (SEC_IMAGE | SEC_PHYSICALMEMORY)))
{
if (!(FileObject) && !(FileHandle))
{
return MmCreateArm3Section(Section,
DesiredAccess,
ObjectAttributes,
MaximumSize,
SectionPageProtection,
AllocationAttributes &~ 1,
FileHandle,
FileObject);
}
}
/* Convert section flag to page flag */
if (AllocationAttributes & SEC_NOCACHE) SectionPageProtection |= PAGE_NOCACHE;
/* Check to make sure the protection is correct. Nt* does this already */
Protection = MiMakeProtectionMask(SectionPageProtection);
if (Protection == MM_INVALID_PROTECTION)
{
DPRINT1("Page protection is invalid\n");
return STATUS_INVALID_PAGE_PROTECTION;
}
/* Check if this is going to be a data or image backed file section */
if ((FileHandle) || (FileObject))
{
/* These cannot be mapped with large pages */
if (AllocationAttributes & SEC_LARGE_PAGES)
{
DPRINT1("Large pages cannot be used with an image mapping\n");
return STATUS_INVALID_PARAMETER_6;
}
/* Did the caller pass an object? */
if (FileObject)
{
/* Reference the object directly */
ObReferenceObject(FileObject);
}
else
{
/* Reference the file handle to get the object */
Status = ObReferenceObjectByHandle(FileHandle,
MmMakeFileAccess[Protection],
IoFileObjectType,
ExGetPreviousMode(),
(PVOID*)&FileObject,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to get a handle to the FO: %lx\n", Status);
return Status;
}
}
}
else
{
/* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
if (AllocationAttributes & SEC_IMAGE) return STATUS_INVALID_FILE_FOR_SECTION;
}
#ifndef NEWCC // A hack for initializing caching.
// This is needed only in the old case.
if (FileHandle)
{
IO_STATUS_BLOCK Iosb;
NTSTATUS Status;
CHAR Buffer;
LARGE_INTEGER ByteOffset;
ByteOffset.QuadPart = 0;
Status = ZwReadFile(FileHandle,
NULL,
NULL,
NULL,
&Iosb,
&Buffer,
sizeof(Buffer),
&ByteOffset,
NULL);
if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
{
DPRINT1("CC failure: %lx\n", Status);
if (FileObject)
ObDereferenceObject(FileObject);
return Status;
}
// Caching is initialized...
// Hack of the hack: actually, it might not be initialized if FSD init on effective right and if file is null-size
// In such case, force cache by initiating a write IRP
if (Status == STATUS_END_OF_FILE && !(AllocationAttributes & SEC_IMAGE) && FileObject != NULL &&
(FileObject->SectionObjectPointer == NULL || FileObject->SectionObjectPointer->SharedCacheMap == NULL))
{
Buffer = 0xdb;
Status = ZwWriteFile(FileHandle,
NULL,
NULL,
NULL,
&Iosb,
&Buffer,
sizeof(Buffer),
&ByteOffset,
NULL);
if (NT_SUCCESS(Status))
{
LARGE_INTEGER Zero;
Zero.QuadPart = 0LL;
Status = IoSetInformation(FileObject,
FileEndOfFileInformation,
sizeof(LARGE_INTEGER),
&Zero);
ASSERT(NT_SUCCESS(Status));
}
}
}
#endif
if (AllocationAttributes & SEC_IMAGE)
{
Status = MmCreateImageSection(SectionObject,
DesiredAccess,
ObjectAttributes,
MaximumSize,
SectionPageProtection,
AllocationAttributes,
FileObject);
}
#ifndef NEWCC
else if (FileHandle != NULL)
{
Status = MmCreateDataFileSection(SectionObject,
DesiredAccess,
ObjectAttributes,
MaximumSize,
SectionPageProtection,
AllocationAttributes,
FileObject);
}
#else
else if (FileHandle != NULL || FileObject != NULL)
{
Status = MmCreateCacheSection(SectionObject,
DesiredAccess,
ObjectAttributes,
MaximumSize,
SectionPageProtection,
AllocationAttributes,
FileObject);
}
#endif
else
{
if ((AllocationAttributes & SEC_PHYSICALMEMORY) == 0)
{
DPRINT1("Invalid path: %lx %p %p\n", AllocationAttributes, FileObject, FileHandle);
}
// ASSERT(AllocationAttributes & SEC_PHYSICALMEMORY);
Status = MmCreatePageFileSection(SectionObject,
DesiredAccess,
ObjectAttributes,
MaximumSize,
SectionPageProtection,
AllocationAttributes);
if (FileObject)
ObDereferenceObject(FileObject);
}
return Status;
}
/* EOF */