2008-03-09 14:11:42 +00:00
|
|
|
/*
|
2005-06-07 17:07:34 +00:00
|
|
|
* Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
|
|
|
|
*
|
2005-06-07 20:15:16 +00:00
|
|
|
* 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.
|
2005-06-07 17:07:34 +00:00
|
|
|
*
|
2005-06-07 20:15:16 +00:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
2005-06-07 17:07:34 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2005-06-07 20:15:16 +00:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2005-06-07 17:07:34 +00:00
|
|
|
*
|
2005-06-07 20:15:16 +00:00
|
|
|
* 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.
|
2005-06-07 17:07:34 +00:00
|
|
|
*
|
|
|
|
*
|
1998-08-25 04:27:26 +00:00
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: ntoskrnl/mm/section.c
|
|
|
|
* PURPOSE: Implements section objects
|
2005-05-09 01:38:29 +00:00
|
|
|
*
|
2005-06-07 17:07:34 +00:00
|
|
|
* 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
|
2007-10-19 23:21:45 +00:00
|
|
|
* Aleksey Bragin
|
2005-06-07 17:07:34 +00:00
|
|
|
* Jason Filby
|
|
|
|
* Thomas Weidenmueller
|
|
|
|
* Gunnar Andre' Dalsnes
|
2005-06-07 20:15:16 +00:00
|
|
|
* Mike Nordell
|
2005-06-07 17:07:34 +00:00
|
|
|
* Alex Ionescu
|
|
|
|
* Gregor Anich
|
|
|
|
* Steven Edwards
|
|
|
|
* Herve Poussineau
|
1998-08-25 04:27:26 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
2004-08-15 16:39:12 +00:00
|
|
|
#include <ntoskrnl.h>
|
1998-10-05 04:01:30 +00:00
|
|
|
#define NDEBUG
|
2008-08-30 16:31:06 +00:00
|
|
|
#include <debug.h>
|
2004-12-30 08:05:12 +00:00
|
|
|
#include <reactos/exeformat.h>
|
|
|
|
|
2005-11-28 23:25:31 +00:00
|
|
|
#if defined (ALLOC_PRAGMA)
|
|
|
|
#pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
|
|
|
|
#pragma alloc_text(INIT, MmInitSectionImplementation)
|
|
|
|
#endif
|
|
|
|
|
2010-10-04 20:19:03 +00:00
|
|
|
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);
|
2005-11-28 23:25:31 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
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));
|
|
|
|
|
2001-12-31 01:53:46 +00:00
|
|
|
/* TYPES *********************************************************************/
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2004-04-10 22:36:07 +00:00
|
|
|
PMM_SECTION_SEGMENT Segment;
|
|
|
|
ULONG Offset;
|
|
|
|
BOOLEAN WasDirty;
|
|
|
|
BOOLEAN Private;
|
|
|
|
}
|
|
|
|
MM_SECTION_PAGEOUT_CONTEXT;
|
2001-12-31 01:53:46 +00:00
|
|
|
|
1998-10-05 04:01:30 +00:00
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
|
2005-11-22 02:30:18 +00:00
|
|
|
POBJECT_TYPE MmSectionObjectType = NULL;
|
1998-10-05 04:01:30 +00:00
|
|
|
|
2010-07-22 23:22:57 +00:00
|
|
|
SIZE_T MmAllocationFragment;
|
2010-04-20 22:47:51 +00:00
|
|
|
|
2009-10-31 01:02:35 +00:00
|
|
|
ULONG_PTR MmSubsectionBase;
|
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
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 */
|
|
|
|
};
|
|
|
|
|
2001-01-28 15:17:52 +00:00
|
|
|
static GENERIC_MAPPING MmpSectionMapping = {
|
2004-04-10 22:36:07 +00:00
|
|
|
STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY,
|
|
|
|
STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE,
|
|
|
|
STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
|
|
|
|
SECTION_ALL_ACCESS};
|
2001-01-28 15:17:52 +00:00
|
|
|
|
2001-12-31 19:06:49 +00:00
|
|
|
#define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
|
2004-08-01 07:24:59 +00:00
|
|
|
#define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
|
2001-12-31 19:06:49 +00:00
|
|
|
#define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
|
|
|
|
#define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
|
|
|
|
#define MAX_SHARE_COUNT 0x7FF
|
|
|
|
#define MAKE_SSE(P, C) ((P) | ((C) << 1))
|
|
|
|
#define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
|
|
|
|
#define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
|
2001-03-29 17:24:43 +00:00
|
|
|
|
2005-02-15 15:46:22 +00:00
|
|
|
static const INFORMATION_CLASS_INFO ExSectionInfoClass[] =
|
|
|
|
{
|
|
|
|
ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */
|
|
|
|
ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionImageInformation */
|
|
|
|
};
|
|
|
|
|
1998-08-25 04:27:26 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
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)
|
2006-07-27 00:22:36 +00:00
|
|
|
{
|
2010-10-05 15:55:52 +00:00
|
|
|
NTSTATUS nStatus;
|
|
|
|
ULONG cbFileHeaderOffsetSize = 0;
|
|
|
|
ULONG cbSectionHeadersOffset = 0;
|
|
|
|
ULONG cbSectionHeadersSize;
|
|
|
|
ULONG cbSectionHeadersOffsetSize = 0;
|
|
|
|
ULONG cbOptHeaderSize;
|
|
|
|
ULONG cbHeadersSize = 0;
|
|
|
|
ULONG nSectionAlignment;
|
|
|
|
ULONG nFileAlignment;
|
|
|
|
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;
|
|
|
|
ULONG nPrevVirtualEndOfSegment = 0;
|
|
|
|
ULONG nFileSizeOfHeaders = 0;
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
/* not a Windows executable */
|
|
|
|
if(pidhDosHeader->e_lfanew <= 0)
|
|
|
|
DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew));
|
|
|
|
|
|
|
|
/* NT HEADER */
|
|
|
|
nStatus = STATUS_INVALID_IMAGE_FORMAT;
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2006-07-27 00:22:36 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
/*
|
|
|
|
* 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;
|
2006-07-27 00:22:36 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
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))
|
|
|
|
DIE(("ReadFile failed, status %08X\n", nStatus));
|
|
|
|
|
|
|
|
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;
|
2006-11-30 05:22:20 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
/* 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
|
2006-11-30 05:22:20 +00:00
|
|
|
{
|
2010-10-05 15:55:52 +00:00
|
|
|
ULONG cbOptHeaderOffsetSize = 0;
|
|
|
|
|
|
|
|
nStatus = STATUS_INVALID_IMAGE_FORMAT;
|
|
|
|
|
|
|
|
/* 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));
|
|
|
|
|
|
|
|
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;
|
2006-11-30 05:22:20 +00:00
|
|
|
}
|
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
/* 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)
|
2006-11-30 05:22:20 +00:00
|
|
|
{
|
2010-10-05 15:55:52 +00:00
|
|
|
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
|
|
|
|
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader->Magic));
|
2006-11-30 05:22:20 +00:00
|
|
|
}
|
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
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;
|
|
|
|
}
|
2006-10-22 20:56:24 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
ASSERT(IsPowerOf2(nSectionAlignment));
|
|
|
|
ASSERT(IsPowerOf2(nFileAlignment));
|
2008-10-11 15:16:28 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
switch(piohOptHeader->Magic)
|
|
|
|
{
|
|
|
|
/* PE32 */
|
|
|
|
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
|
|
|
|
{
|
|
|
|
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, ImageBase))
|
|
|
|
ImageSectionObject->ImageBase = piohOptHeader->ImageBase;
|
2008-10-11 15:16:28 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfImage))
|
|
|
|
ImageSectionObject->ImageSize = piohOptHeader->SizeOfImage;
|
2008-10-11 15:16:28 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackReserve))
|
|
|
|
ImageSectionObject->StackReserve = piohOptHeader->SizeOfStackReserve;
|
2008-10-11 15:16:28 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackCommit))
|
|
|
|
ImageSectionObject->StackCommit = piohOptHeader->SizeOfStackCommit;
|
2008-10-11 15:16:28 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-10-11 15:16:28 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
/* PE32+ */
|
|
|
|
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
|
|
|
|
{
|
|
|
|
const IMAGE_OPTIONAL_HEADER64 * pioh64OptHeader;
|
2008-10-11 15:16:28 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
pioh64OptHeader = (const IMAGE_OPTIONAL_HEADER64 *)piohOptHeader;
|
2008-10-11 15:16:28 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, ImageBase))
|
|
|
|
{
|
|
|
|
if(pioh64OptHeader->ImageBase > MAXULONG_PTR)
|
|
|
|
DIE(("ImageBase exceeds the address space\n"));
|
2008-10-11 15:16:28 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
ImageSectionObject->ImageBase = (ULONG_PTR)pioh64OptHeader->ImageBase;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfImage))
|
|
|
|
{
|
|
|
|
if(pioh64OptHeader->SizeOfImage > MAXULONG_PTR)
|
|
|
|
DIE(("SizeOfImage exceeds the address space\n"));
|
|
|
|
|
|
|
|
ImageSectionObject->ImageSize = pioh64OptHeader->SizeOfImage;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackReserve))
|
|
|
|
{
|
|
|
|
if(pioh64OptHeader->SizeOfStackReserve > MAXULONG_PTR)
|
|
|
|
DIE(("SizeOfStackReserve exceeds the address space\n"));
|
|
|
|
|
|
|
|
ImageSectionObject->StackReserve = pioh64OptHeader->SizeOfStackReserve;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackCommit))
|
|
|
|
{
|
|
|
|
if(pioh64OptHeader->SizeOfStackCommit > MAXULONG_PTR)
|
|
|
|
DIE(("SizeOfStackCommit exceeds the address space\n"));
|
|
|
|
|
|
|
|
ImageSectionObject->StackCommit = pioh64OptHeader->SizeOfStackCommit;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* [1], section 3.4.2 */
|
|
|
|
if((ULONG_PTR)ImageSectionObject->ImageBase % 0x10000)
|
|
|
|
DIE(("ImageBase is not aligned on a 64KB boundary"));
|
|
|
|
|
|
|
|
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Subsystem))
|
|
|
|
{
|
|
|
|
ImageSectionObject->Subsystem = piohOptHeader->Subsystem;
|
|
|
|
|
|
|
|
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MinorSubsystemVersion) &&
|
|
|
|
RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MajorSubsystemVersion))
|
|
|
|
{
|
|
|
|
ImageSectionObject->MinorSubsystemVersion = piohOptHeader->MinorSubsystemVersion;
|
|
|
|
ImageSectionObject->MajorSubsystemVersion = piohOptHeader->MajorSubsystemVersion;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint))
|
|
|
|
{
|
|
|
|
ImageSectionObject->EntryPoint = piohOptHeader->ImageBase +
|
|
|
|
piohOptHeader->AddressOfEntryPoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfCode))
|
|
|
|
ImageSectionObject->Executable = piohOptHeader->SizeOfCode != 0;
|
|
|
|
else
|
|
|
|
ImageSectionObject->Executable = TRUE;
|
|
|
|
|
|
|
|
ImageSectionObject->ImageCharacteristics = pinhNtHeader->FileHeader.Characteristics;
|
|
|
|
ImageSectionObject->Machine = pinhNtHeader->FileHeader.Machine;
|
|
|
|
|
|
|
|
/* 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"));
|
|
|
|
|
|
|
|
if(!AlignUp(&nPrevVirtualEndOfSegment, cbHeadersSize, nSectionAlignment))
|
|
|
|
DIE(("Cannot align the size of the section headers\n"));
|
|
|
|
|
|
|
|
pssSegments[0].FileOffset = 0;
|
|
|
|
pssSegments[0].Protection = PAGE_READONLY;
|
|
|
|
pssSegments[0].Length = nPrevVirtualEndOfSegment;
|
|
|
|
pssSegments[0].RawLength = nFileSizeOfHeaders;
|
|
|
|
pssSegments[0].VirtualAddress = 0;
|
|
|
|
pssSegments[0].Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA;
|
|
|
|
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(("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].FileOffset = pishSectionHeaders[i].PointerToRawData;
|
|
|
|
pssSegments[i].RawLength = pishSectionHeaders[i].SizeOfRawData;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ASSERT(pssSegments[i].FileOffset == 0);
|
|
|
|
ASSERT(pssSegments[i].RawLength == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(Intsafe_CanAddLong64(pssSegments[i].FileOffset, pssSegments[i].RawLength));
|
|
|
|
|
|
|
|
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 = pishSectionHeaders[i].SizeOfRawData;
|
|
|
|
else
|
|
|
|
pssSegments[i].Length = pishSectionHeaders[i].Misc.VirtualSize;
|
|
|
|
|
|
|
|
if(!AlignUp(&pssSegments[i].Length, pssSegments[i].Length, nSectionAlignment))
|
|
|
|
DIE(("Cannot align the virtual size of section %u\n", i));
|
|
|
|
|
|
|
|
ASSERT(IsAligned(pssSegments[i].Length, nSectionAlignment));
|
|
|
|
|
|
|
|
if(pssSegments[i].Length == 0)
|
|
|
|
DIE(("Virtual size of section %u is null\n", i));
|
|
|
|
|
|
|
|
pssSegments[i].VirtualAddress = pishSectionHeaders[i].VirtualAddress;
|
|
|
|
pssSegments[i].Characteristics = pishSectionHeaders[i].Characteristics;
|
|
|
|
|
|
|
|
/* ensure the memory image is no larger than 4GB */
|
|
|
|
if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment, pssSegments[i].VirtualAddress, pssSegments[i].Length))
|
|
|
|
DIE(("The image is larger than 4GB\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* spare our caller some work in validating the segments */
|
|
|
|
*Flags = EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED | EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP;
|
|
|
|
|
|
|
|
if(nSectionAlignment >= PAGE_SIZE)
|
|
|
|
*Flags |= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED;
|
|
|
|
|
|
|
|
/* Success */
|
|
|
|
nStatus = STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
|
|
|
|
|
|
|
|
l_Return:
|
|
|
|
if(pBuffer)
|
|
|
|
ExFreePool(pBuffer);
|
|
|
|
|
|
|
|
return nStatus;
|
2006-10-22 19:53:10 +00:00
|
|
|
}
|
2006-07-27 00:22:36 +00:00
|
|
|
|
2003-12-30 18:52:06 +00:00
|
|
|
/* Note: Mmsp prefix denotes "Memory Manager Section Private". */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
|
|
|
|
* ARGUMENTS: PMM_PAGEOP which event we should wait for.
|
|
|
|
* RETURNS: Status of the wait.
|
|
|
|
*/
|
|
|
|
static NTSTATUS
|
|
|
|
MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp)
|
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
LARGE_INTEGER Timeout;
|
2003-12-30 18:52:06 +00:00
|
|
|
#ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
Timeout.QuadPart = -100000000LL; // 10 sec
|
2003-12-30 18:52:06 +00:00
|
|
|
#else
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
Timeout.QuadPart = -100000000; // 10 sec
|
2003-12-30 18:52:06 +00:00
|
|
|
#endif
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
return KeWaitForSingleObject(&PageOp->CompletionEvent, 0, KernelMode, FALSE, &Timeout);
|
2003-12-30 18:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION: Sets the page op completion event and releases the page op.
|
|
|
|
* ARGUMENTS: PMM_PAGEOP.
|
|
|
|
* RETURNS: In shorter time than it takes you to even read this
|
|
|
|
* description, so don't even think about geting a mug of coffee.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp)
|
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
MmReleasePageOp(PageOp);
|
2003-12-30 18:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION: Waits in kernel mode indefinitely for a file object lock.
|
|
|
|
* ARGUMENTS: PFILE_OBJECT to wait for.
|
|
|
|
* RETURNS: Status of the wait.
|
|
|
|
*/
|
|
|
|
static NTSTATUS
|
|
|
|
MmspWaitForFileLock(PFILE_OBJECT File)
|
|
|
|
{
|
2006-07-27 22:26:40 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
//return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
|
2003-12-30 18:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-03-09 14:40:28 +00:00
|
|
|
VOID
|
|
|
|
MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment)
|
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG i;
|
|
|
|
if (Segment->Length > NR_SECTION_PAGE_TABLES * PAGE_SIZE)
|
|
|
|
{
|
2003-06-06 21:00:28 +00:00
|
|
|
for (i = 0; i < NR_SECTION_PAGE_TABLES; i++)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
if (Segment->PageDirectory.PageTables[i] != NULL)
|
|
|
|
{
|
|
|
|
ExFreePool(Segment->PageDirectory.PageTables[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-03-09 14:40:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2001-03-09 14:40:28 +00:00
|
|
|
MmFreeSectionSegments(PFILE_OBJECT FileObject)
|
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
|
|
|
|
{
|
2001-03-09 14:40:28 +00:00
|
|
|
PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
|
2003-06-27 21:28:30 +00:00
|
|
|
PMM_SECTION_SEGMENT SectionSegments;
|
|
|
|
ULONG NrSegments;
|
2001-03-09 14:40:28 +00:00
|
|
|
ULONG i;
|
|
|
|
|
2003-06-27 21:28:30 +00:00
|
|
|
ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject;
|
|
|
|
NrSegments = ImageSectionObject->NrSegments;
|
|
|
|
SectionSegments = ImageSectionObject->Segments;
|
|
|
|
for (i = 0; i < NrSegments; i++)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
if (SectionSegments[i].ReferenceCount != 0)
|
|
|
|
{
|
|
|
|
DPRINT1("Image segment %d still referenced (was %d)\n", i,
|
|
|
|
SectionSegments[i].ReferenceCount);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
MmFreePageTablesSectionSegment(&SectionSegments[i]);
|
|
|
|
}
|
2004-12-30 08:05:12 +00:00
|
|
|
ExFreePool(ImageSectionObject->Segments);
|
2001-03-09 14:40:28 +00:00
|
|
|
ExFreePool(ImageSectionObject);
|
2003-06-07 Casper S. Hornstrup <chorns@users.sourceforge.net>
Changes for compiling with w32api
* include/ddk/cctypes.h (PREACTOS_COMMON_FCB_HEADER): Remove.
(FSRTL_COMMON_FCB_HEADER): Add.
* include/ddk/iotypes.h (FILE_OBJECT): Rename field
SectionObjectPointers to SectionObjectPointer.
* ntoskrnl/cc/copy.c, ntoskrnl/cc/misc.c, ntoskrnl/cc/pin.c,
ntoskrnl/cc/view.c, ntoskrnl/io/rawfs.c, ntoskrnl/mm/section.c,
drivers/fs/cdfs/cleanup.c, drivers/fs/cdfs/fcb.c,
drivers/fs/cdfs/fsctl.c, drivers/fs/ntfs/fcb.c, drivers/fs/ntfs/fsctl.c,
drivers/fs/vfat/close.c, drivers/fs/vfat/create.c,
drivers/fs/vfat/finfo.c, drivers/fs/vfat/fcb.c, drivers/fs/vfat/fsctl.c:
Use new FILE_OBJECT structure.
* drivers/fs/cdfs/cdfs.h, drivers/fs/ntfs/ntfs.h, drivers/fs/vfat/vfat.h:
Use new FSRTL_COMMON_FCB_HEADER structure.
* drivers/net/afd/include/afd.h (FSRTL_COMMON_FCB_HEADER): Remove.
* include/ddk/ketypes.h (KQUEUE): Match w32api structure.
* ntoskrnl/ke/queue.c, ntoskrnl/ke/wait.c: Use new structure.
* ntoskrnl/ke/spinlock.c (KeAcquireSpinLockAtDpcLevel,
KeReleaseSpinLockFromDpcLevel): Undefine before declaring.
svn path=/trunk/; revision=4865
2003-06-07 11:34:36 +00:00
|
|
|
FileObject->SectionObjectPointer->ImageSectionObject = NULL;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
|
|
|
|
{
|
2001-03-09 14:40:28 +00:00
|
|
|
PMM_SECTION_SEGMENT Segment;
|
|
|
|
|
2003-06-07 Casper S. Hornstrup <chorns@users.sourceforge.net>
Changes for compiling with w32api
* include/ddk/cctypes.h (PREACTOS_COMMON_FCB_HEADER): Remove.
(FSRTL_COMMON_FCB_HEADER): Add.
* include/ddk/iotypes.h (FILE_OBJECT): Rename field
SectionObjectPointers to SectionObjectPointer.
* ntoskrnl/cc/copy.c, ntoskrnl/cc/misc.c, ntoskrnl/cc/pin.c,
ntoskrnl/cc/view.c, ntoskrnl/io/rawfs.c, ntoskrnl/mm/section.c,
drivers/fs/cdfs/cleanup.c, drivers/fs/cdfs/fcb.c,
drivers/fs/cdfs/fsctl.c, drivers/fs/ntfs/fcb.c, drivers/fs/ntfs/fsctl.c,
drivers/fs/vfat/close.c, drivers/fs/vfat/create.c,
drivers/fs/vfat/finfo.c, drivers/fs/vfat/fcb.c, drivers/fs/vfat/fsctl.c:
Use new FILE_OBJECT structure.
* drivers/fs/cdfs/cdfs.h, drivers/fs/ntfs/ntfs.h, drivers/fs/vfat/vfat.h:
Use new FSRTL_COMMON_FCB_HEADER structure.
* drivers/net/afd/include/afd.h (FSRTL_COMMON_FCB_HEADER): Remove.
* include/ddk/ketypes.h (KQUEUE): Match w32api structure.
* ntoskrnl/ke/queue.c, ntoskrnl/ke/wait.c: Use new structure.
* ntoskrnl/ke/spinlock.c (KeAcquireSpinLockAtDpcLevel,
KeReleaseSpinLockFromDpcLevel): Undefine before declaring.
svn path=/trunk/; revision=4865
2003-06-07 11:34:36 +00:00
|
|
|
Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
|
2004-04-10 22:36:07 +00:00
|
|
|
DataSectionObject;
|
2001-03-09 14:40:28 +00:00
|
|
|
|
|
|
|
if (Segment->ReferenceCount != 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT1("Data segment still referenced\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-03-09 14:40:28 +00:00
|
|
|
MmFreePageTablesSectionSegment(Segment);
|
|
|
|
ExFreePool(Segment);
|
2003-06-07 Casper S. Hornstrup <chorns@users.sourceforge.net>
Changes for compiling with w32api
* include/ddk/cctypes.h (PREACTOS_COMMON_FCB_HEADER): Remove.
(FSRTL_COMMON_FCB_HEADER): Add.
* include/ddk/iotypes.h (FILE_OBJECT): Rename field
SectionObjectPointers to SectionObjectPointer.
* ntoskrnl/cc/copy.c, ntoskrnl/cc/misc.c, ntoskrnl/cc/pin.c,
ntoskrnl/cc/view.c, ntoskrnl/io/rawfs.c, ntoskrnl/mm/section.c,
drivers/fs/cdfs/cleanup.c, drivers/fs/cdfs/fcb.c,
drivers/fs/cdfs/fsctl.c, drivers/fs/ntfs/fcb.c, drivers/fs/ntfs/fsctl.c,
drivers/fs/vfat/close.c, drivers/fs/vfat/create.c,
drivers/fs/vfat/finfo.c, drivers/fs/vfat/fcb.c, drivers/fs/vfat/fsctl.c:
Use new FILE_OBJECT structure.
* drivers/fs/cdfs/cdfs.h, drivers/fs/ntfs/ntfs.h, drivers/fs/vfat/vfat.h:
Use new FSRTL_COMMON_FCB_HEADER structure.
* drivers/net/afd/include/afd.h (FSRTL_COMMON_FCB_HEADER): Remove.
* include/ddk/ketypes.h (KQUEUE): Match w32api structure.
* ntoskrnl/ke/queue.c, ntoskrnl/ke/wait.c: Use new structure.
* ntoskrnl/ke/spinlock.c (KeAcquireSpinLockAtDpcLevel,
KeReleaseSpinLockFromDpcLevel): Undefine before declaring.
svn path=/trunk/; revision=4865
2003-06-07 11:34:36 +00:00
|
|
|
FileObject->SectionObjectPointer->DataSectionObject = NULL;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-03-09 14:40:28 +00:00
|
|
|
}
|
|
|
|
|
2003-12-30 18:52:06 +00:00
|
|
|
VOID
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2001-02-10 22:51:11 +00:00
|
|
|
MmLockSectionSegment(PMM_SECTION_SEGMENT Segment)
|
|
|
|
{
|
2003-06-27 21:28:30 +00:00
|
|
|
ExAcquireFastMutex(&Segment->Lock);
|
2001-02-10 22:51:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2001-02-10 22:51:11 +00:00
|
|
|
MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment)
|
|
|
|
{
|
2003-06-27 21:28:30 +00:00
|
|
|
ExReleaseFastMutex(&Segment->Lock);
|
2001-02-10 22:51:11 +00:00
|
|
|
}
|
|
|
|
|
2003-12-30 18:52:06 +00:00
|
|
|
VOID
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2001-02-10 22:51:11 +00:00
|
|
|
MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG Offset,
|
|
|
|
ULONG Entry)
|
2000-04-03 21:54:42 +00:00
|
|
|
{
|
|
|
|
PSECTION_PAGE_TABLE Table;
|
|
|
|
ULONG DirectoryOffset;
|
|
|
|
ULONG TableOffset;
|
2003-06-06 21:00:28 +00:00
|
|
|
|
|
|
|
if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
|
|
|
|
}
|
2003-06-06 21:00:28 +00:00
|
|
|
else
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
|
|
|
|
Table = Segment->PageDirectory.PageTables[DirectoryOffset];
|
|
|
|
if (Table == NULL)
|
|
|
|
{
|
|
|
|
Table =
|
|
|
|
Segment->PageDirectory.PageTables[DirectoryOffset] =
|
2007-05-19 15:13:37 +00:00
|
|
|
ExAllocatePoolWithTag(NonPagedPool, sizeof(SECTION_PAGE_TABLE),
|
2004-04-10 22:36:07 +00:00
|
|
|
TAG_SECTION_PAGE_TABLE);
|
|
|
|
if (Table == NULL)
|
2003-06-06 21:00:28 +00:00
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
memset(Table, 0, sizeof(SECTION_PAGE_TABLE));
|
|
|
|
DPRINT("Table %x\n", Table);
|
|
|
|
}
|
|
|
|
}
|
2000-04-03 21:54:42 +00:00
|
|
|
TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
|
2001-12-31 19:06:49 +00:00
|
|
|
Table->Entry[TableOffset] = Entry;
|
2000-04-03 21:54:42 +00:00
|
|
|
}
|
|
|
|
|
2001-03-29 17:24:43 +00:00
|
|
|
|
2003-12-30 18:52:06 +00:00
|
|
|
ULONG
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2001-02-10 22:51:11 +00:00
|
|
|
MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG Offset)
|
2000-04-03 21:54:42 +00:00
|
|
|
{
|
|
|
|
PSECTION_PAGE_TABLE Table;
|
2000-06-25 03:59:17 +00:00
|
|
|
ULONG Entry;
|
2000-04-03 21:54:42 +00:00
|
|
|
ULONG DirectoryOffset;
|
|
|
|
ULONG TableOffset;
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2007-01-06 02:34:58 +00:00
|
|
|
DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment, Offset);
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2003-06-06 21:00:28 +00:00
|
|
|
if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
|
|
|
|
}
|
2003-06-06 21:00:28 +00:00
|
|
|
else
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
|
|
|
|
Table = Segment->PageDirectory.PageTables[DirectoryOffset];
|
|
|
|
DPRINT("Table %x\n", Table);
|
|
|
|
if (Table == NULL)
|
|
|
|
{
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
}
|
2000-04-03 21:54:42 +00:00
|
|
|
TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
|
2001-12-31 19:06:49 +00:00
|
|
|
Entry = Table->Entry[TableOffset];
|
2000-04-03 21:54:42 +00:00
|
|
|
return(Entry);
|
|
|
|
}
|
|
|
|
|
2001-12-31 01:53:46 +00:00
|
|
|
VOID
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2001-03-29 17:24:43 +00:00
|
|
|
MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG Offset)
|
2001-03-29 17:24:43 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG Entry;
|
2001-03-29 17:24:43 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
|
|
|
|
if (Entry == 0)
|
|
|
|
{
|
2001-03-29 17:24:43 +00:00
|
|
|
DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
|
|
|
|
{
|
2001-03-29 17:24:43 +00:00
|
|
|
DPRINT1("Maximum share count reached\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
if (IS_SWAP_FROM_SSE(Entry))
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1);
|
|
|
|
MmSetPageEntrySectionSegment(Segment, Offset, Entry);
|
2001-03-29 17:24:43 +00:00
|
|
|
}
|
|
|
|
|
2001-12-31 01:53:46 +00:00
|
|
|
BOOLEAN
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2006-05-10 17:47:44 +00:00
|
|
|
MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section,
|
2004-04-10 22:36:07 +00:00
|
|
|
PMM_SECTION_SEGMENT Segment,
|
|
|
|
ULONG Offset,
|
|
|
|
BOOLEAN Dirty,
|
|
|
|
BOOLEAN PageOut)
|
2001-03-29 17:24:43 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG Entry;
|
|
|
|
BOOLEAN IsDirectMapped = FALSE;
|
2001-03-29 17:24:43 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
|
|
|
|
if (Entry == 0)
|
|
|
|
{
|
2003-12-21 19:12:19 +00:00
|
|
|
DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
if (SHARE_COUNT_FROM_SSE(Entry) == 0)
|
|
|
|
{
|
2001-03-29 17:24:43 +00:00
|
|
|
DPRINT1("Zero share count for unshare\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
if (IS_SWAP_FROM_SSE(Entry))
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2001-12-31 01:53:46 +00:00
|
|
|
PFILE_OBJECT FileObject;
|
2003-02-13 22:24:19 +00:00
|
|
|
PBCB Bcb;
|
2002-08-14 20:58:39 +00:00
|
|
|
SWAPENTRY SavedSwapEntry;
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page;
|
2003-06-06 21:00:28 +00:00
|
|
|
BOOLEAN IsImageSection;
|
|
|
|
ULONG FileOffset;
|
|
|
|
|
|
|
|
FileOffset = Offset + Segment->FileOffset;
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2003-06-06 21:00:28 +00:00
|
|
|
IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2004-08-01 07:24:59 +00:00
|
|
|
Page = PFN_FROM_SSE(Entry);
|
2001-12-31 01:53:46 +00:00
|
|
|
FileObject = Section->FileObject;
|
2003-12-31 14:52:06 +00:00
|
|
|
if (FileObject != NULL &&
|
2005-01-02 07:04:56 +00:00
|
|
|
!(Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
if ((FileOffset % PAGE_SIZE) == 0 &&
|
|
|
|
(Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
|
|
|
|
IsDirectMapped = TRUE;
|
|
|
|
Status = CcRosUnmapCacheSegment(Bcb, FileOffset, Dirty);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-08-14 20:58:39 +00:00
|
|
|
|
|
|
|
SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
|
2003-07-14 20:14:11 +00:00
|
|
|
if (SavedSwapEntry == 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
if (!PageOut &&
|
|
|
|
((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
|
2005-01-02 07:04:56 +00:00
|
|
|
(Segment->Characteristics & IMAGE_SCN_MEM_SHARED)))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MmSetPageEntrySectionSegment(Segment, Offset, 0);
|
|
|
|
if (!IsDirectMapped)
|
2003-07-14 20:14:11 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-07-14 20:14:11 +00:00
|
|
|
else
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
|
2005-01-02 07:04:56 +00:00
|
|
|
(Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
if (!PageOut)
|
|
|
|
{
|
|
|
|
if (Dirty)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* FIXME:
|
2005-05-09 01:38:29 +00:00
|
|
|
* We hold all locks. Nobody can do something with the current
|
2004-04-10 22:36:07 +00:00
|
|
|
* process and the current segment (also not within an other process).
|
|
|
|
*/
|
|
|
|
NTSTATUS Status;
|
2004-08-01 07:24:59 +00:00
|
|
|
Status = MmWriteToSwapPage(SavedSwapEntry, Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry));
|
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
|
|
|
}
|
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-12-31 01:53:46 +00:00
|
|
|
MmSetPageEntrySectionSegment(Segment, Offset, Entry);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
return(SHARE_COUNT_FROM_SSE(Entry) > 0);
|
2003-06-06 21:00:28 +00:00
|
|
|
}
|
|
|
|
|
2006-09-07 05:07:34 +00:00
|
|
|
BOOLEAN MiIsPageFromCache(PMEMORY_AREA MemoryArea,
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG SegOffset)
|
2003-06-06 21:00:28 +00:00
|
|
|
{
|
2005-01-02 07:04:56 +00:00
|
|
|
if (!(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2003-12-31 14:52:06 +00:00
|
|
|
PBCB Bcb;
|
|
|
|
PCACHE_SEGMENT CacheSeg;
|
|
|
|
Bcb = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap;
|
|
|
|
CacheSeg = CcRosLookupCacheSegment(Bcb, SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset);
|
|
|
|
if (CacheSeg)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
2001-03-29 17:24:43 +00:00
|
|
|
}
|
|
|
|
|
2009-10-15 17:01:31 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
2010-07-15 22:50:12 +00:00
|
|
|
MiCopyFromUserPage(PFN_NUMBER DestPage, PVOID SourceAddress)
|
2009-10-15 17:01:31 +00:00
|
|
|
{
|
|
|
|
PEPROCESS Process;
|
|
|
|
KIRQL Irql;
|
|
|
|
PVOID TempAddress;
|
|
|
|
|
|
|
|
Process = PsGetCurrentProcess();
|
|
|
|
TempAddress = MiMapPageInHyperSpace(Process, DestPage, &Irql);
|
|
|
|
if (TempAddress == NULL)
|
|
|
|
{
|
|
|
|
return(STATUS_NO_MEMORY);
|
|
|
|
}
|
|
|
|
memcpy(TempAddress, SourceAddress, PAGE_SIZE);
|
|
|
|
MiUnmapPageInHyperSpace(Process, TempAddress, Irql);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2001-04-03 17:25:50 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2001-04-03 17:25:50 +00:00
|
|
|
MiReadPage(PMEMORY_AREA MemoryArea,
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG SegOffset,
|
2010-07-15 22:50:12 +00:00
|
|
|
PPFN_NUMBER Page)
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2001-04-03 17:25:50 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG BaseOffset;
|
|
|
|
ULONG FileOffset;
|
|
|
|
PVOID BaseAddress;
|
|
|
|
BOOLEAN UptoDate;
|
|
|
|
PCACHE_SEGMENT CacheSeg;
|
|
|
|
PFILE_OBJECT FileObject;
|
|
|
|
NTSTATUS Status;
|
|
|
|
ULONG RawLength;
|
|
|
|
PBCB Bcb;
|
|
|
|
BOOLEAN IsImageSection;
|
|
|
|
ULONG Length;
|
|
|
|
|
|
|
|
FileObject = MemoryArea->Data.SectionData.Section->FileObject;
|
|
|
|
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
|
|
|
|
RawLength = MemoryArea->Data.SectionData.Segment->RawLength;
|
|
|
|
FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset;
|
|
|
|
IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
|
|
|
|
|
2004-10-22 20:43:58 +00:00
|
|
|
ASSERT(Bcb);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
DPRINT("%S %x\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 cache segment.
|
|
|
|
*/
|
|
|
|
if ((FileOffset % PAGE_SIZE) == 0 &&
|
2004-08-01 07:24:59 +00:00
|
|
|
(SegOffset + PAGE_SIZE <= RawLength || !IsImageSection) &&
|
2005-01-02 07:04:56 +00:00
|
|
|
!(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2001-09-25 19:41:38 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the related cache segment; we use a lower level interface than
|
|
|
|
* filesystems do because it is safe for us to use an offset with a
|
|
|
|
* alignment less than the file system block size.
|
|
|
|
*/
|
2003-02-13 22:24:19 +00:00
|
|
|
Status = CcRosGetCacheSegment(Bcb,
|
2004-04-10 22:36:07 +00:00
|
|
|
FileOffset,
|
|
|
|
&BaseOffset,
|
|
|
|
&BaseAddress,
|
|
|
|
&UptoDate,
|
|
|
|
&CacheSeg);
|
2001-04-03 17:25:50 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
return(Status);
|
|
|
|
}
|
2001-04-03 17:25:50 +00:00
|
|
|
if (!UptoDate)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If the cache segment isn't up to date then call the file
|
|
|
|
* system to read in the data.
|
|
|
|
*/
|
|
|
|
Status = ReadCacheSegment(CacheSeg);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
2001-09-25 19:41:38 +00:00
|
|
|
/*
|
|
|
|
* Retrieve the page from the cache segment that we actually want.
|
|
|
|
*/
|
2004-01-05 14:28:21 +00:00
|
|
|
(*Page) = MmGetPhysicalAddress((char*)BaseAddress +
|
2007-08-05 11:27:39 +00:00
|
|
|
FileOffset - BaseOffset).LowPart >> PAGE_SHIFT;
|
2001-04-03 17:25:50 +00:00
|
|
|
|
2003-02-13 22:24:19 +00:00
|
|
|
CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, TRUE);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-03-30 09:12:25 +00:00
|
|
|
PEPROCESS Process;
|
|
|
|
KIRQL Irql;
|
2002-11-05 20:50:02 +00:00
|
|
|
PVOID PageAddr;
|
2003-06-06 21:00:28 +00:00
|
|
|
ULONG CacheSegOffset;
|
2009-03-30 09:12:25 +00:00
|
|
|
|
2001-04-03 17:25:50 +00:00
|
|
|
/*
|
|
|
|
* Allocate a page, this is rather complicated by the possibility
|
|
|
|
* we might have to move other things out of memory
|
|
|
|
*/
|
2001-12-31 01:53:46 +00:00
|
|
|
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page);
|
2002-01-01 05:09:50 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
return(Status);
|
|
|
|
}
|
2003-02-13 22:24:19 +00:00
|
|
|
Status = CcRosGetCacheSegment(Bcb,
|
2004-04-10 22:36:07 +00:00
|
|
|
FileOffset,
|
|
|
|
&BaseOffset,
|
|
|
|
&BaseAddress,
|
|
|
|
&UptoDate,
|
|
|
|
&CacheSeg);
|
2002-11-05 20:50:02 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
return(Status);
|
|
|
|
}
|
2002-11-05 20:50:02 +00:00
|
|
|
if (!UptoDate)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If the cache segment isn't up to date then call the file
|
|
|
|
* system to read in the data.
|
|
|
|
*/
|
|
|
|
Status = ReadCacheSegment(CacheSeg);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
2009-03-14 21:29:37 +00:00
|
|
|
|
2009-03-30 09:12:25 +00:00
|
|
|
Process = PsGetCurrentProcess();
|
|
|
|
PageAddr = MiMapPageInHyperSpace(Process, *Page, &Irql);
|
2003-06-06 21:00:28 +00:00
|
|
|
CacheSegOffset = BaseOffset + CacheSeg->Bcb->CacheSegmentSize - FileOffset;
|
|
|
|
Length = RawLength - SegOffset;
|
|
|
|
if (Length <= CacheSegOffset && Length <= PAGE_SIZE)
|
|
|
|
{
|
2003-12-30 18:52:06 +00:00
|
|
|
memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, Length);
|
2003-06-06 21:00:28 +00:00
|
|
|
}
|
|
|
|
else if (CacheSegOffset >= PAGE_SIZE)
|
2002-08-28 07:13:04 +00:00
|
|
|
{
|
2003-12-30 18:52:06 +00:00
|
|
|
memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, PAGE_SIZE);
|
2002-08-28 07:13:04 +00:00
|
|
|
}
|
2002-11-05 20:50:02 +00:00
|
|
|
else
|
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, CacheSegOffset);
|
2009-03-30 09:12:25 +00:00
|
|
|
MiUnmapPageInHyperSpace(Process, PageAddr, Irql);
|
2003-02-13 22:24:19 +00:00
|
|
|
CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
|
2004-04-10 22:36:07 +00:00
|
|
|
Status = CcRosGetCacheSegment(Bcb,
|
|
|
|
FileOffset + CacheSegOffset,
|
|
|
|
&BaseOffset,
|
|
|
|
&BaseAddress,
|
|
|
|
&UptoDate,
|
|
|
|
&CacheSeg);
|
2002-11-05 20:50:02 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
return(Status);
|
|
|
|
}
|
2002-11-05 20:50:02 +00:00
|
|
|
if (!UptoDate)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If the cache segment isn't up to date then call the file
|
|
|
|
* system to read in the data.
|
|
|
|
*/
|
|
|
|
Status = ReadCacheSegment(CacheSeg);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
2009-03-30 09:12:25 +00:00
|
|
|
PageAddr = MiMapPageInHyperSpace(Process, *Page, &Irql);
|
2003-06-06 21:00:28 +00:00
|
|
|
if (Length < PAGE_SIZE)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, Length - CacheSegOffset);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-12-30 18:52:06 +00:00
|
|
|
memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, PAGE_SIZE - CacheSegOffset);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2002-11-05 20:50:02 +00:00
|
|
|
}
|
2009-03-30 09:12:25 +00:00
|
|
|
MiUnmapPageInHyperSpace(Process, PageAddr, Irql);
|
2003-02-13 22:24:19 +00:00
|
|
|
CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
2001-04-03 17:25:50 +00:00
|
|
|
}
|
2001-03-29 17:24:43 +00:00
|
|
|
|
2001-10-10 22:40:36 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2009-04-27 10:12:57 +00:00
|
|
|
MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
MEMORY_AREA* MemoryArea,
|
|
|
|
PVOID Address,
|
|
|
|
BOOLEAN Locked)
|
2000-06-25 03:59:17 +00:00
|
|
|
{
|
2003-06-06 21:00:28 +00:00
|
|
|
ULONG Offset;
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page;
|
2000-06-25 03:59:17 +00:00
|
|
|
NTSTATUS Status;
|
2005-01-02 17:55:06 +00:00
|
|
|
PVOID PAddress;
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2001-02-10 22:51:11 +00:00
|
|
|
PMM_SECTION_SEGMENT Segment;
|
2000-06-25 03:59:17 +00:00
|
|
|
ULONG Entry;
|
|
|
|
ULONG Entry1;
|
2001-02-10 22:51:11 +00:00
|
|
|
ULONG Attributes;
|
2001-03-13 16:25:55 +00:00
|
|
|
PMM_PAGEOP PageOp;
|
2002-08-10 16:41:20 +00:00
|
|
|
PMM_REGION Region;
|
2006-09-07 05:07:34 +00:00
|
|
|
BOOLEAN HasSwapEntry;
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
|
|
|
|
2000-06-26 19:41:43 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
if (MmIsPagePresent(Process, Address))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
|
2007-10-19 23:21:45 +00:00
|
|
|
Offset = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress
|
2005-06-12 10:25:49 +00:00
|
|
|
+ MemoryArea->Data.SectionData.ViewOffset;
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2001-02-10 22:51:11 +00:00
|
|
|
Segment = MemoryArea->Data.SectionData.Segment;
|
2000-06-25 03:59:17 +00:00
|
|
|
Section = MemoryArea->Data.SectionData.Section;
|
2005-01-02 17:55:06 +00:00
|
|
|
Region = MmFindRegion(MemoryArea->StartingAddress,
|
2004-04-10 22:36:07 +00:00
|
|
|
&MemoryArea->Data.SectionData.RegionListHead,
|
|
|
|
Address, NULL);
|
2003-06-27 21:28:30 +00:00
|
|
|
/*
|
|
|
|
* Lock the segment
|
|
|
|
*/
|
2001-02-10 22:51:11 +00:00
|
|
|
MmLockSectionSegment(Segment);
|
2002-08-29 22:12:16 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if this page needs to be mapped COW
|
|
|
|
*/
|
2010-10-05 04:57:32 +00:00
|
|
|
if ((Segment->WriteCopy) &&
|
2004-08-01 07:24:59 +00:00
|
|
|
(Region->Protect == PAGE_READWRITE ||
|
|
|
|
Region->Protect == PAGE_EXECUTE_READWRITE))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ;
|
|
|
|
}
|
2002-08-29 22:12:16 +00:00
|
|
|
else
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
Attributes = Region->Protect;
|
|
|
|
}
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2001-03-13 16:25:55 +00:00
|
|
|
/*
|
|
|
|
* Get or create a page operation descriptor
|
|
|
|
*/
|
2005-01-26 00:03:05 +00:00
|
|
|
PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset, MM_PAGEOP_PAGEIN, FALSE);
|
2001-03-13 16:25:55 +00:00
|
|
|
if (PageOp == NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT1("MmGetPageOp failed\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-03-13 16:25:55 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if someone else is already handling this fault, if so wait
|
|
|
|
* for them
|
|
|
|
*/
|
|
|
|
if (PageOp->Thread != PsGetCurrentThread())
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
Status = MmspWaitForPageOpCompletionEvent(PageOp);
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* Check for various strange conditions
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
if (Status != STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
DPRINT1("Failed to wait for page op, status = %x\n", Status);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
if (PageOp->Status == STATUS_PENDING)
|
|
|
|
{
|
|
|
|
DPRINT1("Woke for page op before completion\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* If this wasn't a pagein then restart the operation
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
if (PageOp->OpType != MM_PAGEOP_PAGEIN)
|
|
|
|
{
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(STATUS_MM_RESTART_OPERATION);
|
|
|
|
}
|
2001-12-31 19:06:49 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
|
|
|
* If the thread handling this fault has failed then we don't retry
|
|
|
|
*/
|
|
|
|
if (!NT_SUCCESS(PageOp->Status))
|
|
|
|
{
|
|
|
|
Status = PageOp->Status;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
MmLockSectionSegment(Segment);
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* If the completed fault was for another address space then set the
|
|
|
|
* page in this one.
|
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
if (!MmIsPagePresent(Process, Address))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
HasSwapEntry = MmIsPageSwapEntry(Process, (PVOID)PAddress);
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
if (PAGE_FROM_SSE(Entry) == 0 || HasSwapEntry)
|
2003-06-06 21:00:28 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
2005-05-09 01:38:29 +00:00
|
|
|
* The page was a private page in another or in our address space
|
2007-01-06 02:34:58 +00:00
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_MM_RESTART_OPERATION);
|
2003-06-06 21:00:28 +00:00
|
|
|
}
|
2001-03-13 16:25:55 +00:00
|
|
|
|
2004-08-01 07:24:59 +00:00
|
|
|
Page = PFN_FROM_SSE(Entry);
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
MmSharePageEntrySectionSegment(Segment, Offset);
|
|
|
|
|
2005-03-15 22:07:05 +00:00
|
|
|
/* FIXME: Should we call MmCreateVirtualMappingUnsafe if
|
|
|
|
* (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
|
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address,
|
|
|
|
Attributes,
|
2004-08-01 07:24:59 +00:00
|
|
|
&Page,
|
|
|
|
1);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2003-06-27 21:28:30 +00:00
|
|
|
{
|
2007-01-06 02:34:58 +00:00
|
|
|
DPRINT1("Unable to create virtual mapping\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2003-12-30 18:52:06 +00:00
|
|
|
}
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmInsertRmap(Page, Process, (PVOID)PAddress);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
1999-11-24 11:51:55 +00:00
|
|
|
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
HasSwapEntry = MmIsPageSwapEntry(Process, (PVOID)PAddress);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (HasSwapEntry)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Must be private page we have swapped out.
|
|
|
|
*/
|
|
|
|
SWAPENTRY SwapEntry;
|
2001-02-10 22:51:11 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
|
|
|
* Sanity check
|
2007-01-06 02:34:58 +00:00
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
if (Segment->Flags & MM_PAGEFILE_SEGMENT)
|
|
|
|
{
|
|
|
|
DPRINT1("Found a swaped out private page in a pagefile section.\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-04-04 22:21:32 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
MmUnlockSectionSegment(Segment);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmDeletePageFileMapping(Process, (PVOID)PAddress, &SwapEntry);
|
2001-02-10 22:51:11 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2004-01-30 23:57:58 +00:00
|
|
|
|
2004-08-01 07:24:59 +00:00
|
|
|
Status = MmReadFromSwapPage(SwapEntry, Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
MmLockAddressSpace(AddressSpace);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address,
|
|
|
|
Region->Protect,
|
2004-08-01 07:24:59 +00:00
|
|
|
&Page,
|
|
|
|
1);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
return(Status);
|
|
|
|
}
|
2004-01-30 23:57:58 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
2004-08-23 22:29:43 +00:00
|
|
|
* Store the swap entry for later use.
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
MmSetSavedSwapEntryPage(Page, SwapEntry);
|
|
|
|
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* Add the page to the process's working set
|
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmInsertRmap(Page, Process, (PVOID)PAddress);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* Finish the operation
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Satisfying a page fault on a map of /Device/PhysicalMemory is easy
|
|
|
|
*/
|
|
|
|
if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
|
|
|
|
{
|
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* Just map the desired physical page
|
|
|
|
*/
|
2005-06-12 10:25:49 +00:00
|
|
|
Page = Offset >> PAGE_SHIFT;
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreateVirtualMappingUnsafe(Process,
|
2005-03-15 22:07:05 +00:00
|
|
|
Address,
|
|
|
|
Region->Protect,
|
|
|
|
&Page,
|
|
|
|
1);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-03-15 22:07:05 +00:00
|
|
|
DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* Cleanup and release locks
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Map anonymous memory for BSS sections
|
|
|
|
*/
|
2005-05-28 07:34:54 +00:00
|
|
|
if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
|
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address,
|
|
|
|
Region->Protect,
|
2004-08-01 07:24:59 +00:00
|
|
|
&Page,
|
|
|
|
1);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
return(Status);
|
|
|
|
}
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmInsertRmap(Page, Process, (PVOID)PAddress);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* Cleanup and release locks
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the entry corresponding to the offset within the section
|
|
|
|
*/
|
|
|
|
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
|
|
|
|
|
|
|
|
if (Entry == 0)
|
|
|
|
{
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* If the entry is zero (and it can't change because we have
|
|
|
|
* locked the segment) then we need to load the page.
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* Release all our locks and read in the page from disk
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
|
|
|
|
if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
|
2004-08-01 07:24:59 +00:00
|
|
|
(Offset >= PAGE_ROUND_UP(Segment->RawLength) && Section->AllocationAttributes & SEC_IMAGE))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Status = MiReadPage(MemoryArea, Offset, &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);
|
|
|
|
PageOp->Status = Status;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* Relock the address space and segment
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
MmLockSectionSegment(Segment);
|
|
|
|
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* Check the entry. No one should change the status of a page
|
|
|
|
* that has a pending page-in.
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
|
|
|
|
if (Entry != Entry1)
|
|
|
|
{
|
2007-01-06 02:34:58 +00:00
|
|
|
DPRINT1("Someone changed ppte entry while we slept\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* Mark the offset within the section as having valid, in-memory
|
|
|
|
* data
|
|
|
|
*/
|
2004-08-01 07:24:59 +00:00
|
|
|
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
|
2004-04-10 22:36:07 +00:00
|
|
|
MmSetPageEntrySectionSegment(Segment, Offset, Entry);
|
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address,
|
|
|
|
Attributes,
|
2004-08-01 07:24:59 +00:00
|
|
|
&Page,
|
|
|
|
1);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2007-01-06 02:34:58 +00:00
|
|
|
DPRINT1("Unable to create virtual mapping\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmInsertRmap(Page, Process, (PVOID)PAddress);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
else if (IS_SWAP_FROM_SSE(Entry))
|
|
|
|
{
|
|
|
|
SWAPENTRY SwapEntry;
|
|
|
|
|
|
|
|
SwapEntry = SWAPENTRY_FROM_SSE(Entry);
|
|
|
|
|
|
|
|
/*
|
2007-01-06 02:50:53 +00:00
|
|
|
* Release all our locks and read in the page from disk
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
|
|
|
|
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
2004-08-01 07:24:59 +00:00
|
|
|
Status = MmReadFromSwapPage(SwapEntry, Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* Relock the address space and segment
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
MmLockSectionSegment(Segment);
|
|
|
|
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* Check the entry. No one should change the status of a page
|
|
|
|
* that has a pending page-in.
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
|
|
|
|
if (Entry != Entry1)
|
|
|
|
{
|
2007-01-06 02:34:58 +00:00
|
|
|
DPRINT1("Someone changed ppte entry while we slept\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* Mark the offset within the section as having valid, in-memory
|
|
|
|
* data
|
|
|
|
*/
|
2004-08-01 07:24:59 +00:00
|
|
|
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
|
2004-04-10 22:36:07 +00:00
|
|
|
MmSetPageEntrySectionSegment(Segment, Offset, Entry);
|
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
|
|
|
|
/*
|
2007-01-06 02:34:58 +00:00
|
|
|
* Save the swap entry.
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
MmSetSavedSwapEntryPage(Page, SwapEntry);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address,
|
|
|
|
Region->Protect,
|
2004-08-01 07:24:59 +00:00
|
|
|
&Page,
|
|
|
|
1);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2007-01-06 02:34:58 +00:00
|
|
|
DPRINT1("Unable to create virtual mapping\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmInsertRmap(Page, Process, (PVOID)PAddress);
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If the section offset is already in-memory and valid then just
|
2007-01-06 02:34:58 +00:00
|
|
|
* take another reference to the page
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2004-08-01 07:24:59 +00:00
|
|
|
Page = PFN_FROM_SSE(Entry);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
MmSharePageEntrySectionSegment(Segment, Offset);
|
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address,
|
|
|
|
Attributes,
|
2004-08-01 07:24:59 +00:00
|
|
|
&Page,
|
|
|
|
1);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2007-01-06 02:34:58 +00:00
|
|
|
DPRINT1("Unable to create virtual mapping\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmInsertRmap(Page, Process, (PVOID)PAddress);
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2009-04-27 10:12:57 +00:00
|
|
|
MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
MEMORY_AREA* MemoryArea,
|
|
|
|
PVOID Address,
|
|
|
|
BOOLEAN Locked)
|
|
|
|
{
|
|
|
|
PMM_SECTION_SEGMENT Segment;
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER OldPage;
|
|
|
|
PFN_NUMBER NewPage;
|
2004-04-10 22:36:07 +00:00
|
|
|
NTSTATUS Status;
|
2005-01-02 17:55:06 +00:00
|
|
|
PVOID PAddress;
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG Offset;
|
|
|
|
PMM_PAGEOP PageOp;
|
|
|
|
PMM_REGION Region;
|
|
|
|
ULONG Entry;
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
|
|
|
|
2007-01-06 02:50:53 +00:00
|
|
|
DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace, MemoryArea, Address, Locked);
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
|
|
|
* Check if the page has been paged out or has already been set readwrite
|
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
if (!MmIsPagePresent(Process, Address) ||
|
|
|
|
MmGetPageProtect(Process, Address) & PAGE_READWRITE)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the offset of the page
|
|
|
|
*/
|
2005-01-02 17:55:06 +00:00
|
|
|
PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
|
2007-10-19 23:21:45 +00:00
|
|
|
Offset = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress
|
2005-06-12 10:25:49 +00:00
|
|
|
+ MemoryArea->Data.SectionData.ViewOffset;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
Segment = MemoryArea->Data.SectionData.Segment;
|
|
|
|
Section = MemoryArea->Data.SectionData.Section;
|
2005-01-02 17:55:06 +00:00
|
|
|
Region = MmFindRegion(MemoryArea->StartingAddress,
|
2004-04-10 22:36:07 +00:00
|
|
|
&MemoryArea->Data.SectionData.RegionListHead,
|
|
|
|
Address, NULL);
|
|
|
|
/*
|
|
|
|
* Lock the segment
|
|
|
|
*/
|
|
|
|
MmLockSectionSegment(Segment);
|
|
|
|
|
2004-08-01 07:24:59 +00:00
|
|
|
OldPage = MmGetPfnForProcess(NULL, Address);
|
2004-04-10 22:36:07 +00:00
|
|
|
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
|
|
|
|
|
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if we are doing COW
|
|
|
|
*/
|
2010-10-05 04:57:32 +00:00
|
|
|
if (!((Segment->WriteCopy) &&
|
2004-04-10 22:36:07 +00:00
|
|
|
(Region->Protect == PAGE_READWRITE ||
|
|
|
|
Region->Protect == PAGE_EXECUTE_READWRITE)))
|
|
|
|
{
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
2008-08-07 16:08:00 +00:00
|
|
|
return(STATUS_ACCESS_VIOLATION);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-02-10 22:51:11 +00:00
|
|
|
|
2004-01-30 23:57:58 +00:00
|
|
|
if (IS_SWAP_FROM_SSE(Entry) ||
|
2004-08-01 07:24:59 +00:00
|
|
|
PFN_FROM_SSE(Entry) != OldPage)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
/* This is a private page. We must only change the page protection. */
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmSetPageProtect(Process, PAddress, Region->Protect);
|
2004-04-10 22:36:07 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
2004-01-30 23:57:58 +00:00
|
|
|
|
2001-02-10 22:51:11 +00:00
|
|
|
/*
|
2001-04-04 22:21:32 +00:00
|
|
|
* Get or create a pageop
|
2001-02-10 22:51:11 +00:00
|
|
|
*/
|
2005-01-26 00:03:05 +00:00
|
|
|
PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset,
|
2004-04-10 22:36:07 +00:00
|
|
|
MM_PAGEOP_ACCESSFAULT, FALSE);
|
2001-04-04 22:21:32 +00:00
|
|
|
if (PageOp == NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT1("MmGetPageOp failed\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-04-04 22:21:32 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait for any other operations to complete
|
|
|
|
*/
|
|
|
|
if (PageOp->Thread != PsGetCurrentThread())
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
Status = MmspWaitForPageOpCompletionEvent(PageOp);
|
|
|
|
/*
|
|
|
|
* Check for various strange conditions
|
|
|
|
*/
|
|
|
|
if (Status == STATUS_TIMEOUT)
|
|
|
|
{
|
|
|
|
DPRINT1("Failed to wait for page op, status = %x\n", Status);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
if (PageOp->Status == STATUS_PENDING)
|
|
|
|
{
|
|
|
|
DPRINT1("Woke for page op before completion\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Restart the operation
|
|
|
|
*/
|
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(STATUS_MM_RESTART_OPERATION);
|
|
|
|
}
|
2001-04-04 22:21:32 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Release locks now we have the pageop
|
|
|
|
*/
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a page
|
|
|
|
*/
|
2001-12-31 01:53:46 +00:00
|
|
|
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
|
2003-06-06 21:00:28 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2003-06-06 21:00:28 +00:00
|
|
|
}
|
2001-02-10 22:51:11 +00:00
|
|
|
|
2001-04-04 22:21:32 +00:00
|
|
|
/*
|
|
|
|
* Copy the old page
|
|
|
|
*/
|
2005-01-25 22:50:47 +00:00
|
|
|
MiCopyFromUserPage(NewPage, PAddress);
|
2001-02-10 22:51:11 +00:00
|
|
|
|
2005-10-29 14:10:35 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2001-12-31 19:06:49 +00:00
|
|
|
/*
|
|
|
|
* Delete the old entry.
|
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
|
2001-12-31 19:06:49 +00:00
|
|
|
|
2001-04-04 22:21:32 +00:00
|
|
|
/*
|
|
|
|
* Set the PTE to point to the new page
|
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address,
|
|
|
|
Region->Protect,
|
2004-08-01 07:24:59 +00:00
|
|
|
&NewPage,
|
|
|
|
1);
|
2003-06-27 21:28:30 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
return(Status);
|
|
|
|
}
|
2001-02-10 22:51:11 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2007-01-06 02:34:58 +00:00
|
|
|
DPRINT1("Unable to create virtual mapping\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-12-31 01:53:46 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Unshare the old page.
|
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmDeleteRmap(OldPage, Process, PAddress);
|
|
|
|
MmInsertRmap(NewPage, Process, PAddress);
|
2003-06-27 21:28:30 +00:00
|
|
|
MmLockSectionSegment(Segment);
|
2003-12-31 14:52:06 +00:00
|
|
|
MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE, FALSE);
|
2003-06-27 21:28:30 +00:00
|
|
|
MmUnlockSectionSegment(Segment);
|
2001-12-31 01:53:46 +00:00
|
|
|
|
2001-04-04 22:21:32 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
2003-12-30 18:52:06 +00:00
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
2003-06-27 21:28:30 +00:00
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
2001-02-10 22:51:11 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2001-12-31 01:53:46 +00:00
|
|
|
VOID
|
2006-05-18 20:32:17 +00:00
|
|
|
MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
|
2001-12-31 01:53:46 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
|
2006-01-08 06:23:17 +00:00
|
|
|
BOOLEAN WasDirty;
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
|
2005-10-29 14:10:35 +00:00
|
|
|
if (Process)
|
|
|
|
{
|
2009-04-27 10:12:57 +00:00
|
|
|
MmLockAddressSpace(&Process->Vm);
|
2005-10-29 14:10:35 +00:00
|
|
|
}
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
MmDeleteVirtualMapping(Process,
|
|
|
|
Address,
|
|
|
|
FALSE,
|
|
|
|
&WasDirty,
|
|
|
|
&Page);
|
|
|
|
if (WasDirty)
|
|
|
|
{
|
2002-01-08 00:49:02 +00:00
|
|
|
PageOutContext->WasDirty = TRUE;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
if (!PageOutContext->Private)
|
|
|
|
{
|
2005-10-29 14:10:35 +00:00
|
|
|
MmLockSectionSegment(PageOutContext->Segment);
|
2006-05-10 17:47:44 +00:00
|
|
|
MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT)PageOutContext->Section,
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOutContext->Segment,
|
|
|
|
PageOutContext->Offset,
|
|
|
|
PageOutContext->WasDirty,
|
|
|
|
TRUE);
|
2005-10-29 14:10:35 +00:00
|
|
|
MmUnlockSectionSegment(PageOutContext->Segment);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-10-29 14:10:35 +00:00
|
|
|
if (Process)
|
|
|
|
{
|
2009-04-27 10:12:57 +00:00
|
|
|
MmUnlockAddressSpace(&Process->Vm);
|
2005-10-29 14:10:35 +00:00
|
|
|
}
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2005-10-29 14:10:35 +00:00
|
|
|
if (PageOutContext->Private)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2003-12-31 14:52:06 +00:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2003-12-31 14:52:06 +00:00
|
|
|
|
2005-10-24 15:56:03 +00:00
|
|
|
DPRINT("PhysicalAddress %x, Address %x\n", Page << PAGE_SHIFT, Address);
|
2001-12-31 01:53:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2009-04-27 10:12:57 +00:00
|
|
|
MmPageOutSectionView(PMMSUPPORT AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
MEMORY_AREA* MemoryArea,
|
|
|
|
PVOID Address,
|
|
|
|
PMM_PAGEOP PageOp)
|
2000-06-25 03:59:17 +00:00
|
|
|
{
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page;
|
2004-04-10 22:36:07 +00:00
|
|
|
MM_SECTION_PAGEOUT_CONTEXT Context;
|
|
|
|
SWAPENTRY SwapEntry;
|
|
|
|
ULONG Entry;
|
|
|
|
ULONG FileOffset;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PFILE_OBJECT FileObject;
|
|
|
|
PBCB Bcb = NULL;
|
|
|
|
BOOLEAN DirectMapped;
|
|
|
|
BOOLEAN IsImageSection;
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
2009-09-30 18:24:00 +00:00
|
|
|
KIRQL OldIrql;
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
Address = (PVOID)PAGE_ROUND_DOWN(Address);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the segment and section.
|
|
|
|
*/
|
|
|
|
Context.Segment = MemoryArea->Data.SectionData.Segment;
|
|
|
|
Context.Section = MemoryArea->Data.SectionData.Section;
|
|
|
|
|
2007-10-19 23:21:45 +00:00
|
|
|
Context.Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
|
2005-06-12 10:25:49 +00:00
|
|
|
+ MemoryArea->Data.SectionData.ViewOffset;
|
2004-04-10 22:36:07 +00:00
|
|
|
FileOffset = Context.Offset + Context.Segment->FileOffset;
|
|
|
|
|
|
|
|
IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
|
|
|
|
|
|
|
|
FileObject = Context.Section->FileObject;
|
|
|
|
DirectMapped = FALSE;
|
|
|
|
if (FileObject != NULL &&
|
2005-01-02 07:04:56 +00:00
|
|
|
!(Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2003-06-07 Casper S. Hornstrup <chorns@users.sourceforge.net>
Changes for compiling with w32api
* include/ddk/cctypes.h (PREACTOS_COMMON_FCB_HEADER): Remove.
(FSRTL_COMMON_FCB_HEADER): Add.
* include/ddk/iotypes.h (FILE_OBJECT): Rename field
SectionObjectPointers to SectionObjectPointer.
* ntoskrnl/cc/copy.c, ntoskrnl/cc/misc.c, ntoskrnl/cc/pin.c,
ntoskrnl/cc/view.c, ntoskrnl/io/rawfs.c, ntoskrnl/mm/section.c,
drivers/fs/cdfs/cleanup.c, drivers/fs/cdfs/fcb.c,
drivers/fs/cdfs/fsctl.c, drivers/fs/ntfs/fcb.c, drivers/fs/ntfs/fsctl.c,
drivers/fs/vfat/close.c, drivers/fs/vfat/create.c,
drivers/fs/vfat/finfo.c, drivers/fs/vfat/fcb.c, drivers/fs/vfat/fsctl.c:
Use new FILE_OBJECT structure.
* drivers/fs/cdfs/cdfs.h, drivers/fs/ntfs/ntfs.h, drivers/fs/vfat/vfat.h:
Use new FSRTL_COMMON_FCB_HEADER structure.
* drivers/net/afd/include/afd.h (FSRTL_COMMON_FCB_HEADER): Remove.
* include/ddk/ketypes.h (KQUEUE): Match w32api structure.
* ntoskrnl/ke/queue.c, ntoskrnl/ke/wait.c: Use new structure.
* ntoskrnl/ke/spinlock.c (KeAcquireSpinLockAtDpcLevel,
KeReleaseSpinLockFromDpcLevel): Undefine before declaring.
svn path=/trunk/; revision=4865
2003-06-07 11:34:36 +00:00
|
|
|
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2001-12-31 01:53:46 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2003-12-31 14:52:06 +00:00
|
|
|
if ((FileOffset % PAGE_SIZE) == 0 &&
|
2004-04-10 22:36:07 +00:00
|
|
|
(Context.Offset + PAGE_SIZE <= Context.Segment->RawLength || !IsImageSection))
|
|
|
|
{
|
|
|
|
DirectMapped = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This should never happen since mappings of physical memory are never
|
|
|
|
* placed in the rmap lists.
|
|
|
|
*/
|
|
|
|
if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY)
|
|
|
|
{
|
2002-01-08 00:49:02 +00:00
|
|
|
DPRINT1("Trying to page out from physical memory section address 0x%X "
|
2004-04-10 22:36:07 +00:00
|
|
|
"process %d\n", Address,
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Process ? Process->UniqueProcessId : 0);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the section segment entry and the physical address.
|
|
|
|
*/
|
|
|
|
Entry = MmGetPageEntrySectionSegment(Context.Segment, Context.Offset);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
if (!MmIsPagePresent(Process, Address))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2002-01-08 00:49:02 +00:00
|
|
|
DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Process ? Process->UniqueProcessId : 0, Address);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Page = MmGetPfnForProcess(Process, Address);
|
2004-08-01 07:24:59 +00:00
|
|
|
SwapEntry = MmGetSavedSwapEntryPage(Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Prepare the context structure for the rmap delete call.
|
|
|
|
*/
|
|
|
|
Context.WasDirty = FALSE;
|
2005-06-12 10:25:49 +00:00
|
|
|
if (Context.Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
|
2004-04-10 22:36:07 +00:00
|
|
|
IS_SWAP_FROM_SSE(Entry) ||
|
2004-08-01 07:24:59 +00:00
|
|
|
PFN_FROM_SSE(Entry) != Page)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2003-06-06 21:00:28 +00:00
|
|
|
Context.Private = TRUE;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-06-06 21:00:28 +00:00
|
|
|
Context.Private = FALSE;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-12-31 01:53:46 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
|
|
|
* Take an additional reference to the page or the cache segment.
|
|
|
|
*/
|
|
|
|
if (DirectMapped && !Context.Private)
|
|
|
|
{
|
2003-06-06 21:00:28 +00:00
|
|
|
if(!MiIsPageFromCache(MemoryArea, Context.Offset))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT1("Direct mapped non private page is not associated with the cache.\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-09-30 18:24:00 +00:00
|
|
|
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
|
2004-08-01 07:24:59 +00:00
|
|
|
MmReferencePage(Page);
|
2009-09-30 18:24:00 +00:00
|
|
|
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2003-06-06 21:00:28 +00:00
|
|
|
|
2004-08-01 07:24:59 +00:00
|
|
|
MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping);
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
|
|
|
* If this wasn't a private page then we should have reduced the entry to
|
|
|
|
* zero by deleting all the rmaps.
|
|
|
|
*/
|
|
|
|
if (!Context.Private && MmGetPageEntrySectionSegment(Context.Segment, Context.Offset) != 0)
|
|
|
|
{
|
2003-12-31 14:52:06 +00:00
|
|
|
if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) &&
|
2005-01-02 07:04:56 +00:00
|
|
|
!(Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2004-08-01 07:24:59 +00:00
|
|
|
SwapEntry = MmGetSavedSwapEntryPage(Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT)
|
|
|
|
{
|
2003-06-06 21:00:28 +00:00
|
|
|
if (Context.Private)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
|
|
|
|
Context.WasDirty ? "dirty" : "clean", Address);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2004-01-27 20:13:08 +00:00
|
|
|
if (!Context.WasDirty && SwapEntry != 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2004-08-01 07:24:59 +00:00
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
2004-04-10 22:36:07 +00:00
|
|
|
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
|
2004-08-01 07:24:59 +00:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
2005-01-02 07:04:56 +00:00
|
|
|
else if (Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2004-01-27 20:13:08 +00:00
|
|
|
if (Context.Private)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
|
|
|
|
Context.WasDirty ? "dirty" : "clean", Address);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2004-01-27 20:13:08 +00:00
|
|
|
if (!Context.WasDirty || SwapEntry != 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2004-08-01 07:24:59 +00:00
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (SwapEntry != 0)
|
|
|
|
{
|
|
|
|
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
|
|
|
|
}
|
2004-08-01 07:24:59 +00:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!Context.Private && DirectMapped)
|
|
|
|
{
|
2004-01-27 20:13:08 +00:00
|
|
|
if (SwapEntry != 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
|
|
|
|
Address);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2004-01-27 20:13:08 +00:00
|
|
|
Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-12-31 01:53:46 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
2003-12-30 18:52:06 +00:00
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
2001-12-31 01:53:46 +00:00
|
|
|
return(STATUS_SUCCESS);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
else if (!Context.WasDirty && !DirectMapped && !Context.Private)
|
|
|
|
{
|
2004-01-27 20:13:08 +00:00
|
|
|
if (SwapEntry != 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
|
|
|
|
Address);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2004-08-01 07:24:59 +00:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2004-01-27 20:13:08 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
|
|
|
|
{
|
2004-08-01 07:24:59 +00:00
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
2005-10-29 14:10:35 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreatePageFileMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address,
|
|
|
|
SwapEntry);
|
2005-10-29 14:10:35 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2003-06-06 21:00:28 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2004-08-01 07:24:59 +00:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2001-12-31 01:53:46 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
2003-12-30 18:52:06 +00:00
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
2001-12-31 01:53:46 +00:00
|
|
|
return(STATUS_SUCCESS);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-12-31 01:53:46 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
|
|
|
* If necessary, allocate an entry in the paging file for this page
|
|
|
|
*/
|
|
|
|
if (SwapEntry == 0)
|
|
|
|
{
|
2001-12-31 01:53:46 +00:00
|
|
|
SwapEntry = MmAllocSwapPage();
|
|
|
|
if (SwapEntry == 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
MmShowOutOfSpaceMessagePagingFile();
|
2005-10-29 14:10:35 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
|
|
|
* For private pages restore the old mappings.
|
|
|
|
*/
|
|
|
|
if (Context.Private)
|
|
|
|
{
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address,
|
2005-11-13 17:28:24 +00:00
|
|
|
MemoryArea->Protect,
|
2004-08-01 07:24:59 +00:00
|
|
|
&Page,
|
|
|
|
1);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmSetDirtyPage(Process, Address);
|
2004-08-01 07:24:59 +00:00
|
|
|
MmInsertRmap(Page,
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address,
|
2005-11-13 17:28:24 +00:00
|
|
|
MemoryArea->Protect,
|
2004-08-01 07:24:59 +00:00
|
|
|
&Page,
|
|
|
|
1);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmSetDirtyPage(Process, Address);
|
2004-08-01 07:24:59 +00:00
|
|
|
MmInsertRmap(Page,
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address);
|
2004-08-01 07:24:59 +00:00
|
|
|
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
|
2004-04-10 22:36:07 +00:00
|
|
|
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
|
|
|
|
}
|
2005-10-29 14:10:35 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_UNSUCCESSFUL;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_PAGEFILE_QUOTA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write the page to the pagefile
|
|
|
|
*/
|
2004-08-01 07:24:59 +00:00
|
|
|
Status = MmWriteToSwapPage(SwapEntry, Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2003-12-30 18:52:06 +00:00
|
|
|
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
|
2004-04-10 22:36:07 +00:00
|
|
|
Status);
|
2001-12-31 01:53:46 +00:00
|
|
|
/*
|
|
|
|
* As above: undo our actions.
|
|
|
|
* FIXME: Also free the swap page.
|
|
|
|
*/
|
2005-10-29 14:10:35 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2003-06-06 21:00:28 +00:00
|
|
|
if (Context.Private)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address,
|
2005-11-13 17:28:24 +00:00
|
|
|
MemoryArea->Protect,
|
2004-08-01 07:24:59 +00:00
|
|
|
&Page,
|
|
|
|
1);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmSetDirtyPage(Process, Address);
|
2004-08-01 07:24:59 +00:00
|
|
|
MmInsertRmap(Page,
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address);
|
|
|
|
}
|
2001-12-31 01:53:46 +00:00
|
|
|
else
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address,
|
2005-11-13 17:28:24 +00:00
|
|
|
MemoryArea->Protect,
|
2004-08-01 07:24:59 +00:00
|
|
|
&Page,
|
|
|
|
1);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmSetDirtyPage(Process, Address);
|
2004-08-01 07:24:59 +00:00
|
|
|
MmInsertRmap(Page,
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address);
|
2004-08-01 07:24:59 +00:00
|
|
|
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
|
2004-04-10 22:36:07 +00:00
|
|
|
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
|
|
|
|
}
|
2005-10-29 14:10:35 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2001-12-31 01:53:46 +00:00
|
|
|
PageOp->Status = STATUS_UNSUCCESSFUL;
|
2003-12-30 18:52:06 +00:00
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
2001-12-31 01:53:46 +00:00
|
|
|
return(STATUS_UNSUCCESSFUL);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise we have succeeded.
|
|
|
|
*/
|
2004-08-01 07:24:59 +00:00
|
|
|
DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
|
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
|
2005-01-02 07:04:56 +00:00
|
|
|
Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2004-01-27 20:13:08 +00:00
|
|
|
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-08-01 07:24:59 +00:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-12-31 19:06:49 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
if (Context.Private)
|
|
|
|
{
|
2005-10-29 14:10:35 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreatePageFileMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address,
|
|
|
|
SwapEntry);
|
2005-10-29 14:10:35 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2001-12-31 19:06:49 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-12-31 19:06:49 +00:00
|
|
|
Entry = MAKE_SWAP_SSE(SwapEntry);
|
2003-06-06 21:00:28 +00:00
|
|
|
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-12-31 01:53:46 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
2000-06-25 03:59:17 +00:00
|
|
|
}
|
|
|
|
|
2003-12-30 18:52:06 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2009-04-27 10:12:57 +00:00
|
|
|
MmWritePageSectionView(PMMSUPPORT AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
PMEMORY_AREA MemoryArea,
|
|
|
|
PVOID Address,
|
|
|
|
PMM_PAGEOP PageOp)
|
2002-08-14 20:58:39 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG Offset;
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2004-04-10 22:36:07 +00:00
|
|
|
PMM_SECTION_SEGMENT Segment;
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page;
|
2004-04-10 22:36:07 +00:00
|
|
|
SWAPENTRY SwapEntry;
|
|
|
|
ULONG Entry;
|
|
|
|
BOOLEAN Private;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PFILE_OBJECT FileObject;
|
|
|
|
PBCB Bcb = NULL;
|
|
|
|
BOOLEAN DirectMapped;
|
|
|
|
BOOLEAN IsImageSection;
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
Address = (PVOID)PAGE_ROUND_DOWN(Address);
|
|
|
|
|
2007-10-19 23:21:45 +00:00
|
|
|
Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
|
2005-06-12 10:25:49 +00:00
|
|
|
+ MemoryArea->Data.SectionData.ViewOffset;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 &&
|
2005-01-02 07:04:56 +00:00
|
|
|
!(Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2003-06-07 Casper S. Hornstrup <chorns@users.sourceforge.net>
Changes for compiling with w32api
* include/ddk/cctypes.h (PREACTOS_COMMON_FCB_HEADER): Remove.
(FSRTL_COMMON_FCB_HEADER): Add.
* include/ddk/iotypes.h (FILE_OBJECT): Rename field
SectionObjectPointers to SectionObjectPointer.
* ntoskrnl/cc/copy.c, ntoskrnl/cc/misc.c, ntoskrnl/cc/pin.c,
ntoskrnl/cc/view.c, ntoskrnl/io/rawfs.c, ntoskrnl/mm/section.c,
drivers/fs/cdfs/cleanup.c, drivers/fs/cdfs/fcb.c,
drivers/fs/cdfs/fsctl.c, drivers/fs/ntfs/fcb.c, drivers/fs/ntfs/fsctl.c,
drivers/fs/vfat/close.c, drivers/fs/vfat/create.c,
drivers/fs/vfat/finfo.c, drivers/fs/vfat/fcb.c, drivers/fs/vfat/fsctl.c:
Use new FILE_OBJECT structure.
* drivers/fs/cdfs/cdfs.h, drivers/fs/ntfs/ntfs.h, drivers/fs/vfat/vfat.h:
Use new FSRTL_COMMON_FCB_HEADER structure.
* drivers/net/afd/include/afd.h (FSRTL_COMMON_FCB_HEADER): Remove.
* include/ddk/ketypes.h (KQUEUE): Match w32api structure.
* ntoskrnl/ke/queue.c, ntoskrnl/ke/wait.c: Use new structure.
* ntoskrnl/ke/spinlock.c (KeAcquireSpinLockAtDpcLevel,
KeReleaseSpinLockFromDpcLevel): Undefine before declaring.
svn path=/trunk/; revision=4865
2003-06-07 11:34:36 +00:00
|
|
|
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2002-08-14 20:58:39 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2005-10-22 15:11:55 +00:00
|
|
|
if (((Offset + Segment->FileOffset) % PAGE_SIZE) == 0 &&
|
2004-04-10 22:36:07 +00:00
|
|
|
(Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
|
|
|
|
{
|
|
|
|
DirectMapped = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This should never happen since mappings of physical memory are never
|
|
|
|
* placed in the rmap lists.
|
|
|
|
*/
|
|
|
|
if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
|
|
|
|
{
|
2002-08-14 20:58:39 +00:00
|
|
|
DPRINT1("Trying to write back page from physical memory mapped at %X "
|
2004-04-10 22:36:07 +00:00
|
|
|
"process %d\n", Address,
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Process ? Process->UniqueProcessId : 0);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the section segment entry and the physical address.
|
|
|
|
*/
|
|
|
|
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
if (!MmIsPagePresent(Process, Address))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2002-08-14 20:58:39 +00:00
|
|
|
DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Process ? Process->UniqueProcessId : 0, Address);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Page = MmGetPfnForProcess(Process, Address);
|
2004-08-01 07:24:59 +00:00
|
|
|
SwapEntry = MmGetSavedSwapEntryPage(Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for a private (COWed) page.
|
|
|
|
*/
|
2005-06-12 10:25:49 +00:00
|
|
|
if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
|
2004-04-10 22:36:07 +00:00
|
|
|
IS_SWAP_FROM_SSE(Entry) ||
|
2004-08-01 07:24:59 +00:00
|
|
|
PFN_FROM_SSE(Entry) != Page)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2002-08-14 20:58:39 +00:00
|
|
|
Private = TRUE;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-08-14 20:58:39 +00:00
|
|
|
Private = FALSE;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Speculatively set all mappings of the page to clean.
|
|
|
|
*/
|
2004-08-01 07:24:59 +00:00
|
|
|
MmSetCleanAllRmaps(Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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)
|
|
|
|
{
|
2004-10-22 20:43:58 +00:00
|
|
|
ASSERT(SwapEntry == 0);
|
2005-06-12 10:25:49 +00:00
|
|
|
CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
|
2002-08-14 20:58:39 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
2003-12-30 18:52:06 +00:00
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
2002-08-14 20:58:39 +00:00
|
|
|
return(STATUS_SUCCESS);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2002-08-14 20:58:39 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
|
|
|
* If necessary, allocate an entry in the paging file for this page
|
|
|
|
*/
|
|
|
|
if (SwapEntry == 0)
|
|
|
|
{
|
2002-08-14 20:58:39 +00:00
|
|
|
SwapEntry = MmAllocSwapPage();
|
|
|
|
if (SwapEntry == 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2004-08-01 07:24:59 +00:00
|
|
|
MmSetDirtyAllRmaps(Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_UNSUCCESSFUL;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_PAGEFILE_QUOTA);
|
|
|
|
}
|
2004-08-01 07:24:59 +00:00
|
|
|
MmSetSavedSwapEntryPage(Page, SwapEntry);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write the page to the pagefile
|
|
|
|
*/
|
2004-08-01 07:24:59 +00:00
|
|
|
Status = MmWriteToSwapPage(SwapEntry, Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2003-12-30 18:52:06 +00:00
|
|
|
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
|
2004-04-10 22:36:07 +00:00
|
|
|
Status);
|
2004-08-01 07:24:59 +00:00
|
|
|
MmSetDirtyAllRmaps(Page);
|
2002-08-14 20:58:39 +00:00
|
|
|
PageOp->Status = STATUS_UNSUCCESSFUL;
|
2003-12-30 18:52:06 +00:00
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
2002-08-14 20:58:39 +00:00
|
|
|
return(STATUS_UNSUCCESSFUL);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise we have succeeded.
|
|
|
|
*/
|
2004-08-01 07:24:59 +00:00
|
|
|
DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
2002-08-14 20:58:39 +00:00
|
|
|
}
|
|
|
|
|
2008-12-03 17:28:59 +00:00
|
|
|
static VOID
|
2009-04-27 10:12:57 +00:00
|
|
|
MmAlterViewAttributes(PMMSUPPORT AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
PVOID BaseAddress,
|
|
|
|
ULONG RegionSize,
|
|
|
|
ULONG OldType,
|
|
|
|
ULONG OldProtect,
|
|
|
|
ULONG NewType,
|
|
|
|
ULONG NewProtect)
|
2002-08-10 16:41:20 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
PMEMORY_AREA MemoryArea;
|
|
|
|
PMM_SECTION_SEGMENT Segment;
|
2006-09-07 05:07:34 +00:00
|
|
|
BOOLEAN DoCOW = FALSE;
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG i;
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-02 19:14:52 +00:00
|
|
|
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
|
2004-04-10 22:36:07 +00:00
|
|
|
Segment = MemoryArea->Data.SectionData.Segment;
|
|
|
|
|
2010-10-05 04:57:32 +00:00
|
|
|
if ((Segment->WriteCopy) &&
|
2004-04-10 22:36:07 +00:00
|
|
|
(NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
|
|
|
|
{
|
|
|
|
DoCOW = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (OldProtect != NewProtect)
|
|
|
|
{
|
2002-11-05 20:50:02 +00:00
|
|
|
for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
|
|
|
|
ULONG Protect = NewProtect;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we doing COW for this segment then check if the page is
|
|
|
|
* already private.
|
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
if (DoCOW && MmIsPagePresent(Process, Address))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
ULONG Offset;
|
|
|
|
ULONG Entry;
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2007-10-19 23:21:45 +00:00
|
|
|
Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
|
2005-06-12 10:25:49 +00:00
|
|
|
+ MemoryArea->Data.SectionData.ViewOffset;
|
2004-04-10 22:36:07 +00:00
|
|
|
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Page = MmGetPfnForProcess(Process, Address);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
Protect = PAGE_READONLY;
|
2005-06-12 10:25:49 +00:00
|
|
|
if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
|
2004-04-10 22:36:07 +00:00
|
|
|
IS_SWAP_FROM_SSE(Entry) ||
|
2004-08-01 07:24:59 +00:00
|
|
|
PFN_FROM_SSE(Entry) != Page)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
Protect = NewProtect;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
if (MmIsPagePresent(Process, Address))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmSetPageProtect(Process, Address,
|
2004-04-10 22:36:07 +00:00
|
|
|
Protect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-08-10 16:41:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2009-04-27 10:12:57 +00:00
|
|
|
MmProtectSectionView(PMMSUPPORT AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
PMEMORY_AREA MemoryArea,
|
|
|
|
PVOID BaseAddress,
|
|
|
|
ULONG Length,
|
|
|
|
ULONG Protect,
|
|
|
|
PULONG OldProtect)
|
2002-08-10 16:41:20 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
PMM_REGION Region;
|
|
|
|
NTSTATUS Status;
|
2005-01-02 17:55:06 +00:00
|
|
|
ULONG_PTR MaxLength;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
MaxLength = (ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)BaseAddress;
|
|
|
|
if (Length > MaxLength)
|
|
|
|
Length = MaxLength;
|
|
|
|
|
|
|
|
Region = MmFindRegion(MemoryArea->StartingAddress,
|
2004-04-10 22:36:07 +00:00
|
|
|
&MemoryArea->Data.SectionData.RegionListHead,
|
|
|
|
BaseAddress, NULL);
|
2005-11-13 17:28:24 +00:00
|
|
|
if ((MemoryArea->Flags & SEC_NO_CHANGE) &&
|
|
|
|
Region->Protect != Protect)
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PAGE_PROTECTION;
|
|
|
|
}
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
*OldProtect = Region->Protect;
|
2005-01-02 17:55:06 +00:00
|
|
|
Status = MmAlterRegion(AddressSpace, MemoryArea->StartingAddress,
|
2004-04-10 22:36:07 +00:00
|
|
|
&MemoryArea->Data.SectionData.RegionListHead,
|
|
|
|
BaseAddress, Length, Region->Type, Protect,
|
|
|
|
MmAlterViewAttributes);
|
|
|
|
|
|
|
|
return(Status);
|
2002-08-10 16:41:20 +00:00
|
|
|
}
|
|
|
|
|
2008-11-29 20:47:48 +00:00
|
|
|
NTSTATUS NTAPI
|
2002-08-10 16:41:20 +00:00
|
|
|
MmQuerySectionView(PMEMORY_AREA MemoryArea,
|
2004-04-10 22:36:07 +00:00
|
|
|
PVOID Address,
|
|
|
|
PMEMORY_BASIC_INFORMATION Info,
|
2010-07-16 00:34:26 +00:00
|
|
|
PSIZE_T ResultLength)
|
2002-08-10 16:41:20 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
PMM_REGION Region;
|
|
|
|
PVOID RegionBaseAddress;
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2005-06-06 20:27:49 +00:00
|
|
|
PMM_SECTION_SEGMENT Segment;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
Region = MmFindRegion((PVOID)MemoryArea->StartingAddress,
|
2004-04-10 22:36:07 +00:00
|
|
|
&MemoryArea->Data.SectionData.RegionListHead,
|
|
|
|
Address, &RegionBaseAddress);
|
|
|
|
if (Region == NULL)
|
|
|
|
{
|
2003-05-13 21:28:26 +00:00
|
|
|
return STATUS_UNSUCCESSFUL;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-06-06 20:27:49 +00:00
|
|
|
|
2004-05-01 17:11:34 +00:00
|
|
|
Section = MemoryArea->Data.SectionData.Section;
|
|
|
|
if (Section->AllocationAttributes & SEC_IMAGE)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-06-06 20:27:49 +00:00
|
|
|
Segment = MemoryArea->Data.SectionData.Segment;
|
2006-09-07 05:07:34 +00:00
|
|
|
Info->AllocationBase = (PUCHAR)MemoryArea->StartingAddress - Segment->VirtualAddress;
|
2002-08-10 16:41:20 +00:00
|
|
|
Info->Type = MEM_IMAGE;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
Info->AllocationBase = MemoryArea->StartingAddress;
|
2002-08-10 16:41:20 +00:00
|
|
|
Info->Type = MEM_MAPPED;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-06-06 20:27:49 +00:00
|
|
|
Info->BaseAddress = RegionBaseAddress;
|
2005-11-13 17:28:24 +00:00
|
|
|
Info->AllocationProtect = MemoryArea->Protect;
|
2005-10-24 15:56:03 +00:00
|
|
|
Info->RegionSize = Region->Length;
|
2004-05-01 17:11:34 +00:00
|
|
|
Info->State = MEM_COMMIT;
|
|
|
|
Info->Protect = Region->Protect;
|
2002-08-10 16:41:20 +00:00
|
|
|
|
2004-05-01 00:25:41 +00:00
|
|
|
*ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
|
2004-04-10 22:36:07 +00:00
|
|
|
return(STATUS_SUCCESS);
|
2002-08-10 16:41:20 +00:00
|
|
|
}
|
|
|
|
|
2003-12-31 14:52:06 +00:00
|
|
|
VOID
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2003-12-31 14:52:06 +00:00
|
|
|
MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment)
|
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG Length;
|
|
|
|
ULONG Offset;
|
|
|
|
ULONG Entry;
|
|
|
|
ULONG SavedSwapEntry;
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page;
|
2003-12-31 14:52:06 +00:00
|
|
|
|
2004-08-01 07:24:59 +00:00
|
|
|
Page = 0;
|
2003-12-31 14:52:06 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
Length = PAGE_ROUND_UP(Segment->Length);
|
|
|
|
for (Offset = 0; Offset < Length; Offset += PAGE_SIZE)
|
|
|
|
{
|
2003-12-31 14:52:06 +00:00
|
|
|
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
|
|
|
|
if (Entry)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
if (IS_SWAP_FROM_SSE(Entry))
|
|
|
|
{
|
|
|
|
MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-08-01 07:24:59 +00:00
|
|
|
Page = PFN_FROM_SSE(Entry);
|
2004-04-10 22:36:07 +00:00
|
|
|
SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
|
|
|
|
if (SavedSwapEntry != 0)
|
2003-12-31 14:52:06 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
|
|
|
MmFreeSwapPage(SavedSwapEntry);
|
2003-12-31 14:52:06 +00:00
|
|
|
}
|
2004-04-10 22:36:07 +00:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
|
|
|
}
|
|
|
|
MmSetPageEntrySectionSegment(Segment, Offset, 0);
|
|
|
|
}
|
|
|
|
}
|
2003-12-31 14:52:06 +00:00
|
|
|
}
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2008-11-29 20:47:48 +00:00
|
|
|
VOID NTAPI
|
2000-12-28 03:38:08 +00:00
|
|
|
MmpDeleteSection(PVOID ObjectBody)
|
1999-02-01 20:58:37 +00:00
|
|
|
{
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section = (PROS_SECTION_OBJECT)ObjectBody;
|
2001-03-09 14:40:28 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
|
|
|
|
if (Section->AllocationAttributes & SEC_IMAGE)
|
|
|
|
{
|
2002-08-14 20:58:39 +00:00
|
|
|
ULONG i;
|
2003-06-27 21:28:30 +00:00
|
|
|
ULONG NrSegments;
|
2003-12-31 14:52:06 +00:00
|
|
|
ULONG RefCount;
|
2003-06-27 21:28:30 +00:00
|
|
|
PMM_SECTION_SEGMENT SectionSegments;
|
|
|
|
|
2004-08-18 02:29:37 +00:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
2003-06-27 21:28:30 +00:00
|
|
|
SectionSegments = Section->ImageSection->Segments;
|
|
|
|
NrSegments = Section->ImageSection->NrSegments;
|
|
|
|
|
|
|
|
for (i = 0; i < NrSegments; i++)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-02 07:04:56 +00:00
|
|
|
if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
MmLockSectionSegment(&SectionSegments[i]);
|
|
|
|
}
|
2004-12-24 17:07:00 +00:00
|
|
|
RefCount = InterlockedDecrementUL(&SectionSegments[i].ReferenceCount);
|
2005-01-02 07:04:56 +00:00
|
|
|
if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
if (RefCount == 0)
|
|
|
|
{
|
|
|
|
MmpFreePageFileSegment(&SectionSegments[i]);
|
|
|
|
}
|
|
|
|
MmUnlockSectionSegment(&SectionSegments[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-08-18 02:29:37 +00:00
|
|
|
/*
|
|
|
|
* NOTE: Section->Segment can be NULL for short time
|
|
|
|
* during the section creating.
|
|
|
|
*/
|
|
|
|
if (Section->Segment == NULL)
|
|
|
|
return;
|
|
|
|
|
2003-08-20 00:02:31 +00:00
|
|
|
if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
MmpFreePageFileSegment(Section->Segment);
|
|
|
|
MmFreePageTablesSectionSegment(Section->Segment);
|
|
|
|
ExFreePool(Section->Segment);
|
|
|
|
Section->Segment = NULL;
|
|
|
|
}
|
2003-08-20 00:02:31 +00:00
|
|
|
else
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2006-03-04 17:27:40 +00:00
|
|
|
(void)InterlockedDecrementUL(&Section->Segment->ReferenceCount);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Section->FileObject != NULL)
|
|
|
|
{
|
2002-08-17 15:12:49 +00:00
|
|
|
CcRosDereferenceCache(Section->FileObject);
|
2001-03-09 14:40:28 +00:00
|
|
|
ObDereferenceObject(Section->FileObject);
|
|
|
|
Section->FileObject = NULL;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2000-04-03 21:54:42 +00:00
|
|
|
}
|
|
|
|
|
2008-11-29 20:47:48 +00:00
|
|
|
VOID NTAPI
|
2006-05-10 17:47:44 +00:00
|
|
|
MmpCloseSection(IN PEPROCESS Process OPTIONAL,
|
|
|
|
IN PVOID Object,
|
|
|
|
IN ACCESS_MASK GrantedAccess,
|
|
|
|
IN ULONG ProcessHandleCount,
|
|
|
|
IN ULONG SystemHandleCount)
|
2000-04-03 21:54:42 +00:00
|
|
|
{
|
2008-01-08 09:49:22 +00:00
|
|
|
DPRINT("MmpCloseSection(OB %x, HC %d)\n",
|
|
|
|
Object, ProcessHandleCount);
|
1999-02-01 20:58:37 +00:00
|
|
|
}
|
|
|
|
|
2005-09-14 01:05:50 +00:00
|
|
|
NTSTATUS
|
|
|
|
INIT_FUNCTION
|
|
|
|
NTAPI
|
2000-12-28 03:38:08 +00:00
|
|
|
MmCreatePhysicalMemorySection(VOID)
|
1998-10-05 04:01:30 +00:00
|
|
|
{
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT PhysSection;
|
2004-04-10 22:36:07 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
OBJECT_ATTRIBUTES Obj;
|
2005-06-25 14:04:56 +00:00
|
|
|
UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
|
2004-04-10 22:36:07 +00:00
|
|
|
LARGE_INTEGER SectionSize;
|
2007-01-09 08:38:07 +00:00
|
|
|
HANDLE Handle;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the section mapping physical memory
|
|
|
|
*/
|
|
|
|
SectionSize.QuadPart = 0xFFFFFFFF;
|
|
|
|
InitializeObjectAttributes(&Obj,
|
|
|
|
&Name,
|
2005-04-27 21:44:27 +00:00
|
|
|
OBJ_PERMANENT,
|
2004-04-10 22:36:07 +00:00
|
|
|
NULL,
|
|
|
|
NULL);
|
2006-01-08 06:23:17 +00:00
|
|
|
Status = MmCreateSection((PVOID)&PhysSection,
|
2004-04-10 22:36:07 +00:00
|
|
|
SECTION_ALL_ACCESS,
|
|
|
|
&Obj,
|
|
|
|
&SectionSize,
|
|
|
|
PAGE_EXECUTE_READWRITE,
|
|
|
|
0,
|
2004-08-05 19:59:13 +00:00
|
|
|
NULL,
|
2004-04-10 22:36:07 +00:00
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2007-01-06 02:34:58 +00:00
|
|
|
DPRINT1("Failed to create PhysicalMemory section\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
Object Manager Patch. This patch continues the work done in the previous patch and makes the following changes in order to support OB 2.0 (it basically temporarily fixes a highly incorrect implementation so that caller code will be ready to work with the OB 2.0 without change):
1) The documented Object Create Information Structure and semantics implemented. All Object Attributes and passed data from user-mode is now probed and saved into this object create structure when ObCreateObject is called.
2) ObCreateObject does NOT PERFORM ANY OTHER OPERATION EXCEPT CREATING THE OBJECT ANYMORE. ObCreateObject will NOT insert the Object into the tree and other operations. These are now done correctly by ObInsertObject. Therefore, the biggest hurdle was changing pieces of code which assumed ObCreateObject would be enough.
3) ObInsertObject uses the captured create info for all operations isntead of the Object Attributes.
4) ObFindObject now uses the captured info as well.
5) The OBject name and directory are now stored in the documented Object Name Information, always allocated and freed from non paged pool.
HACKS:
5) Because the registry code is horribly broken and doesn't use ObFindObjectByName, the old ObFindObject had to be temporarily duplicated into CmpFindObject.
7) Win32k used ObInsertObject in CsrInsertObject as a way to create a handle inside csrss. However, OBInsertObject now does more then this. As a temporary hack, ObpCreateHandle is exported from the kernel and called from win32k. A fix needs to be done for this, but I don't know the design of win32k+csrss well enough to find a solution.
8) SEH has been commented out in some places of the new probing code because it breaks smss and explorer. These need to be investigated (seh did not exist in the previous code, so this is not really a hack)
9) Named objects with a parent directory are NOT allowed. However because of bugs in kernel32, the new check has been temporarily disabled. (this check did not exist in the previous code, so this is not really a hack)
The next patch will add a proper ObFindObject which will support a more complete Parse Procedure with context and security information. This is needed for proper registry access (requested by Eric Kohl) and for proper functionality of the Desktop/File creation, which should use the Parse routine, and not the Create Handle Routine. This will also make it possible to remove some previous hacks and pave the way for a fixed Iop/IoCreateFile
svn path=/trunk/; revision=15395
2005-05-18 19:26:47 +00:00
|
|
|
Status = ObInsertObject(PhysSection,
|
|
|
|
NULL,
|
|
|
|
SECTION_ALL_ACCESS,
|
|
|
|
0,
|
|
|
|
NULL,
|
2007-01-09 08:38:07 +00:00
|
|
|
&Handle);
|
Object Manager Patch. This patch continues the work done in the previous patch and makes the following changes in order to support OB 2.0 (it basically temporarily fixes a highly incorrect implementation so that caller code will be ready to work with the OB 2.0 without change):
1) The documented Object Create Information Structure and semantics implemented. All Object Attributes and passed data from user-mode is now probed and saved into this object create structure when ObCreateObject is called.
2) ObCreateObject does NOT PERFORM ANY OTHER OPERATION EXCEPT CREATING THE OBJECT ANYMORE. ObCreateObject will NOT insert the Object into the tree and other operations. These are now done correctly by ObInsertObject. Therefore, the biggest hurdle was changing pieces of code which assumed ObCreateObject would be enough.
3) ObInsertObject uses the captured create info for all operations isntead of the Object Attributes.
4) ObFindObject now uses the captured info as well.
5) The OBject name and directory are now stored in the documented Object Name Information, always allocated and freed from non paged pool.
HACKS:
5) Because the registry code is horribly broken and doesn't use ObFindObjectByName, the old ObFindObject had to be temporarily duplicated into CmpFindObject.
7) Win32k used ObInsertObject in CsrInsertObject as a way to create a handle inside csrss. However, OBInsertObject now does more then this. As a temporary hack, ObpCreateHandle is exported from the kernel and called from win32k. A fix needs to be done for this, but I don't know the design of win32k+csrss well enough to find a solution.
8) SEH has been commented out in some places of the new probing code because it breaks smss and explorer. These need to be investigated (seh did not exist in the previous code, so this is not really a hack)
9) Named objects with a parent directory are NOT allowed. However because of bugs in kernel32, the new check has been temporarily disabled. (this check did not exist in the previous code, so this is not really a hack)
The next patch will add a proper ObFindObject which will support a more complete Parse Procedure with context and security information. This is needed for proper registry access (requested by Eric Kohl) and for proper functionality of the Desktop/File creation, which should use the Parse routine, and not the Create Handle Routine. This will also make it possible to remove some previous hacks and pave the way for a fixed Iop/IoCreateFile
svn path=/trunk/; revision=15395
2005-05-18 19:26:47 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ObDereferenceObject(PhysSection);
|
|
|
|
}
|
2007-01-09 08:38:07 +00:00
|
|
|
ObCloseHandle(Handle, KernelMode);
|
2004-04-10 22:36:07 +00:00
|
|
|
PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
|
2005-06-12 10:25:49 +00:00
|
|
|
PhysSection->Segment->Flags &= ~MM_PAGEFILE_SEGMENT;
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
return(STATUS_SUCCESS);
|
2000-12-28 03:38:08 +00:00
|
|
|
}
|
|
|
|
|
2005-09-14 01:05:50 +00:00
|
|
|
NTSTATUS
|
|
|
|
INIT_FUNCTION
|
|
|
|
NTAPI
|
2000-12-28 03:38:08 +00:00
|
|
|
MmInitSectionImplementation(VOID)
|
|
|
|
{
|
2005-05-15 17:59:33 +00:00
|
|
|
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
|
|
|
|
UNICODE_STRING Name;
|
|
|
|
|
2005-05-21 16:33:23 +00:00
|
|
|
DPRINT("Creating Section Object Type\n");
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2005-05-15 17:59:33 +00:00
|
|
|
/* Initialize the Section object type */
|
|
|
|
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
|
|
|
|
RtlInitUnicodeString(&Name, L"Section");
|
|
|
|
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
|
2006-05-10 17:47:44 +00:00
|
|
|
ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(ROS_SECTION_OBJECT);
|
2005-06-06 20:27:49 +00:00
|
|
|
ObjectTypeInitializer.PoolType = PagedPool;
|
2005-05-15 17:59:33 +00:00
|
|
|
ObjectTypeInitializer.UseDefaultObject = TRUE;
|
|
|
|
ObjectTypeInitializer.GenericMapping = MmpSectionMapping;
|
|
|
|
ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection;
|
|
|
|
ObjectTypeInitializer.CloseProcedure = MmpCloseSection;
|
2007-01-09 17:18:22 +00:00
|
|
|
ObjectTypeInitializer.ValidAccessMask = SECTION_ALL_ACCESS;
|
2006-06-05 06:31:42 +00:00
|
|
|
ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &MmSectionObjectType);
|
2009-07-27 00:52:44 +00:00
|
|
|
|
|
|
|
MmCreatePhysicalMemorySection();
|
2003-10-07 14:08:43 +00:00
|
|
|
|
2001-01-28 15:17:52 +00:00
|
|
|
return(STATUS_SUCCESS);
|
1998-10-05 04:01:30 +00:00
|
|
|
}
|
|
|
|
|
2001-02-10 22:51:11 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2006-05-10 17:47:44 +00:00
|
|
|
MmCreatePageFileSection(PROS_SECTION_OBJECT *SectionObject,
|
2004-04-10 22:36:07 +00:00
|
|
|
ACCESS_MASK DesiredAccess,
|
|
|
|
POBJECT_ATTRIBUTES ObjectAttributes,
|
|
|
|
PLARGE_INTEGER UMaximumSize,
|
|
|
|
ULONG SectionPageProtection,
|
|
|
|
ULONG AllocationAttributes)
|
|
|
|
/*
|
|
|
|
* Create a section which is backed by the pagefile
|
|
|
|
*/
|
1998-09-05 17:34:23 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
LARGE_INTEGER MaximumSize;
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2004-04-10 22:36:07 +00:00
|
|
|
PMM_SECTION_SEGMENT Segment;
|
|
|
|
NTSTATUS Status;
|
1998-10-05 04:01:30 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
if (UMaximumSize == NULL)
|
|
|
|
{
|
2001-02-10 22:51:11 +00:00
|
|
|
return(STATUS_UNSUCCESSFUL);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
MaximumSize = *UMaximumSize;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the section
|
|
|
|
*/
|
|
|
|
Status = ObCreateObject(ExGetPreviousMode(),
|
|
|
|
MmSectionObjectType,
|
|
|
|
ObjectAttributes,
|
|
|
|
ExGetPreviousMode(),
|
|
|
|
NULL,
|
2006-05-10 17:47:44 +00:00
|
|
|
sizeof(ROS_SECTION_OBJECT),
|
2004-04-10 22:36:07 +00:00
|
|
|
0,
|
|
|
|
0,
|
2004-08-23 22:29:43 +00:00
|
|
|
(PVOID*)(PVOID)&Section);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2001-06-16 14:11:31 +00:00
|
|
|
return(Status);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize it
|
|
|
|
*/
|
2009-07-15 18:35:31 +00:00
|
|
|
RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
|
2004-04-10 22:36:07 +00:00
|
|
|
Section->SectionPageProtection = SectionPageProtection;
|
|
|
|
Section->AllocationAttributes = AllocationAttributes;
|
|
|
|
Section->MaximumSize = MaximumSize;
|
2005-06-05 21:12:30 +00:00
|
|
|
Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
|
2004-04-10 22:36:07 +00:00
|
|
|
TAG_MM_SECTION_SEGMENT);
|
|
|
|
if (Segment == NULL)
|
|
|
|
{
|
2001-02-10 22:51:11 +00:00
|
|
|
ObDereferenceObject(Section);
|
|
|
|
return(STATUS_NO_MEMORY);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
Section->Segment = Segment;
|
|
|
|
Segment->ReferenceCount = 1;
|
|
|
|
ExInitializeFastMutex(&Segment->Lock);
|
|
|
|
Segment->FileOffset = 0;
|
|
|
|
Segment->Protection = SectionPageProtection;
|
|
|
|
Segment->RawLength = MaximumSize.u.LowPart;
|
|
|
|
Segment->Length = PAGE_ROUND_UP(MaximumSize.u.LowPart);
|
|
|
|
Segment->Flags = MM_PAGEFILE_SEGMENT;
|
|
|
|
Segment->WriteCopy = FALSE;
|
|
|
|
RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
|
|
|
|
Segment->VirtualAddress = 0;
|
|
|
|
Segment->Characteristics = 0;
|
2004-08-05 19:59:13 +00:00
|
|
|
*SectionObject = Section;
|
2004-04-10 22:36:07 +00:00
|
|
|
return(STATUS_SUCCESS);
|
2001-06-16 14:11:31 +00:00
|
|
|
}
|
|
|
|
|
1998-09-05 17:34:23 +00:00
|
|
|
|
2001-02-10 22:51:11 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2006-05-10 17:47:44 +00:00
|
|
|
MmCreateDataFileSection(PROS_SECTION_OBJECT *SectionObject,
|
2004-04-10 22:36:07 +00:00
|
|
|
ACCESS_MASK DesiredAccess,
|
|
|
|
POBJECT_ATTRIBUTES ObjectAttributes,
|
|
|
|
PLARGE_INTEGER UMaximumSize,
|
|
|
|
ULONG SectionPageProtection,
|
|
|
|
ULONG AllocationAttributes,
|
|
|
|
HANDLE FileHandle)
|
|
|
|
/*
|
|
|
|
* Create a section backed by a data file
|
|
|
|
*/
|
1998-08-25 04:27:26 +00:00
|
|
|
{
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2004-04-10 22:36:07 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
LARGE_INTEGER MaximumSize;
|
|
|
|
PFILE_OBJECT FileObject;
|
|
|
|
PMM_SECTION_SEGMENT Segment;
|
|
|
|
ULONG FileAccess;
|
|
|
|
IO_STATUS_BLOCK Iosb;
|
|
|
|
LARGE_INTEGER Offset;
|
|
|
|
CHAR Buffer;
|
2004-08-18 02:29:37 +00:00
|
|
|
FILE_STANDARD_INFORMATION FileInfo;
|
2009-12-06 03:24:18 +00:00
|
|
|
ULONG Length;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the section
|
|
|
|
*/
|
|
|
|
Status = ObCreateObject(ExGetPreviousMode(),
|
|
|
|
MmSectionObjectType,
|
|
|
|
ObjectAttributes,
|
|
|
|
ExGetPreviousMode(),
|
|
|
|
NULL,
|
2006-05-10 17:47:44 +00:00
|
|
|
sizeof(ROS_SECTION_OBJECT),
|
2004-04-10 22:36:07 +00:00
|
|
|
0,
|
|
|
|
0,
|
2004-08-23 22:29:43 +00:00
|
|
|
(PVOID*)(PVOID)&Section);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2001-06-16 14:11:31 +00:00
|
|
|
return(Status);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Initialize it
|
|
|
|
*/
|
2009-07-15 18:35:31 +00:00
|
|
|
RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
|
2004-04-10 22:36:07 +00:00
|
|
|
Section->SectionPageProtection = SectionPageProtection;
|
|
|
|
Section->AllocationAttributes = AllocationAttributes;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check file access required
|
|
|
|
*/
|
|
|
|
if (SectionPageProtection & PAGE_READWRITE ||
|
|
|
|
SectionPageProtection & PAGE_EXECUTE_READWRITE)
|
|
|
|
{
|
2001-02-10 22:51:11 +00:00
|
|
|
FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-02-10 22:51:11 +00:00
|
|
|
FileAccess = FILE_READ_DATA;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reference the file handle
|
|
|
|
*/
|
|
|
|
Status = ObReferenceObjectByHandle(FileHandle,
|
|
|
|
FileAccess,
|
|
|
|
IoFileObjectType,
|
2007-09-30 13:11:36 +00:00
|
|
|
ExGetPreviousMode(),
|
2004-08-23 22:29:43 +00:00
|
|
|
(PVOID*)(PVOID)&FileObject,
|
2004-04-10 22:36:07 +00:00
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2001-02-10 22:51:11 +00:00
|
|
|
ObDereferenceObject(Section);
|
|
|
|
return(Status);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2004-08-18 02:29:37 +00:00
|
|
|
* 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).
|
2004-04-10 22:36:07 +00:00
|
|
|
*/
|
2005-07-26 19:38:33 +00:00
|
|
|
Status = IoQueryFileInformation(FileObject,
|
|
|
|
FileStandardInformation,
|
2004-08-18 02:29:37 +00:00
|
|
|
sizeof(FILE_STANDARD_INFORMATION),
|
2005-07-26 19:38:33 +00:00
|
|
|
&FileInfo,
|
2009-12-06 03:24:18 +00:00
|
|
|
&Length);
|
|
|
|
Iosb.Information = Length;
|
2004-08-18 02:29:37 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2001-02-10 22:51:11 +00:00
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
2004-08-18 02:29:37 +00:00
|
|
|
return Status;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME: Revise this once a locking order for file size changes is
|
|
|
|
* decided
|
|
|
|
*/
|
2008-09-25 11:24:51 +00:00
|
|
|
if ((UMaximumSize != NULL) && (UMaximumSize->QuadPart != 0))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2008-09-25 11:24:51 +00:00
|
|
|
MaximumSize = *UMaximumSize;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-08-18 02:29:37 +00:00
|
|
|
MaximumSize = FileInfo.EndOfFile;
|
2004-08-28 22:18:24 +00:00
|
|
|
/* Mapping zero-sized files isn't allowed. */
|
|
|
|
if (MaximumSize.QuadPart == 0)
|
|
|
|
{
|
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return STATUS_FILE_INVALID;
|
|
|
|
}
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-02-10 22:51:11 +00:00
|
|
|
|
2004-08-18 02:29:37 +00:00
|
|
|
if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-07-26 19:38:33 +00:00
|
|
|
Status = IoSetInformation(FileObject,
|
|
|
|
FileAllocationInformation,
|
|
|
|
sizeof(LARGE_INTEGER),
|
|
|
|
&MaximumSize);
|
2002-08-14 20:58:39 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return(STATUS_SECTION_NOT_EXTENDED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FileObject->SectionObjectPointer == NULL ||
|
|
|
|
FileObject->SectionObjectPointer->SharedCacheMap == NULL)
|
|
|
|
{
|
2003-10-18 09:35:11 +00:00
|
|
|
/*
|
|
|
|
* Read a bit so caching is initiated for the file object.
|
|
|
|
* This is only needed because MiReadPage currently cannot
|
|
|
|
* handle non-cached streams.
|
|
|
|
*/
|
|
|
|
Offset.QuadPart = 0;
|
|
|
|
Status = ZwReadFile(FileHandle,
|
2004-04-10 22:36:07 +00:00
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&Iosb,
|
|
|
|
&Buffer,
|
|
|
|
sizeof (Buffer),
|
|
|
|
&Offset,
|
|
|
|
0);
|
2003-10-18 09:35:11 +00:00
|
|
|
if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return(Status);
|
|
|
|
}
|
2003-10-18 09:35:11 +00:00
|
|
|
if (FileObject->SectionObjectPointer == NULL ||
|
2004-04-10 22:36:07 +00:00
|
|
|
FileObject->SectionObjectPointer->SharedCacheMap == NULL)
|
|
|
|
{
|
|
|
|
/* FIXME: handle this situation */
|
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Lock the file
|
|
|
|
*/
|
|
|
|
Status = MmspWaitForFileLock(FileObject);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
|
|
{
|
2001-02-10 22:51:11 +00:00
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return(Status);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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)
|
|
|
|
{
|
2005-06-05 21:12:30 +00:00
|
|
|
Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
|
2004-04-10 22:36:07 +00:00
|
|
|
TAG_MM_SECTION_SEGMENT);
|
2001-02-10 22:51:11 +00:00
|
|
|
if (Segment == NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2006-07-27 22:26:40 +00:00
|
|
|
//KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
|
2004-04-10 22:36:07 +00:00
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return(STATUS_NO_MEMORY);
|
|
|
|
}
|
2003-06-27 21:28:30 +00:00
|
|
|
Section->Segment = Segment;
|
2001-02-10 22:51:11 +00:00
|
|
|
Segment->ReferenceCount = 1;
|
2003-06-27 21:28:30 +00:00
|
|
|
ExInitializeFastMutex(&Segment->Lock);
|
2001-02-10 22:51:11 +00:00
|
|
|
/*
|
|
|
|
* Set the lock before assigning the segment to the file object
|
|
|
|
*/
|
2003-06-27 21:28:30 +00:00
|
|
|
ExAcquireFastMutex(&Segment->Lock);
|
2003-06-07 Casper S. Hornstrup <chorns@users.sourceforge.net>
Changes for compiling with w32api
* include/ddk/cctypes.h (PREACTOS_COMMON_FCB_HEADER): Remove.
(FSRTL_COMMON_FCB_HEADER): Add.
* include/ddk/iotypes.h (FILE_OBJECT): Rename field
SectionObjectPointers to SectionObjectPointer.
* ntoskrnl/cc/copy.c, ntoskrnl/cc/misc.c, ntoskrnl/cc/pin.c,
ntoskrnl/cc/view.c, ntoskrnl/io/rawfs.c, ntoskrnl/mm/section.c,
drivers/fs/cdfs/cleanup.c, drivers/fs/cdfs/fcb.c,
drivers/fs/cdfs/fsctl.c, drivers/fs/ntfs/fcb.c, drivers/fs/ntfs/fsctl.c,
drivers/fs/vfat/close.c, drivers/fs/vfat/create.c,
drivers/fs/vfat/finfo.c, drivers/fs/vfat/fcb.c, drivers/fs/vfat/fsctl.c:
Use new FILE_OBJECT structure.
* drivers/fs/cdfs/cdfs.h, drivers/fs/ntfs/ntfs.h, drivers/fs/vfat/vfat.h:
Use new FSRTL_COMMON_FCB_HEADER structure.
* drivers/net/afd/include/afd.h (FSRTL_COMMON_FCB_HEADER): Remove.
* include/ddk/ketypes.h (KQUEUE): Match w32api structure.
* ntoskrnl/ke/queue.c, ntoskrnl/ke/wait.c: Use new structure.
* ntoskrnl/ke/spinlock.c (KeAcquireSpinLockAtDpcLevel,
KeReleaseSpinLockFromDpcLevel): Undefine before declaring.
svn path=/trunk/; revision=4865
2003-06-07 11:34:36 +00:00
|
|
|
FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
|
2001-02-10 22:51:11 +00:00
|
|
|
|
|
|
|
Segment->FileOffset = 0;
|
2004-01-27 20:13:08 +00:00
|
|
|
Segment->Protection = SectionPageProtection;
|
2002-08-14 20:58:39 +00:00
|
|
|
Segment->Flags = MM_DATAFILE_SEGMENT;
|
2001-02-10 22:51:11 +00:00
|
|
|
Segment->Characteristics = 0;
|
2002-01-01 03:29:16 +00:00
|
|
|
Segment->WriteCopy = FALSE;
|
2001-02-10 22:51:11 +00:00
|
|
|
if (AllocationAttributes & SEC_RESERVE)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
Segment->Length = Segment->RawLength = 0;
|
|
|
|
}
|
2001-02-10 22:51:11 +00:00
|
|
|
else
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
Segment->RawLength = MaximumSize.u.LowPart;
|
|
|
|
Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
|
|
|
|
}
|
2004-12-30 08:05:12 +00:00
|
|
|
Segment->VirtualAddress = 0;
|
2004-03-04 00:07:03 +00:00
|
|
|
RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-02-10 22:51:11 +00:00
|
|
|
/*
|
|
|
|
* If the file is already mapped as a data file then we may need
|
|
|
|
* to extend it
|
2003-12-30 18:52:06 +00:00
|
|
|
*/
|
|
|
|
Segment =
|
2004-04-10 22:36:07 +00:00
|
|
|
(PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
|
|
|
|
DataSectionObject;
|
2003-06-27 21:28:30 +00:00
|
|
|
Section->Segment = Segment;
|
2006-03-04 17:27:40 +00:00
|
|
|
(void)InterlockedIncrementUL(&Segment->ReferenceCount);
|
2003-06-27 21:28:30 +00:00
|
|
|
MmLockSectionSegment(Segment);
|
|
|
|
|
2003-12-30 18:52:06 +00:00
|
|
|
if (MaximumSize.u.LowPart > Segment->RawLength &&
|
2004-04-10 22:36:07 +00:00
|
|
|
!(AllocationAttributes & SEC_RESERVE))
|
|
|
|
{
|
|
|
|
Segment->RawLength = MaximumSize.u.LowPart;
|
|
|
|
Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
Section->FileObject = FileObject;
|
|
|
|
Section->MaximumSize = MaximumSize;
|
|
|
|
CcRosReferenceCache(FileObject);
|
2006-07-27 22:26:40 +00:00
|
|
|
//KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
|
2004-08-05 19:59:13 +00:00
|
|
|
*SectionObject = Section;
|
2004-04-10 22:36:07 +00:00
|
|
|
return(STATUS_SUCCESS);
|
2001-02-10 22:51:11 +00:00
|
|
|
}
|
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
/*
|
|
|
|
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
|
|
|
|
);
|
|
|
|
|
|
|
|
/* TODO: this is a standard DDK/PSDK macro */
|
|
|
|
#ifndef RTL_NUMBER_OF
|
|
|
|
#define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static PEXEFMT_LOADER ExeFmtpLoaders[] =
|
|
|
|
{
|
|
|
|
PeFmtCreateSection,
|
2008-02-07 06:36:31 +00:00
|
|
|
#ifdef __ELF
|
2004-12-30 08:05:12 +00:00
|
|
|
ElfFmtCreateSection
|
2008-02-07 06:36:31 +00:00
|
|
|
#endif
|
2004-12-30 08:05:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2005-06-05 21:12:30 +00:00
|
|
|
Segments = ExAllocatePoolWithTag(NonPagedPool,
|
2004-12-30 08:05:12 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
ASSERT_IRQL_LESS(DISPATCH_LEVEL);
|
|
|
|
|
|
|
|
if(Length == 0)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-12-30 08:05:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FileOffset = *Offset;
|
|
|
|
|
|
|
|
/* Negative/special offset: it cannot be used in this context */
|
|
|
|
if(FileOffset.u.HighPart < 0)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-12-30 08:05:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart);
|
|
|
|
OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset;
|
|
|
|
FileOffset.u.LowPart = AdjustOffset;
|
|
|
|
|
|
|
|
BufferSize = Length + OffsetAdjustment;
|
|
|
|
BufferSize = PAGE_ROUND_UP(BufferSize);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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,
|
2009-08-24 18:19:53 +00:00
|
|
|
'rXmM');
|
2009-09-02 13:02:30 +00:00
|
|
|
if (!Buffer)
|
|
|
|
{
|
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
|
|
|
}
|
2004-12-30 08:05:12 +00:00
|
|
|
|
|
|
|
UsedSize = 0;
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
Status = MmspPageRead(File,
|
|
|
|
Buffer,
|
|
|
|
BufferSize,
|
|
|
|
&FileOffset,
|
|
|
|
&UsedSize);
|
|
|
|
#else
|
|
|
|
/*
|
|
|
|
* FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
|
|
|
|
* nothing will work. But using ZwReadFile is wrong, and using its side effects
|
|
|
|
* to initialize internal state is even worse. Our cache manager is in need of
|
|
|
|
* professional help
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
IO_STATUS_BLOCK Iosb;
|
|
|
|
|
|
|
|
Status = ZwReadFile(File,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&Iosb,
|
|
|
|
Buffer,
|
|
|
|
BufferSize,
|
|
|
|
&FileOffset,
|
|
|
|
NULL);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
if(NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
UsedSize = Iosb.Information;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2009-08-24 18:19:53 +00:00
|
|
|
ExFreePoolWithTag(Buffer, 'rXmM');
|
2004-12-30 08:05:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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].VirtualAddress >=
|
|
|
|
ImageSectionObject->Segments[i - 1].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 > 0);
|
|
|
|
|
|
|
|
if(i > 0)
|
|
|
|
{
|
|
|
|
ASSERT(ImageSectionObject->Segments[i].VirtualAddress >=
|
|
|
|
(ImageSectionObject->Segments[i - 1].VirtualAddress +
|
|
|
|
ImageSectionObject->Segments[i - 1].Length));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
|
|
|
|
{
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
|
|
|
|
{
|
|
|
|
ASSERT((ImageSectionObject->Segments[i].VirtualAddress % PAGE_SIZE) == 0);
|
|
|
|
ASSERT((ImageSectionObject->Segments[i].Length % PAGE_SIZE) == 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static
|
|
|
|
int
|
|
|
|
__cdecl
|
|
|
|
MmspCompareSegments(const void * x,
|
|
|
|
const void * y)
|
|
|
|
{
|
2005-11-29 11:44:04 +00:00
|
|
|
const MM_SECTION_SEGMENT *Segment1 = (const MM_SECTION_SEGMENT *)x;
|
|
|
|
const MM_SECTION_SEGMENT *Segment2 = (const MM_SECTION_SEGMENT *)y;
|
2004-12-30 08:05:12 +00:00
|
|
|
|
|
|
|
return
|
|
|
|
(Segment1->VirtualAddress - Segment2->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 == 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
|
2005-05-09 01:38:29 +00:00
|
|
|
* (NtMapViewOfSection could then refuse to map them, and they could
|
2004-12-30 08:05:12 +00:00
|
|
|
* e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
|
|
|
|
*/
|
|
|
|
if ((ImageSectionObject->Segments[i - 1].VirtualAddress +
|
|
|
|
ImageSectionObject->Segments[i - 1].Length) !=
|
|
|
|
ImageSectionObject->Segments[i].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;
|
2005-10-22 15:11:55 +00:00
|
|
|
PMM_SECTION_SEGMENT EffectiveSegment;
|
2004-12-30 08:05:12 +00:00
|
|
|
|
|
|
|
if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED)
|
|
|
|
{
|
|
|
|
MmspAssertSegmentsPageAligned(ImageSectionObject);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
LastSegment = 0;
|
2005-10-22 15:11:55 +00:00
|
|
|
EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
|
2004-12-30 08:05:12 +00:00
|
|
|
|
|
|
|
for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The first segment requires special handling
|
|
|
|
*/
|
|
|
|
if (i == 0)
|
|
|
|
{
|
|
|
|
ULONG_PTR VirtualAddress;
|
|
|
|
ULONG_PTR VirtualOffset;
|
|
|
|
|
|
|
|
VirtualAddress = EffectiveSegment->VirtualAddress;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
/* Round down the virtual address to the nearest page */
|
|
|
|
EffectiveSegment->VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
/* Round up the virtual size to the nearest page */
|
|
|
|
EffectiveSegment->Length = PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length) -
|
|
|
|
EffectiveSegment->VirtualAddress;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
/* Adjust the raw address and size */
|
|
|
|
VirtualOffset = VirtualAddress - EffectiveSegment->VirtualAddress;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
if (EffectiveSegment->FileOffset < VirtualOffset)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
/*
|
2005-05-09 01:38:29 +00:00
|
|
|
* Garbage in, garbage out: unaligned base addresses make the file
|
|
|
|
* offset point in curious and odd places, but that's what we were
|
2004-12-30 08:05:12 +00:00
|
|
|
* asked for
|
|
|
|
*/
|
|
|
|
EffectiveSegment->FileOffset -= VirtualOffset;
|
|
|
|
EffectiveSegment->RawLength += VirtualOffset;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
|
|
|
|
ULONG_PTR EndOfEffectiveSegment;
|
|
|
|
|
|
|
|
EndOfEffectiveSegment = EffectiveSegment->VirtualAddress + EffectiveSegment->Length;
|
|
|
|
ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
/*
|
|
|
|
* The current segment begins exactly where the current effective
|
|
|
|
* segment ended, therefore beginning a new effective segment
|
|
|
|
*/
|
|
|
|
if (EndOfEffectiveSegment == Segment->VirtualAddress)
|
|
|
|
{
|
|
|
|
LastSegment ++;
|
|
|
|
ASSERT(LastSegment <= i);
|
|
|
|
ASSERT(LastSegment < ImageSectionObject->NrSegments);
|
|
|
|
|
|
|
|
EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
|
|
|
|
|
2005-10-22 15:11:55 +00:00
|
|
|
if (LastSegment != i)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Copy the current segment. If necessary, the effective segment
|
|
|
|
* will be expanded later
|
|
|
|
*/
|
|
|
|
*EffectiveSegment = *Segment;
|
|
|
|
}
|
2004-12-30 08:05:12 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Page-align the virtual size. We know for sure the virtual address
|
|
|
|
* already is
|
|
|
|
*/
|
|
|
|
ASSERT((EffectiveSegment->VirtualAddress % PAGE_SIZE) == 0);
|
|
|
|
EffectiveSegment->Length = PAGE_ROUND_UP(EffectiveSegment->Length);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* The current segment is still part of the current effective segment:
|
|
|
|
* extend the effective segment to reflect this
|
|
|
|
*/
|
|
|
|
else if (EndOfEffectiveSegment > Segment->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
|
|
|
|
*/
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
/* Unaligned segments must be contiguous within the file */
|
|
|
|
if (Segment->FileOffset != (EffectiveSegment->FileOffset +
|
|
|
|
EffectiveSegment->RawLength))
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
EffectiveSegment->RawLength += Segment->RawLength;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
/*
|
|
|
|
* Extend the virtual size
|
|
|
|
*/
|
2005-10-22 15:11:55 +00:00
|
|
|
ASSERT(PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) >= EndOfEffectiveSegment);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
EffectiveSegment->Length = PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) -
|
|
|
|
EffectiveSegment->VirtualAddress;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-12-30 08:05:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-10-22 15:11:55 +00:00
|
|
|
ImageSectionObject->NrSegments = LastSegment + 1;
|
2004-12-30 08:05:12 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
ExeFmtpCreateImageSection(HANDLE FileHandle,
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* FIXME: use FileObject instead of FileHandle */
|
|
|
|
Status = ExeFmtpReadFile (FileHandle,
|
|
|
|
&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;
|
|
|
|
|
|
|
|
/* FIXME: use FileObject instead of FileHandle */
|
|
|
|
Status = ExeFmtpLoaders[i](FileHeader,
|
|
|
|
FileHeaderSize,
|
|
|
|
FileHandle,
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-08-24 18:19:53 +00:00
|
|
|
ExFreePoolWithTag(FileHeaderBuffer, 'rXmM');
|
2004-12-30 08:05:12 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* No loader handled the format
|
|
|
|
*/
|
|
|
|
if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
|
|
|
|
{
|
2005-07-08 16:37:07 +00:00
|
|
|
Status = STATUS_INVALID_IMAGE_NOT_MZ;
|
2004-12-30 08:05:12 +00:00
|
|
|
ASSERT(!NT_SUCCESS(Status));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
return Status;
|
|
|
|
|
|
|
|
ASSERT(ImageSectionObject->Segments != NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Some defaults
|
|
|
|
*/
|
|
|
|
/* FIXME? are these values platform-dependent? */
|
|
|
|
if(ImageSectionObject->StackReserve == 0)
|
|
|
|
ImageSectionObject->StackReserve = 0x40000;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
if(ImageSectionObject->StackCommit == 0)
|
|
|
|
ImageSectionObject->StackCommit = 0x1000;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
if(ImageSectionObject->ImageBase == 0)
|
|
|
|
{
|
|
|
|
if(ImageSectionObject->ImageCharacteristics & IMAGE_FILE_DLL)
|
|
|
|
ImageSectionObject->ImageBase = 0x10000000;
|
|
|
|
else
|
|
|
|
ImageSectionObject->ImageBase = 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;
|
|
|
|
|
2005-05-26 13:41:04 +00:00
|
|
|
Segments = ExAllocatePoolWithTag(PagedPool,
|
2004-12-30 08:05:12 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
RtlZeroMemory(&ImageSectionObject->Segments[i].PageDirectory,
|
|
|
|
sizeof(ImageSectionObject->Segments[i].PageDirectory));
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
return Status;
|
|
|
|
}
|
2002-01-01 03:29:16 +00:00
|
|
|
|
2001-02-10 22:51:11 +00:00
|
|
|
NTSTATUS
|
2006-05-10 17:47:44 +00:00
|
|
|
MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
|
2004-04-10 22:36:07 +00:00
|
|
|
ACCESS_MASK DesiredAccess,
|
|
|
|
POBJECT_ATTRIBUTES ObjectAttributes,
|
|
|
|
PLARGE_INTEGER UMaximumSize,
|
|
|
|
ULONG SectionPageProtection,
|
|
|
|
ULONG AllocationAttributes,
|
|
|
|
HANDLE FileHandle)
|
2001-02-10 22:51:11 +00:00
|
|
|
{
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2004-04-10 22:36:07 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
PFILE_OBJECT FileObject;
|
|
|
|
PMM_SECTION_SEGMENT SectionSegments;
|
|
|
|
PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
|
|
|
|
ULONG i;
|
|
|
|
ULONG FileAccess = 0;
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
/*
|
|
|
|
* Check file access required
|
|
|
|
*/
|
|
|
|
if (SectionPageProtection & PAGE_READWRITE ||
|
|
|
|
SectionPageProtection & PAGE_EXECUTE_READWRITE)
|
|
|
|
{
|
|
|
|
FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FileAccess = FILE_READ_DATA;
|
|
|
|
}
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
|
|
|
* Reference the file handle
|
|
|
|
*/
|
|
|
|
Status = ObReferenceObjectByHandle(FileHandle,
|
|
|
|
FileAccess,
|
|
|
|
IoFileObjectType,
|
2007-02-23 05:39:42 +00:00
|
|
|
ExGetPreviousMode(),
|
2004-08-23 22:29:43 +00:00
|
|
|
(PVOID*)(PVOID)&FileObject,
|
2004-04-10 22:36:07 +00:00
|
|
|
NULL);
|
Object Manager Patch. This patch continues the work done in the previous patch and makes the following changes in order to support OB 2.0 (it basically temporarily fixes a highly incorrect implementation so that caller code will be ready to work with the OB 2.0 without change):
1) The documented Object Create Information Structure and semantics implemented. All Object Attributes and passed data from user-mode is now probed and saved into this object create structure when ObCreateObject is called.
2) ObCreateObject does NOT PERFORM ANY OTHER OPERATION EXCEPT CREATING THE OBJECT ANYMORE. ObCreateObject will NOT insert the Object into the tree and other operations. These are now done correctly by ObInsertObject. Therefore, the biggest hurdle was changing pieces of code which assumed ObCreateObject would be enough.
3) ObInsertObject uses the captured create info for all operations isntead of the Object Attributes.
4) ObFindObject now uses the captured info as well.
5) The OBject name and directory are now stored in the documented Object Name Information, always allocated and freed from non paged pool.
HACKS:
5) Because the registry code is horribly broken and doesn't use ObFindObjectByName, the old ObFindObject had to be temporarily duplicated into CmpFindObject.
7) Win32k used ObInsertObject in CsrInsertObject as a way to create a handle inside csrss. However, OBInsertObject now does more then this. As a temporary hack, ObpCreateHandle is exported from the kernel and called from win32k. A fix needs to be done for this, but I don't know the design of win32k+csrss well enough to find a solution.
8) SEH has been commented out in some places of the new probing code because it breaks smss and explorer. These need to be investigated (seh did not exist in the previous code, so this is not really a hack)
9) Named objects with a parent directory are NOT allowed. However because of bugs in kernel32, the new check has been temporarily disabled. (this check did not exist in the previous code, so this is not really a hack)
The next patch will add a proper ObFindObject which will support a more complete Parse Procedure with context and security information. This is needed for proper registry access (requested by Eric Kohl) and for proper functionality of the Desktop/File creation, which should use the Parse routine, and not the Create Handle Routine. This will also make it possible to remove some previous hacks and pave the way for a fixed Iop/IoCreateFile
svn path=/trunk/; revision=15395
2005-05-18 19:26:47 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2003-06-27 21:28:30 +00:00
|
|
|
return Status;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-02-10 22:51:11 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
/*
|
|
|
|
* Create the section
|
|
|
|
*/
|
|
|
|
Status = ObCreateObject (ExGetPreviousMode(),
|
|
|
|
MmSectionObjectType,
|
|
|
|
ObjectAttributes,
|
|
|
|
ExGetPreviousMode(),
|
|
|
|
NULL,
|
2006-05-10 17:47:44 +00:00
|
|
|
sizeof(ROS_SECTION_OBJECT),
|
2004-12-30 08:05:12 +00:00
|
|
|
0,
|
|
|
|
0,
|
|
|
|
(PVOID*)(PVOID)&Section);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize it
|
|
|
|
*/
|
2009-07-15 18:35:31 +00:00
|
|
|
RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
|
2004-12-30 08:05:12 +00:00
|
|
|
Section->SectionPageProtection = SectionPageProtection;
|
|
|
|
Section->AllocationAttributes = AllocationAttributes;
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
|
|
|
* Initialized caching for this file object if previously caching
|
|
|
|
* was initialized for the same on disk file
|
|
|
|
*/
|
|
|
|
Status = CcTryToInitializeFileCache(FileObject);
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
|
|
|
|
{
|
2004-12-30 08:05:12 +00:00
|
|
|
NTSTATUS StatusExeFmt;
|
2001-02-10 22:51:11 +00:00
|
|
|
|
2005-05-26 13:41:04 +00:00
|
|
|
ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
|
2004-12-30 08:05:12 +00:00
|
|
|
if (ImageSectionObject == NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
ObDereferenceObject(FileObject);
|
2004-12-30 08:05:12 +00:00
|
|
|
ObDereferenceObject(Section);
|
2004-04-10 22:36:07 +00:00
|
|
|
return(STATUS_NO_MEMORY);
|
|
|
|
}
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2005-09-28 19:56:05 +00:00
|
|
|
RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT));
|
2002-01-01 05:09:50 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
StatusExeFmt = ExeFmtpCreateImageSection(FileHandle, ImageSectionObject);
|
2001-02-10 22:51:11 +00:00
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
if (!NT_SUCCESS(StatusExeFmt))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2004-12-30 08:05:12 +00:00
|
|
|
if(ImageSectionObject->Segments != NULL)
|
|
|
|
ExFreePool(ImageSectionObject->Segments);
|
|
|
|
|
|
|
|
ExFreePool(ImageSectionObject);
|
|
|
|
ObDereferenceObject(Section);
|
2004-04-10 22:36:07 +00:00
|
|
|
ObDereferenceObject(FileObject);
|
2004-12-30 08:05:12 +00:00
|
|
|
return(StatusExeFmt);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
Section->ImageSection = ImageSectionObject;
|
|
|
|
ASSERT(ImageSectionObject->Segments);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Lock the file
|
|
|
|
*/
|
|
|
|
Status = MmspWaitForFileLock(FileObject);
|
2004-12-30 08:05:12 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2004-12-30 08:05:12 +00:00
|
|
|
ExFreePool(ImageSectionObject->Segments);
|
|
|
|
ExFreePool(ImageSectionObject);
|
2004-04-10 22:36:07 +00:00
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
2005-01-12 10:05:31 +00:00
|
|
|
if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject,
|
|
|
|
ImageSectionObject, NULL))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
/*
|
2008-09-25 11:24:51 +00:00
|
|
|
* An other thread has initialized the same image in the background
|
2004-04-10 22:36:07 +00:00
|
|
|
*/
|
2004-12-30 08:05:12 +00:00
|
|
|
ExFreePool(ImageSectionObject->Segments);
|
2004-04-10 22:36:07 +00:00
|
|
|
ExFreePool(ImageSectionObject);
|
|
|
|
ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
|
|
|
|
Section->ImageSection = ImageSectionObject;
|
|
|
|
SectionSegments = ImageSectionObject->Segments;
|
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
for (i = 0; i < ImageSectionObject->NrSegments; i++)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2006-03-04 17:27:40 +00:00
|
|
|
(void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
2004-12-30 08:05:12 +00:00
|
|
|
|
|
|
|
Status = StatusExeFmt;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-06-27 21:28:30 +00:00
|
|
|
/*
|
|
|
|
* Lock the file
|
|
|
|
*/
|
2003-12-30 18:52:06 +00:00
|
|
|
Status = MmspWaitForFileLock(FileObject);
|
2003-06-27 21:28:30 +00:00
|
|
|
if (Status != STATUS_SUCCESS)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return(Status);
|
|
|
|
}
|
2003-06-27 21:28:30 +00:00
|
|
|
|
|
|
|
ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
|
|
|
|
Section->ImageSection = ImageSectionObject;
|
2001-03-09 14:40:28 +00:00
|
|
|
SectionSegments = ImageSectionObject->Segments;
|
2001-02-10 22:51:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise just reference all the section segments
|
|
|
|
*/
|
2004-12-30 08:05:12 +00:00
|
|
|
for (i = 0; i < ImageSectionObject->NrSegments; i++)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2006-03-04 17:27:40 +00:00
|
|
|
(void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
2004-12-30 08:05:12 +00:00
|
|
|
Status = STATUS_SUCCESS;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
Section->FileObject = FileObject;
|
|
|
|
CcRosReferenceCache(FileObject);
|
2006-07-27 22:26:40 +00:00
|
|
|
//KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
|
2004-08-05 19:59:13 +00:00
|
|
|
*SectionObject = Section;
|
2004-12-30 08:05:12 +00:00
|
|
|
return(Status);
|
2001-02-10 22:51:11 +00:00
|
|
|
}
|
|
|
|
|
2003-05-14 10:52:46 +00:00
|
|
|
|
2001-02-10 22:51:11 +00:00
|
|
|
|
2008-12-03 17:28:59 +00:00
|
|
|
static NTSTATUS
|
2009-04-27 10:12:57 +00:00
|
|
|
MmMapViewOfSegment(PMMSUPPORT AddressSpace,
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section,
|
2004-04-10 22:36:07 +00:00
|
|
|
PMM_SECTION_SEGMENT Segment,
|
|
|
|
PVOID* BaseAddress,
|
2005-11-28 23:43:40 +00:00
|
|
|
SIZE_T ViewSize,
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG Protect,
|
|
|
|
ULONG ViewOffset,
|
2005-11-13 17:28:24 +00:00
|
|
|
ULONG AllocationType)
|
2001-02-10 22:51:11 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
PMEMORY_AREA MArea;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PHYSICAL_ADDRESS BoundaryAddressMultiple;
|
|
|
|
|
|
|
|
BoundaryAddressMultiple.QuadPart = 0;
|
|
|
|
|
2005-11-13 17:28:24 +00:00
|
|
|
Status = MmCreateMemoryArea(AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
MEMORY_AREA_SECTION_VIEW,
|
|
|
|
BaseAddress,
|
|
|
|
ViewSize,
|
|
|
|
Protect,
|
|
|
|
&MArea,
|
|
|
|
FALSE,
|
2005-11-13 17:28:24 +00:00
|
|
|
AllocationType,
|
2004-04-10 22:36:07 +00:00
|
|
|
BoundaryAddressMultiple);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2004-12-19 16:16:58 +00:00
|
|
|
DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
|
|
|
|
(*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
|
2002-05-17 23:01:57 +00:00
|
|
|
return(Status);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
2005-11-13 17:28:24 +00:00
|
|
|
ObReferenceObject((PVOID)Section);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
MArea->Data.SectionData.Segment = Segment;
|
|
|
|
MArea->Data.SectionData.Section = Section;
|
|
|
|
MArea->Data.SectionData.ViewOffset = ViewOffset;
|
2005-11-28 23:43:40 +00:00
|
|
|
MmInitializeRegion(&MArea->Data.SectionData.RegionListHead,
|
2004-04-10 22:36:07 +00:00
|
|
|
ViewSize, 0, Protect);
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
2001-11-13 22:46:49 +00:00
|
|
|
}
|
2001-02-10 22:51:11 +00:00
|
|
|
|
|
|
|
|
1998-10-05 04:01:30 +00:00
|
|
|
|
2008-12-03 17:28:59 +00:00
|
|
|
static VOID
|
2002-06-04 David Welch <welch@whitehall1-5.seh.ox.ac.uk>
* ntoskrnl/ke/i386/exp.c (KiDoubleFaultHandler): Print CR3
correctly.
2002-06-04 David Welch <welch@whitehall1-5.seh.ox.ac.uk>
* ntoskrnl/include/internal/ps.h: Added KTHREAD_STACK_LIMIT definition.
* ntoskrnl/ke/i386/tskswitch.S (Ki386ContextSwitch): Force all the
pages of the kernel stack to be accessible from this process.
2002-06-04 David Welch <welch@cwcom.net>
* ntoskrnl/cc/view.c (ReadCacheSegmentChain): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/cc/copy.c (CcRosCreateCacheSegment): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/cc/copy.c (CcFreeCachePage): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/include/internal/mm.h: Changed prototypes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/include/internal/ps.h (KPROCESS): Changed type of
page directory base to PHYSICAL_ADDRESS.
* ntoskrnl/include/internal/i386/mm.h: Changed prototypes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/ke/kthread.c (KeFreeStackPage): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/ke/kthread.c (KeInitializeThread): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/ke/process.c (KeAttachProcess, KeDetachProcess): Changes
to use PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/ke/kernel.c (PcrPages, KeApplicationProcessorInit): Changes
to use PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/balance.c (MM_ALLOCATION_REQUEST): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/balance.c (MmReleasePageMemoryConsumer): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/balance.c (MmRequestPageMemoryConsumer): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/cont.c (MmFreeContinuousPage): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/cont.c (MmAllocateContinuousAlignedMemory): Changes to
use PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/freelist.c (MmTransferOwnershipPage,
MmGetLRUFirstUserPage, MmGetLRUNextUserPage, MmGetContinuousPages,
MmInitializePageList, MmSetFlagsPage, MmSetRmapListHeadPage,
MmGetRmapListHeadPage, MmMarkPageMapped, MmMarkPageUnmapped,
MmGetFlagsPage, MmSetSavedSwapEntryPage, MmGetSavedSwapEntryPage,
MmReferencePage, MmGetReferenceCountPage, MmIsUsablePage,
MmDereferencePage, MmGetLockCountPage, MmLockPage, MmUnlockPage,
MmAllocPage): Changes to use PHYSICAL_ADDRESS type for physical
addresses.
* ntoskrnl/mm/iospace.c (MmMapIoSpace): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/kmap.c (ExAllocatePage, MiZeroPage, MiCopyFromUserPage,
ExAllocatePageWithPhysPage): Changes to use PHYSICAL_ADDRESS type for
physical addresses.
* ntoskrnl/mm/marea.c (MmFreeMemoryArea): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/mdl.c (MmUnlockPages, MmMapLockedPages,
MmProbeAndLockPages): Changes to use PHYSICAL_ADDRESS type for
physical addresses.
* ntoskrnl/mm/mm.c (MmSharedDataPagePhysicalAddress,
MmCommitPagedPoolAddress, MmNotPresentFault): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/mminit.c (MmInitVirtualMemory): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/ncache.c (MmAllocateNonCachedMemory,
MmFreeNonCachedPage): Changes to use PHYSICAL_ADDRESS type for
physical addresses.
* ntoskrnl/mm/npool.c (grow_kernel_pool): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/rmap.c (MmPageOutPhysicalAddress, MmInsertRmap,
MmDeleteAllRmaps, MmDeleteRmap): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/section.c (MiReadPage, MmNotPresentFaultSectionView,
MmAccessFaultSectionView, MmPageOutDeleteMapping,
MmPageOutSectionView, MmFreeSectionPage): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/slab.c (ExGrowSlabCache): Changes to use
PHYSICAL_ADDRESS type for physical address.
* ntoskrnl/mm/virtual.c (MmPageOutVirtualMemory,
MmNotPresentFaultVirtualMemory, MmFreeVirtualMemoryPage): Changes to
use PHYSICAL_ADDRESS type for physical address.
* ntoskrnl/mm/wset.c (MmTrimUserMemory): Changes to use
PHYSICAL_ADDRESS type for physical address.
* ntoskrnl/mm/page.c (Mmi386ReleaseMmInfo, MmCopyMmInfo,
MmGetPhysicalAddressForProcess, MmCreateVirtualMapping,
MmCreateVirtualMappingUnsafe, MmCreateVirtualMappingForProcess,
MmDeleteVirtualMapping): Changes to use PHYSICAL_ADDRESS type for
physical address.
* ntoskrnl/ps/process (PsInitProcessManagment): Changes to use
PHYSICAL_ADDRESS type for physical address.
* ntoskrnl/ps/thread.c (PsAllocateCallbackStack): Changes to use
PHYSICAL_ADDRESS type for physical address.
2002-06-04 David Welch <welch@cwcom.net>
* Lots of change since the ChangeLog was last updated.
svn path=/trunk/; revision=3000
2002-06-04 15:26:58 +00:00
|
|
|
MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
|
2001-02-10 22:51:11 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG Entry;
|
|
|
|
PFILE_OBJECT FileObject;
|
|
|
|
PBCB Bcb;
|
|
|
|
ULONG Offset;
|
|
|
|
SWAPENTRY SavedSwapEntry;
|
|
|
|
PMM_PAGEOP PageOp;
|
|
|
|
NTSTATUS Status;
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2004-04-10 22:36:07 +00:00
|
|
|
PMM_SECTION_SEGMENT Segment;
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace;
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
PEPROCESS Process;
|
2001-02-10 22:51:11 +00:00
|
|
|
|
2009-04-27 10:12:57 +00:00
|
|
|
AddressSpace = (PMMSUPPORT)Context;
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Process = MmGetAddressSpaceOwner(AddressSpace);
|
2001-02-10 22:51:11 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
Address = (PVOID)PAGE_ROUND_DOWN(Address);
|
2003-06-06 21:00:28 +00:00
|
|
|
|
2005-06-07 17:07:34 +00:00
|
|
|
Offset = ((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress) +
|
2004-10-01 20:06:43 +00:00
|
|
|
MemoryArea->Data.SectionData.ViewOffset;
|
2002-08-14 20:58:39 +00:00
|
|
|
|
2005-06-07 17:07:34 +00:00
|
|
|
Section = MemoryArea->Data.SectionData.Section;
|
|
|
|
Segment = MemoryArea->Data.SectionData.Segment;
|
2003-06-27 21:28:30 +00:00
|
|
|
|
2005-06-07 17:07:34 +00:00
|
|
|
PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
while (PageOp)
|
|
|
|
{
|
|
|
|
MmUnlockSectionSegment(Segment);
|
2005-06-07 17:07:34 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2003-06-27 21:28:30 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
Status = MmspWaitForPageOpCompletionEvent(PageOp);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
|
|
{
|
2003-06-06 21:00:28 +00:00
|
|
|
DPRINT1("Failed to wait for page op, status = %x\n", Status);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
2005-06-07 17:07:34 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2004-04-10 22:36:07 +00:00
|
|
|
MmLockSectionSegment(Segment);
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
2005-06-07 17:07:34 +00:00
|
|
|
PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2004-08-01 07:24:59 +00:00
|
|
|
if (Page == PFN_FROM_SSE(Entry) && Dirty)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
FileObject = MemoryArea->Data.SectionData.Section->FileObject;
|
|
|
|
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
|
2005-06-12 10:25:49 +00:00
|
|
|
CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
|
2004-10-22 20:43:58 +00:00
|
|
|
ASSERT(SwapEntry == 0);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SwapEntry != 0)
|
|
|
|
{
|
2003-07-14 20:14:11 +00:00
|
|
|
/*
|
|
|
|
* Sanity check
|
|
|
|
*/
|
|
|
|
if (Segment->Flags & MM_PAGEFILE_SEGMENT)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT1("Found a swap entry for a page in a pagefile section.\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-12-31 19:06:49 +00:00
|
|
|
MmFreeSwapPage(SwapEntry);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2004-08-01 07:24:59 +00:00
|
|
|
else if (Page != 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2003-12-30 18:52:06 +00:00
|
|
|
if (IS_SWAP_FROM_SSE(Entry) ||
|
2004-08-01 07:24:59 +00:00
|
|
|
Page != PFN_FROM_SSE(Entry))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Sanity check
|
|
|
|
*/
|
|
|
|
if (Segment->Flags & MM_PAGEFILE_SEGMENT)
|
|
|
|
{
|
|
|
|
DPRINT1("Found a private page in a pagefile section.\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Just dereference private pages
|
|
|
|
*/
|
2004-08-01 07:24:59 +00:00
|
|
|
SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (SavedSwapEntry != 0)
|
|
|
|
{
|
|
|
|
MmFreeSwapPage(SavedSwapEntry);
|
2004-08-01 07:24:59 +00:00
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmDeleteRmap(Page, Process, Address);
|
2004-08-01 07:24:59 +00:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-03-29 17:24:43 +00:00
|
|
|
else
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmDeleteRmap(Page, Process, Address);
|
2004-04-10 22:36:07 +00:00
|
|
|
MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty, FALSE);
|
|
|
|
}
|
|
|
|
}
|
2001-02-10 22:51:11 +00:00
|
|
|
}
|
|
|
|
|
2006-09-07 05:07:34 +00:00
|
|
|
static NTSTATUS
|
2009-04-27 10:12:57 +00:00
|
|
|
MmUnmapViewOfSegment(PMMSUPPORT AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
PVOID BaseAddress)
|
1999-11-24 11:51:55 +00:00
|
|
|
{
|
2003-07-26 12:47:51 +00:00
|
|
|
NTSTATUS Status;
|
2001-02-10 22:51:11 +00:00
|
|
|
PMEMORY_AREA MemoryArea;
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2001-02-10 22:51:11 +00:00
|
|
|
PMM_SECTION_SEGMENT Segment;
|
2002-08-10 16:41:20 +00:00
|
|
|
PLIST_ENTRY CurrentEntry;
|
|
|
|
PMM_REGION CurrentRegion;
|
2003-07-26 12:47:51 +00:00
|
|
|
PLIST_ENTRY RegionListHead;
|
2003-06-06 21:00:28 +00:00
|
|
|
|
2005-01-02 19:14:52 +00:00
|
|
|
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
|
|
|
|
BaseAddress);
|
2001-02-10 22:51:11 +00:00
|
|
|
if (MemoryArea == NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
2002-08-14 20:58:39 +00:00
|
|
|
|
|
|
|
MemoryArea->DeleteInProgress = TRUE;
|
2001-02-10 22:51:11 +00:00
|
|
|
Section = MemoryArea->Data.SectionData.Section;
|
|
|
|
Segment = MemoryArea->Data.SectionData.Segment;
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2003-06-27 21:28:30 +00:00
|
|
|
MmLockSectionSegment(Segment);
|
2002-08-10 16:41:20 +00:00
|
|
|
|
2003-07-26 12:47:51 +00:00
|
|
|
RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
|
|
|
|
while (!IsListEmpty(RegionListHead))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
CurrentEntry = RemoveHeadList(RegionListHead);
|
|
|
|
CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
|
2008-08-31 15:29:21 +00:00
|
|
|
ExFreePoolWithTag(CurrentRegion, TAG_MM_REGION);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2002-08-10 16:41:20 +00:00
|
|
|
|
2003-06-27 21:28:30 +00:00
|
|
|
if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
Status = MmFreeMemoryArea(AddressSpace,
|
2005-01-02 17:55:06 +00:00
|
|
|
MemoryArea,
|
2004-04-10 22:36:07 +00:00
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
}
|
2001-02-10 22:51:11 +00:00
|
|
|
else
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
Status = MmFreeMemoryArea(AddressSpace,
|
2005-01-02 17:55:06 +00:00
|
|
|
MemoryArea,
|
2004-04-10 22:36:07 +00:00
|
|
|
MmFreeSectionPage,
|
2005-06-07 17:07:34 +00:00
|
|
|
AddressSpace);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-02-10 22:51:11 +00:00
|
|
|
MmUnlockSectionSegment(Segment);
|
2001-03-08 22:06:02 +00:00
|
|
|
ObDereferenceObject(Section);
|
[NTOS]: Remove useless variables in kernel code that were set, but never actually used (dead code, tests, copy/pasters). If a variable was set but not used because of missing/#if'ed out code, a note was added instead.
[NTOS]: In the process, fix bugs in the Event dispatcher code that used Win32 EVENT_TYPE instead of NT KOBJECTS enumeration.
[NTOS]: Fix a bug in ObpInsertHandleCount, where the object access check was being done with the previous mode, instead of honoring the probe mode, which is defined by OBJ_FORCE_ACCESS_CHECK.
[NTOS]: Fix a bug in a section function which was always returning STATUS_SUCCESS, now it returns the result of the previous Status = function assignment. If this isn't desired, then don't check for the Status anymore.
[NTOS]: Note that MDL code does not support SkipBytes argument. If it is used, MDL could be invalid.
[NTOS]: Add checks for VerifierAllocation and set it when needed (WIP).
[NTOS]: Clarify what _WORKING_LINKER_ is, and the legal risks in continuing to use a linker that builds non-Microsoft drivers when used with headers whose EULA specify that they can only be used for Microsoft drivers.
svn path=/trunk/; revision=48692
2010-09-04 08:17:17 +00:00
|
|
|
return(Status);
|
1999-11-24 11:51:55 +00:00
|
|
|
}
|
1998-08-25 04:27:26 +00:00
|
|
|
|
2003-07-26 12:47:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2008-11-29 20:47:48 +00:00
|
|
|
NTSTATUS NTAPI
|
2003-07-26 12:47:51 +00:00
|
|
|
MmUnmapViewOfSection(PEPROCESS Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
PVOID BaseAddress)
|
2003-07-26 12:47:51 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
NTSTATUS Status;
|
2003-07-26 12:47:51 +00:00
|
|
|
PMEMORY_AREA MemoryArea;
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace;
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2005-10-29 14:10:35 +00:00
|
|
|
PMM_PAGEOP PageOp;
|
|
|
|
ULONG_PTR Offset;
|
2006-11-30 01:57:25 +00:00
|
|
|
PVOID ImageBaseAddress = 0;
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2003-07-26 12:47:51 +00:00
|
|
|
DPRINT("Opening memory area Process %x BaseAddress %x\n",
|
2004-04-10 22:36:07 +00:00
|
|
|
Process, BaseAddress);
|
2003-07-26 12:47:51 +00:00
|
|
|
|
2004-10-22 20:43:58 +00:00
|
|
|
ASSERT(Process);
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2009-04-27 10:12:57 +00:00
|
|
|
AddressSpace = &Process->Vm;
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2005-10-29 14:10:35 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2005-01-02 19:14:52 +00:00
|
|
|
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
|
|
|
|
BaseAddress);
|
2004-08-23 22:29:43 +00:00
|
|
|
if (MemoryArea == NULL ||
|
|
|
|
MemoryArea->Type != MEMORY_AREA_SECTION_VIEW ||
|
|
|
|
MemoryArea->DeleteInProgress)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-10-29 14:10:35 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2004-08-23 22:29:43 +00:00
|
|
|
return STATUS_NOT_MAPPED_VIEW;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2003-07-26 12:47:51 +00:00
|
|
|
|
2005-10-29 14:10:35 +00:00
|
|
|
MemoryArea->DeleteInProgress = TRUE;
|
|
|
|
|
|
|
|
while (MemoryArea->PageOpCount)
|
|
|
|
{
|
|
|
|
Offset = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)MemoryArea->StartingAddress);
|
|
|
|
|
|
|
|
while (Offset)
|
|
|
|
{
|
|
|
|
Offset -= PAGE_SIZE;
|
|
|
|
PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL,
|
|
|
|
MemoryArea->Data.SectionData.Segment,
|
|
|
|
Offset + MemoryArea->Data.SectionData.ViewOffset);
|
|
|
|
if (PageOp)
|
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
Status = MmspWaitForPageOpCompletionEvent(PageOp);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
DPRINT1("Failed to wait for page op, status = %x\n", Status);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2005-10-29 14:10:35 +00:00
|
|
|
}
|
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
|
|
|
|
BaseAddress);
|
|
|
|
if (MemoryArea == NULL ||
|
|
|
|
MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
|
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
return STATUS_NOT_MAPPED_VIEW;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-07-26 12:47:51 +00:00
|
|
|
Section = MemoryArea->Data.SectionData.Section;
|
|
|
|
|
|
|
|
if (Section->AllocationAttributes & SEC_IMAGE)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* Search for the current segment within the section segments
|
|
|
|
* and calculate the image base address */
|
|
|
|
for (i = 0; i < NrSegments; i++)
|
|
|
|
{
|
2006-09-10 10:26:58 +00:00
|
|
|
if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
|
2003-07-26 12:47:51 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
if (Segment == &SectionSegments[i])
|
|
|
|
{
|
|
|
|
ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i >= NrSegments)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < NrSegments; i++)
|
|
|
|
{
|
2006-09-10 10:26:58 +00:00
|
|
|
if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
|
2003-07-26 12:47:51 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
PVOID SBaseAddress = (PVOID)
|
|
|
|
((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress);
|
|
|
|
|
|
|
|
Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-07-26 12:47:51 +00:00
|
|
|
else
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
|
|
|
|
}
|
2006-11-30 01:57:25 +00:00
|
|
|
|
2009-06-09 12:50:32 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
|
2006-11-30 01:57:25 +00:00
|
|
|
/* Notify debugger */
|
|
|
|
if (ImageBaseAddress) DbgkUnMapViewOfSection(ImageBaseAddress);
|
|
|
|
|
2003-07-26 12:47:51 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2005-02-15 15:46:22 +00:00
|
|
|
|
1998-10-05 04:01:30 +00:00
|
|
|
|
|
|
|
|
2004-08-20 21:23:49 +00:00
|
|
|
/**
|
|
|
|
* Queries the information of a section object.
|
2005-05-09 01:38:29 +00:00
|
|
|
*
|
2004-08-20 21:23:49 +00:00
|
|
|
* @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.
|
1998-10-05 04:01:30 +00:00
|
|
|
*
|
2004-08-20 21:23:49 +00:00
|
|
|
* @implemented
|
1998-10-05 04:01:30 +00:00
|
|
|
*/
|
2008-11-29 20:47:48 +00:00
|
|
|
NTSTATUS NTAPI
|
2004-08-20 21:23:49 +00:00
|
|
|
NtQuerySection(IN HANDLE SectionHandle,
|
2005-02-15 15:46:22 +00:00
|
|
|
IN SECTION_INFORMATION_CLASS SectionInformationClass,
|
2004-08-20 21:23:49 +00:00
|
|
|
OUT PVOID SectionInformation,
|
2009-12-06 03:24:18 +00:00
|
|
|
IN SIZE_T SectionInformationLength,
|
|
|
|
OUT PSIZE_T ResultLength OPTIONAL)
|
1998-10-05 04:01:30 +00:00
|
|
|
{
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2005-02-15 15:46:22 +00:00
|
|
|
KPROCESSOR_MODE PreviousMode;
|
2009-08-24 20:39:23 +00:00
|
|
|
NTSTATUS Status;
|
2009-06-14 08:57:25 +00:00
|
|
|
PAGED_CODE();
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-02-15 15:46:22 +00:00
|
|
|
PreviousMode = ExGetPreviousMode();
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-10-10 13:03:55 +00:00
|
|
|
Status = DefaultQueryInfoBufferCheck(SectionInformationClass,
|
|
|
|
ExSectionInfoClass,
|
|
|
|
sizeof(ExSectionInfoClass) / sizeof(ExSectionInfoClass[0]),
|
|
|
|
SectionInformation,
|
|
|
|
SectionInformationLength,
|
2010-01-13 22:35:43 +00:00
|
|
|
NULL,
|
2005-10-10 13:03:55 +00:00
|
|
|
ResultLength,
|
|
|
|
PreviousMode);
|
2005-02-15 15:46:22 +00:00
|
|
|
|
|
|
|
if(!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
Status = ObReferenceObjectByHandle(SectionHandle,
|
2004-08-20 21:23:49 +00:00
|
|
|
SECTION_QUERY,
|
2004-04-10 22:36:07 +00:00
|
|
|
MmSectionObjectType,
|
2005-02-15 15:46:22 +00:00
|
|
|
PreviousMode,
|
2004-08-23 22:29:43 +00:00
|
|
|
(PVOID*)(PVOID)&Section,
|
2004-04-10 22:36:07 +00:00
|
|
|
NULL);
|
2005-02-15 15:46:22 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-02-15 15:46:22 +00:00
|
|
|
switch (SectionInformationClass)
|
|
|
|
{
|
|
|
|
case SectionBasicInformation:
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-02-15 15:46:22 +00:00
|
|
|
PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
|
2001-02-10 22:51:11 +00:00
|
|
|
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_TRY
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-02-15 15:46:22 +00:00
|
|
|
Sbi->Attributes = Section->AllocationAttributes;
|
|
|
|
if (Section->AllocationAttributes & SEC_IMAGE)
|
|
|
|
{
|
|
|
|
Sbi->BaseAddress = 0;
|
|
|
|
Sbi->Size.QuadPart = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Sbi->BaseAddress = (PVOID)Section->Segment->VirtualAddress;
|
|
|
|
Sbi->Size.QuadPart = Section->Segment->Length;
|
|
|
|
}
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2005-02-15 15:46:22 +00:00
|
|
|
if (ResultLength != NULL)
|
|
|
|
{
|
|
|
|
*ResultLength = sizeof(SECTION_BASIC_INFORMATION);
|
|
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
2004-08-20 21:23:49 +00:00
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
2004-08-20 21:23:49 +00:00
|
|
|
{
|
2008-11-24 13:40:26 +00:00
|
|
|
Status = _SEH2_GetExceptionCode();
|
2004-08-20 21:23:49 +00:00
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_END;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
break;
|
|
|
|
}
|
2001-02-10 22:51:11 +00:00
|
|
|
|
2005-02-15 15:46:22 +00:00
|
|
|
case SectionImageInformation:
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-02-15 15:46:22 +00:00
|
|
|
PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_TRY
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-02-15 15:46:22 +00:00
|
|
|
memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
|
|
|
|
if (Section->AllocationAttributes & SEC_IMAGE)
|
|
|
|
{
|
|
|
|
PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
|
|
|
|
ImageSectionObject = Section->ImageSection;
|
|
|
|
|
2005-07-12 01:56:14 +00:00
|
|
|
Sii->TransferAddress = (PVOID)ImageSectionObject->EntryPoint;
|
|
|
|
Sii->MaximumStackSize = ImageSectionObject->StackReserve;
|
|
|
|
Sii->CommittedStackSize = ImageSectionObject->StackCommit;
|
2008-06-11 11:48:59 +00:00
|
|
|
Sii->SubSystemType = ImageSectionObject->Subsystem;
|
2005-07-12 01:56:14 +00:00
|
|
|
Sii->SubSystemMinorVersion = ImageSectionObject->MinorSubsystemVersion;
|
|
|
|
Sii->SubSystemMajorVersion = ImageSectionObject->MajorSubsystemVersion;
|
|
|
|
Sii->ImageCharacteristics = ImageSectionObject->ImageCharacteristics;
|
|
|
|
Sii->Machine = ImageSectionObject->Machine;
|
|
|
|
Sii->ImageContainsCode = ImageSectionObject->Executable;
|
2005-02-15 15:46:22 +00:00
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-02-15 15:46:22 +00:00
|
|
|
if (ResultLength != NULL)
|
|
|
|
{
|
|
|
|
*ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
|
|
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2008-11-24 13:40:26 +00:00
|
|
|
Status = _SEH2_GetExceptionCode();
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_END;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-02-15 15:46:22 +00:00
|
|
|
}
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-02-15 15:46:22 +00:00
|
|
|
ObDereferenceObject(Section);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
return(Status);
|
1998-10-05 04:01:30 +00:00
|
|
|
}
|
2010-10-05 14:36:09 +00:00
|
|
|
|
2000-04-02 13:32:43 +00:00
|
|
|
/**********************************************************************
|
2004-04-10 22:36:07 +00:00
|
|
|
* NAME EXPORTED
|
|
|
|
* MmMapViewOfSection
|
2000-04-02 13:32:43 +00:00
|
|
|
*
|
|
|
|
* DESCRIPTION
|
2004-04-10 22:36:07 +00:00
|
|
|
* Maps a view of a section into the virtual address space of a
|
|
|
|
* process.
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2000-04-02 13:32:43 +00:00
|
|
|
* ARGUMENTS
|
2004-04-10 22:36:07 +00:00
|
|
|
* Section
|
|
|
|
* Pointer to the section object.
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* ProcessHandle
|
|
|
|
* Pointer to the process.
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* BaseAddress
|
|
|
|
* Desired base address (or NULL) on entry;
|
|
|
|
* Actual base address of the view on exit.
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* ZeroBits
|
|
|
|
* Number of high order address bits that must be zero.
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* CommitSize
|
|
|
|
* Size in bytes of the initially committed section of
|
|
|
|
* the view.
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* SectionOffset
|
|
|
|
* Offset in bytes from the beginning of the section
|
|
|
|
* to the beginning of the view.
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* ViewSize
|
|
|
|
* Desired length of map (or zero to map all) on entry
|
|
|
|
* Actual length mapped on exit.
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* InheritDisposition
|
|
|
|
* Specified how the view is to be shared with
|
|
|
|
* child processes.
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* AllocationType
|
|
|
|
* Type of allocation for the pages.
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* Protect
|
|
|
|
* Protection for the committed region of the view.
|
2000-04-02 13:32:43 +00:00
|
|
|
*
|
|
|
|
* RETURN VALUE
|
2004-04-10 22:36:07 +00:00
|
|
|
* Status.
|
2003-07-10 21:05:04 +00:00
|
|
|
*
|
|
|
|
* @implemented
|
2000-04-02 13:32:43 +00:00
|
|
|
*/
|
2008-11-29 20:47:48 +00:00
|
|
|
NTSTATUS NTAPI
|
2001-11-13 22:46:49 +00:00
|
|
|
MmMapViewOfSection(IN PVOID SectionObject,
|
2004-04-10 22:36:07 +00:00
|
|
|
IN PEPROCESS Process,
|
|
|
|
IN OUT PVOID *BaseAddress,
|
2008-09-24 15:27:54 +00:00
|
|
|
IN ULONG_PTR ZeroBits,
|
|
|
|
IN SIZE_T CommitSize,
|
2004-04-10 22:36:07 +00:00
|
|
|
IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
|
2005-11-28 23:43:40 +00:00
|
|
|
IN OUT PSIZE_T ViewSize,
|
2004-04-10 22:36:07 +00:00
|
|
|
IN SECTION_INHERIT InheritDisposition,
|
|
|
|
IN ULONG AllocationType,
|
|
|
|
IN ULONG Protect)
|
2000-04-02 13:32:43 +00:00
|
|
|
{
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace;
|
2001-11-13 22:46:49 +00:00
|
|
|
ULONG ViewOffset;
|
2002-09-15 10:45:05 +00:00
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2001-11-13 22:46:49 +00:00
|
|
|
|
2010-10-05 14:36:09 +00:00
|
|
|
if ((ULONG_PTR)SectionObject & 1)
|
|
|
|
{
|
|
|
|
return MmMapViewOfArm3Section((PVOID)((ULONG_PTR)SectionObject & ~1),
|
|
|
|
Process,
|
|
|
|
BaseAddress,
|
|
|
|
ZeroBits,
|
|
|
|
CommitSize,
|
|
|
|
SectionOffset,
|
|
|
|
ViewSize,
|
|
|
|
InheritDisposition,
|
|
|
|
AllocationType,
|
|
|
|
Protect);
|
|
|
|
}
|
|
|
|
|
2004-10-22 20:43:58 +00:00
|
|
|
ASSERT(Process);
|
2003-06-06 21:00:28 +00:00
|
|
|
|
2009-01-24 00:54:02 +00:00
|
|
|
if (!Protect || Protect & ~PAGE_FLAGS_VALID_FOR_SECTION)
|
2005-11-13 17:28:24 +00:00
|
|
|
{
|
|
|
|
return STATUS_INVALID_PAGE_PROTECTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-05-10 17:47:44 +00:00
|
|
|
Section = (PROS_SECTION_OBJECT)SectionObject;
|
2009-04-27 10:12:57 +00:00
|
|
|
AddressSpace = &Process->Vm;
|
2001-11-13 22:46:49 +00:00
|
|
|
|
2005-11-13 17:28:24 +00:00
|
|
|
AllocationType |= (Section->AllocationAttributes & SEC_NO_CHANGE);
|
|
|
|
|
2003-06-27 21:28:30 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2003-05-14 10:52:46 +00:00
|
|
|
|
2002-08-14 20:58:39 +00:00
|
|
|
if (Section->AllocationAttributes & SEC_IMAGE)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
ULONG i;
|
|
|
|
ULONG NrSegments;
|
2005-01-02 17:55:06 +00:00
|
|
|
ULONG_PTR ImageBase;
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG ImageSize;
|
|
|
|
PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
|
|
|
|
PMM_SECTION_SEGMENT SectionSegments;
|
|
|
|
|
|
|
|
ImageSectionObject = Section->ImageSection;
|
|
|
|
SectionSegments = ImageSectionObject->Segments;
|
|
|
|
NrSegments = ImageSectionObject->NrSegments;
|
|
|
|
|
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
ImageBase = (ULONG_PTR)*BaseAddress;
|
|
|
|
if (ImageBase == 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
ImageBase = ImageSectionObject->ImageBase;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ImageSize = 0;
|
|
|
|
for (i = 0; i < NrSegments; i++)
|
|
|
|
{
|
2006-09-10 10:26:58 +00:00
|
|
|
if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
ULONG_PTR MaxExtent;
|
|
|
|
MaxExtent = (ULONG_PTR)SectionSegments[i].VirtualAddress +
|
|
|
|
SectionSegments[i].Length;
|
2004-04-10 22:36:07 +00:00
|
|
|
ImageSize = max(ImageSize, MaxExtent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-23 15:31:45 +00:00
|
|
|
ImageSectionObject->ImageSize = ImageSize;
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
/* Check there is enough space to map the section at that point. */
|
2005-01-02 19:14:52 +00:00
|
|
|
if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase,
|
|
|
|
PAGE_ROUND_UP(ImageSize)) != NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
/* Fail if the user requested a fixed base address. */
|
|
|
|
if ((*BaseAddress) != NULL)
|
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
|
|
|
/* Otherwise find a gap to map the image. */
|
2005-01-02 17:55:06 +00:00
|
|
|
ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), PAGE_SIZE, FALSE);
|
|
|
|
if (ImageBase == 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < NrSegments; i++)
|
|
|
|
{
|
2006-09-10 10:26:58 +00:00
|
|
|
if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
PVOID SBaseAddress = (PVOID)
|
|
|
|
((char*)ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
|
|
|
|
MmLockSectionSegment(&SectionSegments[i]);
|
2005-11-13 17:28:24 +00:00
|
|
|
Status = MmMapViewOfSegment(AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
Section,
|
|
|
|
&SectionSegments[i],
|
|
|
|
&SBaseAddress,
|
|
|
|
SectionSegments[i].Length,
|
|
|
|
SectionSegments[i].Protection,
|
2004-10-01 20:06:43 +00:00
|
|
|
0,
|
2005-11-13 17:28:24 +00:00
|
|
|
0);
|
2004-04-10 22:36:07 +00:00
|
|
|
MmUnlockSectionSegment(&SectionSegments[i]);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
*BaseAddress = (PVOID)ImageBase;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-11-13 22:46:49 +00:00
|
|
|
else
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-11-13 17:28:24 +00:00
|
|
|
/* check for write access */
|
|
|
|
if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) &&
|
|
|
|
!(Section->SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)))
|
|
|
|
{
|
2008-10-29 16:10:20 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2005-11-13 17:28:24 +00:00
|
|
|
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)))
|
|
|
|
{
|
2008-10-29 16:10:20 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2005-11-13 17:28:24 +00:00
|
|
|
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)))
|
|
|
|
{
|
2008-10-29 16:10:20 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2005-11-13 17:28:24 +00:00
|
|
|
return STATUS_SECTION_PROTECTION;
|
|
|
|
}
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
if (ViewSize == NULL)
|
|
|
|
{
|
|
|
|
/* Following this pointer would lead to us to the dark side */
|
|
|
|
/* What to do? Bugcheck? Return status? Do the mambo? */
|
2008-08-24 15:48:05 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-05-08 14:12:12 +00:00
|
|
|
*ViewSize = PAGE_ROUND_UP(*ViewSize);
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
MmLockSectionSegment(Section->Segment);
|
2005-11-13 17:28:24 +00:00
|
|
|
Status = MmMapViewOfSegment(AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
Section,
|
|
|
|
Section->Segment,
|
|
|
|
BaseAddress,
|
|
|
|
*ViewSize,
|
|
|
|
Protect,
|
|
|
|
ViewOffset,
|
2005-11-13 17:28:24 +00:00
|
|
|
AllocationType & (MEM_TOP_DOWN|SEC_NO_CHANGE));
|
2004-04-10 22:36:07 +00:00
|
|
|
MmUnlockSectionSegment(Section->Segment);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
}
|
2001-11-13 22:46:49 +00:00
|
|
|
|
2003-06-27 21:28:30 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2001-11-13 22:46:49 +00:00
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
2000-04-02 13:32:43 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 21:05:04 +00:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
2008-11-29 20:47:48 +00:00
|
|
|
BOOLEAN NTAPI
|
2004-04-10 22:36:07 +00:00
|
|
|
MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
|
|
|
|
IN PLARGE_INTEGER NewFileSize)
|
2000-04-02 13:32:43 +00:00
|
|
|
{
|
2009-02-02 17:14:24 +00:00
|
|
|
/* Check whether an ImageSectionObject exists */
|
|
|
|
if (SectionObjectPointer->ImageSectionObject != NULL)
|
|
|
|
{
|
2009-02-03 12:39:55 +00:00
|
|
|
DPRINT1("ERROR: File can't be truncated because it has an image section\n");
|
2009-02-02 17:14:24 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SectionObjectPointer->DataSectionObject != NULL)
|
|
|
|
{
|
|
|
|
PMM_SECTION_SEGMENT Segment;
|
|
|
|
|
|
|
|
Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->
|
|
|
|
DataSectionObject;
|
|
|
|
|
|
|
|
if (Segment->ReferenceCount != 0)
|
|
|
|
{
|
2009-02-03 12:39:55 +00:00
|
|
|
/* Check size of file */
|
|
|
|
if (SectionObjectPointer->SharedCacheMap)
|
|
|
|
{
|
|
|
|
PBCB Bcb = SectionObjectPointer->SharedCacheMap;
|
|
|
|
if (NewFileSize->QuadPart <= Bcb->FileSize.QuadPart)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Something must gone wrong
|
|
|
|
* how can we have a Section but no
|
|
|
|
* reference? */
|
2009-10-16 22:03:38 +00:00
|
|
|
DPRINT("ERROR: DataSectionObject without reference!\n");
|
2009-02-02 17:14:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-15 07:47:15 +00:00
|
|
|
DPRINT("FIXME: didn't check for outstanding write probes\n");
|
2009-02-02 17:14:24 +00:00
|
|
|
|
2009-02-03 12:39:55 +00:00
|
|
|
return TRUE;
|
2000-04-02 13:32:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-02 02:14:39 +00:00
|
|
|
|
2000-04-02 13:32:43 +00:00
|
|
|
|
2003-07-10 21:05:04 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2008-11-29 20:47:48 +00:00
|
|
|
BOOLEAN NTAPI
|
2004-04-10 22:36:07 +00:00
|
|
|
MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
|
|
|
|
IN MMFLUSH_TYPE FlushType)
|
2000-04-02 13:32:43 +00:00
|
|
|
{
|
2003-01-11 15:31:05 +00:00
|
|
|
switch(FlushType)
|
|
|
|
{
|
2003-12-30 18:52:06 +00:00
|
|
|
case MmFlushForDelete:
|
|
|
|
if (SectionObjectPointer->ImageSectionObject ||
|
2004-04-10 22:36:07 +00:00
|
|
|
SectionObjectPointer->DataSectionObject)
|
|
|
|
{
|
2003-01-11 15:31:05 +00:00
|
|
|
return FALSE;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
CcRosSetRemoveOnClose(SectionObjectPointer);
|
2003-01-11 15:31:05 +00:00
|
|
|
return TRUE;
|
|
|
|
case MmFlushForWrite:
|
2004-04-10 22:36:07 +00:00
|
|
|
break;
|
2003-01-11 15:31:05 +00:00
|
|
|
}
|
|
|
|
return FALSE;
|
2000-04-02 13:32:43 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 21:05:04 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2008-11-29 20:47:48 +00:00
|
|
|
NTSTATUS NTAPI
|
2004-04-10 22:36:07 +00:00
|
|
|
MmMapViewInSystemSpace (IN PVOID SectionObject,
|
|
|
|
OUT PVOID * MappedBase,
|
2009-12-06 03:24:18 +00:00
|
|
|
IN OUT PSIZE_T ViewSize)
|
2000-04-02 13:32:43 +00:00
|
|
|
{
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace;
|
2004-04-10 22:36:07 +00:00
|
|
|
NTSTATUS Status;
|
2010-10-05 14:36:09 +00:00
|
|
|
PAGED_CODE();
|
|
|
|
|
2010-10-04 20:19:03 +00:00
|
|
|
if ((ULONG_PTR)SectionObject & 1)
|
|
|
|
{
|
|
|
|
extern PVOID MmSession;
|
|
|
|
return MiMapViewInSystemSpace((PVOID)((ULONG_PTR)SectionObject & ~1),
|
|
|
|
&MmSession,
|
|
|
|
MappedBase,
|
|
|
|
ViewSize);
|
|
|
|
}
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
DPRINT("MmMapViewInSystemSpace() called\n");
|
2003-05-17 13:43:44 +00:00
|
|
|
|
2006-05-10 17:47:44 +00:00
|
|
|
Section = (PROS_SECTION_OBJECT)SectionObject;
|
2004-04-10 22:36:07 +00:00
|
|
|
AddressSpace = MmGetKernelAddressSpace();
|
2003-05-17 13:43:44 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2003-05-17 13:43:44 +00:00
|
|
|
|
2003-12-30 18:52:06 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
if ((*ViewSize) == 0)
|
|
|
|
{
|
2003-05-17 13:43:44 +00:00
|
|
|
(*ViewSize) = Section->MaximumSize.u.LowPart;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
|
|
|
|
{
|
2003-05-17 13:43:44 +00:00
|
|
|
(*ViewSize) = Section->MaximumSize.u.LowPart;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2003-05-17 13:43:44 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
MmLockSectionSegment(Section->Segment);
|
2003-05-17 13:43:44 +00:00
|
|
|
|
|
|
|
|
2005-11-13 17:28:24 +00:00
|
|
|
Status = MmMapViewOfSegment(AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
Section,
|
|
|
|
Section->Segment,
|
|
|
|
MappedBase,
|
|
|
|
*ViewSize,
|
|
|
|
PAGE_READWRITE,
|
|
|
|
0,
|
2005-11-13 17:28:24 +00:00
|
|
|
0);
|
2003-05-17 13:43:44 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
MmUnlockSectionSegment(Section->Segment);
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2003-05-17 13:43:44 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
return Status;
|
2000-04-02 13:32:43 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 21:05:04 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2008-11-29 20:47:48 +00:00
|
|
|
NTSTATUS NTAPI
|
2004-04-10 22:36:07 +00:00
|
|
|
MmUnmapViewInSystemSpace (IN PVOID MappedBase)
|
2000-04-02 13:32:43 +00:00
|
|
|
{
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace;
|
2004-04-10 22:36:07 +00:00
|
|
|
NTSTATUS Status;
|
2003-05-17 13:43:44 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
DPRINT("MmUnmapViewInSystemSpace() called\n");
|
2003-05-17 13:43:44 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
AddressSpace = MmGetKernelAddressSpace();
|
2003-05-17 13:43:44 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
|
2003-05-17 13:43:44 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
return Status;
|
2000-04-02 13:32:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
2004-04-10 22:36:07 +00:00
|
|
|
* NAME EXPORTED
|
|
|
|
* MmCreateSection@
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2000-04-02 13:32:43 +00:00
|
|
|
* DESCRIPTION
|
2004-04-10 22:36:07 +00:00
|
|
|
* Creates a section object.
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2000-04-02 13:32:43 +00:00
|
|
|
* ARGUMENTS
|
2004-08-05 19:59:13 +00:00
|
|
|
* SectionObject (OUT)
|
2004-04-10 22:36:07 +00:00
|
|
|
* Caller supplied storage for the resulting pointer
|
|
|
|
* to a SECTION_OBJECT instance;
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* 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
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* ObjectAttributes [OPTIONAL]
|
|
|
|
* Initialized attributes for the object can be used
|
|
|
|
* to create a named section;
|
2000-04-02 13:32:43 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* 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.
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* SectionPageProtection
|
|
|
|
* Can be a combination of:
|
|
|
|
* PAGE_READONLY |
|
|
|
|
* PAGE_READWRITE |
|
|
|
|
* PAGE_WRITEONLY |
|
|
|
|
* PAGE_WRITECOPY
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* AllocationAttributes
|
|
|
|
* Can be a combination of:
|
|
|
|
* SEC_IMAGE |
|
|
|
|
* SEC_RESERVE
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* FileHandle
|
|
|
|
* Handle to a file to create a section mapped to a file
|
|
|
|
* instead of a memory backed section;
|
2000-04-02 13:32:43 +00:00
|
|
|
*
|
2004-04-10 22:36:07 +00:00
|
|
|
* File
|
|
|
|
* Unknown.
|
2003-12-30 18:52:06 +00:00
|
|
|
*
|
2000-04-02 13:32:43 +00:00
|
|
|
* RETURN VALUE
|
2004-04-10 22:36:07 +00:00
|
|
|
* Status.
|
2003-07-10 21:05:04 +00:00
|
|
|
*
|
2004-08-05 19:59:13 +00:00
|
|
|
* @implemented
|
2000-04-02 13:32:43 +00:00
|
|
|
*/
|
2008-11-29 20:47:48 +00:00
|
|
|
NTSTATUS NTAPI
|
2006-01-08 06:23:17 +00:00
|
|
|
MmCreateSection (OUT PVOID * Section,
|
2004-04-10 22:36:07 +00:00
|
|
|
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 File OPTIONAL)
|
2000-04-02 13:32:43 +00:00
|
|
|
{
|
2005-11-13 17:28:24 +00:00
|
|
|
ULONG Protection;
|
2006-05-10 17:47:44 +00:00
|
|
|
PROS_SECTION_OBJECT *SectionObject = (PROS_SECTION_OBJECT *)Section;
|
2010-10-04 20:19:03 +00:00
|
|
|
|
|
|
|
/* Check if an ARM3 section is being created instead */
|
2010-10-19 17:01:28 +00:00
|
|
|
if (AllocationAttributes & 1)
|
2010-10-04 20:19:03 +00:00
|
|
|
{
|
|
|
|
DPRINT1("arm 3 path\n");
|
|
|
|
return MmCreateArm3Section(Section,
|
|
|
|
DesiredAccess,
|
|
|
|
ObjectAttributes,
|
|
|
|
MaximumSize,
|
|
|
|
SectionPageProtection,
|
2010-10-19 17:01:28 +00:00
|
|
|
AllocationAttributes &~ 1,
|
2010-10-04 20:19:03 +00:00
|
|
|
FileHandle,
|
|
|
|
File);
|
|
|
|
}
|
2005-11-13 17:28:24 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the protection
|
|
|
|
*/
|
|
|
|
Protection = SectionPageProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
|
2009-05-12 09:00:06 +00:00
|
|
|
if (Protection != PAGE_READONLY &&
|
2005-11-13 17:28:24 +00:00
|
|
|
Protection != PAGE_READWRITE &&
|
|
|
|
Protection != PAGE_WRITECOPY &&
|
|
|
|
Protection != PAGE_EXECUTE &&
|
|
|
|
Protection != PAGE_EXECUTE_READ &&
|
|
|
|
Protection != PAGE_EXECUTE_READWRITE &&
|
|
|
|
Protection != PAGE_EXECUTE_WRITECOPY)
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PAGE_PROTECTION;
|
|
|
|
}
|
|
|
|
|
2004-08-05 19:59:13 +00:00
|
|
|
if (AllocationAttributes & SEC_IMAGE)
|
|
|
|
{
|
|
|
|
return(MmCreateImageSection(SectionObject,
|
|
|
|
DesiredAccess,
|
|
|
|
ObjectAttributes,
|
|
|
|
MaximumSize,
|
|
|
|
SectionPageProtection,
|
|
|
|
AllocationAttributes,
|
|
|
|
FileHandle));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FileHandle != NULL)
|
|
|
|
{
|
|
|
|
return(MmCreateDataFileSection(SectionObject,
|
|
|
|
DesiredAccess,
|
|
|
|
ObjectAttributes,
|
|
|
|
MaximumSize,
|
|
|
|
SectionPageProtection,
|
|
|
|
AllocationAttributes,
|
|
|
|
FileHandle));
|
|
|
|
}
|
|
|
|
|
|
|
|
return(MmCreatePageFileSection(SectionObject,
|
|
|
|
DesiredAccess,
|
|
|
|
ObjectAttributes,
|
|
|
|
MaximumSize,
|
|
|
|
SectionPageProtection,
|
|
|
|
AllocationAttributes));
|
2000-04-02 13:32:43 +00:00
|
|
|
}
|
|
|
|
|
2006-10-23 18:12:12 +00:00
|
|
|
|
|
|
|
|
1999-08-29 06:59:11 +00:00
|
|
|
/* EOF */
|