2008-03-09 22:11:42 +08:00
|
|
|
/*
|
2005-06-08 01:07:34 +08:00
|
|
|
* Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
|
|
|
|
*
|
2005-06-08 04:15:16 +08: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-08 01:07:34 +08:00
|
|
|
*
|
2005-06-08 04:15:16 +08:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
2005-06-08 01:07:34 +08:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2005-06-08 04:15:16 +08:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2005-06-08 01:07:34 +08:00
|
|
|
*
|
2005-06-08 04:15:16 +08: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-08 01:07:34 +08:00
|
|
|
*
|
|
|
|
*
|
1998-08-25 12:27:26 +08:00
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: ntoskrnl/mm/section.c
|
|
|
|
* PURPOSE: Implements section objects
|
2005-05-09 09:38:29 +08:00
|
|
|
*
|
2005-06-08 01:07:34 +08: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-20 07:21:45 +08:00
|
|
|
* Aleksey Bragin
|
2005-06-08 01:07:34 +08:00
|
|
|
* Jason Filby
|
|
|
|
* Thomas Weidenmueller
|
|
|
|
* Gunnar Andre' Dalsnes
|
2005-06-08 04:15:16 +08:00
|
|
|
* Mike Nordell
|
2005-06-08 01:07:34 +08:00
|
|
|
* Alex Ionescu
|
|
|
|
* Gregor Anich
|
|
|
|
* Steven Edwards
|
|
|
|
* Herve Poussineau
|
1998-08-25 12:27:26 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
2004-08-16 00:39:12 +08:00
|
|
|
#include <ntoskrnl.h>
|
1998-10-05 12:01:30 +08:00
|
|
|
#define NDEBUG
|
2008-08-31 00:31:06 +08:00
|
|
|
#include <debug.h>
|
2004-12-30 16:05:12 +08:00
|
|
|
#include <reactos/exeformat.h>
|
|
|
|
|
2005-11-29 07:25:31 +08:00
|
|
|
#if defined (ALLOC_PRAGMA)
|
|
|
|
#pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
|
|
|
|
#pragma alloc_text(INIT, MmInitSectionImplementation)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2001-12-31 09:53:46 +08:00
|
|
|
/* TYPES *********************************************************************/
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2004-04-11 06:36:07 +08:00
|
|
|
PMM_SECTION_SEGMENT Segment;
|
|
|
|
ULONG Offset;
|
|
|
|
BOOLEAN WasDirty;
|
|
|
|
BOOLEAN Private;
|
|
|
|
}
|
|
|
|
MM_SECTION_PAGEOUT_CONTEXT;
|
2001-12-31 09:53:46 +08:00
|
|
|
|
1998-10-05 12:01:30 +08:00
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
|
2005-11-22 10:30:18 +08:00
|
|
|
POBJECT_TYPE MmSectionObjectType = NULL;
|
1998-10-05 12:01:30 +08:00
|
|
|
|
2001-01-28 23:17:52 +08:00
|
|
|
static GENERIC_MAPPING MmpSectionMapping = {
|
2004-04-11 06:36:07 +08: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 23:17:52 +08:00
|
|
|
|
2002-01-01 03:06:49 +08:00
|
|
|
#define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
|
2004-08-01 15:24:59 +08:00
|
|
|
#define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
|
2002-01-01 03:06:49 +08: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-30 01:24:43 +08:00
|
|
|
|
2005-02-15 23:46:22 +08: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 12:27:26 +08:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
2006-07-27 08:22:36 +08:00
|
|
|
PFILE_OBJECT
|
|
|
|
NTAPI
|
|
|
|
MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section)
|
|
|
|
{
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(Section);
|
|
|
|
|
|
|
|
/* Return the file object */
|
|
|
|
return Section->FileObject; // Section->ControlArea->FileObject on NT
|
|
|
|
}
|
|
|
|
|
2006-10-23 04:56:24 +08:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section,
|
2006-11-30 13:22:20 +08:00
|
|
|
OUT POBJECT_NAME_INFORMATION *ModuleName)
|
2006-10-23 04:56:24 +08:00
|
|
|
{
|
2006-11-30 13:22:20 +08:00
|
|
|
POBJECT_NAME_INFORMATION ObjectNameInfo;
|
|
|
|
NTSTATUS Status;
|
|
|
|
ULONG ReturnLength;
|
|
|
|
|
|
|
|
/* Make sure it's an image section */
|
|
|
|
*ModuleName = NULL;
|
|
|
|
if (!(Section->AllocationAttributes & SEC_IMAGE))
|
|
|
|
{
|
|
|
|
/* It's not, fail */
|
|
|
|
return STATUS_SECTION_NOT_IMAGE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate memory for our structure */
|
|
|
|
ObjectNameInfo = ExAllocatePoolWithTag(PagedPool,
|
|
|
|
1024,
|
|
|
|
TAG('M', 'm', ' ', ' '));
|
|
|
|
if (!ObjectNameInfo) return STATUS_NO_MEMORY;
|
|
|
|
|
|
|
|
/* Query the name */
|
|
|
|
Status = ObQueryNameString(Section->FileObject,
|
|
|
|
ObjectNameInfo,
|
|
|
|
1024,
|
|
|
|
&ReturnLength);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Failed, free memory */
|
2008-08-31 23:29:21 +08:00
|
|
|
ExFreePoolWithTag(ObjectNameInfo, TAG('M', 'm', ' ', ' '));
|
2006-11-30 13:22:20 +08:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Success */
|
|
|
|
*ModuleName = ObjectNameInfo;
|
2006-10-23 04:56:24 +08:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2006-10-23 03:53:10 +08:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
MmGetFileNameForAddress(IN PVOID Address,
|
|
|
|
OUT PUNICODE_STRING ModuleName)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* FIXME: TODO.
|
2008-07-28 09:49:23 +08:00
|
|
|
* Filip says to get the MM_AVL_TABLE from EPROCESS,
|
2007-10-20 07:21:45 +08:00
|
|
|
* then use the MmMarea routines to locate the Marea that
|
2006-10-23 03:53:10 +08:00
|
|
|
* corresponds to the address. Then make sure it's a section
|
|
|
|
* view type (MEMORY_AREA_SECTION_VIEW) and use the marea's
|
|
|
|
* per-type union to get the .u.SectionView.Section pointer to
|
2006-10-23 04:56:24 +08:00
|
|
|
* the SECTION_OBJECT. Then we can use MmGetFileNameForSection
|
|
|
|
* to get the full filename.
|
2006-10-23 03:53:10 +08:00
|
|
|
*/
|
|
|
|
RtlCreateUnicodeString(ModuleName, L"C:\\ReactOS\\system32\\ntdll.dll");
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
2006-07-27 08:22:36 +08:00
|
|
|
|
2003-12-31 02:52:06 +08: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-11 06:36:07 +08:00
|
|
|
LARGE_INTEGER Timeout;
|
2003-12-31 02:52:06 +08:00
|
|
|
#ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
Timeout.QuadPart = -100000000LL; // 10 sec
|
2003-12-31 02:52:06 +08:00
|
|
|
#else
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
Timeout.QuadPart = -100000000; // 10 sec
|
2003-12-31 02:52:06 +08:00
|
|
|
#endif
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
return KeWaitForSingleObject(&PageOp->CompletionEvent, 0, KernelMode, FALSE, &Timeout);
|
2003-12-31 02:52:06 +08: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-11 06:36:07 +08:00
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
MmReleasePageOp(PageOp);
|
2003-12-31 02:52:06 +08: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-28 06:26:40 +08:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
//return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
|
2003-12-31 02:52:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-03-09 22:40:28 +08:00
|
|
|
VOID
|
|
|
|
MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment)
|
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
ULONG i;
|
|
|
|
if (Segment->Length > NR_SECTION_PAGE_TABLES * PAGE_SIZE)
|
|
|
|
{
|
2003-06-07 05:00:28 +08:00
|
|
|
for (i = 0; i < NR_SECTION_PAGE_TABLES; i++)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
if (Segment->PageDirectory.PageTables[i] != NULL)
|
|
|
|
{
|
|
|
|
ExFreePool(Segment->PageDirectory.PageTables[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-03-09 22:40:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2001-03-09 22:40:28 +08:00
|
|
|
MmFreeSectionSegments(PFILE_OBJECT FileObject)
|
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
|
|
|
|
{
|
2001-03-09 22:40:28 +08:00
|
|
|
PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
|
2003-06-28 05:28:30 +08:00
|
|
|
PMM_SECTION_SEGMENT SectionSegments;
|
|
|
|
ULONG NrSegments;
|
2001-03-09 22:40:28 +08:00
|
|
|
ULONG i;
|
|
|
|
|
2003-06-28 05:28:30 +08:00
|
|
|
ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject;
|
|
|
|
NrSegments = ImageSectionObject->NrSegments;
|
|
|
|
SectionSegments = ImageSectionObject->Segments;
|
|
|
|
for (i = 0; i < NrSegments; i++)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
if (SectionSegments[i].ReferenceCount != 0)
|
|
|
|
{
|
|
|
|
DPRINT1("Image segment %d still referenced (was %d)\n", i,
|
|
|
|
SectionSegments[i].ReferenceCount);
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
MmFreePageTablesSectionSegment(&SectionSegments[i]);
|
|
|
|
}
|
2004-12-30 16:05:12 +08:00
|
|
|
ExFreePool(ImageSectionObject->Segments);
|
2001-03-09 22:40:28 +08: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 19:34:36 +08:00
|
|
|
FileObject->SectionObjectPointer->ImageSectionObject = NULL;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
|
|
|
|
{
|
2001-03-09 22:40:28 +08: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 19:34:36 +08:00
|
|
|
Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
|
2004-04-11 06:36:07 +08:00
|
|
|
DataSectionObject;
|
2001-03-09 22:40:28 +08:00
|
|
|
|
|
|
|
if (Segment->ReferenceCount != 0)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
DPRINT1("Data segment still referenced\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-03-09 22:40:28 +08: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 19:34:36 +08:00
|
|
|
FileObject->SectionObjectPointer->DataSectionObject = NULL;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-03-09 22:40:28 +08:00
|
|
|
}
|
|
|
|
|
2003-12-31 02:52:06 +08:00
|
|
|
VOID
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2001-02-11 06:51:11 +08:00
|
|
|
MmLockSectionSegment(PMM_SECTION_SEGMENT Segment)
|
|
|
|
{
|
2003-06-28 05:28:30 +08:00
|
|
|
ExAcquireFastMutex(&Segment->Lock);
|
2001-02-11 06:51:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2001-02-11 06:51:11 +08:00
|
|
|
MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment)
|
|
|
|
{
|
2003-06-28 05:28:30 +08:00
|
|
|
ExReleaseFastMutex(&Segment->Lock);
|
2001-02-11 06:51:11 +08:00
|
|
|
}
|
|
|
|
|
2003-12-31 02:52:06 +08:00
|
|
|
VOID
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2001-02-11 06:51:11 +08:00
|
|
|
MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
|
2004-04-11 06:36:07 +08:00
|
|
|
ULONG Offset,
|
|
|
|
ULONG Entry)
|
2000-04-04 05:54:42 +08:00
|
|
|
{
|
|
|
|
PSECTION_PAGE_TABLE Table;
|
|
|
|
ULONG DirectoryOffset;
|
|
|
|
ULONG TableOffset;
|
2003-06-07 05:00:28 +08:00
|
|
|
|
|
|
|
if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
|
|
|
|
}
|
2003-06-07 05:00:28 +08:00
|
|
|
else
|
2004-04-11 06:36:07 +08: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 23:13:37 +08:00
|
|
|
ExAllocatePoolWithTag(NonPagedPool, sizeof(SECTION_PAGE_TABLE),
|
2004-04-11 06:36:07 +08:00
|
|
|
TAG_SECTION_PAGE_TABLE);
|
|
|
|
if (Table == NULL)
|
2003-06-07 05:00:28 +08:00
|
|
|
{
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
memset(Table, 0, sizeof(SECTION_PAGE_TABLE));
|
|
|
|
DPRINT("Table %x\n", Table);
|
|
|
|
}
|
|
|
|
}
|
2000-04-04 05:54:42 +08:00
|
|
|
TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
|
2002-01-01 03:06:49 +08:00
|
|
|
Table->Entry[TableOffset] = Entry;
|
2000-04-04 05:54:42 +08:00
|
|
|
}
|
|
|
|
|
2001-03-30 01:24:43 +08:00
|
|
|
|
2003-12-31 02:52:06 +08:00
|
|
|
ULONG
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2001-02-11 06:51:11 +08:00
|
|
|
MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
|
2004-04-11 06:36:07 +08:00
|
|
|
ULONG Offset)
|
2000-04-04 05:54:42 +08:00
|
|
|
{
|
|
|
|
PSECTION_PAGE_TABLE Table;
|
2000-06-25 11:59:17 +08:00
|
|
|
ULONG Entry;
|
2000-04-04 05:54:42 +08:00
|
|
|
ULONG DirectoryOffset;
|
|
|
|
ULONG TableOffset;
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2007-01-06 10:34:58 +08:00
|
|
|
DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment, Offset);
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2003-06-07 05:00:28 +08:00
|
|
|
if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
|
|
|
|
}
|
2003-06-07 05:00:28 +08:00
|
|
|
else
|
2004-04-11 06:36:07 +08: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-04 05:54:42 +08:00
|
|
|
TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
|
2002-01-01 03:06:49 +08:00
|
|
|
Entry = Table->Entry[TableOffset];
|
2000-04-04 05:54:42 +08:00
|
|
|
return(Entry);
|
|
|
|
}
|
|
|
|
|
2001-12-31 09:53:46 +08:00
|
|
|
VOID
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2001-03-30 01:24:43 +08:00
|
|
|
MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
|
2004-04-11 06:36:07 +08:00
|
|
|
ULONG Offset)
|
2001-03-30 01:24:43 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
ULONG Entry;
|
2001-03-30 01:24:43 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
|
|
|
|
if (Entry == 0)
|
|
|
|
{
|
2001-03-30 01:24:43 +08:00
|
|
|
DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
|
|
|
|
{
|
2001-03-30 01:24:43 +08:00
|
|
|
DPRINT1("Maximum share count reached\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
if (IS_SWAP_FROM_SSE(Entry))
|
|
|
|
{
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1);
|
|
|
|
MmSetPageEntrySectionSegment(Segment, Offset, Entry);
|
2001-03-30 01:24:43 +08:00
|
|
|
}
|
|
|
|
|
2001-12-31 09:53:46 +08:00
|
|
|
BOOLEAN
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2006-05-11 01:47:44 +08:00
|
|
|
MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section,
|
2004-04-11 06:36:07 +08:00
|
|
|
PMM_SECTION_SEGMENT Segment,
|
|
|
|
ULONG Offset,
|
|
|
|
BOOLEAN Dirty,
|
|
|
|
BOOLEAN PageOut)
|
2001-03-30 01:24:43 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
ULONG Entry;
|
|
|
|
BOOLEAN IsDirectMapped = FALSE;
|
2001-03-30 01:24:43 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
|
|
|
|
if (Entry == 0)
|
|
|
|
{
|
2003-12-22 03:12:19 +08:00
|
|
|
DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
if (SHARE_COUNT_FROM_SSE(Entry) == 0)
|
|
|
|
{
|
2001-03-30 01:24:43 +08:00
|
|
|
DPRINT1("Zero share count for unshare\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
if (IS_SWAP_FROM_SSE(Entry))
|
|
|
|
{
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08: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 09:53:46 +08:00
|
|
|
PFILE_OBJECT FileObject;
|
2003-02-14 06:24:19 +08:00
|
|
|
PBCB Bcb;
|
2002-08-15 04:58:39 +08:00
|
|
|
SWAPENTRY SavedSwapEntry;
|
2004-08-01 15:24:59 +08:00
|
|
|
PFN_TYPE Page;
|
2003-06-07 05:00:28 +08:00
|
|
|
BOOLEAN IsImageSection;
|
|
|
|
ULONG FileOffset;
|
|
|
|
|
|
|
|
FileOffset = Offset + Segment->FileOffset;
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2003-06-07 05:00:28 +08:00
|
|
|
IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2004-08-01 15:24:59 +08:00
|
|
|
Page = PFN_FROM_SSE(Entry);
|
2001-12-31 09:53:46 +08:00
|
|
|
FileObject = Section->FileObject;
|
2003-12-31 22:52:06 +08:00
|
|
|
if (FileObject != NULL &&
|
2005-01-02 15:04:56 +08:00
|
|
|
!(Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
|
2004-04-11 06:36:07 +08: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-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-08-15 04:58:39 +08:00
|
|
|
|
|
|
|
SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
|
2003-07-15 04:14:11 +08:00
|
|
|
if (SavedSwapEntry == 0)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
if (!PageOut &&
|
|
|
|
((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
|
2005-01-02 15:04:56 +08:00
|
|
|
(Segment->Characteristics & IMAGE_SCN_MEM_SHARED)))
|
2004-04-11 06:36:07 +08: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-15 04:14:11 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-07-15 04:14:11 +08:00
|
|
|
else
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
|
2005-01-02 15:04:56 +08:00
|
|
|
(Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
if (!PageOut)
|
|
|
|
{
|
|
|
|
if (Dirty)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* FIXME:
|
2005-05-09 09:38:29 +08:00
|
|
|
* We hold all locks. Nobody can do something with the current
|
2004-04-11 06:36:07 +08:00
|
|
|
* process and the current segment (also not within an other process).
|
|
|
|
*/
|
|
|
|
NTSTATUS Status;
|
2004-08-01 15:24:59 +08:00
|
|
|
Status = MmWriteToSwapPage(SavedSwapEntry, Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status);
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08: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-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-12-31 09:53:46 +08:00
|
|
|
MmSetPageEntrySectionSegment(Segment, Offset, Entry);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
return(SHARE_COUNT_FROM_SSE(Entry) > 0);
|
2003-06-07 05:00:28 +08:00
|
|
|
}
|
|
|
|
|
2006-09-07 13:07:34 +08:00
|
|
|
BOOLEAN MiIsPageFromCache(PMEMORY_AREA MemoryArea,
|
2004-04-11 06:36:07 +08:00
|
|
|
ULONG SegOffset)
|
2003-06-07 05:00:28 +08:00
|
|
|
{
|
2005-01-02 15:04:56 +08:00
|
|
|
if (!(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2003-12-31 22:52:06 +08: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-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
2001-03-30 01:24:43 +08:00
|
|
|
}
|
|
|
|
|
2001-04-04 01:25:50 +08:00
|
|
|
NTSTATUS
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2001-04-04 01:25:50 +08:00
|
|
|
MiReadPage(PMEMORY_AREA MemoryArea,
|
2004-04-11 06:36:07 +08:00
|
|
|
ULONG SegOffset,
|
2004-08-01 15:24:59 +08:00
|
|
|
PPFN_TYPE Page)
|
2004-04-11 06:36:07 +08: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-04 01:25:50 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08: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-23 04:43:58 +08:00
|
|
|
ASSERT(Bcb);
|
2004-04-11 06:36:07 +08: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 15:24:59 +08:00
|
|
|
(SegOffset + PAGE_SIZE <= RawLength || !IsImageSection) &&
|
2005-01-02 15:04:56 +08:00
|
|
|
!(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2001-09-26 03:41:38 +08: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-14 06:24:19 +08:00
|
|
|
Status = CcRosGetCacheSegment(Bcb,
|
2004-04-11 06:36:07 +08:00
|
|
|
FileOffset,
|
|
|
|
&BaseOffset,
|
|
|
|
&BaseAddress,
|
|
|
|
&UptoDate,
|
|
|
|
&CacheSeg);
|
2001-04-04 01:25:50 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
return(Status);
|
|
|
|
}
|
2001-04-04 01:25:50 +08:00
|
|
|
if (!UptoDate)
|
2004-04-11 06:36:07 +08: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-26 03:41:38 +08:00
|
|
|
/*
|
|
|
|
* Retrieve the page from the cache segment that we actually want.
|
|
|
|
*/
|
2004-01-05 22:28:21 +08:00
|
|
|
(*Page) = MmGetPhysicalAddress((char*)BaseAddress +
|
2007-08-05 19:27:39 +08:00
|
|
|
FileOffset - BaseOffset).LowPart >> PAGE_SHIFT;
|
2001-04-04 01:25:50 +08:00
|
|
|
|
2003-02-14 06:24:19 +08:00
|
|
|
CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, TRUE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-11-06 04:50:02 +08:00
|
|
|
PVOID PageAddr;
|
2003-06-07 05:00:28 +08:00
|
|
|
ULONG CacheSegOffset;
|
2001-04-04 01:25:50 +08:00
|
|
|
/*
|
|
|
|
* Allocate a page, this is rather complicated by the possibility
|
|
|
|
* we might have to move other things out of memory
|
|
|
|
*/
|
2001-12-31 09:53:46 +08:00
|
|
|
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page);
|
2002-01-01 13:09:50 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
return(Status);
|
|
|
|
}
|
2003-02-14 06:24:19 +08:00
|
|
|
Status = CcRosGetCacheSegment(Bcb,
|
2004-04-11 06:36:07 +08:00
|
|
|
FileOffset,
|
|
|
|
&BaseOffset,
|
|
|
|
&BaseAddress,
|
|
|
|
&UptoDate,
|
|
|
|
&CacheSeg);
|
2002-11-06 04:50:02 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
return(Status);
|
|
|
|
}
|
2002-11-06 04:50:02 +08:00
|
|
|
if (!UptoDate)
|
2004-04-11 06:36:07 +08: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;
|
|
|
|
}
|
|
|
|
}
|
2005-01-26 06:50:47 +08:00
|
|
|
PageAddr = MmCreateHyperspaceMapping(*Page);
|
2003-06-07 05:00:28 +08:00
|
|
|
CacheSegOffset = BaseOffset + CacheSeg->Bcb->CacheSegmentSize - FileOffset;
|
|
|
|
Length = RawLength - SegOffset;
|
|
|
|
if (Length <= CacheSegOffset && Length <= PAGE_SIZE)
|
|
|
|
{
|
2003-12-31 02:52:06 +08:00
|
|
|
memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, Length);
|
2003-06-07 05:00:28 +08:00
|
|
|
}
|
|
|
|
else if (CacheSegOffset >= PAGE_SIZE)
|
2002-08-28 15:13:04 +08:00
|
|
|
{
|
2003-12-31 02:52:06 +08:00
|
|
|
memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, PAGE_SIZE);
|
2002-08-28 15:13:04 +08:00
|
|
|
}
|
2002-11-06 04:50:02 +08:00
|
|
|
else
|
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, CacheSegOffset);
|
2003-02-14 06:24:19 +08:00
|
|
|
CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
Status = CcRosGetCacheSegment(Bcb,
|
|
|
|
FileOffset + CacheSegOffset,
|
|
|
|
&BaseOffset,
|
|
|
|
&BaseAddress,
|
|
|
|
&UptoDate,
|
|
|
|
&CacheSeg);
|
2002-11-06 04:50:02 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2005-01-26 06:50:47 +08:00
|
|
|
MmDeleteHyperspaceMapping(PageAddr);
|
2004-04-11 06:36:07 +08:00
|
|
|
return(Status);
|
|
|
|
}
|
2002-11-06 04:50:02 +08:00
|
|
|
if (!UptoDate)
|
2004-04-11 06:36:07 +08: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);
|
2005-01-26 06:50:47 +08:00
|
|
|
MmDeleteHyperspaceMapping(PageAddr);
|
2004-04-11 06:36:07 +08:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
2003-06-07 05:00:28 +08:00
|
|
|
if (Length < PAGE_SIZE)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, Length - CacheSegOffset);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-12-31 02:52:06 +08:00
|
|
|
memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, PAGE_SIZE - CacheSegOffset);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2002-11-06 04:50:02 +08:00
|
|
|
}
|
2003-02-14 06:24:19 +08:00
|
|
|
CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
|
2005-01-26 06:50:47 +08:00
|
|
|
MmDeleteHyperspaceMapping(PageAddr);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
2001-04-04 01:25:50 +08:00
|
|
|
}
|
2001-03-30 01:24:43 +08:00
|
|
|
|
2001-10-11 06:40:36 +08:00
|
|
|
NTSTATUS
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2008-07-28 09:49:23 +08:00
|
|
|
MmNotPresentFaultSectionView(PMM_AVL_TABLE AddressSpace,
|
2004-04-11 06:36:07 +08:00
|
|
|
MEMORY_AREA* MemoryArea,
|
|
|
|
PVOID Address,
|
|
|
|
BOOLEAN Locked)
|
2000-06-25 11:59:17 +08:00
|
|
|
{
|
2003-06-07 05:00:28 +08:00
|
|
|
ULONG Offset;
|
2004-08-01 15:24:59 +08:00
|
|
|
PFN_TYPE Page;
|
2000-06-25 11:59:17 +08:00
|
|
|
NTSTATUS Status;
|
2005-01-03 01:55:06 +08:00
|
|
|
PVOID PAddress;
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2001-02-11 06:51:11 +08:00
|
|
|
PMM_SECTION_SEGMENT Segment;
|
2000-06-25 11:59:17 +08:00
|
|
|
ULONG Entry;
|
|
|
|
ULONG Entry1;
|
2001-02-11 06:51:11 +08:00
|
|
|
ULONG Attributes;
|
2001-03-14 00:25:55 +08:00
|
|
|
PMM_PAGEOP PageOp;
|
2002-08-11 00:41:20 +08:00
|
|
|
PMM_REGION Region;
|
2006-09-07 13:07:34 +08: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-28 07:53:04 +08:00
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
|
|
|
|
2000-06-27 03:41:43 +08: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-28 07:53:04 +08:00
|
|
|
if (MmIsPagePresent(Process, Address))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
if (Locked)
|
|
|
|
{
|
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-28 07:53:04 +08:00
|
|
|
MmLockPage(MmGetPfnForProcess(Process, Address));
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2005-01-03 01:55:06 +08:00
|
|
|
PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
|
2007-10-20 07:21:45 +08:00
|
|
|
Offset = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress
|
2005-06-12 18:25:49 +08:00
|
|
|
+ MemoryArea->Data.SectionData.ViewOffset;
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2001-02-11 06:51:11 +08:00
|
|
|
Segment = MemoryArea->Data.SectionData.Segment;
|
2000-06-25 11:59:17 +08:00
|
|
|
Section = MemoryArea->Data.SectionData.Section;
|
2005-01-03 01:55:06 +08:00
|
|
|
Region = MmFindRegion(MemoryArea->StartingAddress,
|
2004-04-11 06:36:07 +08:00
|
|
|
&MemoryArea->Data.SectionData.RegionListHead,
|
|
|
|
Address, NULL);
|
2003-06-28 05:28:30 +08:00
|
|
|
/*
|
|
|
|
* Lock the segment
|
|
|
|
*/
|
2001-02-11 06:51:11 +08:00
|
|
|
MmLockSectionSegment(Segment);
|
2002-08-30 06:12:16 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if this page needs to be mapped COW
|
|
|
|
*/
|
|
|
|
if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
|
2004-08-01 15:24:59 +08:00
|
|
|
(Region->Protect == PAGE_READWRITE ||
|
|
|
|
Region->Protect == PAGE_EXECUTE_READWRITE))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ;
|
|
|
|
}
|
2002-08-30 06:12:16 +08:00
|
|
|
else
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
Attributes = Region->Protect;
|
|
|
|
}
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2001-03-14 00:25:55 +08:00
|
|
|
/*
|
|
|
|
* Get or create a page operation descriptor
|
|
|
|
*/
|
2005-01-26 08:03:05 +08:00
|
|
|
PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset, MM_PAGEOP_PAGEIN, FALSE);
|
2001-03-14 00:25:55 +08:00
|
|
|
if (PageOp == NULL)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
DPRINT1("MmGetPageOp failed\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-03-14 00:25:55 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if someone else is already handling this fault, if so wait
|
|
|
|
* for them
|
|
|
|
*/
|
|
|
|
if (PageOp->Thread != PsGetCurrentThread())
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
Status = MmspWaitForPageOpCompletionEvent(PageOp);
|
|
|
|
/*
|
2007-01-06 10:34:58 +08:00
|
|
|
* Check for various strange conditions
|
|
|
|
*/
|
2004-04-11 06:36:07 +08:00
|
|
|
if (Status != STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
DPRINT1("Failed to wait for page op, status = %x\n", Status);
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
if (PageOp->Status == STATUS_PENDING)
|
|
|
|
{
|
|
|
|
DPRINT1("Woke for page op before completion\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
/*
|
2007-01-06 10:34:58 +08:00
|
|
|
* If this wasn't a pagein then restart the operation
|
|
|
|
*/
|
2004-04-11 06:36:07 +08:00
|
|
|
if (PageOp->OpType != MM_PAGEOP_PAGEIN)
|
|
|
|
{
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(STATUS_MM_RESTART_OPERATION);
|
|
|
|
}
|
2002-01-01 03:06:49 +08:00
|
|
|
|
2004-04-11 06:36:07 +08: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 10:34:58 +08: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-28 07:53:04 +08:00
|
|
|
if (!MmIsPagePresent(Process, Address))
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
HasSwapEntry = MmIsPageSwapEntry(Process, (PVOID)PAddress);
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
if (PAGE_FROM_SSE(Entry) == 0 || HasSwapEntry)
|
2003-06-07 05:00:28 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
/*
|
2005-05-09 09:38:29 +08:00
|
|
|
* The page was a private page in another or in our address space
|
2007-01-06 10:34:58 +08:00
|
|
|
*/
|
2004-04-11 06:36:07 +08:00
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_MM_RESTART_OPERATION);
|
2003-06-07 05:00:28 +08:00
|
|
|
}
|
2001-03-14 00:25:55 +08:00
|
|
|
|
2004-08-01 15:24:59 +08:00
|
|
|
Page = PFN_FROM_SSE(Entry);
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
MmSharePageEntrySectionSegment(Segment, Offset);
|
|
|
|
|
2005-03-16 06:07:05 +08: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-28 07:53:04 +08:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address,
|
|
|
|
Attributes,
|
2004-08-01 15:24:59 +08:00
|
|
|
&Page,
|
|
|
|
1);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
2003-06-28 05:28:30 +08:00
|
|
|
{
|
2007-01-06 10:34:58 +08:00
|
|
|
DPRINT1("Unable to create virtual mapping\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2003-12-31 02:52:06 +08: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-28 07:53:04 +08:00
|
|
|
MmInsertRmap(Page, Process, (PVOID)PAddress);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
if (Locked)
|
|
|
|
{
|
|
|
|
MmLockPage(Page);
|
|
|
|
}
|
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
1999-11-24 19:51:55 +08: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-28 07:53:04 +08:00
|
|
|
HasSwapEntry = MmIsPageSwapEntry(Process, (PVOID)PAddress);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (HasSwapEntry)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Must be private page we have swapped out.
|
|
|
|
*/
|
|
|
|
SWAPENTRY SwapEntry;
|
2001-02-11 06:51:11 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
/*
|
|
|
|
* Sanity check
|
2007-01-06 10:34:58 +08:00
|
|
|
*/
|
2004-04-11 06:36:07 +08:00
|
|
|
if (Segment->Flags & MM_PAGEFILE_SEGMENT)
|
|
|
|
{
|
|
|
|
DPRINT1("Found a swaped out private page in a pagefile section.\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-04-05 06:21:32 +08:00
|
|
|
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
MmDeletePageFileMapping(Process, (PVOID)PAddress, &SwapEntry);
|
2001-02-11 06:51:11 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2004-01-31 07:57:58 +08:00
|
|
|
|
2004-08-01 15:24:59 +08:00
|
|
|
Status = MmReadFromSwapPage(SwapEntry, Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address,
|
|
|
|
Region->Protect,
|
2004-08-01 15:24:59 +08:00
|
|
|
&Page,
|
|
|
|
1);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
return(Status);
|
|
|
|
}
|
2004-01-31 07:57:58 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
/*
|
2004-08-24 06:29:43 +08:00
|
|
|
* Store the swap entry for later use.
|
|
|
|
*/
|
2004-04-11 06:36:07 +08:00
|
|
|
MmSetSavedSwapEntryPage(Page, SwapEntry);
|
|
|
|
|
|
|
|
/*
|
2007-01-06 10:34:58 +08: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-28 07:53:04 +08:00
|
|
|
MmInsertRmap(Page, Process, (PVOID)PAddress);
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
/*
|
2007-01-06 10:34:58 +08:00
|
|
|
* Finish the operation
|
|
|
|
*/
|
2004-04-11 06:36:07 +08:00
|
|
|
if (Locked)
|
|
|
|
{
|
2004-08-01 15:24:59 +08:00
|
|
|
MmLockPage(Page);
|
2004-04-11 06:36:07 +08: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 10:34:58 +08:00
|
|
|
* Just map the desired physical page
|
|
|
|
*/
|
2005-06-12 18:25:49 +08: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-28 07:53:04 +08:00
|
|
|
Status = MmCreateVirtualMappingUnsafe(Process,
|
2005-03-16 06:07:05 +08:00
|
|
|
Address,
|
|
|
|
Region->Protect,
|
|
|
|
&Page,
|
|
|
|
1);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-03-16 06:07:05 +08:00
|
|
|
DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Don't add an rmap entry since the page mapped could be for
|
2007-01-06 10:34:58 +08:00
|
|
|
* anything.
|
|
|
|
*/
|
2004-04-11 06:36:07 +08:00
|
|
|
if (Locked)
|
|
|
|
{
|
2005-03-16 06:07:05 +08:00
|
|
|
MmLockPageUnsafe(Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-01-06 10:34:58 +08:00
|
|
|
* Cleanup and release locks
|
|
|
|
*/
|
2004-04-11 06:36:07 +08: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 15:34:54 +08:00
|
|
|
if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
|
2004-04-11 06:36:07 +08: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-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address,
|
|
|
|
Region->Protect,
|
2004-08-01 15:24:59 +08:00
|
|
|
&Page,
|
|
|
|
1);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
MmInsertRmap(Page, Process, (PVOID)PAddress);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (Locked)
|
|
|
|
{
|
|
|
|
MmLockPage(Page);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-01-06 10:34:58 +08:00
|
|
|
* Cleanup and release locks
|
|
|
|
*/
|
2004-04-11 06:36:07 +08: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 10:34:58 +08: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-11 06:36:07 +08:00
|
|
|
|
|
|
|
/*
|
2007-01-06 10:34:58 +08:00
|
|
|
* Release all our locks and read in the page from disk
|
|
|
|
*/
|
2004-04-11 06:36:07 +08:00
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
|
|
|
|
if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
|
2004-08-01 15:24:59 +08:00
|
|
|
(Offset >= PAGE_ROUND_UP(Segment->RawLength) && Section->AllocationAttributes & SEC_IMAGE))
|
2004-04-11 06:36:07 +08: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 10:34:58 +08:00
|
|
|
* Relock the address space and segment
|
|
|
|
*/
|
2004-04-11 06:36:07 +08:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
MmLockSectionSegment(Segment);
|
|
|
|
|
|
|
|
/*
|
2007-01-06 10:34:58 +08:00
|
|
|
* Check the entry. No one should change the status of a page
|
|
|
|
* that has a pending page-in.
|
|
|
|
*/
|
2004-04-11 06:36:07 +08:00
|
|
|
Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
|
|
|
|
if (Entry != Entry1)
|
|
|
|
{
|
2007-01-06 10:34:58 +08:00
|
|
|
DPRINT1("Someone changed ppte entry while we slept\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-01-06 10:34:58 +08:00
|
|
|
* Mark the offset within the section as having valid, in-memory
|
|
|
|
* data
|
|
|
|
*/
|
2004-08-01 15:24:59 +08:00
|
|
|
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address,
|
|
|
|
Attributes,
|
2004-08-01 15:24:59 +08:00
|
|
|
&Page,
|
|
|
|
1);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2007-01-06 10:34:58 +08:00
|
|
|
DPRINT1("Unable to create virtual mapping\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
MmInsertRmap(Page, Process, (PVOID)PAddress);
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
if (Locked)
|
|
|
|
{
|
|
|
|
MmLockPage(Page);
|
|
|
|
}
|
|
|
|
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 10:50:53 +08:00
|
|
|
* Release all our locks and read in the page from disk
|
|
|
|
*/
|
2004-04-11 06:36:07 +08:00
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
|
|
|
|
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
2004-08-01 15:24:59 +08:00
|
|
|
Status = MmReadFromSwapPage(SwapEntry, Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-01-06 10:34:58 +08:00
|
|
|
* Relock the address space and segment
|
|
|
|
*/
|
2004-04-11 06:36:07 +08:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
MmLockSectionSegment(Segment);
|
|
|
|
|
|
|
|
/*
|
2007-01-06 10:34:58 +08:00
|
|
|
* Check the entry. No one should change the status of a page
|
|
|
|
* that has a pending page-in.
|
|
|
|
*/
|
2004-04-11 06:36:07 +08:00
|
|
|
Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
|
|
|
|
if (Entry != Entry1)
|
|
|
|
{
|
2007-01-06 10:34:58 +08:00
|
|
|
DPRINT1("Someone changed ppte entry while we slept\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-01-06 10:34:58 +08:00
|
|
|
* Mark the offset within the section as having valid, in-memory
|
|
|
|
* data
|
|
|
|
*/
|
2004-08-01 15:24:59 +08:00
|
|
|
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
|
2004-04-11 06:36:07 +08:00
|
|
|
MmSetPageEntrySectionSegment(Segment, Offset, Entry);
|
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
|
|
|
|
/*
|
2007-01-06 10:34:58 +08:00
|
|
|
* Save the swap entry.
|
|
|
|
*/
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address,
|
|
|
|
Region->Protect,
|
2004-08-01 15:24:59 +08:00
|
|
|
&Page,
|
|
|
|
1);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2007-01-06 10:34:58 +08:00
|
|
|
DPRINT1("Unable to create virtual mapping\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
MmInsertRmap(Page, Process, (PVOID)PAddress);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (Locked)
|
|
|
|
{
|
|
|
|
MmLockPage(Page);
|
|
|
|
}
|
|
|
|
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 10:34:58 +08:00
|
|
|
* take another reference to the page
|
|
|
|
*/
|
2004-04-11 06:36:07 +08:00
|
|
|
|
2004-08-01 15:24:59 +08:00
|
|
|
Page = PFN_FROM_SSE(Entry);
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address,
|
|
|
|
Attributes,
|
2004-08-01 15:24:59 +08:00
|
|
|
&Page,
|
|
|
|
1);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2007-01-06 10:34:58 +08:00
|
|
|
DPRINT1("Unable to create virtual mapping\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
MmInsertRmap(Page, Process, (PVOID)PAddress);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (Locked)
|
|
|
|
{
|
|
|
|
MmLockPage(Page);
|
|
|
|
}
|
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2008-07-28 09:49:23 +08:00
|
|
|
MmAccessFaultSectionView(PMM_AVL_TABLE AddressSpace,
|
2004-04-11 06:36:07 +08:00
|
|
|
MEMORY_AREA* MemoryArea,
|
|
|
|
PVOID Address,
|
|
|
|
BOOLEAN Locked)
|
|
|
|
{
|
|
|
|
PMM_SECTION_SEGMENT Segment;
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2004-08-01 15:24:59 +08:00
|
|
|
PFN_TYPE OldPage;
|
|
|
|
PFN_TYPE NewPage;
|
2004-04-11 06:36:07 +08:00
|
|
|
NTSTATUS Status;
|
2005-01-03 01:55:06 +08:00
|
|
|
PVOID PAddress;
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
|
|
|
|
2007-01-06 10:50:53 +08:00
|
|
|
DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace, MemoryArea, Address, Locked);
|
|
|
|
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
if (!MmIsPagePresent(Process, Address) ||
|
|
|
|
MmGetPageProtect(Process, Address) & PAGE_READWRITE)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the offset of the page
|
|
|
|
*/
|
2005-01-03 01:55:06 +08:00
|
|
|
PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
|
2007-10-20 07:21:45 +08:00
|
|
|
Offset = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress
|
2005-06-12 18:25:49 +08:00
|
|
|
+ MemoryArea->Data.SectionData.ViewOffset;
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
Segment = MemoryArea->Data.SectionData.Segment;
|
|
|
|
Section = MemoryArea->Data.SectionData.Section;
|
2005-01-03 01:55:06 +08:00
|
|
|
Region = MmFindRegion(MemoryArea->StartingAddress,
|
2004-04-11 06:36:07 +08:00
|
|
|
&MemoryArea->Data.SectionData.RegionListHead,
|
|
|
|
Address, NULL);
|
|
|
|
/*
|
|
|
|
* Lock the segment
|
|
|
|
*/
|
|
|
|
MmLockSectionSegment(Segment);
|
|
|
|
|
2004-08-01 15:24:59 +08:00
|
|
|
OldPage = MmGetPfnForProcess(NULL, Address);
|
2004-04-11 06:36:07 +08:00
|
|
|
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
|
|
|
|
|
|
|
|
MmUnlockSectionSegment(Segment);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if we are doing COW
|
|
|
|
*/
|
|
|
|
if (!((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
|
|
|
|
(Region->Protect == PAGE_READWRITE ||
|
|
|
|
Region->Protect == PAGE_EXECUTE_READWRITE)))
|
|
|
|
{
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
2008-08-08 00:08:00 +08:00
|
|
|
return(STATUS_ACCESS_VIOLATION);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-02-11 06:51:11 +08:00
|
|
|
|
2004-01-31 07:57:58 +08:00
|
|
|
if (IS_SWAP_FROM_SSE(Entry) ||
|
2004-08-01 15:24:59 +08:00
|
|
|
PFN_FROM_SSE(Entry) != OldPage)
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
MmSetPageProtect(Process, PAddress, Region->Protect);
|
2004-04-11 06:36:07 +08:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
2004-01-31 07:57:58 +08:00
|
|
|
|
2001-02-11 06:51:11 +08:00
|
|
|
/*
|
2001-04-05 06:21:32 +08:00
|
|
|
* Get or create a pageop
|
2001-02-11 06:51:11 +08:00
|
|
|
*/
|
2005-01-26 08:03:05 +08:00
|
|
|
PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset,
|
2004-04-11 06:36:07 +08:00
|
|
|
MM_PAGEOP_ACCESSFAULT, FALSE);
|
2001-04-05 06:21:32 +08:00
|
|
|
if (PageOp == NULL)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
DPRINT1("MmGetPageOp failed\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-04-05 06:21:32 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait for any other operations to complete
|
|
|
|
*/
|
|
|
|
if (PageOp->Thread != PsGetCurrentThread())
|
2004-04-11 06:36:07 +08: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-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
if (PageOp->Status == STATUS_PENDING)
|
|
|
|
{
|
|
|
|
DPRINT1("Woke for page op before completion\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Restart the operation
|
|
|
|
*/
|
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
|
|
|
return(STATUS_MM_RESTART_OPERATION);
|
|
|
|
}
|
2001-04-05 06:21:32 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Release locks now we have the pageop
|
|
|
|
*/
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a page
|
|
|
|
*/
|
2001-12-31 09:53:46 +08:00
|
|
|
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
|
2003-06-07 05:00:28 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2003-06-07 05:00:28 +08:00
|
|
|
}
|
2001-02-11 06:51:11 +08:00
|
|
|
|
2001-04-05 06:21:32 +08:00
|
|
|
/*
|
|
|
|
* Copy the old page
|
|
|
|
*/
|
2005-01-26 06:50:47 +08:00
|
|
|
MiCopyFromUserPage(NewPage, PAddress);
|
2001-02-11 06:51:11 +08:00
|
|
|
|
2005-10-29 22:10:35 +08:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2002-01-01 03:06:49 +08: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-28 07:53:04 +08:00
|
|
|
MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
|
2002-01-01 03:06:49 +08:00
|
|
|
|
2001-04-05 06:21:32 +08: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-28 07:53:04 +08:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address,
|
|
|
|
Region->Protect,
|
2004-08-01 15:24:59 +08:00
|
|
|
&NewPage,
|
|
|
|
1);
|
2003-06-28 05:28:30 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
return(Status);
|
|
|
|
}
|
2001-02-11 06:51:11 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2007-01-06 10:34:58 +08:00
|
|
|
DPRINT1("Unable to create virtual mapping\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-02-14 10:53:54 +08:00
|
|
|
if (Locked)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
MmLockPage(NewPage);
|
|
|
|
MmUnlockPage(OldPage);
|
|
|
|
}
|
2001-12-31 09:53:46 +08: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-28 07:53:04 +08:00
|
|
|
MmDeleteRmap(OldPage, Process, PAddress);
|
|
|
|
MmInsertRmap(NewPage, Process, PAddress);
|
2003-06-28 05:28:30 +08:00
|
|
|
MmLockSectionSegment(Segment);
|
2003-12-31 22:52:06 +08:00
|
|
|
MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE, FALSE);
|
2003-06-28 05:28:30 +08:00
|
|
|
MmUnlockSectionSegment(Segment);
|
2001-12-31 09:53:46 +08:00
|
|
|
|
2001-04-05 06:21:32 +08:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
2003-12-31 02:52:06 +08:00
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
2003-06-28 05:28:30 +08:00
|
|
|
DPRINT("Address 0x%.8X\n", Address);
|
2001-02-11 06:51:11 +08:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2001-12-31 09:53:46 +08:00
|
|
|
VOID
|
2006-05-19 04:32:17 +08:00
|
|
|
MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
|
2001-12-31 09:53:46 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
|
2006-01-08 14:23:17 +08:00
|
|
|
BOOLEAN WasDirty;
|
2004-08-01 15:24:59 +08:00
|
|
|
PFN_TYPE Page;
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
|
2005-10-29 22:10:35 +08:00
|
|
|
if (Process)
|
|
|
|
{
|
2008-07-28 09:49:23 +08:00
|
|
|
MmLockAddressSpace(&Process->VadRoot);
|
2005-10-29 22:10:35 +08:00
|
|
|
}
|
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
MmDeleteVirtualMapping(Process,
|
|
|
|
Address,
|
|
|
|
FALSE,
|
|
|
|
&WasDirty,
|
|
|
|
&Page);
|
|
|
|
if (WasDirty)
|
|
|
|
{
|
2002-01-08 08:49:02 +08:00
|
|
|
PageOutContext->WasDirty = TRUE;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
if (!PageOutContext->Private)
|
|
|
|
{
|
2005-10-29 22:10:35 +08:00
|
|
|
MmLockSectionSegment(PageOutContext->Segment);
|
2006-05-11 01:47:44 +08:00
|
|
|
MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT)PageOutContext->Section,
|
2004-04-11 06:36:07 +08:00
|
|
|
PageOutContext->Segment,
|
|
|
|
PageOutContext->Offset,
|
|
|
|
PageOutContext->WasDirty,
|
|
|
|
TRUE);
|
2005-10-29 22:10:35 +08:00
|
|
|
MmUnlockSectionSegment(PageOutContext->Segment);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2005-10-29 22:10:35 +08:00
|
|
|
if (Process)
|
|
|
|
{
|
2008-07-28 09:49:23 +08:00
|
|
|
MmUnlockAddressSpace(&Process->VadRoot);
|
2005-10-29 22:10:35 +08:00
|
|
|
}
|
2007-10-20 07:21:45 +08:00
|
|
|
|
2005-10-29 22:10:35 +08:00
|
|
|
if (PageOutContext->Private)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2003-12-31 22:52:06 +08:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2003-12-31 22:52:06 +08:00
|
|
|
|
2005-10-24 23:56:03 +08:00
|
|
|
DPRINT("PhysicalAddress %x, Address %x\n", Page << PAGE_SHIFT, Address);
|
2001-12-31 09:53:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2008-07-28 09:49:23 +08:00
|
|
|
MmPageOutSectionView(PMM_AVL_TABLE AddressSpace,
|
2004-04-11 06:36:07 +08:00
|
|
|
MEMORY_AREA* MemoryArea,
|
|
|
|
PVOID Address,
|
|
|
|
PMM_PAGEOP PageOp)
|
2000-06-25 11:59:17 +08:00
|
|
|
{
|
2004-08-01 15:24:59 +08:00
|
|
|
PFN_TYPE Page;
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
|
|
|
|
2004-04-11 06:36:07 +08: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-20 07:21:45 +08:00
|
|
|
Context.Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
|
2005-06-12 18:25:49 +08:00
|
|
|
+ MemoryArea->Data.SectionData.ViewOffset;
|
2004-04-11 06:36:07 +08: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 15:04:56 +08:00
|
|
|
!(Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
|
2004-04-11 06:36:07 +08: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 19:34:36 +08:00
|
|
|
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2001-12-31 09:53:46 +08: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 22:52:06 +08:00
|
|
|
if ((FileOffset % PAGE_SIZE) == 0 &&
|
2004-04-11 06:36:07 +08: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 08:49:02 +08:00
|
|
|
DPRINT1("Trying to page out from physical memory section address 0x%X "
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
Process ? Process->UniqueProcessId : 0);
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
if (!MmIsPagePresent(Process, Address))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2002-01-08 08:49:02 +08: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-28 07:53:04 +08:00
|
|
|
Process ? Process->UniqueProcessId : 0, Address);
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
Page = MmGetPfnForProcess(Process, Address);
|
2004-08-01 15:24:59 +08:00
|
|
|
SwapEntry = MmGetSavedSwapEntryPage(Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Prepare the context structure for the rmap delete call.
|
|
|
|
*/
|
|
|
|
Context.WasDirty = FALSE;
|
2005-06-12 18:25:49 +08:00
|
|
|
if (Context.Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
|
2004-04-11 06:36:07 +08:00
|
|
|
IS_SWAP_FROM_SSE(Entry) ||
|
2004-08-01 15:24:59 +08:00
|
|
|
PFN_FROM_SSE(Entry) != Page)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2003-06-07 05:00:28 +08:00
|
|
|
Context.Private = TRUE;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-06-07 05:00:28 +08:00
|
|
|
Context.Private = FALSE;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-12-31 09:53:46 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
/*
|
|
|
|
* Take an additional reference to the page or the cache segment.
|
|
|
|
*/
|
|
|
|
if (DirectMapped && !Context.Private)
|
|
|
|
{
|
2003-06-07 05:00:28 +08:00
|
|
|
if(!MiIsPageFromCache(MemoryArea, Context.Offset))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
DPRINT1("Direct mapped non private page is not associated with the cache.\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-08-01 15:24:59 +08:00
|
|
|
MmReferencePage(Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2003-06-07 05:00:28 +08:00
|
|
|
|
2004-08-01 15:24:59 +08:00
|
|
|
MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping);
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2004-04-11 06:36:07 +08: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 22:52:06 +08:00
|
|
|
if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) &&
|
2005-01-02 15:04:56 +08:00
|
|
|
!(Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08: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 15:24:59 +08:00
|
|
|
SwapEntry = MmGetSavedSwapEntryPage(Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT)
|
|
|
|
{
|
2003-06-07 05:00:28 +08:00
|
|
|
if (Context.Private)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
|
|
|
|
Context.WasDirty ? "dirty" : "clean", Address);
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2004-01-28 04:13:08 +08:00
|
|
|
if (!Context.WasDirty && SwapEntry != 0)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2004-08-01 15:24:59 +08:00
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
2004-04-11 06:36:07 +08:00
|
|
|
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
|
2004-08-01 15:24:59 +08:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
2005-01-02 15:04:56 +08:00
|
|
|
else if (Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2004-01-28 04:13:08 +08:00
|
|
|
if (Context.Private)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
|
|
|
|
Context.WasDirty ? "dirty" : "clean", Address);
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2004-01-28 04:13:08 +08:00
|
|
|
if (!Context.WasDirty || SwapEntry != 0)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2004-08-01 15:24:59 +08:00
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (SwapEntry != 0)
|
|
|
|
{
|
|
|
|
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
|
|
|
|
}
|
2004-08-01 15:24:59 +08:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!Context.Private && DirectMapped)
|
|
|
|
{
|
2004-01-28 04:13:08 +08:00
|
|
|
if (SwapEntry != 0)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
|
|
|
|
Address);
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2004-01-28 04:13:08 +08:00
|
|
|
Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-12-31 09:53:46 +08:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
2003-12-31 02:52:06 +08:00
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
2001-12-31 09:53:46 +08:00
|
|
|
return(STATUS_SUCCESS);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
else if (!Context.WasDirty && !DirectMapped && !Context.Private)
|
|
|
|
{
|
2004-01-28 04:13:08 +08:00
|
|
|
if (SwapEntry != 0)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
|
|
|
|
Address);
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2004-08-01 15:24:59 +08:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2004-01-28 04:13:08 +08:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
|
|
|
|
{
|
2004-08-01 15:24:59 +08:00
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
2005-10-29 22:10:35 +08: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-28 07:53:04 +08:00
|
|
|
Status = MmCreatePageFileMapping(Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address,
|
|
|
|
SwapEntry);
|
2005-10-29 22:10:35 +08:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2003-06-07 05:00:28 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2004-08-01 15:24:59 +08:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2001-12-31 09:53:46 +08:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
2003-12-31 02:52:06 +08:00
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
2001-12-31 09:53:46 +08:00
|
|
|
return(STATUS_SUCCESS);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-12-31 09:53:46 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
/*
|
|
|
|
* If necessary, allocate an entry in the paging file for this page
|
|
|
|
*/
|
|
|
|
if (SwapEntry == 0)
|
|
|
|
{
|
2001-12-31 09:53:46 +08:00
|
|
|
SwapEntry = MmAllocSwapPage();
|
|
|
|
if (SwapEntry == 0)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
MmShowOutOfSpaceMessagePagingFile();
|
2005-10-29 22:10:35 +08:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address,
|
2005-11-14 01:28:24 +08:00
|
|
|
MemoryArea->Protect,
|
2004-08-01 15:24:59 +08: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-28 07:53:04 +08:00
|
|
|
MmSetDirtyPage(Process, Address);
|
2004-08-01 15:24:59 +08: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-28 07:53:04 +08:00
|
|
|
Process,
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address,
|
2005-11-14 01:28:24 +08:00
|
|
|
MemoryArea->Protect,
|
2004-08-01 15:24:59 +08: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-28 07:53:04 +08:00
|
|
|
MmSetDirtyPage(Process, Address);
|
2004-08-01 15:24:59 +08: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-28 07:53:04 +08:00
|
|
|
Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address);
|
2004-08-01 15:24:59 +08:00
|
|
|
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
|
2004-04-11 06:36:07 +08:00
|
|
|
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
|
|
|
|
}
|
2005-10-29 22:10:35 +08:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2004-04-11 06:36:07 +08:00
|
|
|
PageOp->Status = STATUS_UNSUCCESSFUL;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_PAGEFILE_QUOTA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write the page to the pagefile
|
|
|
|
*/
|
2004-08-01 15:24:59 +08:00
|
|
|
Status = MmWriteToSwapPage(SwapEntry, Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2003-12-31 02:52:06 +08:00
|
|
|
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
|
2004-04-11 06:36:07 +08:00
|
|
|
Status);
|
2001-12-31 09:53:46 +08:00
|
|
|
/*
|
|
|
|
* As above: undo our actions.
|
|
|
|
* FIXME: Also free the swap page.
|
|
|
|
*/
|
2005-10-29 22:10:35 +08:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2003-06-07 05:00:28 +08:00
|
|
|
if (Context.Private)
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address,
|
2005-11-14 01:28:24 +08:00
|
|
|
MemoryArea->Protect,
|
2004-08-01 15:24:59 +08: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-28 07:53:04 +08:00
|
|
|
MmSetDirtyPage(Process, Address);
|
2004-08-01 15:24:59 +08: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-28 07:53:04 +08:00
|
|
|
Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address);
|
|
|
|
}
|
2001-12-31 09:53:46 +08:00
|
|
|
else
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address,
|
2005-11-14 01:28:24 +08:00
|
|
|
MemoryArea->Protect,
|
2004-08-01 15:24:59 +08: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-28 07:53:04 +08:00
|
|
|
MmSetDirtyPage(Process, Address);
|
2004-08-01 15:24:59 +08: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-28 07:53:04 +08:00
|
|
|
Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address);
|
2004-08-01 15:24:59 +08:00
|
|
|
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
|
2004-04-11 06:36:07 +08:00
|
|
|
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
|
|
|
|
}
|
2005-10-29 22:10:35 +08:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2001-12-31 09:53:46 +08:00
|
|
|
PageOp->Status = STATUS_UNSUCCESSFUL;
|
2003-12-31 02:52:06 +08:00
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
2001-12-31 09:53:46 +08:00
|
|
|
return(STATUS_UNSUCCESSFUL);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise we have succeeded.
|
|
|
|
*/
|
2004-08-01 15:24:59 +08:00
|
|
|
DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
|
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
|
2005-01-02 15:04:56 +08:00
|
|
|
Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2004-01-28 04:13:08 +08:00
|
|
|
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-08-01 15:24:59 +08:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2002-01-01 03:06:49 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
if (Context.Private)
|
|
|
|
{
|
2005-10-29 22:10:35 +08: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-28 07:53:04 +08:00
|
|
|
Status = MmCreatePageFileMapping(Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
Address,
|
|
|
|
SwapEntry);
|
2005-10-29 22:10:35 +08:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2002-01-01 03:06:49 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-01-01 03:06:49 +08:00
|
|
|
Entry = MAKE_SWAP_SSE(SwapEntry);
|
2003-06-07 05:00:28 +08:00
|
|
|
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-12-31 09:53:46 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
2000-06-25 11:59:17 +08:00
|
|
|
}
|
|
|
|
|
2003-12-31 02:52:06 +08:00
|
|
|
NTSTATUS
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2008-07-28 09:49:23 +08:00
|
|
|
MmWritePageSectionView(PMM_AVL_TABLE AddressSpace,
|
2004-04-11 06:36:07 +08:00
|
|
|
PMEMORY_AREA MemoryArea,
|
|
|
|
PVOID Address,
|
|
|
|
PMM_PAGEOP PageOp)
|
2002-08-15 04:58:39 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
ULONG Offset;
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2004-04-11 06:36:07 +08:00
|
|
|
PMM_SECTION_SEGMENT Segment;
|
2004-08-01 15:24:59 +08:00
|
|
|
PFN_TYPE Page;
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
Address = (PVOID)PAGE_ROUND_DOWN(Address);
|
|
|
|
|
2007-10-20 07:21:45 +08:00
|
|
|
Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
|
2005-06-12 18:25:49 +08:00
|
|
|
+ MemoryArea->Data.SectionData.ViewOffset;
|
2004-04-11 06:36:07 +08: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 15:04:56 +08:00
|
|
|
!(Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
|
2004-04-11 06:36:07 +08: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 19:34:36 +08:00
|
|
|
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2002-08-15 04:58:39 +08: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 23:11:55 +08:00
|
|
|
if (((Offset + Segment->FileOffset) % PAGE_SIZE) == 0 &&
|
2004-04-11 06:36:07 +08: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-15 04:58:39 +08:00
|
|
|
DPRINT1("Trying to write back page from physical memory mapped at %X "
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
Process ? Process->UniqueProcessId : 0);
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
if (!MmIsPagePresent(Process, Address))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2002-08-15 04:58:39 +08: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-28 07:53:04 +08:00
|
|
|
Process ? Process->UniqueProcessId : 0, Address);
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
Page = MmGetPfnForProcess(Process, Address);
|
2004-08-01 15:24:59 +08:00
|
|
|
SwapEntry = MmGetSavedSwapEntryPage(Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for a private (COWed) page.
|
|
|
|
*/
|
2005-06-12 18:25:49 +08:00
|
|
|
if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
|
2004-04-11 06:36:07 +08:00
|
|
|
IS_SWAP_FROM_SSE(Entry) ||
|
2004-08-01 15:24:59 +08:00
|
|
|
PFN_FROM_SSE(Entry) != Page)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2002-08-15 04:58:39 +08:00
|
|
|
Private = TRUE;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-08-15 04:58:39 +08:00
|
|
|
Private = FALSE;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Speculatively set all mappings of the page to clean.
|
|
|
|
*/
|
2004-08-01 15:24:59 +08:00
|
|
|
MmSetCleanAllRmaps(Page);
|
2004-04-11 06:36:07 +08: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-23 04:43:58 +08:00
|
|
|
ASSERT(SwapEntry == 0);
|
2005-06-12 18:25:49 +08:00
|
|
|
CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
|
2002-08-15 04:58:39 +08:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
2003-12-31 02:52:06 +08:00
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
2002-08-15 04:58:39 +08:00
|
|
|
return(STATUS_SUCCESS);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2002-08-15 04:58:39 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
/*
|
|
|
|
* If necessary, allocate an entry in the paging file for this page
|
|
|
|
*/
|
|
|
|
if (SwapEntry == 0)
|
|
|
|
{
|
2002-08-15 04:58:39 +08:00
|
|
|
SwapEntry = MmAllocSwapPage();
|
|
|
|
if (SwapEntry == 0)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2004-08-01 15:24:59 +08:00
|
|
|
MmSetDirtyAllRmaps(Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
PageOp->Status = STATUS_UNSUCCESSFUL;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_PAGEFILE_QUOTA);
|
|
|
|
}
|
2004-08-01 15:24:59 +08:00
|
|
|
MmSetSavedSwapEntryPage(Page, SwapEntry);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write the page to the pagefile
|
|
|
|
*/
|
2004-08-01 15:24:59 +08:00
|
|
|
Status = MmWriteToSwapPage(SwapEntry, Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2003-12-31 02:52:06 +08:00
|
|
|
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
|
2004-04-11 06:36:07 +08:00
|
|
|
Status);
|
2004-08-01 15:24:59 +08:00
|
|
|
MmSetDirtyAllRmaps(Page);
|
2002-08-15 04:58:39 +08:00
|
|
|
PageOp->Status = STATUS_UNSUCCESSFUL;
|
2003-12-31 02:52:06 +08:00
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
2002-08-15 04:58:39 +08:00
|
|
|
return(STATUS_UNSUCCESSFUL);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise we have succeeded.
|
|
|
|
*/
|
2004-08-01 15:24:59 +08:00
|
|
|
DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
|
2004-04-11 06:36:07 +08:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
2002-08-15 04:58:39 +08:00
|
|
|
}
|
|
|
|
|
2006-09-07 13:07:34 +08:00
|
|
|
VOID static
|
2008-07-28 09:49:23 +08:00
|
|
|
MmAlterViewAttributes(PMM_AVL_TABLE AddressSpace,
|
2004-04-11 06:36:07 +08:00
|
|
|
PVOID BaseAddress,
|
|
|
|
ULONG RegionSize,
|
|
|
|
ULONG OldType,
|
|
|
|
ULONG OldProtect,
|
|
|
|
ULONG NewType,
|
|
|
|
ULONG NewProtect)
|
2002-08-11 00:41:20 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
PMEMORY_AREA MemoryArea;
|
|
|
|
PMM_SECTION_SEGMENT Segment;
|
2006-09-07 13:07:34 +08:00
|
|
|
BOOLEAN DoCOW = FALSE;
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
2004-04-11 06:36:07 +08:00
|
|
|
|
2005-01-03 03:14:52 +08:00
|
|
|
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
|
2004-04-11 06:36:07 +08:00
|
|
|
Segment = MemoryArea->Data.SectionData.Segment;
|
|
|
|
|
|
|
|
if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
|
|
|
|
(NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
|
|
|
|
{
|
|
|
|
DoCOW = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (OldProtect != NewProtect)
|
|
|
|
{
|
2002-11-06 04:50:02 +08:00
|
|
|
for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
if (DoCOW && MmIsPagePresent(Process, Address))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
ULONG Offset;
|
|
|
|
ULONG Entry;
|
2004-08-01 15:24:59 +08:00
|
|
|
PFN_TYPE Page;
|
2004-04-11 06:36:07 +08:00
|
|
|
|
2007-10-20 07:21:45 +08:00
|
|
|
Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
|
2005-06-12 18:25:49 +08:00
|
|
|
+ MemoryArea->Data.SectionData.ViewOffset;
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
Page = MmGetPfnForProcess(Process, Address);
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
Protect = PAGE_READONLY;
|
2005-06-12 18:25:49 +08:00
|
|
|
if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
|
2004-04-11 06:36:07 +08:00
|
|
|
IS_SWAP_FROM_SSE(Entry) ||
|
2004-08-01 15:24:59 +08:00
|
|
|
PFN_FROM_SSE(Entry) != Page)
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
if (MmIsPagePresent(Process, Address))
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
MmSetPageProtect(Process, Address,
|
2004-04-11 06:36:07 +08:00
|
|
|
Protect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-08-11 00:41:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2008-07-28 09:49:23 +08:00
|
|
|
MmProtectSectionView(PMM_AVL_TABLE AddressSpace,
|
2004-04-11 06:36:07 +08:00
|
|
|
PMEMORY_AREA MemoryArea,
|
|
|
|
PVOID BaseAddress,
|
|
|
|
ULONG Length,
|
|
|
|
ULONG Protect,
|
|
|
|
PULONG OldProtect)
|
2002-08-11 00:41:20 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
PMM_REGION Region;
|
|
|
|
NTSTATUS Status;
|
2005-01-03 01:55:06 +08:00
|
|
|
ULONG_PTR MaxLength;
|
2004-04-11 06:36:07 +08:00
|
|
|
|
2005-01-03 01:55:06 +08:00
|
|
|
MaxLength = (ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)BaseAddress;
|
|
|
|
if (Length > MaxLength)
|
|
|
|
Length = MaxLength;
|
|
|
|
|
|
|
|
Region = MmFindRegion(MemoryArea->StartingAddress,
|
2004-04-11 06:36:07 +08:00
|
|
|
&MemoryArea->Data.SectionData.RegionListHead,
|
|
|
|
BaseAddress, NULL);
|
2005-11-14 01:28:24 +08:00
|
|
|
if ((MemoryArea->Flags & SEC_NO_CHANGE) &&
|
|
|
|
Region->Protect != Protect)
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PAGE_PROTECTION;
|
|
|
|
}
|
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
*OldProtect = Region->Protect;
|
2005-01-03 01:55:06 +08:00
|
|
|
Status = MmAlterRegion(AddressSpace, MemoryArea->StartingAddress,
|
2004-04-11 06:36:07 +08:00
|
|
|
&MemoryArea->Data.SectionData.RegionListHead,
|
|
|
|
BaseAddress, Length, Region->Type, Protect,
|
|
|
|
MmAlterViewAttributes);
|
|
|
|
|
|
|
|
return(Status);
|
2002-08-11 00:41:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS STDCALL
|
|
|
|
MmQuerySectionView(PMEMORY_AREA MemoryArea,
|
2004-04-11 06:36:07 +08:00
|
|
|
PVOID Address,
|
|
|
|
PMEMORY_BASIC_INFORMATION Info,
|
|
|
|
PULONG ResultLength)
|
2002-08-11 00:41:20 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
PMM_REGION Region;
|
|
|
|
PVOID RegionBaseAddress;
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2005-06-07 04:27:49 +08:00
|
|
|
PMM_SECTION_SEGMENT Segment;
|
2004-04-11 06:36:07 +08:00
|
|
|
|
2005-01-03 01:55:06 +08:00
|
|
|
Region = MmFindRegion((PVOID)MemoryArea->StartingAddress,
|
2004-04-11 06:36:07 +08:00
|
|
|
&MemoryArea->Data.SectionData.RegionListHead,
|
|
|
|
Address, &RegionBaseAddress);
|
|
|
|
if (Region == NULL)
|
|
|
|
{
|
2003-05-14 05:28:26 +08:00
|
|
|
return STATUS_UNSUCCESSFUL;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2005-06-07 04:27:49 +08:00
|
|
|
|
2004-05-02 01:11:34 +08:00
|
|
|
Section = MemoryArea->Data.SectionData.Section;
|
|
|
|
if (Section->AllocationAttributes & SEC_IMAGE)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2005-06-07 04:27:49 +08:00
|
|
|
Segment = MemoryArea->Data.SectionData.Segment;
|
2006-09-07 13:07:34 +08:00
|
|
|
Info->AllocationBase = (PUCHAR)MemoryArea->StartingAddress - Segment->VirtualAddress;
|
2002-08-11 00:41:20 +08:00
|
|
|
Info->Type = MEM_IMAGE;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-01-03 01:55:06 +08:00
|
|
|
Info->AllocationBase = MemoryArea->StartingAddress;
|
2002-08-11 00:41:20 +08:00
|
|
|
Info->Type = MEM_MAPPED;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2005-06-07 04:27:49 +08:00
|
|
|
Info->BaseAddress = RegionBaseAddress;
|
2005-11-14 01:28:24 +08:00
|
|
|
Info->AllocationProtect = MemoryArea->Protect;
|
2005-10-24 23:56:03 +08:00
|
|
|
Info->RegionSize = Region->Length;
|
2004-05-02 01:11:34 +08:00
|
|
|
Info->State = MEM_COMMIT;
|
|
|
|
Info->Protect = Region->Protect;
|
2002-08-11 00:41:20 +08:00
|
|
|
|
2004-05-01 08:25:41 +08:00
|
|
|
*ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
|
2004-04-11 06:36:07 +08:00
|
|
|
return(STATUS_SUCCESS);
|
2002-08-11 00:41:20 +08:00
|
|
|
}
|
|
|
|
|
2003-12-31 22:52:06 +08:00
|
|
|
VOID
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2003-12-31 22:52:06 +08:00
|
|
|
MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment)
|
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
ULONG Length;
|
|
|
|
ULONG Offset;
|
|
|
|
ULONG Entry;
|
|
|
|
ULONG SavedSwapEntry;
|
2004-08-01 15:24:59 +08:00
|
|
|
PFN_TYPE Page;
|
2003-12-31 22:52:06 +08:00
|
|
|
|
2004-08-01 15:24:59 +08:00
|
|
|
Page = 0;
|
2003-12-31 22:52:06 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
Length = PAGE_ROUND_UP(Segment->Length);
|
|
|
|
for (Offset = 0; Offset < Length; Offset += PAGE_SIZE)
|
|
|
|
{
|
2003-12-31 22:52:06 +08:00
|
|
|
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
|
|
|
|
if (Entry)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
if (IS_SWAP_FROM_SSE(Entry))
|
|
|
|
{
|
|
|
|
MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-08-01 15:24:59 +08:00
|
|
|
Page = PFN_FROM_SSE(Entry);
|
2004-04-11 06:36:07 +08:00
|
|
|
SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
|
|
|
|
if (SavedSwapEntry != 0)
|
2003-12-31 22:52:06 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
|
|
|
MmFreeSwapPage(SavedSwapEntry);
|
2003-12-31 22:52:06 +08:00
|
|
|
}
|
2004-04-11 06:36:07 +08:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
|
|
|
}
|
|
|
|
MmSetPageEntrySectionSegment(Segment, Offset, 0);
|
|
|
|
}
|
|
|
|
}
|
2003-12-31 22:52:06 +08:00
|
|
|
}
|
2004-04-11 06:36:07 +08:00
|
|
|
|
2001-08-27 01:30:21 +08:00
|
|
|
VOID STDCALL
|
2000-12-28 11:38:08 +08:00
|
|
|
MmpDeleteSection(PVOID ObjectBody)
|
1999-02-02 04:58:37 +08:00
|
|
|
{
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section = (PROS_SECTION_OBJECT)ObjectBody;
|
2001-03-09 22:40:28 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
|
|
|
|
if (Section->AllocationAttributes & SEC_IMAGE)
|
|
|
|
{
|
2002-08-15 04:58:39 +08:00
|
|
|
ULONG i;
|
2003-06-28 05:28:30 +08:00
|
|
|
ULONG NrSegments;
|
2003-12-31 22:52:06 +08:00
|
|
|
ULONG RefCount;
|
2003-06-28 05:28:30 +08:00
|
|
|
PMM_SECTION_SEGMENT SectionSegments;
|
|
|
|
|
2004-08-18 10:29:37 +08: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-28 05:28:30 +08:00
|
|
|
SectionSegments = Section->ImageSection->Segments;
|
|
|
|
NrSegments = Section->ImageSection->NrSegments;
|
|
|
|
|
|
|
|
for (i = 0; i < NrSegments; i++)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2005-01-02 15:04:56 +08:00
|
|
|
if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
MmLockSectionSegment(&SectionSegments[i]);
|
|
|
|
}
|
2004-12-25 01:07:00 +08:00
|
|
|
RefCount = InterlockedDecrementUL(&SectionSegments[i].ReferenceCount);
|
2005-01-02 15:04:56 +08:00
|
|
|
if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
if (RefCount == 0)
|
|
|
|
{
|
|
|
|
MmpFreePageFileSegment(&SectionSegments[i]);
|
|
|
|
}
|
|
|
|
MmUnlockSectionSegment(&SectionSegments[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-08-18 10:29:37 +08:00
|
|
|
/*
|
|
|
|
* NOTE: Section->Segment can be NULL for short time
|
|
|
|
* during the section creating.
|
|
|
|
*/
|
|
|
|
if (Section->Segment == NULL)
|
|
|
|
return;
|
|
|
|
|
2003-08-20 08:02:31 +08:00
|
|
|
if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
MmpFreePageFileSegment(Section->Segment);
|
|
|
|
MmFreePageTablesSectionSegment(Section->Segment);
|
|
|
|
ExFreePool(Section->Segment);
|
|
|
|
Section->Segment = NULL;
|
|
|
|
}
|
2003-08-20 08:02:31 +08:00
|
|
|
else
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2006-03-05 01:27:40 +08:00
|
|
|
(void)InterlockedDecrementUL(&Section->Segment->ReferenceCount);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Section->FileObject != NULL)
|
|
|
|
{
|
2002-08-17 23:12:49 +08:00
|
|
|
CcRosDereferenceCache(Section->FileObject);
|
2001-03-09 22:40:28 +08:00
|
|
|
ObDereferenceObject(Section->FileObject);
|
|
|
|
Section->FileObject = NULL;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2000-04-04 05:54:42 +08:00
|
|
|
}
|
|
|
|
|
2001-08-27 01:30:21 +08:00
|
|
|
VOID STDCALL
|
2006-05-11 01:47:44 +08:00
|
|
|
MmpCloseSection(IN PEPROCESS Process OPTIONAL,
|
|
|
|
IN PVOID Object,
|
|
|
|
IN ACCESS_MASK GrantedAccess,
|
|
|
|
IN ULONG ProcessHandleCount,
|
|
|
|
IN ULONG SystemHandleCount)
|
2000-04-04 05:54:42 +08:00
|
|
|
{
|
2008-01-08 17:49:22 +08:00
|
|
|
DPRINT("MmpCloseSection(OB %x, HC %d)\n",
|
|
|
|
Object, ProcessHandleCount);
|
1999-02-02 04:58:37 +08:00
|
|
|
}
|
|
|
|
|
2005-09-14 09:05:50 +08:00
|
|
|
NTSTATUS
|
|
|
|
INIT_FUNCTION
|
|
|
|
NTAPI
|
2000-12-28 11:38:08 +08:00
|
|
|
MmCreatePhysicalMemorySection(VOID)
|
1998-10-05 12:01:30 +08:00
|
|
|
{
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT PhysSection;
|
2004-04-11 06:36:07 +08:00
|
|
|
NTSTATUS Status;
|
|
|
|
OBJECT_ATTRIBUTES Obj;
|
2005-06-25 22:04:56 +08:00
|
|
|
UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
|
2004-04-11 06:36:07 +08:00
|
|
|
LARGE_INTEGER SectionSize;
|
2007-01-09 16:38:07 +08:00
|
|
|
HANDLE Handle;
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the section mapping physical memory
|
|
|
|
*/
|
|
|
|
SectionSize.QuadPart = 0xFFFFFFFF;
|
|
|
|
InitializeObjectAttributes(&Obj,
|
|
|
|
&Name,
|
2005-04-28 05:44:27 +08:00
|
|
|
OBJ_PERMANENT,
|
2004-04-11 06:36:07 +08:00
|
|
|
NULL,
|
|
|
|
NULL);
|
2006-01-08 14:23:17 +08:00
|
|
|
Status = MmCreateSection((PVOID)&PhysSection,
|
2004-04-11 06:36:07 +08:00
|
|
|
SECTION_ALL_ACCESS,
|
|
|
|
&Obj,
|
|
|
|
&SectionSize,
|
|
|
|
PAGE_EXECUTE_READWRITE,
|
|
|
|
0,
|
2004-08-06 03:59:13 +08:00
|
|
|
NULL,
|
2004-04-11 06:36:07 +08:00
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2007-01-06 10:34:58 +08:00
|
|
|
DPRINT1("Failed to create PhysicalMemory section\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08: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-19 03:26:47 +08:00
|
|
|
Status = ObInsertObject(PhysSection,
|
|
|
|
NULL,
|
|
|
|
SECTION_ALL_ACCESS,
|
|
|
|
0,
|
|
|
|
NULL,
|
2007-01-09 16:38:07 +08: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-19 03:26:47 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ObDereferenceObject(PhysSection);
|
|
|
|
}
|
2007-01-09 16:38:07 +08:00
|
|
|
ObCloseHandle(Handle, KernelMode);
|
2004-04-11 06:36:07 +08:00
|
|
|
PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
|
2005-06-12 18:25:49 +08:00
|
|
|
PhysSection->Segment->Flags &= ~MM_PAGEFILE_SEGMENT;
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
return(STATUS_SUCCESS);
|
2000-12-28 11:38:08 +08:00
|
|
|
}
|
|
|
|
|
2005-09-14 09:05:50 +08:00
|
|
|
NTSTATUS
|
|
|
|
INIT_FUNCTION
|
|
|
|
NTAPI
|
2000-12-28 11:38:08 +08:00
|
|
|
MmInitSectionImplementation(VOID)
|
|
|
|
{
|
2005-05-16 01:59:33 +08:00
|
|
|
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
|
|
|
|
UNICODE_STRING Name;
|
|
|
|
|
2005-05-22 00:33:23 +08:00
|
|
|
DPRINT("Creating Section Object Type\n");
|
2007-10-20 07:21:45 +08:00
|
|
|
|
2005-05-16 01:59:33 +08:00
|
|
|
/* Initialize the Section object type */
|
|
|
|
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
|
|
|
|
RtlInitUnicodeString(&Name, L"Section");
|
|
|
|
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
|
2006-05-11 01:47:44 +08:00
|
|
|
ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(ROS_SECTION_OBJECT);
|
2005-06-07 04:27:49 +08:00
|
|
|
ObjectTypeInitializer.PoolType = PagedPool;
|
2005-05-16 01:59:33 +08:00
|
|
|
ObjectTypeInitializer.UseDefaultObject = TRUE;
|
|
|
|
ObjectTypeInitializer.GenericMapping = MmpSectionMapping;
|
|
|
|
ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection;
|
|
|
|
ObjectTypeInitializer.CloseProcedure = MmpCloseSection;
|
2007-01-10 01:18:22 +08:00
|
|
|
ObjectTypeInitializer.ValidAccessMask = SECTION_ALL_ACCESS;
|
2006-06-05 14:31:42 +08:00
|
|
|
ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &MmSectionObjectType);
|
2003-10-07 22:08:43 +08:00
|
|
|
|
2001-01-28 23:17:52 +08:00
|
|
|
return(STATUS_SUCCESS);
|
1998-10-05 12:01:30 +08:00
|
|
|
}
|
|
|
|
|
2001-02-11 06:51:11 +08:00
|
|
|
NTSTATUS
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2006-05-11 01:47:44 +08:00
|
|
|
MmCreatePageFileSection(PROS_SECTION_OBJECT *SectionObject,
|
2004-04-11 06:36:07 +08: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-06 01:34:23 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
LARGE_INTEGER MaximumSize;
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2004-04-11 06:36:07 +08:00
|
|
|
PMM_SECTION_SEGMENT Segment;
|
|
|
|
NTSTATUS Status;
|
1998-10-05 12:01:30 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
if (UMaximumSize == NULL)
|
|
|
|
{
|
2001-02-11 06:51:11 +08:00
|
|
|
return(STATUS_UNSUCCESSFUL);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
MaximumSize = *UMaximumSize;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the section
|
|
|
|
*/
|
|
|
|
Status = ObCreateObject(ExGetPreviousMode(),
|
|
|
|
MmSectionObjectType,
|
|
|
|
ObjectAttributes,
|
|
|
|
ExGetPreviousMode(),
|
|
|
|
NULL,
|
2006-05-11 01:47:44 +08:00
|
|
|
sizeof(ROS_SECTION_OBJECT),
|
2004-04-11 06:36:07 +08:00
|
|
|
0,
|
|
|
|
0,
|
2004-08-24 06:29:43 +08:00
|
|
|
(PVOID*)(PVOID)&Section);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2001-06-16 22:11:31 +08:00
|
|
|
return(Status);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize it
|
|
|
|
*/
|
|
|
|
Section->SectionPageProtection = SectionPageProtection;
|
|
|
|
Section->AllocationAttributes = AllocationAttributes;
|
2004-08-18 10:29:37 +08:00
|
|
|
Section->Segment = NULL;
|
2004-04-11 06:36:07 +08:00
|
|
|
Section->FileObject = NULL;
|
|
|
|
Section->MaximumSize = MaximumSize;
|
2005-06-06 05:12:30 +08:00
|
|
|
Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
|
2004-04-11 06:36:07 +08:00
|
|
|
TAG_MM_SECTION_SEGMENT);
|
|
|
|
if (Segment == NULL)
|
|
|
|
{
|
2001-02-11 06:51:11 +08:00
|
|
|
ObDereferenceObject(Section);
|
|
|
|
return(STATUS_NO_MEMORY);
|
2004-04-11 06:36:07 +08: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-06 03:59:13 +08:00
|
|
|
*SectionObject = Section;
|
2004-04-11 06:36:07 +08:00
|
|
|
return(STATUS_SUCCESS);
|
2001-06-16 22:11:31 +08:00
|
|
|
}
|
|
|
|
|
1998-09-06 01:34:23 +08:00
|
|
|
|
2001-02-11 06:51:11 +08:00
|
|
|
NTSTATUS
|
2005-09-14 09:05:50 +08:00
|
|
|
NTAPI
|
2006-05-11 01:47:44 +08:00
|
|
|
MmCreateDataFileSection(PROS_SECTION_OBJECT *SectionObject,
|
2004-04-11 06:36:07 +08: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 12:27:26 +08:00
|
|
|
{
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2004-04-11 06:36:07 +08: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 10:29:37 +08:00
|
|
|
FILE_STANDARD_INFORMATION FileInfo;
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the section
|
|
|
|
*/
|
|
|
|
Status = ObCreateObject(ExGetPreviousMode(),
|
|
|
|
MmSectionObjectType,
|
|
|
|
ObjectAttributes,
|
|
|
|
ExGetPreviousMode(),
|
|
|
|
NULL,
|
2006-05-11 01:47:44 +08:00
|
|
|
sizeof(ROS_SECTION_OBJECT),
|
2004-04-11 06:36:07 +08:00
|
|
|
0,
|
|
|
|
0,
|
2004-08-24 06:29:43 +08:00
|
|
|
(PVOID*)(PVOID)&Section);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2001-06-16 22:11:31 +08:00
|
|
|
return(Status);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Initialize it
|
|
|
|
*/
|
|
|
|
Section->SectionPageProtection = SectionPageProtection;
|
|
|
|
Section->AllocationAttributes = AllocationAttributes;
|
2004-08-18 10:29:37 +08:00
|
|
|
Section->Segment = NULL;
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check file access required
|
|
|
|
*/
|
|
|
|
if (SectionPageProtection & PAGE_READWRITE ||
|
|
|
|
SectionPageProtection & PAGE_EXECUTE_READWRITE)
|
|
|
|
{
|
2001-02-11 06:51:11 +08:00
|
|
|
FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-02-11 06:51:11 +08:00
|
|
|
FileAccess = FILE_READ_DATA;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reference the file handle
|
|
|
|
*/
|
|
|
|
Status = ObReferenceObjectByHandle(FileHandle,
|
|
|
|
FileAccess,
|
|
|
|
IoFileObjectType,
|
2007-09-30 21:11:36 +08:00
|
|
|
ExGetPreviousMode(),
|
2004-08-24 06:29:43 +08:00
|
|
|
(PVOID*)(PVOID)&FileObject,
|
2004-04-11 06:36:07 +08:00
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2001-02-11 06:51:11 +08:00
|
|
|
ObDereferenceObject(Section);
|
|
|
|
return(Status);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2004-08-18 10:29:37 +08: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-11 06:36:07 +08:00
|
|
|
*/
|
2005-07-27 03:38:33 +08:00
|
|
|
Status = IoQueryFileInformation(FileObject,
|
|
|
|
FileStandardInformation,
|
2004-08-18 10:29:37 +08:00
|
|
|
sizeof(FILE_STANDARD_INFORMATION),
|
2005-07-27 03:38:33 +08:00
|
|
|
&FileInfo,
|
|
|
|
&Iosb.Information);
|
2004-08-18 10:29:37 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2001-02-11 06:51:11 +08:00
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
2004-08-18 10:29:37 +08:00
|
|
|
return Status;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME: Revise this once a locking order for file size changes is
|
|
|
|
* decided
|
|
|
|
*/
|
|
|
|
if (UMaximumSize != NULL)
|
|
|
|
{
|
2001-02-11 06:51:11 +08:00
|
|
|
MaximumSize = *UMaximumSize;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-08-18 10:29:37 +08:00
|
|
|
MaximumSize = FileInfo.EndOfFile;
|
2004-08-29 06:18:24 +08:00
|
|
|
/* Mapping zero-sized files isn't allowed. */
|
|
|
|
if (MaximumSize.QuadPart == 0)
|
|
|
|
{
|
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return STATUS_FILE_INVALID;
|
|
|
|
}
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-02-11 06:51:11 +08:00
|
|
|
|
2004-08-18 10:29:37 +08:00
|
|
|
if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2005-07-27 03:38:33 +08:00
|
|
|
Status = IoSetInformation(FileObject,
|
|
|
|
FileAllocationInformation,
|
|
|
|
sizeof(LARGE_INTEGER),
|
|
|
|
&MaximumSize);
|
2002-08-15 04:58:39 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return(STATUS_SECTION_NOT_EXTENDED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FileObject->SectionObjectPointer == NULL ||
|
|
|
|
FileObject->SectionObjectPointer->SharedCacheMap == NULL)
|
|
|
|
{
|
2003-10-18 17:35:11 +08: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-11 06:36:07 +08:00
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&Iosb,
|
|
|
|
&Buffer,
|
|
|
|
sizeof (Buffer),
|
|
|
|
&Offset,
|
|
|
|
0);
|
2003-10-18 17:35:11 +08:00
|
|
|
if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return(Status);
|
|
|
|
}
|
2003-10-18 17:35:11 +08:00
|
|
|
if (FileObject->SectionObjectPointer == NULL ||
|
2004-04-11 06:36:07 +08: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-11 06:51:11 +08:00
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return(Status);
|
2004-04-11 06:36:07 +08: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-06 05:12:30 +08:00
|
|
|
Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
|
2004-04-11 06:36:07 +08:00
|
|
|
TAG_MM_SECTION_SEGMENT);
|
2001-02-11 06:51:11 +08:00
|
|
|
if (Segment == NULL)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2006-07-28 06:26:40 +08:00
|
|
|
//KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return(STATUS_NO_MEMORY);
|
|
|
|
}
|
2003-06-28 05:28:30 +08:00
|
|
|
Section->Segment = Segment;
|
2001-02-11 06:51:11 +08:00
|
|
|
Segment->ReferenceCount = 1;
|
2003-06-28 05:28:30 +08:00
|
|
|
ExInitializeFastMutex(&Segment->Lock);
|
2001-02-11 06:51:11 +08:00
|
|
|
/*
|
|
|
|
* Set the lock before assigning the segment to the file object
|
|
|
|
*/
|
2003-06-28 05:28:30 +08: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 19:34:36 +08:00
|
|
|
FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
|
2001-02-11 06:51:11 +08:00
|
|
|
|
|
|
|
Segment->FileOffset = 0;
|
2004-01-28 04:13:08 +08:00
|
|
|
Segment->Protection = SectionPageProtection;
|
2002-08-15 04:58:39 +08:00
|
|
|
Segment->Flags = MM_DATAFILE_SEGMENT;
|
2001-02-11 06:51:11 +08:00
|
|
|
Segment->Characteristics = 0;
|
2002-01-01 11:29:16 +08:00
|
|
|
Segment->WriteCopy = FALSE;
|
2001-02-11 06:51:11 +08:00
|
|
|
if (AllocationAttributes & SEC_RESERVE)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
Segment->Length = Segment->RawLength = 0;
|
|
|
|
}
|
2001-02-11 06:51:11 +08:00
|
|
|
else
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
Segment->RawLength = MaximumSize.u.LowPart;
|
|
|
|
Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
|
|
|
|
}
|
2004-12-30 16:05:12 +08:00
|
|
|
Segment->VirtualAddress = 0;
|
2004-03-04 08:07:03 +08:00
|
|
|
RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-02-11 06:51:11 +08:00
|
|
|
/*
|
|
|
|
* If the file is already mapped as a data file then we may need
|
|
|
|
* to extend it
|
2003-12-31 02:52:06 +08:00
|
|
|
*/
|
|
|
|
Segment =
|
2004-04-11 06:36:07 +08:00
|
|
|
(PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
|
|
|
|
DataSectionObject;
|
2003-06-28 05:28:30 +08:00
|
|
|
Section->Segment = Segment;
|
2006-03-05 01:27:40 +08:00
|
|
|
(void)InterlockedIncrementUL(&Segment->ReferenceCount);
|
2003-06-28 05:28:30 +08:00
|
|
|
MmLockSectionSegment(Segment);
|
|
|
|
|
2003-12-31 02:52:06 +08:00
|
|
|
if (MaximumSize.u.LowPart > Segment->RawLength &&
|
2004-04-11 06:36:07 +08: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-28 06:26:40 +08:00
|
|
|
//KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
|
2004-08-06 03:59:13 +08:00
|
|
|
*SectionObject = Section;
|
2004-04-11 06:36:07 +08:00
|
|
|
return(STATUS_SUCCESS);
|
2001-02-11 06:51:11 +08:00
|
|
|
}
|
|
|
|
|
2004-12-30 16:05:12 +08: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 14:36:31 +08:00
|
|
|
#ifdef __ELF
|
2004-12-30 16:05:12 +08:00
|
|
|
ElfFmtCreateSection
|
2008-02-07 14:36:31 +08:00
|
|
|
#endif
|
2004-12-30 16:05:12 +08: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-06 05:12:30 +08:00
|
|
|
Segments = ExAllocatePoolWithTag(NonPagedPool,
|
2004-12-30 16:05:12 +08: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-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-12-30 16:05:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
FileOffset = *Offset;
|
|
|
|
|
|
|
|
/* Negative/special offset: it cannot be used in this context */
|
|
|
|
if(FileOffset.u.HighPart < 0)
|
|
|
|
{
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-12-30 16:05:12 +08: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,
|
|
|
|
TAG('M', 'm', 'X', 'r'));
|
|
|
|
|
|
|
|
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 09:38:29 +08:00
|
|
|
|
2004-12-30 16:05:12 +08: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
|
|
|
|
{
|
2008-08-31 23:29:21 +08:00
|
|
|
ExFreePoolWithTag(Buffer, TAG('M', 'm', 'X', 'r'));
|
2004-12-30 16:05:12 +08: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 19:44:04 +08:00
|
|
|
const MM_SECTION_SEGMENT *Segment1 = (const MM_SECTION_SEGMENT *)x;
|
|
|
|
const MM_SECTION_SEGMENT *Segment2 = (const MM_SECTION_SEGMENT *)y;
|
2004-12-30 16:05:12 +08: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 09:38:29 +08:00
|
|
|
* (NtMapViewOfSection could then refuse to map them, and they could
|
2004-12-30 16:05:12 +08: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;
|
|
|
|
BOOLEAN Initialized;
|
2005-10-22 23:11:55 +08:00
|
|
|
PMM_SECTION_SEGMENT EffectiveSegment;
|
2004-12-30 16:05:12 +08:00
|
|
|
|
|
|
|
if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED)
|
|
|
|
{
|
|
|
|
MmspAssertSegmentsPageAligned(ImageSectionObject);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Initialized = FALSE;
|
|
|
|
LastSegment = 0;
|
2005-10-22 23:11:55 +08:00
|
|
|
EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
|
2004-12-30 16:05:12 +08: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 09:38:29 +08:00
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
/* Round down the virtual address to the nearest page */
|
|
|
|
EffectiveSegment->VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress);
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
/* Round up the virtual size to the nearest page */
|
|
|
|
EffectiveSegment->Length = PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length) -
|
|
|
|
EffectiveSegment->VirtualAddress;
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
/* Adjust the raw address and size */
|
|
|
|
VirtualOffset = VirtualAddress - EffectiveSegment->VirtualAddress;
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
if (EffectiveSegment->FileOffset < VirtualOffset)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
/*
|
2005-05-09 09:38:29 +08: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 16:05:12 +08: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 09:38:29 +08:00
|
|
|
|
2004-12-30 16:05:12 +08: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 23:11:55 +08:00
|
|
|
if (LastSegment != i)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Copy the current segment. If necessary, the effective segment
|
|
|
|
* will be expanded later
|
|
|
|
*/
|
|
|
|
*EffectiveSegment = *Segment;
|
|
|
|
}
|
2004-12-30 16:05:12 +08: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 09:38:29 +08:00
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
/* Unaligned segments must be contiguous within the file */
|
|
|
|
if (Segment->FileOffset != (EffectiveSegment->FileOffset +
|
|
|
|
EffectiveSegment->RawLength))
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
EffectiveSegment->RawLength += Segment->RawLength;
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
/*
|
|
|
|
* Extend the virtual size
|
|
|
|
*/
|
2005-10-22 23:11:55 +08:00
|
|
|
ASSERT(PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) >= EndOfEffectiveSegment);
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
EffectiveSegment->Length = PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) -
|
|
|
|
EffectiveSegment->VirtualAddress;
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2004-12-30 16:05:12 +08: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
|
|
|
|
{
|
|
|
|
ASSERT(FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-10-22 23:11:55 +08:00
|
|
|
ImageSectionObject->NrSegments = LastSegment + 1;
|
2004-12-30 16:05:12 +08: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;
|
|
|
|
}
|
|
|
|
|
2008-08-31 23:29:21 +08:00
|
|
|
ExFreePoolWithTag(FileHeaderBuffer, TAG('M', 'm', 'X', 'r'));
|
2004-12-30 16:05:12 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* No loader handled the format
|
|
|
|
*/
|
|
|
|
if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
|
|
|
|
{
|
2005-07-09 00:37:07 +08:00
|
|
|
Status = STATUS_INVALID_IMAGE_NOT_MZ;
|
2004-12-30 16:05:12 +08: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 09:38:29 +08:00
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
if(ImageSectionObject->StackCommit == 0)
|
|
|
|
ImageSectionObject->StackCommit = 0x1000;
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2004-12-30 16:05:12 +08: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 21:41:04 +08:00
|
|
|
Segments = ExAllocatePoolWithTag(PagedPool,
|
2004-12-30 16:05:12 +08: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 11:29:16 +08:00
|
|
|
|
2001-02-11 06:51:11 +08:00
|
|
|
NTSTATUS
|
2006-05-11 01:47:44 +08:00
|
|
|
MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
|
2004-04-11 06:36:07 +08:00
|
|
|
ACCESS_MASK DesiredAccess,
|
|
|
|
POBJECT_ATTRIBUTES ObjectAttributes,
|
|
|
|
PLARGE_INTEGER UMaximumSize,
|
|
|
|
ULONG SectionPageProtection,
|
|
|
|
ULONG AllocationAttributes,
|
|
|
|
HANDLE FileHandle)
|
2001-02-11 06:51:11 +08:00
|
|
|
{
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2004-04-11 06:36:07 +08:00
|
|
|
NTSTATUS Status;
|
|
|
|
PFILE_OBJECT FileObject;
|
|
|
|
PMM_SECTION_SEGMENT SectionSegments;
|
|
|
|
PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
|
|
|
|
ULONG i;
|
|
|
|
ULONG FileAccess = 0;
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
/*
|
|
|
|
* Specifying a maximum size is meaningless for an image section
|
|
|
|
*/
|
|
|
|
if (UMaximumSize != NULL)
|
|
|
|
{
|
2001-02-11 06:51:11 +08:00
|
|
|
return(STATUS_INVALID_PARAMETER_4);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
2004-12-30 16:05:12 +08: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-11 06:36:07 +08:00
|
|
|
/*
|
|
|
|
* Reference the file handle
|
|
|
|
*/
|
|
|
|
Status = ObReferenceObjectByHandle(FileHandle,
|
|
|
|
FileAccess,
|
|
|
|
IoFileObjectType,
|
2007-02-23 13:39:42 +08:00
|
|
|
ExGetPreviousMode(),
|
2004-08-24 06:29:43 +08:00
|
|
|
(PVOID*)(PVOID)&FileObject,
|
2004-04-11 06:36:07 +08: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-19 03:26:47 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2003-06-28 05:28:30 +08:00
|
|
|
return Status;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-02-11 06:51:11 +08:00
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
/*
|
|
|
|
* Create the section
|
|
|
|
*/
|
|
|
|
Status = ObCreateObject (ExGetPreviousMode(),
|
|
|
|
MmSectionObjectType,
|
|
|
|
ObjectAttributes,
|
|
|
|
ExGetPreviousMode(),
|
|
|
|
NULL,
|
2006-05-11 01:47:44 +08:00
|
|
|
sizeof(ROS_SECTION_OBJECT),
|
2004-12-30 16:05:12 +08:00
|
|
|
0,
|
|
|
|
0,
|
|
|
|
(PVOID*)(PVOID)&Section);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize it
|
|
|
|
*/
|
|
|
|
Section->SectionPageProtection = SectionPageProtection;
|
|
|
|
Section->AllocationAttributes = AllocationAttributes;
|
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
/*
|
|
|
|
* Initialized caching for this file object if previously caching
|
|
|
|
* was initialized for the same on disk file
|
|
|
|
*/
|
|
|
|
Status = CcTryToInitializeFileCache(FileObject);
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
|
|
|
|
{
|
2004-12-30 16:05:12 +08:00
|
|
|
NTSTATUS StatusExeFmt;
|
2001-02-11 06:51:11 +08:00
|
|
|
|
2005-05-26 21:41:04 +08:00
|
|
|
ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
|
2004-12-30 16:05:12 +08:00
|
|
|
if (ImageSectionObject == NULL)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
ObDereferenceObject(FileObject);
|
2004-12-30 16:05:12 +08:00
|
|
|
ObDereferenceObject(Section);
|
2004-04-11 06:36:07 +08:00
|
|
|
return(STATUS_NO_MEMORY);
|
|
|
|
}
|
2007-10-20 07:21:45 +08:00
|
|
|
|
2005-09-29 03:56:05 +08:00
|
|
|
RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT));
|
2002-01-01 13:09:50 +08:00
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
StatusExeFmt = ExeFmtpCreateImageSection(FileHandle, ImageSectionObject);
|
2001-02-11 06:51:11 +08:00
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
if (!NT_SUCCESS(StatusExeFmt))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2004-12-30 16:05:12 +08:00
|
|
|
if(ImageSectionObject->Segments != NULL)
|
|
|
|
ExFreePool(ImageSectionObject->Segments);
|
|
|
|
|
|
|
|
ExFreePool(ImageSectionObject);
|
|
|
|
ObDereferenceObject(Section);
|
2004-04-11 06:36:07 +08:00
|
|
|
ObDereferenceObject(FileObject);
|
2004-12-30 16:05:12 +08:00
|
|
|
return(StatusExeFmt);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
Section->ImageSection = ImageSectionObject;
|
|
|
|
ASSERT(ImageSectionObject->Segments);
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Lock the file
|
|
|
|
*/
|
|
|
|
Status = MmspWaitForFileLock(FileObject);
|
2004-12-30 16:05:12 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2004-12-30 16:05:12 +08:00
|
|
|
ExFreePool(ImageSectionObject->Segments);
|
|
|
|
ExFreePool(ImageSectionObject);
|
2004-04-11 06:36:07 +08:00
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
2005-01-12 18:05:31 +08:00
|
|
|
if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject,
|
|
|
|
ImageSectionObject, NULL))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* An other thread has initialized the some image in the background
|
|
|
|
*/
|
2004-12-30 16:05:12 +08:00
|
|
|
ExFreePool(ImageSectionObject->Segments);
|
2004-04-11 06:36:07 +08:00
|
|
|
ExFreePool(ImageSectionObject);
|
|
|
|
ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
|
|
|
|
Section->ImageSection = ImageSectionObject;
|
|
|
|
SectionSegments = ImageSectionObject->Segments;
|
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
for (i = 0; i < ImageSectionObject->NrSegments; i++)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2006-03-05 01:27:40 +08:00
|
|
|
(void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
}
|
2004-12-30 16:05:12 +08:00
|
|
|
|
|
|
|
Status = StatusExeFmt;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-06-28 05:28:30 +08:00
|
|
|
/*
|
|
|
|
* Lock the file
|
|
|
|
*/
|
2003-12-31 02:52:06 +08:00
|
|
|
Status = MmspWaitForFileLock(FileObject);
|
2003-06-28 05:28:30 +08:00
|
|
|
if (Status != STATUS_SUCCESS)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
ObDereferenceObject(Section);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return(Status);
|
|
|
|
}
|
2003-06-28 05:28:30 +08:00
|
|
|
|
|
|
|
ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
|
|
|
|
Section->ImageSection = ImageSectionObject;
|
2001-03-09 22:40:28 +08:00
|
|
|
SectionSegments = ImageSectionObject->Segments;
|
2001-02-11 06:51:11 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise just reference all the section segments
|
|
|
|
*/
|
2004-12-30 16:05:12 +08:00
|
|
|
for (i = 0; i < ImageSectionObject->NrSegments; i++)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2006-03-05 01:27:40 +08:00
|
|
|
(void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
2004-12-30 16:05:12 +08:00
|
|
|
Status = STATUS_SUCCESS;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
Section->FileObject = FileObject;
|
|
|
|
CcRosReferenceCache(FileObject);
|
2006-07-28 06:26:40 +08:00
|
|
|
//KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
|
2004-08-06 03:59:13 +08:00
|
|
|
*SectionObject = Section;
|
2004-12-30 16:05:12 +08:00
|
|
|
return(Status);
|
2001-02-11 06:51:11 +08:00
|
|
|
}
|
|
|
|
|
2003-07-11 05:05:04 +08:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2001-02-11 06:51:11 +08:00
|
|
|
NTSTATUS STDCALL
|
|
|
|
NtCreateSection (OUT PHANDLE SectionHandle,
|
2004-04-11 06:36:07 +08:00
|
|
|
IN ACCESS_MASK DesiredAccess,
|
|
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
|
|
|
|
IN PLARGE_INTEGER MaximumSize OPTIONAL,
|
|
|
|
IN ULONG SectionPageProtection OPTIONAL,
|
|
|
|
IN ULONG AllocationAttributes,
|
|
|
|
IN HANDLE FileHandle OPTIONAL)
|
2001-02-11 06:51:11 +08:00
|
|
|
{
|
2005-02-15 23:46:22 +08:00
|
|
|
LARGE_INTEGER SafeMaximumSize;
|
2006-01-08 14:23:17 +08:00
|
|
|
PVOID SectionObject;
|
2005-02-15 23:46:22 +08:00
|
|
|
KPROCESSOR_MODE PreviousMode;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2004-04-11 06:36:07 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
PreviousMode = ExGetPreviousMode();
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
if(MaximumSize != NULL && PreviousMode != KernelMode)
|
|
|
|
{
|
|
|
|
_SEH_TRY
|
|
|
|
{
|
|
|
|
/* make a copy on the stack */
|
2005-08-22 03:04:23 +08:00
|
|
|
SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
|
2005-02-15 23:46:22 +08:00
|
|
|
MaximumSize = &SafeMaximumSize;
|
|
|
|
}
|
|
|
|
_SEH_HANDLE
|
|
|
|
{
|
|
|
|
Status = _SEH_GetExceptionCode();
|
|
|
|
}
|
|
|
|
_SEH_END;
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
if(!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2004-08-06 03:59:13 +08:00
|
|
|
Status = MmCreateSection(&SectionObject,
|
|
|
|
DesiredAccess,
|
|
|
|
ObjectAttributes,
|
|
|
|
MaximumSize,
|
|
|
|
SectionPageProtection,
|
|
|
|
AllocationAttributes,
|
|
|
|
FileHandle,
|
|
|
|
NULL);
|
|
|
|
if (NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2004-08-06 03:59:13 +08:00
|
|
|
Status = ObInsertObject ((PVOID)SectionObject,
|
|
|
|
NULL,
|
|
|
|
DesiredAccess,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
SectionHandle);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
2004-08-06 03:59:13 +08:00
|
|
|
return Status;
|
2001-02-11 06:51:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* NAME
|
2004-04-11 06:36:07 +08:00
|
|
|
* NtOpenSection
|
2001-02-11 06:51:11 +08:00
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
*
|
|
|
|
* ARGUMENTS
|
2004-04-11 06:36:07 +08:00
|
|
|
* SectionHandle
|
2001-02-11 06:51:11 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* DesiredAccess
|
2001-02-11 06:51:11 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* ObjectAttributes
|
2001-02-11 06:51:11 +08:00
|
|
|
*
|
|
|
|
* RETURN VALUE
|
|
|
|
*
|
|
|
|
* REVISIONS
|
|
|
|
*/
|
|
|
|
NTSTATUS STDCALL
|
2004-04-11 06:36:07 +08:00
|
|
|
NtOpenSection(PHANDLE SectionHandle,
|
|
|
|
ACCESS_MASK DesiredAccess,
|
|
|
|
POBJECT_ATTRIBUTES ObjectAttributes)
|
2001-02-11 06:51:11 +08:00
|
|
|
{
|
2005-02-15 23:46:22 +08:00
|
|
|
HANDLE hSection;
|
|
|
|
KPROCESSOR_MODE PreviousMode;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
PreviousMode = ExGetPreviousMode();
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
if(PreviousMode != KernelMode)
|
|
|
|
{
|
|
|
|
_SEH_TRY
|
|
|
|
{
|
2005-08-22 03:04:23 +08:00
|
|
|
ProbeForWriteHandle(SectionHandle);
|
2005-02-15 23:46:22 +08:00
|
|
|
}
|
|
|
|
_SEH_HANDLE
|
|
|
|
{
|
|
|
|
Status = _SEH_GetExceptionCode();
|
|
|
|
}
|
|
|
|
_SEH_END;
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
if(!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
2001-02-11 06:51:11 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
Status = ObOpenObjectByName(ObjectAttributes,
|
|
|
|
MmSectionObjectType,
|
2005-02-15 23:46:22 +08:00
|
|
|
PreviousMode,
|
2006-05-26 04:50:58 +08:00
|
|
|
NULL,
|
2004-04-11 06:36:07 +08:00
|
|
|
DesiredAccess,
|
|
|
|
NULL,
|
2005-02-15 23:46:22 +08:00
|
|
|
&hSection);
|
|
|
|
|
|
|
|
if(NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
_SEH_TRY
|
|
|
|
{
|
|
|
|
*SectionHandle = hSection;
|
|
|
|
}
|
|
|
|
_SEH_HANDLE
|
|
|
|
{
|
|
|
|
Status = _SEH_GetExceptionCode();
|
|
|
|
}
|
|
|
|
_SEH_END;
|
|
|
|
}
|
2003-05-14 18:52:46 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
return(Status);
|
2001-02-11 06:51:11 +08:00
|
|
|
}
|
|
|
|
|
2006-09-07 13:07:34 +08:00
|
|
|
NTSTATUS static
|
2008-07-28 09:49:23 +08:00
|
|
|
MmMapViewOfSegment(PMM_AVL_TABLE AddressSpace,
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section,
|
2004-04-11 06:36:07 +08:00
|
|
|
PMM_SECTION_SEGMENT Segment,
|
|
|
|
PVOID* BaseAddress,
|
2005-11-29 07:43:40 +08:00
|
|
|
SIZE_T ViewSize,
|
2004-04-11 06:36:07 +08:00
|
|
|
ULONG Protect,
|
|
|
|
ULONG ViewOffset,
|
2005-11-14 01:28:24 +08:00
|
|
|
ULONG AllocationType)
|
2001-02-11 06:51:11 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
PMEMORY_AREA MArea;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PHYSICAL_ADDRESS BoundaryAddressMultiple;
|
|
|
|
|
|
|
|
BoundaryAddressMultiple.QuadPart = 0;
|
|
|
|
|
2005-11-14 01:28:24 +08:00
|
|
|
Status = MmCreateMemoryArea(AddressSpace,
|
2004-04-11 06:36:07 +08:00
|
|
|
MEMORY_AREA_SECTION_VIEW,
|
|
|
|
BaseAddress,
|
|
|
|
ViewSize,
|
|
|
|
Protect,
|
|
|
|
&MArea,
|
|
|
|
FALSE,
|
2005-11-14 01:28:24 +08:00
|
|
|
AllocationType,
|
2004-04-11 06:36:07 +08:00
|
|
|
BoundaryAddressMultiple);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2004-12-20 00:16:58 +08:00
|
|
|
DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
|
|
|
|
(*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
|
2002-05-18 07:01:57 +08:00
|
|
|
return(Status);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
2005-11-14 01:28:24 +08:00
|
|
|
ObReferenceObject((PVOID)Section);
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
MArea->Data.SectionData.Segment = Segment;
|
|
|
|
MArea->Data.SectionData.Section = Section;
|
|
|
|
MArea->Data.SectionData.ViewOffset = ViewOffset;
|
|
|
|
MArea->Data.SectionData.WriteCopyView = FALSE;
|
2005-11-29 07:43:40 +08:00
|
|
|
MmInitializeRegion(&MArea->Data.SectionData.RegionListHead,
|
2004-04-11 06:36:07 +08:00
|
|
|
ViewSize, 0, Protect);
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
2001-11-14 06:46:49 +08:00
|
|
|
}
|
2001-02-11 06:51:11 +08:00
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
2004-04-11 06:36:07 +08:00
|
|
|
* NAME EXPORTED
|
|
|
|
* NtMapViewOfSection
|
2001-02-11 06:51:11 +08:00
|
|
|
*
|
|
|
|
* DESCRIPTION
|
2004-04-11 06:36:07 +08:00
|
|
|
* Maps a view of a section into the virtual address space of a
|
|
|
|
* process.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
1999-08-29 14:59:11 +08:00
|
|
|
* ARGUMENTS
|
2004-04-11 06:36:07 +08:00
|
|
|
* SectionHandle
|
|
|
|
* Handle of the section.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* ProcessHandle
|
|
|
|
* Handle of the process.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* BaseAddress
|
|
|
|
* Desired base address (or NULL) on entry;
|
|
|
|
* Actual base address of the view on exit.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* ZeroBits
|
|
|
|
* Number of high order address bits that must be zero.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* CommitSize
|
|
|
|
* Size in bytes of the initially committed section of
|
|
|
|
* the view.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* SectionOffset
|
|
|
|
* Offset in bytes from the beginning of the section
|
|
|
|
* to the beginning of the view.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* ViewSize
|
|
|
|
* Desired length of map (or zero to map all) on entry
|
|
|
|
* Actual length mapped on exit.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* InheritDisposition
|
|
|
|
* Specified how the view is to be shared with
|
|
|
|
* child processes.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* AllocateType
|
|
|
|
* Type of allocation for the pages.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* Protect
|
|
|
|
* Protection for the committed region of the view.
|
1999-08-29 14:59:11 +08:00
|
|
|
*
|
|
|
|
* RETURN VALUE
|
2004-04-11 06:36:07 +08:00
|
|
|
* Status.
|
2003-07-11 05:05:04 +08:00
|
|
|
*
|
|
|
|
* @implemented
|
1999-08-29 14:59:11 +08:00
|
|
|
*/
|
2001-11-14 06:46:49 +08:00
|
|
|
NTSTATUS STDCALL
|
2005-02-15 23:46:22 +08:00
|
|
|
NtMapViewOfSection(IN HANDLE SectionHandle,
|
|
|
|
IN HANDLE ProcessHandle,
|
|
|
|
IN OUT PVOID* BaseAddress OPTIONAL,
|
|
|
|
IN ULONG ZeroBits OPTIONAL,
|
|
|
|
IN ULONG CommitSize,
|
|
|
|
IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
|
2005-11-29 07:43:40 +08:00
|
|
|
IN OUT PSIZE_T ViewSize,
|
2005-02-15 23:46:22 +08:00
|
|
|
IN SECTION_INHERIT InheritDisposition,
|
|
|
|
IN ULONG AllocationType OPTIONAL,
|
|
|
|
IN ULONG Protect)
|
2001-11-14 06:46:49 +08:00
|
|
|
{
|
2005-02-15 23:46:22 +08:00
|
|
|
PVOID SafeBaseAddress;
|
|
|
|
LARGE_INTEGER SafeSectionOffset;
|
2005-11-29 07:43:40 +08:00
|
|
|
SIZE_T SafeViewSize;
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2006-05-19 04:32:17 +08:00
|
|
|
PEPROCESS Process;
|
2007-04-02 23:08:54 +08:00
|
|
|
KPROCESSOR_MODE PreviousMode;
|
2008-07-28 09:49:23 +08:00
|
|
|
PMM_AVL_TABLE AddressSpace;
|
2005-02-15 23:46:22 +08:00
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2005-11-14 01:28:24 +08:00
|
|
|
ULONG tmpProtect;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the protection
|
|
|
|
*/
|
|
|
|
if (Protect & ~PAGE_FLAGS_VALID_FROM_USER_MODE)
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER_10;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmpProtect = Protect & ~(PAGE_GUARD|PAGE_NOCACHE);
|
|
|
|
if (tmpProtect != PAGE_NOACCESS &&
|
|
|
|
tmpProtect != PAGE_READONLY &&
|
|
|
|
tmpProtect != PAGE_READWRITE &&
|
|
|
|
tmpProtect != PAGE_WRITECOPY &&
|
|
|
|
tmpProtect != PAGE_EXECUTE &&
|
|
|
|
tmpProtect != PAGE_EXECUTE_READ &&
|
|
|
|
tmpProtect != PAGE_EXECUTE_READWRITE &&
|
|
|
|
tmpProtect != PAGE_EXECUTE_WRITECOPY)
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PAGE_PROTECTION;
|
|
|
|
}
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
PreviousMode = ExGetPreviousMode();
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
if(PreviousMode != KernelMode)
|
|
|
|
{
|
|
|
|
SafeBaseAddress = NULL;
|
|
|
|
SafeSectionOffset.QuadPart = 0;
|
|
|
|
SafeViewSize = 0;
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
_SEH_TRY
|
|
|
|
{
|
|
|
|
if(BaseAddress != NULL)
|
|
|
|
{
|
2005-08-22 03:04:23 +08:00
|
|
|
ProbeForWritePointer(BaseAddress);
|
2005-02-15 23:46:22 +08:00
|
|
|
SafeBaseAddress = *BaseAddress;
|
|
|
|
}
|
|
|
|
if(SectionOffset != NULL)
|
|
|
|
{
|
2005-08-22 03:04:23 +08:00
|
|
|
ProbeForWriteLargeInteger(SectionOffset);
|
2007-03-17 16:30:26 +08:00
|
|
|
SafeSectionOffset = *SectionOffset;
|
2005-02-15 23:46:22 +08:00
|
|
|
}
|
2005-11-29 07:43:40 +08:00
|
|
|
ProbeForWriteSize_t(ViewSize);
|
2005-02-15 23:46:22 +08:00
|
|
|
SafeViewSize = *ViewSize;
|
|
|
|
}
|
|
|
|
_SEH_HANDLE
|
|
|
|
{
|
|
|
|
Status = _SEH_GetExceptionCode();
|
|
|
|
}
|
|
|
|
_SEH_END;
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
if(!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SafeBaseAddress = (BaseAddress != NULL ? *BaseAddress : NULL);
|
2007-03-17 16:30:26 +08:00
|
|
|
SafeSectionOffset.QuadPart = (SectionOffset != NULL ? SectionOffset->QuadPart : 0);
|
2005-02-15 23:46:22 +08:00
|
|
|
SafeViewSize = (ViewSize != NULL ? *ViewSize : 0);
|
|
|
|
}
|
2001-02-11 06:51:11 +08:00
|
|
|
|
2007-03-17 16:30:26 +08:00
|
|
|
SafeSectionOffset.LowPart = PAGE_ROUND_DOWN(SafeSectionOffset.LowPart);
|
|
|
|
|
2001-02-11 06:51:11 +08:00
|
|
|
Status = ObReferenceObjectByHandle(ProcessHandle,
|
2004-04-11 06:36:07 +08:00
|
|
|
PROCESS_VM_OPERATION,
|
|
|
|
PsProcessType,
|
2005-02-15 23:46:22 +08:00
|
|
|
PreviousMode,
|
2004-08-24 06:29:43 +08:00
|
|
|
(PVOID*)(PVOID)&Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
NULL);
|
2001-02-11 06:51:11 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
return(Status);
|
|
|
|
}
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2008-07-28 09:49:23 +08:00
|
|
|
AddressSpace = &Process->VadRoot;
|
2003-12-31 02:52:06 +08:00
|
|
|
|
1999-11-24 19:51:55 +08:00
|
|
|
Status = ObReferenceObjectByHandle(SectionHandle,
|
2004-04-11 06:36:07 +08:00
|
|
|
SECTION_MAP_READ,
|
|
|
|
MmSectionObjectType,
|
2005-02-15 23:46:22 +08:00
|
|
|
PreviousMode,
|
2004-08-24 06:29:43 +08:00
|
|
|
(PVOID*)(PVOID)&Section,
|
2004-04-11 06:36:07 +08:00
|
|
|
NULL);
|
1999-11-24 19:51:55 +08:00
|
|
|
if (!(NT_SUCCESS(Status)))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
DPRINT("ObReference failed rc=%x\n",Status);
|
|
|
|
ObDereferenceObject(Process);
|
|
|
|
return(Status);
|
|
|
|
}
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2001-11-14 06:46:49 +08:00
|
|
|
Status = MmMapViewOfSection(Section,
|
2006-05-11 01:47:44 +08:00
|
|
|
(PEPROCESS)Process,
|
2005-02-15 23:46:22 +08:00
|
|
|
(BaseAddress != NULL ? &SafeBaseAddress : NULL),
|
2004-04-11 06:36:07 +08:00
|
|
|
ZeroBits,
|
|
|
|
CommitSize,
|
2005-02-15 23:46:22 +08:00
|
|
|
(SectionOffset != NULL ? &SafeSectionOffset : NULL),
|
|
|
|
(ViewSize != NULL ? &SafeViewSize : NULL),
|
2004-04-11 06:36:07 +08:00
|
|
|
InheritDisposition,
|
|
|
|
AllocationType,
|
|
|
|
Protect);
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2006-11-30 09:57:25 +08:00
|
|
|
/* Check if this is an image for the current process */
|
|
|
|
if ((Section->AllocationAttributes & SEC_IMAGE) &&
|
|
|
|
(Process == PsGetCurrentProcess()) &&
|
|
|
|
(Status != STATUS_IMAGE_NOT_AT_BASE))
|
|
|
|
{
|
|
|
|
/* Notify the debugger */
|
2006-12-01 15:36:49 +08:00
|
|
|
DbgkMapViewOfSection(Section,
|
2006-11-30 09:57:25 +08:00
|
|
|
SafeBaseAddress,
|
|
|
|
SafeSectionOffset.LowPart,
|
|
|
|
SafeViewSize);
|
|
|
|
}
|
|
|
|
|
2001-03-09 06:06:02 +08:00
|
|
|
ObDereferenceObject(Section);
|
2001-11-14 06:46:49 +08:00
|
|
|
ObDereferenceObject(Process);
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
if(NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* copy parameters back to the caller */
|
|
|
|
_SEH_TRY
|
|
|
|
{
|
|
|
|
if(BaseAddress != NULL)
|
|
|
|
{
|
|
|
|
*BaseAddress = SafeBaseAddress;
|
|
|
|
}
|
|
|
|
if(SectionOffset != NULL)
|
|
|
|
{
|
|
|
|
*SectionOffset = SafeSectionOffset;
|
|
|
|
}
|
|
|
|
if(ViewSize != NULL)
|
|
|
|
{
|
|
|
|
*ViewSize = SafeViewSize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_SEH_HANDLE
|
|
|
|
{
|
|
|
|
Status = _SEH_GetExceptionCode();
|
|
|
|
}
|
|
|
|
_SEH_END;
|
|
|
|
}
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2001-11-14 06:46:49 +08:00
|
|
|
return(Status);
|
1998-10-05 12:01:30 +08:00
|
|
|
}
|
|
|
|
|
2006-09-07 13:07:34 +08:00
|
|
|
VOID static
|
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 23:26:58 +08:00
|
|
|
MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
|
2004-08-01 15:24:59 +08:00
|
|
|
PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
|
2001-02-11 06:51:11 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
ULONG Entry;
|
|
|
|
PFILE_OBJECT FileObject;
|
|
|
|
PBCB Bcb;
|
|
|
|
ULONG Offset;
|
|
|
|
SWAPENTRY SavedSwapEntry;
|
|
|
|
PMM_PAGEOP PageOp;
|
|
|
|
NTSTATUS Status;
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2004-04-11 06:36:07 +08:00
|
|
|
PMM_SECTION_SEGMENT Segment;
|
2008-07-28 09:49:23 +08:00
|
|
|
PMM_AVL_TABLE 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-28 07:53:04 +08:00
|
|
|
PEPROCESS Process;
|
2001-02-11 06:51:11 +08:00
|
|
|
|
2008-07-28 09:49:23 +08:00
|
|
|
AddressSpace = (PMM_AVL_TABLE)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-28 07:53:04 +08:00
|
|
|
Process = MmGetAddressSpaceOwner(AddressSpace);
|
2001-02-11 06:51:11 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
Address = (PVOID)PAGE_ROUND_DOWN(Address);
|
2003-06-07 05:00:28 +08:00
|
|
|
|
2005-06-08 01:07:34 +08:00
|
|
|
Offset = ((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress) +
|
2004-10-02 04:06:43 +08:00
|
|
|
MemoryArea->Data.SectionData.ViewOffset;
|
2002-08-15 04:58:39 +08:00
|
|
|
|
2005-06-08 01:07:34 +08:00
|
|
|
Section = MemoryArea->Data.SectionData.Section;
|
|
|
|
Segment = MemoryArea->Data.SectionData.Segment;
|
2003-06-28 05:28:30 +08:00
|
|
|
|
2005-06-08 01:07:34 +08:00
|
|
|
PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
while (PageOp)
|
|
|
|
{
|
|
|
|
MmUnlockSectionSegment(Segment);
|
2005-06-08 01:07:34 +08:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2003-06-28 05:28:30 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
Status = MmspWaitForPageOpCompletionEvent(PageOp);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
|
|
{
|
2003-06-07 05:00:28 +08:00
|
|
|
DPRINT1("Failed to wait for page op, status = %x\n", Status);
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
2005-06-08 01:07:34 +08:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2004-04-11 06:36:07 +08:00
|
|
|
MmLockSectionSegment(Segment);
|
|
|
|
MmspCompleteAndReleasePageOp(PageOp);
|
2005-06-08 01:07:34 +08:00
|
|
|
PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
|
2004-04-11 06:36:07 +08: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 15:24:59 +08:00
|
|
|
if (Page == PFN_FROM_SSE(Entry) && Dirty)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
FileObject = MemoryArea->Data.SectionData.Section->FileObject;
|
|
|
|
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
|
2005-06-12 18:25:49 +08:00
|
|
|
CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
|
2004-10-23 04:43:58 +08:00
|
|
|
ASSERT(SwapEntry == 0);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SwapEntry != 0)
|
|
|
|
{
|
2003-07-15 04:14:11 +08:00
|
|
|
/*
|
|
|
|
* Sanity check
|
|
|
|
*/
|
|
|
|
if (Segment->Flags & MM_PAGEFILE_SEGMENT)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
DPRINT1("Found a swap entry for a page in a pagefile section.\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2002-01-01 03:06:49 +08:00
|
|
|
MmFreeSwapPage(SwapEntry);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2004-08-01 15:24:59 +08:00
|
|
|
else if (Page != 0)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2003-12-31 02:52:06 +08:00
|
|
|
if (IS_SWAP_FROM_SSE(Entry) ||
|
2004-08-01 15:24:59 +08:00
|
|
|
Page != PFN_FROM_SSE(Entry))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Sanity check
|
|
|
|
*/
|
|
|
|
if (Segment->Flags & MM_PAGEFILE_SEGMENT)
|
|
|
|
{
|
|
|
|
DPRINT1("Found a private page in a pagefile section.\n");
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Just dereference private pages
|
|
|
|
*/
|
2004-08-01 15:24:59 +08:00
|
|
|
SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
if (SavedSwapEntry != 0)
|
|
|
|
{
|
|
|
|
MmFreeSwapPage(SavedSwapEntry);
|
2004-08-01 15:24:59 +08:00
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
MmDeleteRmap(Page, Process, Address);
|
2004-08-01 15:24:59 +08:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-03-30 01:24:43 +08:00
|
|
|
else
|
2004-04-11 06:36:07 +08: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-28 07:53:04 +08:00
|
|
|
MmDeleteRmap(Page, Process, Address);
|
2004-04-11 06:36:07 +08:00
|
|
|
MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty, FALSE);
|
|
|
|
}
|
|
|
|
}
|
2001-02-11 06:51:11 +08:00
|
|
|
}
|
|
|
|
|
2006-09-07 13:07:34 +08:00
|
|
|
static NTSTATUS
|
2008-07-28 09:49:23 +08:00
|
|
|
MmUnmapViewOfSegment(PMM_AVL_TABLE AddressSpace,
|
2004-04-11 06:36:07 +08:00
|
|
|
PVOID BaseAddress)
|
1999-11-24 19:51:55 +08:00
|
|
|
{
|
2003-07-26 20:47:51 +08:00
|
|
|
NTSTATUS Status;
|
2001-02-11 06:51:11 +08:00
|
|
|
PMEMORY_AREA MemoryArea;
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2001-02-11 06:51:11 +08:00
|
|
|
PMM_SECTION_SEGMENT Segment;
|
2002-08-11 00:41:20 +08:00
|
|
|
PLIST_ENTRY CurrentEntry;
|
|
|
|
PMM_REGION CurrentRegion;
|
2003-07-26 20:47:51 +08:00
|
|
|
PLIST_ENTRY RegionListHead;
|
2003-06-07 05:00:28 +08:00
|
|
|
|
2005-01-03 03:14:52 +08:00
|
|
|
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
|
|
|
|
BaseAddress);
|
2001-02-11 06:51:11 +08:00
|
|
|
if (MemoryArea == NULL)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
2002-08-15 04:58:39 +08:00
|
|
|
|
|
|
|
MemoryArea->DeleteInProgress = TRUE;
|
2001-02-11 06:51:11 +08:00
|
|
|
Section = MemoryArea->Data.SectionData.Section;
|
|
|
|
Segment = MemoryArea->Data.SectionData.Segment;
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2003-06-28 05:28:30 +08:00
|
|
|
MmLockSectionSegment(Segment);
|
2002-08-11 00:41:20 +08:00
|
|
|
|
2003-07-26 20:47:51 +08:00
|
|
|
RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
|
|
|
|
while (!IsListEmpty(RegionListHead))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
CurrentEntry = RemoveHeadList(RegionListHead);
|
|
|
|
CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
|
2008-08-31 23:29:21 +08:00
|
|
|
ExFreePoolWithTag(CurrentRegion, TAG_MM_REGION);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2002-08-11 00:41:20 +08:00
|
|
|
|
2003-06-28 05:28:30 +08:00
|
|
|
if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
Status = MmFreeMemoryArea(AddressSpace,
|
2005-01-03 01:55:06 +08:00
|
|
|
MemoryArea,
|
2004-04-11 06:36:07 +08:00
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
}
|
2001-02-11 06:51:11 +08:00
|
|
|
else
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
Status = MmFreeMemoryArea(AddressSpace,
|
2005-01-03 01:55:06 +08:00
|
|
|
MemoryArea,
|
2004-04-11 06:36:07 +08:00
|
|
|
MmFreeSectionPage,
|
2005-06-08 01:07:34 +08:00
|
|
|
AddressSpace);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-02-11 06:51:11 +08:00
|
|
|
MmUnlockSectionSegment(Segment);
|
2001-03-09 06:06:02 +08:00
|
|
|
ObDereferenceObject(Section);
|
1999-11-24 19:51:55 +08:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
1998-08-25 12:27:26 +08:00
|
|
|
|
2003-07-26 20:47:51 +08:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
NTSTATUS STDCALL
|
|
|
|
MmUnmapViewOfSection(PEPROCESS Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
PVOID BaseAddress)
|
2003-07-26 20:47:51 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
NTSTATUS Status;
|
2003-07-26 20:47:51 +08:00
|
|
|
PMEMORY_AREA MemoryArea;
|
2008-07-28 09:49:23 +08:00
|
|
|
PMM_AVL_TABLE AddressSpace;
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2005-10-29 22:10:35 +08:00
|
|
|
PMM_PAGEOP PageOp;
|
|
|
|
ULONG_PTR Offset;
|
2006-11-30 09:57:25 +08:00
|
|
|
PVOID ImageBaseAddress = 0;
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2003-07-26 20:47:51 +08:00
|
|
|
DPRINT("Opening memory area Process %x BaseAddress %x\n",
|
2004-04-11 06:36:07 +08:00
|
|
|
Process, BaseAddress);
|
2003-07-26 20:47:51 +08:00
|
|
|
|
2004-10-23 04:43:58 +08:00
|
|
|
ASSERT(Process);
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2008-07-28 09:49:23 +08:00
|
|
|
AddressSpace = &Process->VadRoot;
|
2007-10-20 07:21:45 +08:00
|
|
|
|
2005-10-29 22:10:35 +08:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2005-01-03 03:14:52 +08:00
|
|
|
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
|
|
|
|
BaseAddress);
|
2004-08-24 06:29:43 +08:00
|
|
|
if (MemoryArea == NULL ||
|
|
|
|
MemoryArea->Type != MEMORY_AREA_SECTION_VIEW ||
|
|
|
|
MemoryArea->DeleteInProgress)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2005-10-29 22:10:35 +08:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2004-08-24 06:29:43 +08:00
|
|
|
return STATUS_NOT_MAPPED_VIEW;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2003-07-26 20:47:51 +08:00
|
|
|
|
2005-10-29 22:10:35 +08: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-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2005-10-29 22:10:35 +08: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 20:47:51 +08:00
|
|
|
Section = MemoryArea->Data.SectionData.Section;
|
|
|
|
|
|
|
|
if (Section->AllocationAttributes & SEC_IMAGE)
|
2004-04-11 06:36:07 +08: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 18:26:58 +08:00
|
|
|
if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
|
2003-07-26 20:47:51 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
if (Segment == &SectionSegments[i])
|
|
|
|
{
|
|
|
|
ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i >= NrSegments)
|
|
|
|
{
|
2008-08-24 23:48:05 +08:00
|
|
|
ASSERT(FALSE);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < NrSegments; i++)
|
|
|
|
{
|
2006-09-10 18:26:58 +08:00
|
|
|
if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
|
2003-07-26 20:47:51 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
PVOID SBaseAddress = (PVOID)
|
|
|
|
((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress);
|
|
|
|
|
|
|
|
Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-07-26 20:47:51 +08:00
|
|
|
else
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
|
|
|
|
}
|
2006-11-30 09:57:25 +08:00
|
|
|
|
|
|
|
/* Notify debugger */
|
|
|
|
if (ImageBaseAddress) DbgkUnMapViewOfSection(ImageBaseAddress);
|
|
|
|
|
2005-10-29 22:10:35 +08:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2003-07-26 20:47:51 +08:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
1999-08-29 14:59:11 +08:00
|
|
|
/**********************************************************************
|
2004-04-11 06:36:07 +08:00
|
|
|
* NAME EXPORTED
|
|
|
|
* NtUnmapViewOfSection
|
1999-08-29 14:59:11 +08:00
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
*
|
|
|
|
* ARGUMENTS
|
2004-04-11 06:36:07 +08:00
|
|
|
* ProcessHandle
|
1999-08-29 14:59:11 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* BaseAddress
|
1999-08-29 14:59:11 +08:00
|
|
|
*
|
|
|
|
* RETURN VALUE
|
2004-04-11 06:36:07 +08:00
|
|
|
* Status.
|
1999-08-29 14:59:11 +08:00
|
|
|
*
|
|
|
|
* REVISIONS
|
|
|
|
*/
|
2001-11-14 06:46:49 +08:00
|
|
|
NTSTATUS STDCALL
|
2004-04-11 06:36:07 +08:00
|
|
|
NtUnmapViewOfSection (HANDLE ProcessHandle,
|
|
|
|
PVOID BaseAddress)
|
1998-10-05 12:01:30 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
PEPROCESS Process;
|
2005-02-15 23:46:22 +08:00
|
|
|
KPROCESSOR_MODE PreviousMode;
|
2001-02-11 06:51:11 +08:00
|
|
|
NTSTATUS Status;
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2000-02-14 00:05:19 +08:00
|
|
|
DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
|
2004-04-11 06:36:07 +08:00
|
|
|
ProcessHandle, BaseAddress);
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
PreviousMode = ExGetPreviousMode();
|
|
|
|
|
2000-02-14 00:05:19 +08:00
|
|
|
DPRINT("Referencing process\n");
|
1999-11-24 19:51:55 +08:00
|
|
|
Status = ObReferenceObjectByHandle(ProcessHandle,
|
2004-04-11 06:36:07 +08:00
|
|
|
PROCESS_VM_OPERATION,
|
|
|
|
PsProcessType,
|
2005-02-15 23:46:22 +08:00
|
|
|
PreviousMode,
|
2004-08-24 06:29:43 +08:00
|
|
|
(PVOID*)(PVOID)&Process,
|
2004-04-11 06:36:07 +08:00
|
|
|
NULL);
|
2000-02-14 00:05:19 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status);
|
|
|
|
return(Status);
|
|
|
|
}
|
2001-02-11 06:51:11 +08:00
|
|
|
|
|
|
|
Status = MmUnmapViewOfSection(Process, BaseAddress);
|
|
|
|
|
1999-11-24 19:51:55 +08:00
|
|
|
ObDereferenceObject(Process);
|
1999-08-29 14:59:11 +08:00
|
|
|
|
1999-11-24 19:51:55 +08:00
|
|
|
return Status;
|
1998-10-05 12:01:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-08-21 05:23:49 +08:00
|
|
|
/**
|
|
|
|
* Queries the information of a section object.
|
2005-05-09 09:38:29 +08:00
|
|
|
*
|
2004-08-21 05:23:49 +08: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 12:01:30 +08:00
|
|
|
*
|
2004-08-21 05:23:49 +08:00
|
|
|
* @implemented
|
1998-10-05 12:01:30 +08:00
|
|
|
*/
|
2004-08-21 05:23:49 +08:00
|
|
|
NTSTATUS STDCALL
|
|
|
|
NtQuerySection(IN HANDLE SectionHandle,
|
2005-02-15 23:46:22 +08:00
|
|
|
IN SECTION_INFORMATION_CLASS SectionInformationClass,
|
2004-08-21 05:23:49 +08:00
|
|
|
OUT PVOID SectionInformation,
|
2005-02-15 23:46:22 +08:00
|
|
|
IN ULONG SectionInformationLength,
|
|
|
|
OUT PULONG ResultLength OPTIONAL)
|
1998-10-05 12:01:30 +08:00
|
|
|
{
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2005-02-15 23:46:22 +08:00
|
|
|
KPROCESSOR_MODE PreviousMode;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
PreviousMode = ExGetPreviousMode();
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-10-10 21:03:55 +08:00
|
|
|
Status = DefaultQueryInfoBufferCheck(SectionInformationClass,
|
|
|
|
ExSectionInfoClass,
|
|
|
|
sizeof(ExSectionInfoClass) / sizeof(ExSectionInfoClass[0]),
|
|
|
|
SectionInformation,
|
|
|
|
SectionInformationLength,
|
|
|
|
ResultLength,
|
|
|
|
PreviousMode);
|
2005-02-15 23:46:22 +08:00
|
|
|
|
|
|
|
if(!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
2004-04-11 06:36:07 +08:00
|
|
|
|
|
|
|
Status = ObReferenceObjectByHandle(SectionHandle,
|
2004-08-21 05:23:49 +08:00
|
|
|
SECTION_QUERY,
|
2004-04-11 06:36:07 +08:00
|
|
|
MmSectionObjectType,
|
2005-02-15 23:46:22 +08:00
|
|
|
PreviousMode,
|
2004-08-24 06:29:43 +08:00
|
|
|
(PVOID*)(PVOID)&Section,
|
2004-04-11 06:36:07 +08:00
|
|
|
NULL);
|
2005-02-15 23:46:22 +08:00
|
|
|
if (NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2005-02-15 23:46:22 +08:00
|
|
|
switch (SectionInformationClass)
|
|
|
|
{
|
|
|
|
case SectionBasicInformation:
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2005-02-15 23:46:22 +08:00
|
|
|
PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
|
2001-02-11 06:51:11 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
_SEH_TRY
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2005-02-15 23:46:22 +08: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-31 02:52:06 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
if (ResultLength != NULL)
|
|
|
|
{
|
|
|
|
*ResultLength = sizeof(SECTION_BASIC_INFORMATION);
|
|
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
2004-08-21 05:23:49 +08:00
|
|
|
}
|
2005-02-15 23:46:22 +08:00
|
|
|
_SEH_HANDLE
|
2004-08-21 05:23:49 +08:00
|
|
|
{
|
2005-02-15 23:46:22 +08:00
|
|
|
Status = _SEH_GetExceptionCode();
|
2004-08-21 05:23:49 +08:00
|
|
|
}
|
2005-02-15 23:46:22 +08:00
|
|
|
_SEH_END;
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
break;
|
|
|
|
}
|
2001-02-11 06:51:11 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
case SectionImageInformation:
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2005-02-15 23:46:22 +08:00
|
|
|
PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
|
2004-04-11 06:36:07 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
_SEH_TRY
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2005-02-15 23:46:22 +08:00
|
|
|
memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
|
|
|
|
if (Section->AllocationAttributes & SEC_IMAGE)
|
|
|
|
{
|
|
|
|
PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
|
|
|
|
ImageSectionObject = Section->ImageSection;
|
|
|
|
|
2005-07-12 09:56:14 +08:00
|
|
|
Sii->TransferAddress = (PVOID)ImageSectionObject->EntryPoint;
|
|
|
|
Sii->MaximumStackSize = ImageSectionObject->StackReserve;
|
|
|
|
Sii->CommittedStackSize = ImageSectionObject->StackCommit;
|
2008-06-11 19:48:59 +08:00
|
|
|
Sii->SubSystemType = ImageSectionObject->Subsystem;
|
2005-07-12 09:56:14 +08:00
|
|
|
Sii->SubSystemMinorVersion = ImageSectionObject->MinorSubsystemVersion;
|
|
|
|
Sii->SubSystemMajorVersion = ImageSectionObject->MajorSubsystemVersion;
|
|
|
|
Sii->ImageCharacteristics = ImageSectionObject->ImageCharacteristics;
|
|
|
|
Sii->Machine = ImageSectionObject->Machine;
|
|
|
|
Sii->ImageContainsCode = ImageSectionObject->Executable;
|
2005-02-15 23:46:22 +08:00
|
|
|
}
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
if (ResultLength != NULL)
|
|
|
|
{
|
|
|
|
*ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
|
|
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2005-02-15 23:46:22 +08:00
|
|
|
_SEH_HANDLE
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2005-02-15 23:46:22 +08:00
|
|
|
Status = _SEH_GetExceptionCode();
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2005-02-15 23:46:22 +08:00
|
|
|
_SEH_END;
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
break;
|
|
|
|
}
|
2005-02-15 23:46:22 +08:00
|
|
|
}
|
2004-04-11 06:36:07 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
ObDereferenceObject(Section);
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
return(Status);
|
1998-10-05 12:01:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-08-21 05:23:49 +08:00
|
|
|
/**
|
|
|
|
* Extends size of file backed section.
|
2005-05-09 09:38:29 +08:00
|
|
|
*
|
2004-08-21 05:23:49 +08:00
|
|
|
* @param SectionHandle
|
|
|
|
* Handle to the section object. It must be opened with
|
|
|
|
* SECTION_EXTEND_SIZE access.
|
|
|
|
* @param NewMaximumSize
|
|
|
|
* New maximum size of the section in bytes.
|
|
|
|
*
|
|
|
|
* @return Status.
|
|
|
|
*
|
|
|
|
* @todo Move the actual code to internal function MmExtendSection.
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
2003-12-31 02:52:06 +08:00
|
|
|
NTSTATUS STDCALL
|
2004-04-11 06:36:07 +08:00
|
|
|
NtExtendSection(IN HANDLE SectionHandle,
|
2004-08-21 05:23:49 +08:00
|
|
|
IN PLARGE_INTEGER NewMaximumSize)
|
1998-08-25 12:27:26 +08:00
|
|
|
{
|
2005-02-15 23:46:22 +08:00
|
|
|
LARGE_INTEGER SafeNewMaximumSize;
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2005-02-15 23:46:22 +08:00
|
|
|
KPROCESSOR_MODE PreviousMode;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
PreviousMode = ExGetPreviousMode();
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
if(PreviousMode != KernelMode)
|
|
|
|
{
|
|
|
|
_SEH_TRY
|
|
|
|
{
|
|
|
|
/* make a copy on the stack */
|
2005-08-22 03:04:23 +08:00
|
|
|
SafeNewMaximumSize = ProbeForReadLargeInteger(NewMaximumSize);
|
2005-02-15 23:46:22 +08:00
|
|
|
NewMaximumSize = &SafeNewMaximumSize;
|
|
|
|
}
|
|
|
|
_SEH_HANDLE
|
|
|
|
{
|
|
|
|
Status = _SEH_GetExceptionCode();
|
|
|
|
}
|
|
|
|
_SEH_END;
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2005-02-15 23:46:22 +08:00
|
|
|
if(!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
2004-08-21 05:23:49 +08:00
|
|
|
|
|
|
|
Status = ObReferenceObjectByHandle(SectionHandle,
|
|
|
|
SECTION_EXTEND_SIZE,
|
|
|
|
MmSectionObjectType,
|
2005-02-15 23:46:22 +08:00
|
|
|
PreviousMode,
|
2004-08-21 05:23:49 +08:00
|
|
|
(PVOID*)&Section,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(Section->AllocationAttributes & SEC_FILE))
|
|
|
|
{
|
|
|
|
ObfDereferenceObject(Section);
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
2005-05-09 09:38:29 +08:00
|
|
|
|
2004-08-21 05:23:49 +08:00
|
|
|
/*
|
|
|
|
* - Acquire file extneding resource.
|
|
|
|
* - Check if we're not resizing the section below it's actual size!
|
|
|
|
* - Extend segments if needed.
|
|
|
|
* - Set file information (FileAllocationInformation) to the new size.
|
|
|
|
* - Release file extending resource.
|
|
|
|
*/
|
|
|
|
|
|
|
|
ObDereferenceObject(Section);
|
|
|
|
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
1998-08-25 12:27:26 +08:00
|
|
|
}
|
1999-08-29 14:59:11 +08:00
|
|
|
|
|
|
|
|
2000-03-19 17:14:52 +08:00
|
|
|
/**********************************************************************
|
2004-04-11 06:36:07 +08:00
|
|
|
* NAME INTERNAL
|
|
|
|
* MmAllocateSection@4
|
2000-03-19 17:14:52 +08:00
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
*
|
|
|
|
* ARGUMENTS
|
2004-04-11 06:36:07 +08:00
|
|
|
* Length
|
2000-03-19 17:14:52 +08:00
|
|
|
*
|
|
|
|
* RETURN VALUE
|
|
|
|
*
|
|
|
|
* NOTE
|
2004-04-11 06:36:07 +08:00
|
|
|
* Code taken from ntoskrnl/mm/special.c.
|
2000-03-19 17:14:52 +08:00
|
|
|
*
|
|
|
|
* REVISIONS
|
|
|
|
*/
|
2003-12-31 02:52:06 +08:00
|
|
|
PVOID STDCALL
|
2004-10-09 20:17:54 +08:00
|
|
|
MmAllocateSection (IN ULONG Length, PVOID BaseAddress)
|
2000-03-19 17:14:52 +08:00
|
|
|
{
|
2000-03-29 21:11:55 +08:00
|
|
|
PVOID Result;
|
|
|
|
MEMORY_AREA* marea;
|
|
|
|
NTSTATUS Status;
|
2008-07-28 09:49:23 +08:00
|
|
|
PMM_AVL_TABLE AddressSpace;
|
2003-12-31 13:33:04 +08:00
|
|
|
PHYSICAL_ADDRESS BoundaryAddressMultiple;
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2000-03-29 21:11:55 +08:00
|
|
|
DPRINT("MmAllocateSection(Length %x)\n",Length);
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2003-12-31 13:33:04 +08:00
|
|
|
BoundaryAddressMultiple.QuadPart = 0;
|
2004-01-05 22:28:21 +08:00
|
|
|
|
2000-03-29 21:11:55 +08:00
|
|
|
AddressSpace = MmGetKernelAddressSpace();
|
2004-10-09 20:17:54 +08:00
|
|
|
Result = BaseAddress;
|
2000-03-29 21:11:55 +08:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2005-11-14 01:28:24 +08:00
|
|
|
Status = MmCreateMemoryArea (AddressSpace,
|
2004-04-11 06:36:07 +08:00
|
|
|
MEMORY_AREA_SYSTEM,
|
|
|
|
&Result,
|
|
|
|
Length,
|
|
|
|
0,
|
|
|
|
&marea,
|
|
|
|
FALSE,
|
2005-11-14 01:28:24 +08:00
|
|
|
0,
|
2004-04-11 06:36:07 +08:00
|
|
|
BoundaryAddressMultiple);
|
2003-12-31 02:52:06 +08:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2004-01-05 22:28:21 +08:00
|
|
|
|
2001-10-11 06:40:36 +08:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
return (NULL);
|
|
|
|
}
|
2000-03-29 21:11:55 +08:00
|
|
|
DPRINT("Result %p\n",Result);
|
2004-04-11 06:36:07 +08:00
|
|
|
|
2008-03-13 21:17:57 +08:00
|
|
|
/* Create a virtual mapping for this memory area */
|
|
|
|
MmMapMemoryArea(Result, Length, MC_NPPOOL, PAGE_READWRITE);
|
|
|
|
|
2000-03-29 21:11:55 +08:00
|
|
|
return ((PVOID)Result);
|
2000-03-19 17:14:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-04-02 21:32:43 +08:00
|
|
|
/**********************************************************************
|
2004-04-11 06:36:07 +08:00
|
|
|
* NAME EXPORTED
|
|
|
|
* MmMapViewOfSection
|
2000-04-02 21:32:43 +08:00
|
|
|
*
|
|
|
|
* DESCRIPTION
|
2004-04-11 06:36:07 +08:00
|
|
|
* Maps a view of a section into the virtual address space of a
|
|
|
|
* process.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2000-04-02 21:32:43 +08:00
|
|
|
* ARGUMENTS
|
2004-04-11 06:36:07 +08:00
|
|
|
* Section
|
|
|
|
* Pointer to the section object.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* ProcessHandle
|
|
|
|
* Pointer to the process.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* BaseAddress
|
|
|
|
* Desired base address (or NULL) on entry;
|
|
|
|
* Actual base address of the view on exit.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* ZeroBits
|
|
|
|
* Number of high order address bits that must be zero.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* CommitSize
|
|
|
|
* Size in bytes of the initially committed section of
|
|
|
|
* the view.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* SectionOffset
|
|
|
|
* Offset in bytes from the beginning of the section
|
|
|
|
* to the beginning of the view.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* ViewSize
|
|
|
|
* Desired length of map (or zero to map all) on entry
|
|
|
|
* Actual length mapped on exit.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* InheritDisposition
|
|
|
|
* Specified how the view is to be shared with
|
|
|
|
* child processes.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* AllocationType
|
|
|
|
* Type of allocation for the pages.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* Protect
|
|
|
|
* Protection for the committed region of the view.
|
2000-04-02 21:32:43 +08:00
|
|
|
*
|
|
|
|
* RETURN VALUE
|
2004-04-11 06:36:07 +08:00
|
|
|
* Status.
|
2003-07-11 05:05:04 +08:00
|
|
|
*
|
|
|
|
* @implemented
|
2000-04-02 21:32:43 +08:00
|
|
|
*/
|
2001-11-14 06:46:49 +08:00
|
|
|
NTSTATUS STDCALL
|
|
|
|
MmMapViewOfSection(IN PVOID SectionObject,
|
2004-04-11 06:36:07 +08:00
|
|
|
IN PEPROCESS Process,
|
|
|
|
IN OUT PVOID *BaseAddress,
|
|
|
|
IN ULONG ZeroBits,
|
|
|
|
IN ULONG CommitSize,
|
|
|
|
IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
|
2005-11-29 07:43:40 +08:00
|
|
|
IN OUT PSIZE_T ViewSize,
|
2004-04-11 06:36:07 +08:00
|
|
|
IN SECTION_INHERIT InheritDisposition,
|
|
|
|
IN ULONG AllocationType,
|
|
|
|
IN ULONG Protect)
|
2000-04-02 21:32:43 +08:00
|
|
|
{
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2008-07-28 09:49:23 +08:00
|
|
|
PMM_AVL_TABLE AddressSpace;
|
2001-11-14 06:46:49 +08:00
|
|
|
ULONG ViewOffset;
|
2002-09-15 18:45:05 +08:00
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2001-11-14 06:46:49 +08:00
|
|
|
|
2004-10-23 04:43:58 +08:00
|
|
|
ASSERT(Process);
|
2003-06-07 05:00:28 +08:00
|
|
|
|
2005-11-14 01:28:24 +08:00
|
|
|
if (Protect != PAGE_READONLY &&
|
|
|
|
Protect != PAGE_READWRITE &&
|
|
|
|
Protect != PAGE_WRITECOPY &&
|
|
|
|
Protect != PAGE_EXECUTE &&
|
|
|
|
Protect != PAGE_EXECUTE_READ &&
|
|
|
|
Protect != PAGE_EXECUTE_READWRITE &&
|
|
|
|
Protect != PAGE_EXECUTE_WRITECOPY)
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PAGE_PROTECTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-05-11 01:47:44 +08:00
|
|
|
Section = (PROS_SECTION_OBJECT)SectionObject;
|
2008-07-28 09:49:23 +08:00
|
|
|
AddressSpace = &Process->VadRoot;
|
2001-11-14 06:46:49 +08:00
|
|
|
|
2005-11-14 01:28:24 +08:00
|
|
|
AllocationType |= (Section->AllocationAttributes & SEC_NO_CHANGE);
|
|
|
|
|
2003-06-28 05:28:30 +08:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2003-05-14 18:52:46 +08:00
|
|
|
|
2002-08-15 04:58:39 +08:00
|
|
|
if (Section->AllocationAttributes & SEC_IMAGE)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
ULONG i;
|
|
|
|
ULONG NrSegments;
|
2005-01-03 01:55:06 +08:00
|
|
|
ULONG_PTR ImageBase;
|
2004-04-11 06:36:07 +08:00
|
|
|
ULONG ImageSize;
|
|
|
|
PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
|
|
|
|
PMM_SECTION_SEGMENT SectionSegments;
|
|
|
|
|
|
|
|
ImageSectionObject = Section->ImageSection;
|
|
|
|
SectionSegments = ImageSectionObject->Segments;
|
|
|
|
NrSegments = ImageSectionObject->NrSegments;
|
|
|
|
|
|
|
|
|
2005-01-03 01:55:06 +08:00
|
|
|
ImageBase = (ULONG_PTR)*BaseAddress;
|
|
|
|
if (ImageBase == 0)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2005-01-03 01:55:06 +08:00
|
|
|
ImageBase = ImageSectionObject->ImageBase;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ImageSize = 0;
|
|
|
|
for (i = 0; i < NrSegments; i++)
|
|
|
|
{
|
2006-09-10 18:26:58 +08:00
|
|
|
if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2005-01-12 18:05:31 +08:00
|
|
|
ULONG_PTR MaxExtent;
|
|
|
|
MaxExtent = (ULONG_PTR)SectionSegments[i].VirtualAddress +
|
|
|
|
SectionSegments[i].Length;
|
2004-04-11 06:36:07 +08:00
|
|
|
ImageSize = max(ImageSize, MaxExtent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-23 23:31:45 +08:00
|
|
|
ImageSectionObject->ImageSize = ImageSize;
|
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
/* Check there is enough space to map the section at that point. */
|
2005-01-03 03:14:52 +08:00
|
|
|
if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase,
|
|
|
|
PAGE_ROUND_UP(ImageSize)) != NULL)
|
2004-04-11 06:36:07 +08: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-03 01:55:06 +08:00
|
|
|
ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), PAGE_SIZE, FALSE);
|
|
|
|
if (ImageBase == 0)
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < NrSegments; i++)
|
|
|
|
{
|
2006-09-10 18:26:58 +08:00
|
|
|
if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
|
|
|
PVOID SBaseAddress = (PVOID)
|
|
|
|
((char*)ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
|
|
|
|
MmLockSectionSegment(&SectionSegments[i]);
|
2005-11-14 01:28:24 +08:00
|
|
|
Status = MmMapViewOfSegment(AddressSpace,
|
2004-04-11 06:36:07 +08:00
|
|
|
Section,
|
|
|
|
&SectionSegments[i],
|
|
|
|
&SBaseAddress,
|
|
|
|
SectionSegments[i].Length,
|
|
|
|
SectionSegments[i].Protection,
|
2004-10-02 04:06:43 +08:00
|
|
|
0,
|
2005-11-14 01:28:24 +08:00
|
|
|
0);
|
2004-04-11 06:36:07 +08:00
|
|
|
MmUnlockSectionSegment(&SectionSegments[i]);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-01-03 01:55:06 +08:00
|
|
|
*BaseAddress = (PVOID)ImageBase;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2001-11-14 06:46:49 +08:00
|
|
|
else
|
2004-04-11 06:36:07 +08:00
|
|
|
{
|
2005-11-14 01:28:24 +08:00
|
|
|
/* check for write access */
|
|
|
|
if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) &&
|
|
|
|
!(Section->SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)))
|
|
|
|
{
|
|
|
|
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)))
|
|
|
|
{
|
|
|
|
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)))
|
|
|
|
{
|
|
|
|
return STATUS_SECTION_PROTECTION;
|
|
|
|
}
|
|
|
|
|
2004-04-11 06:36:07 +08: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 23:48:05 +08:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-11 06:36:07 +08: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;
|
|
|
|
}
|
|
|
|
|
|
|
|
MmLockSectionSegment(Section->Segment);
|
2005-11-14 01:28:24 +08:00
|
|
|
Status = MmMapViewOfSegment(AddressSpace,
|
2004-04-11 06:36:07 +08:00
|
|
|
Section,
|
|
|
|
Section->Segment,
|
|
|
|
BaseAddress,
|
|
|
|
*ViewSize,
|
|
|
|
Protect,
|
|
|
|
ViewOffset,
|
2005-11-14 01:28:24 +08:00
|
|
|
AllocationType & (MEM_TOP_DOWN|SEC_NO_CHANGE));
|
2004-04-11 06:36:07 +08:00
|
|
|
MmUnlockSectionSegment(Section->Segment);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
}
|
2001-11-14 06:46:49 +08:00
|
|
|
|
2003-06-28 05:28:30 +08:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2001-11-14 06:46:49 +08:00
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
2000-04-02 21:32:43 +08:00
|
|
|
}
|
|
|
|
|
2003-07-11 05:05:04 +08:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
2000-12-28 11:38:08 +08:00
|
|
|
BOOLEAN STDCALL
|
2004-04-11 06:36:07 +08:00
|
|
|
MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
|
|
|
|
IN PLARGE_INTEGER NewFileSize)
|
2000-04-02 21:32:43 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
UNIMPLEMENTED;
|
|
|
|
return (FALSE);
|
2000-04-02 21:32:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-07-11 05:05:04 +08:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
2000-12-28 11:38:08 +08:00
|
|
|
BOOLEAN STDCALL
|
2006-09-07 13:07:34 +08:00
|
|
|
MmDisableModifiedWriteOfSection (ULONG Unknown0)
|
2000-04-02 21:32:43 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
UNIMPLEMENTED;
|
|
|
|
return (FALSE);
|
2000-04-02 21:32:43 +08:00
|
|
|
}
|
|
|
|
|
2003-07-11 05:05:04 +08:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2000-12-28 11:38:08 +08:00
|
|
|
BOOLEAN STDCALL
|
2004-04-11 06:36:07 +08:00
|
|
|
MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
|
|
|
|
IN MMFLUSH_TYPE FlushType)
|
2000-04-02 21:32:43 +08:00
|
|
|
{
|
2003-01-11 23:31:05 +08:00
|
|
|
switch(FlushType)
|
|
|
|
{
|
2003-12-31 02:52:06 +08:00
|
|
|
case MmFlushForDelete:
|
|
|
|
if (SectionObjectPointer->ImageSectionObject ||
|
2004-04-11 06:36:07 +08:00
|
|
|
SectionObjectPointer->DataSectionObject)
|
|
|
|
{
|
2003-01-11 23:31:05 +08:00
|
|
|
return FALSE;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
CcRosSetRemoveOnClose(SectionObjectPointer);
|
2003-01-11 23:31:05 +08:00
|
|
|
return TRUE;
|
|
|
|
case MmFlushForWrite:
|
2004-04-11 06:36:07 +08:00
|
|
|
break;
|
2003-01-11 23:31:05 +08:00
|
|
|
}
|
|
|
|
return FALSE;
|
2000-04-02 21:32:43 +08:00
|
|
|
}
|
|
|
|
|
2003-07-11 05:05:04 +08:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
2000-12-28 11:38:08 +08:00
|
|
|
BOOLEAN STDCALL
|
2005-01-02 15:04:56 +08:00
|
|
|
MmForceSectionClosed (
|
|
|
|
IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
|
|
|
|
IN BOOLEAN DelayClose)
|
2000-04-02 21:32:43 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
UNIMPLEMENTED;
|
|
|
|
return (FALSE);
|
2000-04-02 21:32:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-07-11 05:05:04 +08:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2000-12-28 11:38:08 +08:00
|
|
|
NTSTATUS STDCALL
|
2004-04-11 06:36:07 +08:00
|
|
|
MmMapViewInSystemSpace (IN PVOID SectionObject,
|
|
|
|
OUT PVOID * MappedBase,
|
|
|
|
IN OUT PULONG ViewSize)
|
2000-04-02 21:32:43 +08:00
|
|
|
{
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT Section;
|
2008-07-28 09:49:23 +08:00
|
|
|
PMM_AVL_TABLE AddressSpace;
|
2004-04-11 06:36:07 +08:00
|
|
|
NTSTATUS Status;
|
2003-05-17 21:43:44 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
DPRINT("MmMapViewInSystemSpace() called\n");
|
2003-05-17 21:43:44 +08:00
|
|
|
|
2006-05-11 01:47:44 +08:00
|
|
|
Section = (PROS_SECTION_OBJECT)SectionObject;
|
2004-04-11 06:36:07 +08:00
|
|
|
AddressSpace = MmGetKernelAddressSpace();
|
2003-05-17 21:43:44 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2003-05-17 21:43:44 +08:00
|
|
|
|
2003-12-31 02:52:06 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
if ((*ViewSize) == 0)
|
|
|
|
{
|
2003-05-17 21:43:44 +08:00
|
|
|
(*ViewSize) = Section->MaximumSize.u.LowPart;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
|
|
|
else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
|
|
|
|
{
|
2003-05-17 21:43:44 +08:00
|
|
|
(*ViewSize) = Section->MaximumSize.u.LowPart;
|
2004-04-11 06:36:07 +08:00
|
|
|
}
|
2003-05-17 21:43:44 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
MmLockSectionSegment(Section->Segment);
|
2003-05-17 21:43:44 +08:00
|
|
|
|
|
|
|
|
2005-11-14 01:28:24 +08:00
|
|
|
Status = MmMapViewOfSegment(AddressSpace,
|
2004-04-11 06:36:07 +08:00
|
|
|
Section,
|
|
|
|
Section->Segment,
|
|
|
|
MappedBase,
|
|
|
|
*ViewSize,
|
|
|
|
PAGE_READWRITE,
|
|
|
|
0,
|
2005-11-14 01:28:24 +08:00
|
|
|
0);
|
2003-05-17 21:43:44 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
MmUnlockSectionSegment(Section->Segment);
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2003-05-17 21:43:44 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
return Status;
|
2000-04-02 21:32:43 +08:00
|
|
|
}
|
|
|
|
|
2004-07-17 11:03:52 +08:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
NTSTATUS
|
|
|
|
STDCALL
|
|
|
|
MmMapViewInSessionSpace (
|
|
|
|
IN PVOID Section,
|
|
|
|
OUT PVOID *MappedBase,
|
|
|
|
IN OUT PSIZE_T ViewSize
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2003-05-14 18:52:46 +08:00
|
|
|
|
2003-07-11 05:05:04 +08:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2000-12-28 11:38:08 +08:00
|
|
|
NTSTATUS STDCALL
|
2004-04-11 06:36:07 +08:00
|
|
|
MmUnmapViewInSystemSpace (IN PVOID MappedBase)
|
2000-04-02 21:32:43 +08:00
|
|
|
{
|
2008-07-28 09:49:23 +08:00
|
|
|
PMM_AVL_TABLE AddressSpace;
|
2004-04-11 06:36:07 +08:00
|
|
|
NTSTATUS Status;
|
2003-05-17 21:43:44 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
DPRINT("MmUnmapViewInSystemSpace() called\n");
|
2003-05-17 21:43:44 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
AddressSpace = MmGetKernelAddressSpace();
|
2003-05-17 21:43:44 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
|
2003-05-17 21:43:44 +08:00
|
|
|
|
2004-04-11 06:36:07 +08:00
|
|
|
return Status;
|
2000-04-02 21:32:43 +08:00
|
|
|
}
|
|
|
|
|
2004-07-17 11:03:52 +08:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
NTSTATUS
|
|
|
|
STDCALL
|
|
|
|
MmUnmapViewInSessionSpace (
|
|
|
|
IN PVOID MappedBase
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
2000-04-02 21:32:43 +08:00
|
|
|
|
2003-07-11 05:05:04 +08:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
2000-12-28 11:38:08 +08:00
|
|
|
NTSTATUS STDCALL
|
2006-09-07 13:07:34 +08:00
|
|
|
MmSetBankedSection (ULONG Unknown0,
|
|
|
|
ULONG Unknown1,
|
|
|
|
ULONG Unknown2,
|
|
|
|
ULONG Unknown3,
|
|
|
|
ULONG Unknown4,
|
|
|
|
ULONG Unknown5)
|
2000-04-02 21:32:43 +08:00
|
|
|
{
|
2004-04-11 06:36:07 +08:00
|
|
|
UNIMPLEMENTED;
|
|
|
|
return (STATUS_NOT_IMPLEMENTED);
|
2000-04-02 21:32:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
2004-04-11 06:36:07 +08:00
|
|
|
* NAME EXPORTED
|
|
|
|
* MmCreateSection@
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2000-04-02 21:32:43 +08:00
|
|
|
* DESCRIPTION
|
2004-04-11 06:36:07 +08:00
|
|
|
* Creates a section object.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2000-04-02 21:32:43 +08:00
|
|
|
* ARGUMENTS
|
2004-08-06 03:59:13 +08:00
|
|
|
* SectionObject (OUT)
|
2004-04-11 06:36:07 +08:00
|
|
|
* Caller supplied storage for the resulting pointer
|
|
|
|
* to a SECTION_OBJECT instance;
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08: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-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* ObjectAttributes [OPTIONAL]
|
|
|
|
* Initialized attributes for the object can be used
|
|
|
|
* to create a named section;
|
2000-04-02 21:32:43 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08: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-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* SectionPageProtection
|
|
|
|
* Can be a combination of:
|
|
|
|
* PAGE_READONLY |
|
|
|
|
* PAGE_READWRITE |
|
|
|
|
* PAGE_WRITEONLY |
|
|
|
|
* PAGE_WRITECOPY
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* AllocationAttributes
|
|
|
|
* Can be a combination of:
|
|
|
|
* SEC_IMAGE |
|
|
|
|
* SEC_RESERVE
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* FileHandle
|
|
|
|
* Handle to a file to create a section mapped to a file
|
|
|
|
* instead of a memory backed section;
|
2000-04-02 21:32:43 +08:00
|
|
|
*
|
2004-04-11 06:36:07 +08:00
|
|
|
* File
|
|
|
|
* Unknown.
|
2003-12-31 02:52:06 +08:00
|
|
|
*
|
2000-04-02 21:32:43 +08:00
|
|
|
* RETURN VALUE
|
2004-04-11 06:36:07 +08:00
|
|
|
* Status.
|
2003-07-11 05:05:04 +08:00
|
|
|
*
|
2004-08-06 03:59:13 +08:00
|
|
|
* @implemented
|
2000-04-02 21:32:43 +08:00
|
|
|
*/
|
2000-12-28 11:38:08 +08:00
|
|
|
NTSTATUS STDCALL
|
2006-01-08 14:23:17 +08:00
|
|
|
MmCreateSection (OUT PVOID * Section,
|
2004-04-11 06:36:07 +08: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 21:32:43 +08:00
|
|
|
{
|
2005-11-14 01:28:24 +08:00
|
|
|
ULONG Protection;
|
2006-05-11 01:47:44 +08:00
|
|
|
PROS_SECTION_OBJECT *SectionObject = (PROS_SECTION_OBJECT *)Section;
|
2005-11-14 01:28:24 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the protection
|
|
|
|
*/
|
|
|
|
Protection = SectionPageProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
|
|
|
|
if (Protection != PAGE_NOACCESS &&
|
|
|
|
Protection != PAGE_READONLY &&
|
|
|
|
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-06 03:59:13 +08: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 21:32:43 +08:00
|
|
|
}
|
|
|
|
|
2006-10-24 02:12:12 +08:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle,
|
|
|
|
IN OUT PULONG NumberOfPages,
|
|
|
|
IN OUT PULONG UserPfnArray)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
2008-06-27 16:23:45 +08:00
|
|
|
NtMapUserPhysicalPages(IN PVOID VirtualAddresses,
|
2006-10-24 02:12:12 +08:00
|
|
|
IN ULONG NumberOfPages,
|
|
|
|
IN OUT PULONG UserPfnArray)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NtMapUserPhysicalPagesScatter(IN PVOID *VirtualAddresses,
|
|
|
|
IN ULONG NumberOfPages,
|
|
|
|
IN OUT PULONG UserPfnArray)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NtFreeUserPhysicalPages(IN HANDLE ProcessHandle,
|
|
|
|
IN OUT PULONG NumberOfPages,
|
|
|
|
IN OUT PULONG UserPfnArray)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage,
|
|
|
|
IN PVOID File2MappedAsFile)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-08-29 14:59:11 +08:00
|
|
|
/* EOF */
|