2008-03-09 14:11:42 +00:00
|
|
|
/*
|
2005-06-07 17:07:34 +00:00
|
|
|
* Copyright (C) 2002-2005 ReactOS Team (and the authors from the programmers section)
|
|
|
|
*
|
2005-06-07 20:15:16 +00:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
2005-06-07 17:07:34 +00:00
|
|
|
*
|
2005-06-07 20:15:16 +00:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
2005-06-07 17:07:34 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2005-06-07 20:15:16 +00:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2005-06-07 17:07:34 +00:00
|
|
|
*
|
2005-06-07 20:15:16 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2005-06-07 17:07:34 +00:00
|
|
|
*
|
|
|
|
*
|
2005-01-26 13:58:37 +00:00
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: ntoskrnl/mm/anonmem.c
|
|
|
|
* PURPOSE: Implementing anonymous memory.
|
|
|
|
*
|
|
|
|
* PROGRAMMERS: David Welch
|
2005-06-07 17:07:34 +00:00
|
|
|
* Casper Hornstrup
|
|
|
|
* KJK::Hyperion
|
|
|
|
* Ge van Geldorp
|
|
|
|
* Eric Kohl
|
|
|
|
* Royce Mitchell III
|
2007-10-19 23:21:45 +00:00
|
|
|
* Aleksey Bragin
|
2005-06-07 17:07:34 +00:00
|
|
|
* Jason Filby
|
|
|
|
* Art Yerkes
|
|
|
|
* Gunnar Andre' Dalsnes
|
|
|
|
* Filip Navara
|
|
|
|
* Thomas Weidenmueller
|
|
|
|
* Alex Ionescu
|
2007-10-19 23:21:45 +00:00
|
|
|
* Trevor McCort
|
2005-06-07 17:07:34 +00:00
|
|
|
* Steven Edwards
|
2002-08-10 16:41:20 +00:00
|
|
|
*/
|
2003-05-17 15:29:50 +00:00
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
/* INCLUDE *****************************************************************/
|
|
|
|
|
2004-08-15 16:39:12 +00:00
|
|
|
#include <ntoskrnl.h>
|
2002-08-10 16:41:20 +00:00
|
|
|
#define NDEBUG
|
2008-08-30 16:31:06 +00:00
|
|
|
#include <debug.h>
|
2002-08-10 16:41:20 +00:00
|
|
|
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2009-04-27 10:12:57 +00:00
|
|
|
MmWritePageVirtualMemory(PMMSUPPORT AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
PMEMORY_AREA MemoryArea,
|
|
|
|
PVOID Address,
|
|
|
|
PMM_PAGEOP PageOp)
|
2002-08-10 16:41:20 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
SWAPENTRY SwapEntry;
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page;
|
2004-04-10 22:36:07 +00:00
|
|
|
NTSTATUS Status;
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for paging out from a deleted virtual memory area.
|
|
|
|
*/
|
|
|
|
if (MemoryArea->DeleteInProgress)
|
|
|
|
{
|
2002-08-14 20:58:39 +00:00
|
|
|
PageOp->Status = STATUS_UNSUCCESSFUL;
|
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
MmReleasePageOp(PageOp);
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2002-08-14 20:58:39 +00:00
|
|
|
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Page = MmGetPfnForProcess(Process, Address);
|
2002-08-10 16:41:20 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
|
|
|
* Get that the page actually is dirty.
|
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
if (!MmIsDirtyPage(Process, Address))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2002-08-14 20:58:39 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
MmReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Speculatively set the mapping to clean.
|
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmSetCleanPage(Process, Address);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If necessary, allocate an entry in the paging file for this page
|
|
|
|
*/
|
2004-08-01 07:24:59 +00:00
|
|
|
SwapEntry = MmGetSavedSwapEntryPage(Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (SwapEntry == 0)
|
|
|
|
{
|
2002-08-14 20:58:39 +00:00
|
|
|
SwapEntry = MmAllocSwapPage();
|
|
|
|
if (SwapEntry == 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmSetDirtyPage(Process, Address);
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_PAGEFILE_QUOTA_EXCEEDED;
|
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
MmReleasePageOp(PageOp);
|
|
|
|
return(STATUS_PAGEFILE_QUOTA_EXCEEDED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write the page to the pagefile
|
|
|
|
*/
|
2004-08-01 07:24:59 +00:00
|
|
|
Status = MmWriteToSwapPage(SwapEntry, Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
|
|
|
|
Status);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmSetDirtyPage(Process, Address);
|
2002-08-14 20:58:39 +00:00
|
|
|
PageOp->Status = STATUS_UNSUCCESSFUL;
|
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
MmReleasePageOp(PageOp);
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise we have succeeded.
|
|
|
|
*/
|
2004-08-01 07:24:59 +00:00
|
|
|
MmSetSavedSwapEntryPage(Page, SwapEntry);
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
MmReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
2002-08-14 20:58:39 +00:00
|
|
|
}
|
2002-08-10 16:41:20 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2009-04-27 10:12:57 +00:00
|
|
|
MmPageOutVirtualMemory(PMMSUPPORT AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
PMEMORY_AREA MemoryArea,
|
|
|
|
PVOID Address,
|
|
|
|
PMM_PAGEOP PageOp)
|
2002-08-10 16:41:20 +00:00
|
|
|
{
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page;
|
2006-01-08 06:23:17 +00:00
|
|
|
BOOLEAN WasDirty;
|
2002-08-10 16:41:20 +00:00
|
|
|
SWAPENTRY SwapEntry;
|
|
|
|
NTSTATUS Status;
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
DPRINT("MmPageOutVirtualMemory(Address 0x%.8X) PID %d\n",
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Address, Process->UniqueProcessId);
|
2002-08-10 16:41:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for paging out from a deleted virtual memory area.
|
|
|
|
*/
|
|
|
|
if (MemoryArea->DeleteInProgress)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
PageOp->Status = STATUS_UNSUCCESSFUL;
|
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
MmReleasePageOp(PageOp);
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
2002-08-10 16:41:20 +00:00
|
|
|
|
|
|
|
/*
|
2002-08-14 20:58:39 +00:00
|
|
|
* Disable the virtual mapping.
|
2002-08-10 16:41:20 +00:00
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmDisableVirtualMapping(Process, Address,
|
2004-08-01 07:24:59 +00:00
|
|
|
&WasDirty, &Page);
|
2002-11-05 20:31:34 +00:00
|
|
|
|
2004-08-01 07:24:59 +00:00
|
|
|
if (Page == 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2002-08-14 20:58:39 +00:00
|
|
|
|
|
|
|
/*
|
2005-05-09 01:38:29 +00:00
|
|
|
* Paging out non-dirty data is easy.
|
2002-08-14 20:58:39 +00:00
|
|
|
*/
|
2002-08-10 16:41:20 +00:00
|
|
|
if (!WasDirty)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-10-29 14:09:00 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
|
2004-08-01 07:24:59 +00:00
|
|
|
MmDeleteAllRmaps(Page, NULL, NULL);
|
|
|
|
if ((SwapEntry = MmGetSavedSwapEntryPage(Page)) != 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmCreatePageFileMapping(Process, Address, SwapEntry);
|
2004-08-01 07:24:59 +00:00
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-10-29 14:09:00 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2004-08-01 07:24:59 +00:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
MmReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
2002-08-10 16:41:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If necessary, allocate an entry in the paging file for this page
|
|
|
|
*/
|
2004-08-01 07:24:59 +00:00
|
|
|
SwapEntry = MmGetSavedSwapEntryPage(Page);
|
2002-08-10 16:41:20 +00:00
|
|
|
if (SwapEntry == 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
SwapEntry = MmAllocSwapPage();
|
|
|
|
if (SwapEntry == 0)
|
|
|
|
{
|
|
|
|
MmShowOutOfSpaceMessagePagingFile();
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmEnableVirtualMapping(Process, Address);
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_UNSUCCESSFUL;
|
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
MmReleasePageOp(PageOp);
|
|
|
|
return(STATUS_PAGEFILE_QUOTA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
/*
|
|
|
|
* Write the page to the pagefile
|
|
|
|
*/
|
2004-08-01 07:24:59 +00:00
|
|
|
Status = MmWriteToSwapPage(SwapEntry, Page);
|
2002-08-10 16:41:20 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
|
|
|
|
Status);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmEnableVirtualMapping(Process, Address);
|
2004-04-10 22:36:07 +00:00
|
|
|
PageOp->Status = STATUS_UNSUCCESSFUL;
|
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
MmReleasePageOp(PageOp);
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
2002-08-10 16:41:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise we have succeeded, free the page
|
|
|
|
*/
|
2004-08-01 07:24:59 +00:00
|
|
|
DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", Page << PAGE_SHIFT);
|
2005-10-29 14:09:00 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
|
|
|
|
MmCreatePageFileMapping(Process, Address, SwapEntry);
|
2005-10-29 14:09:00 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
2004-08-01 07:24:59 +00:00
|
|
|
MmDeleteAllRmaps(Page, NULL, NULL);
|
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2002-08-10 16:41:20 +00:00
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
MmReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2009-04-27 10:12:57 +00:00
|
|
|
MmNotPresentFaultVirtualMemory(PMMSUPPORT AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
MEMORY_AREA* MemoryArea,
|
|
|
|
PVOID Address,
|
|
|
|
BOOLEAN Locked)
|
2002-08-10 16:41:20 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Move data into memory to satisfy a page not present fault
|
|
|
|
* ARGUMENTS:
|
|
|
|
* AddressSpace = Address space within which the fault occurred
|
|
|
|
* MemoryArea = The memory area within which the fault occurred
|
|
|
|
* Address = The absolute address of fault
|
|
|
|
* RETURNS: Status
|
|
|
|
* NOTES: This function is called with the address space lock held.
|
|
|
|
*/
|
|
|
|
{
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page;
|
2002-08-10 16:41:20 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
PMM_REGION Region;
|
|
|
|
PMM_PAGEOP PageOp;
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
/*
|
|
|
|
* There is a window between taking the page fault and locking the
|
|
|
|
* address space when another thread could load the page so we check
|
|
|
|
* that.
|
|
|
|
*/
|
|
|
|
if (MmIsPagePresent(NULL, Address))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
2002-08-10 16:41:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for the virtual memory area being deleted.
|
|
|
|
*/
|
|
|
|
if (MemoryArea->DeleteInProgress)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
2002-08-10 16:41:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the segment corresponding to the virtual address
|
|
|
|
*/
|
2005-01-02 17:55:06 +00:00
|
|
|
Region = MmFindRegion(MemoryArea->StartingAddress,
|
2004-04-10 22:36:07 +00:00
|
|
|
&MemoryArea->Data.VirtualMemoryData.RegionListHead,
|
|
|
|
Address, NULL);
|
2009-02-07 19:29:39 +00:00
|
|
|
|
2003-08-25 19:26:10 +00:00
|
|
|
if (Region->Type == MEM_RESERVE || Region->Protect == PAGE_NOACCESS)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
return(STATUS_ACCESS_VIOLATION);
|
|
|
|
}
|
2002-08-10 16:41:20 +00:00
|
|
|
|
2009-02-07 19:29:39 +00:00
|
|
|
/*
|
|
|
|
* FIXME
|
|
|
|
*/
|
|
|
|
if (Region->Protect & PAGE_GUARD)
|
|
|
|
{
|
|
|
|
return(STATUS_GUARD_PAGE_VIOLATION);
|
|
|
|
}
|
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
/*
|
|
|
|
* Get or create a page operation
|
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
PageOp = MmGetPageOp(MemoryArea, Process->UniqueProcessId,
|
2004-04-10 22:36:07 +00:00
|
|
|
(PVOID)PAGE_ROUND_DOWN(Address), NULL, 0,
|
|
|
|
MM_PAGEOP_PAGEIN, FALSE);
|
2002-08-10 16:41:20 +00:00
|
|
|
if (PageOp == NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT1("MmGetPageOp failed");
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2002-08-10 16:41:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if someone else is already handling this fault, if so wait
|
|
|
|
* for them
|
|
|
|
*/
|
|
|
|
if (PageOp->Thread != PsGetCurrentThread())
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
|
|
|
|
0,
|
|
|
|
KernelMode,
|
|
|
|
FALSE,
|
|
|
|
NULL);
|
|
|
|
/*
|
|
|
|
* Check for various strange conditions
|
|
|
|
*/
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
DPRINT1("Failed to wait for page op\n");
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
if (PageOp->Status == STATUS_PENDING)
|
|
|
|
{
|
|
|
|
DPRINT1("Woke for page op before completion\n");
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If this wasn't a pagein then we need to restart the handling
|
|
|
|
*/
|
|
|
|
if (PageOp->OpType != MM_PAGEOP_PAGEIN)
|
|
|
|
{
|
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
MmReleasePageOp(PageOp);
|
|
|
|
return(STATUS_MM_RESTART_OPERATION);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If the thread handling this fault has failed then we don't retry
|
|
|
|
*/
|
|
|
|
if (!NT_SUCCESS(PageOp->Status))
|
|
|
|
{
|
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
Status = PageOp->Status;
|
|
|
|
MmReleasePageOp(PageOp);
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
MmReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
/*
|
|
|
|
* Try to allocate a page
|
|
|
|
*/
|
|
|
|
Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
|
|
|
|
if (Status == STATUS_NO_MEMORY)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
|
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
}
|
2003-01-11 15:45:55 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("MmRequestPageMemoryConsumer failed, status = %x\n", Status);
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2003-01-11 15:45:55 +00:00
|
|
|
}
|
2002-08-10 16:41:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle swapped out pages.
|
|
|
|
*/
|
|
|
|
if (MmIsPageSwapEntry(NULL, Address))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
SWAPENTRY SwapEntry;
|
|
|
|
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmDeletePageFileMapping(Process, Address, &SwapEntry);
|
2004-08-01 07:24:59 +00:00
|
|
|
Status = MmReadFromSwapPage(SwapEntry, Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
MmSetSavedSwapEntryPage(Page, SwapEntry);
|
|
|
|
}
|
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
/*
|
|
|
|
* Set the page. If we fail because we are out of memory then
|
|
|
|
* try again
|
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
(PVOID)PAGE_ROUND_DOWN(Address),
|
|
|
|
Region->Protect,
|
2004-08-01 07:24:59 +00:00
|
|
|
&Page,
|
|
|
|
1);
|
2002-08-10 16:41:20 +00:00
|
|
|
while (Status == STATUS_NO_MEMORY)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
Status = MmCreateVirtualMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
Address,
|
|
|
|
Region->Protect,
|
2004-08-01 07:24:59 +00:00
|
|
|
&Page,
|
|
|
|
1);
|
2004-04-10 22:36:07 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
}
|
2002-08-10 16:41:20 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
return(Status);
|
|
|
|
}
|
2002-08-10 16:41:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Add the page to the process's working set
|
|
|
|
*/
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmInsertRmap(Page, Process, (PVOID)PAGE_ROUND_DOWN(Address));
|
2002-08-10 16:41:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Finish the operation
|
|
|
|
*/
|
|
|
|
PageOp->Status = STATUS_SUCCESS;
|
|
|
|
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
MmReleasePageOp(PageOp);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2008-12-03 17:28:59 +00:00
|
|
|
static VOID
|
2009-04-27 10:12:57 +00:00
|
|
|
MmModifyAttributes(PMMSUPPORT AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
PVOID BaseAddress,
|
|
|
|
ULONG RegionSize,
|
|
|
|
ULONG OldType,
|
|
|
|
ULONG OldProtect,
|
|
|
|
ULONG NewType,
|
|
|
|
ULONG NewProtect)
|
2002-08-10 16:41:20 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Modify the attributes of a memory region
|
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
|
|
|
* If we are switching a previously committed region to reserved then
|
|
|
|
* free any allocated pages within the region
|
|
|
|
*/
|
|
|
|
if (NewType == MEM_RESERVE && OldType == MEM_COMMIT)
|
|
|
|
{
|
2002-08-10 16:41:20 +00:00
|
|
|
ULONG i;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2002-11-05 20:31:34 +00:00
|
|
|
for (i=0; i < PAGE_ROUND_UP(RegionSize)/PAGE_SIZE; i++)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
if (MmIsPageSwapEntry(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
(char*)BaseAddress + (i * PAGE_SIZE)))
|
|
|
|
{
|
|
|
|
SWAPENTRY SwapEntry;
|
|
|
|
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmDeletePageFileMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
(char*)BaseAddress + (i * PAGE_SIZE),
|
|
|
|
&SwapEntry);
|
|
|
|
MmFreeSwapPage(SwapEntry);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmDeleteVirtualMapping(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
(char*)BaseAddress + (i*PAGE_SIZE),
|
2004-08-01 07:24:59 +00:00
|
|
|
FALSE, NULL, &Page);
|
|
|
|
if (Page != 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
SWAPENTRY SavedSwapEntry;
|
2004-08-01 07:24:59 +00:00
|
|
|
SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (SavedSwapEntry != 0)
|
|
|
|
{
|
|
|
|
MmFreeSwapPage(SavedSwapEntry);
|
2004-08-01 07:24:59 +00:00
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmDeleteRmap(Page, Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
(char*)BaseAddress + (i * PAGE_SIZE));
|
2004-08-01 07:24:59 +00:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we are changing the protection attributes of a committed region then
|
|
|
|
* alter the attributes for any allocated pages within the region
|
|
|
|
*/
|
|
|
|
if (NewType == MEM_COMMIT && OldType == MEM_COMMIT &&
|
2004-08-01 07:24:59 +00:00
|
|
|
OldProtect != NewProtect)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2002-08-10 16:41:20 +00:00
|
|
|
ULONG i;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2002-11-05 20:31:34 +00:00
|
|
|
for (i=0; i < PAGE_ROUND_UP(RegionSize)/PAGE_SIZE; i++)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
if (MmIsPagePresent(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
(char*)BaseAddress + (i*PAGE_SIZE)))
|
|
|
|
{
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
MmSetPageProtect(Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
(char*)BaseAddress + (i*PAGE_SIZE),
|
|
|
|
NewProtect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-08-10 16:41:20 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 21:05:04 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2008-11-29 20:47:48 +00:00
|
|
|
NTSTATUS NTAPI
|
2007-10-17 08:16:20 +00:00
|
|
|
NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
|
|
|
|
IN OUT PVOID* UBaseAddress,
|
2008-09-24 15:27:54 +00:00
|
|
|
IN ULONG_PTR ZeroBits,
|
2008-08-27 20:56:16 +00:00
|
|
|
IN OUT PSIZE_T URegionSize,
|
2007-10-17 08:16:20 +00:00
|
|
|
IN ULONG AllocationType,
|
|
|
|
IN ULONG Protect)
|
2002-08-10 16:41:20 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Allocates a block of virtual memory in the process address space
|
|
|
|
* ARGUMENTS:
|
|
|
|
* ProcessHandle = The handle of the process which owns the virtual memory
|
2005-05-09 01:38:29 +00:00
|
|
|
* BaseAddress = A pointer to the virtual memory allocated. If you
|
|
|
|
* supply a non zero value the system will try to
|
|
|
|
* allocate the memory at the address supplied. It round
|
2002-08-10 16:41:20 +00:00
|
|
|
* it down to a multiple of the page size.
|
2005-05-09 01:38:29 +00:00
|
|
|
* ZeroBits = (OPTIONAL) You can specify the number of high order bits
|
|
|
|
* that must be zero, ensuring that the memory will be
|
2002-08-10 16:41:20 +00:00
|
|
|
* allocated at a address below a certain value.
|
|
|
|
* RegionSize = The number of bytes to allocate
|
2005-05-09 01:38:29 +00:00
|
|
|
* AllocationType = Indicates the type of virtual memory you like to
|
|
|
|
* allocated, can be a combination of MEM_COMMIT,
|
2002-08-10 16:41:20 +00:00
|
|
|
* MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN.
|
2009-05-09 17:00:18 +00:00
|
|
|
* Protect = Indicates the protection type of the pages allocated.
|
2002-08-10 16:41:20 +00:00
|
|
|
* RETURNS: Status
|
|
|
|
*/
|
|
|
|
{
|
2006-05-18 20:32:17 +00:00
|
|
|
PEPROCESS Process;
|
2002-08-10 16:41:20 +00:00
|
|
|
MEMORY_AREA* MemoryArea;
|
2005-01-02 17:55:06 +00:00
|
|
|
ULONG_PTR MemoryAreaLength;
|
2002-08-10 16:41:20 +00:00
|
|
|
ULONG Type;
|
|
|
|
NTSTATUS Status;
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace;
|
2002-08-10 16:41:20 +00:00
|
|
|
PVOID BaseAddress;
|
|
|
|
ULONG RegionSize;
|
|
|
|
PVOID PBaseAddress;
|
|
|
|
ULONG PRegionSize;
|
2009-05-09 17:00:18 +00:00
|
|
|
ULONG MemProtection;
|
2003-12-31 05:33:04 +00:00
|
|
|
PHYSICAL_ADDRESS BoundaryAddressMultiple;
|
2007-10-17 08:16:20 +00:00
|
|
|
KPROCESSOR_MODE PreviousMode;
|
|
|
|
|
|
|
|
PAGED_CODE();
|
2002-08-10 16:41:20 +00:00
|
|
|
|
|
|
|
DPRINT("NtAllocateVirtualMemory(*UBaseAddress %x, "
|
2004-04-10 22:36:07 +00:00
|
|
|
"ZeroBits %d, *URegionSize %x, AllocationType %x, Protect %x)\n",
|
|
|
|
*UBaseAddress,ZeroBits,*URegionSize,AllocationType,
|
|
|
|
Protect);
|
|
|
|
|
2005-08-07 07:11:03 +00:00
|
|
|
/* Check for valid protection flags */
|
2009-05-09 17:00:18 +00:00
|
|
|
MemProtection = Protect & ~(PAGE_GUARD|PAGE_NOCACHE);
|
|
|
|
if (MemProtection != PAGE_NOACCESS &&
|
|
|
|
MemProtection != PAGE_READONLY &&
|
|
|
|
MemProtection != PAGE_READWRITE &&
|
|
|
|
MemProtection != PAGE_WRITECOPY &&
|
|
|
|
MemProtection != PAGE_EXECUTE &&
|
|
|
|
MemProtection != PAGE_EXECUTE_READ &&
|
|
|
|
MemProtection != PAGE_EXECUTE_READWRITE &&
|
|
|
|
MemProtection != PAGE_EXECUTE_WRITECOPY)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-08-07 07:11:03 +00:00
|
|
|
DPRINT1("Invalid page protection\n");
|
|
|
|
return STATUS_INVALID_PAGE_PROTECTION;
|
|
|
|
}
|
|
|
|
|
2005-08-07 07:14:52 +00:00
|
|
|
/* Check for valid Zero bits */
|
|
|
|
if (ZeroBits > 21)
|
|
|
|
{
|
|
|
|
DPRINT1("Too many zero bits\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_3;
|
|
|
|
}
|
|
|
|
|
2005-08-07 07:11:03 +00:00
|
|
|
/* Check for valid Allocation Types */
|
2007-10-17 08:16:20 +00:00
|
|
|
if ((AllocationType & ~(MEM_COMMIT | MEM_RESERVE | MEM_RESET | MEM_PHYSICAL |
|
2005-08-07 07:11:03 +00:00
|
|
|
MEM_TOP_DOWN | MEM_WRITE_WATCH)))
|
|
|
|
{
|
|
|
|
DPRINT1("Invalid Allocation Type\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_5;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for at least one of these Allocation Types to be set */
|
|
|
|
if (!(AllocationType & (MEM_COMMIT | MEM_RESERVE | MEM_RESET)))
|
|
|
|
{
|
|
|
|
DPRINT1("No memory allocation base type\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_5;
|
|
|
|
}
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2005-08-07 07:11:03 +00:00
|
|
|
/* MEM_RESET is an exclusive flag, make sure that is valid too */
|
|
|
|
if ((AllocationType & MEM_RESET) && (AllocationType != MEM_RESET))
|
|
|
|
{
|
2007-10-17 08:16:20 +00:00
|
|
|
DPRINT1("Invalid use of MEM_RESET\n");
|
2005-08-07 07:11:03 +00:00
|
|
|
return STATUS_INVALID_PARAMETER_5;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-08-07 07:11:03 +00:00
|
|
|
|
|
|
|
/* MEM_WRITE_WATCH can only be used if MEM_RESERVE is also used */
|
|
|
|
if ((AllocationType & MEM_WRITE_WATCH) && !(AllocationType & MEM_RESERVE))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-08-07 07:11:03 +00:00
|
|
|
DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_5;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* MEM_PHYSICAL can only be used with MEM_RESERVE, and can only be R/W */
|
|
|
|
if (AllocationType & MEM_PHYSICAL)
|
|
|
|
{
|
|
|
|
/* First check for MEM_RESERVE exclusivity */
|
|
|
|
if (AllocationType != (MEM_RESERVE | MEM_PHYSICAL))
|
|
|
|
{
|
|
|
|
DPRINT1("MEM_PHYSICAL used with other flags then MEM_RESERVE or"
|
|
|
|
"MEM_RESERVE was not present at all\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_5;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then make sure PAGE_READWRITE is used */
|
|
|
|
if (Protect != PAGE_READWRITE)
|
|
|
|
{
|
|
|
|
DPRINT1("MEM_PHYSICAL used without PAGE_READWRITE\n");
|
|
|
|
return STATUS_INVALID_PAGE_PROTECTION;
|
|
|
|
}
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
2007-10-17 08:16:20 +00:00
|
|
|
PreviousMode = KeGetPreviousMode();
|
|
|
|
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_TRY
|
2007-10-17 08:16:20 +00:00
|
|
|
{
|
|
|
|
if (PreviousMode != KernelMode)
|
|
|
|
{
|
|
|
|
ProbeForWritePointer(UBaseAddress);
|
|
|
|
ProbeForWriteUlong(URegionSize);
|
|
|
|
}
|
|
|
|
PBaseAddress = *UBaseAddress;
|
|
|
|
PRegionSize = *URegionSize;
|
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
2007-10-17 08:16:20 +00:00
|
|
|
{
|
2009-08-24 20:39:23 +00:00
|
|
|
/* Return the exception code */
|
|
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
2007-10-17 08:16:20 +00:00
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_END;
|
2007-10-17 08:16:20 +00:00
|
|
|
|
2003-12-31 05:33:04 +00:00
|
|
|
BoundaryAddressMultiple.QuadPart = 0;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
BaseAddress = (PVOID)PAGE_ROUND_DOWN(PBaseAddress);
|
2007-10-17 08:16:20 +00:00
|
|
|
RegionSize = PAGE_ROUND_UP((ULONG_PTR)PBaseAddress + PRegionSize) -
|
2004-04-10 22:36:07 +00:00
|
|
|
PAGE_ROUND_DOWN(PBaseAddress);
|
|
|
|
|
2007-10-19 23:21:45 +00:00
|
|
|
/*
|
2005-08-07 07:11:03 +00:00
|
|
|
* We've captured and calculated the data, now do more checks
|
|
|
|
* Yes, MmCreateMemoryArea does similar checks, but they don't return
|
|
|
|
* the right status codes that a caller of this routine would expect.
|
|
|
|
*/
|
2008-07-21 09:40:12 +00:00
|
|
|
if ((ULONG_PTR)BaseAddress >= USER_SHARED_DATA)
|
2005-08-07 07:11:03 +00:00
|
|
|
{
|
2007-10-17 08:16:20 +00:00
|
|
|
DPRINT1("Virtual allocation base above User Space\n");
|
2005-08-07 07:11:03 +00:00
|
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
|
|
}
|
|
|
|
if (!RegionSize)
|
|
|
|
{
|
2007-10-17 08:16:20 +00:00
|
|
|
DPRINT1("Region size is invalid (zero)\n");
|
2005-08-07 07:11:03 +00:00
|
|
|
return STATUS_INVALID_PARAMETER_4;
|
|
|
|
}
|
2008-07-21 09:40:12 +00:00
|
|
|
if ((USER_SHARED_DATA - (ULONG_PTR)BaseAddress) < RegionSize)
|
2005-08-07 07:11:03 +00:00
|
|
|
{
|
|
|
|
DPRINT1("Region size would overflow into kernel-memory\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_4;
|
|
|
|
}
|
|
|
|
|
2007-10-19 23:21:45 +00:00
|
|
|
/*
|
2005-08-07 07:30:46 +00:00
|
|
|
* Copy on Write is reserved for system use. This case is a certain failure
|
|
|
|
* but there may be other cases...needs more testing
|
|
|
|
*/
|
2007-10-19 23:21:45 +00:00
|
|
|
if ((!BaseAddress || (AllocationType & MEM_RESERVE)) &&
|
2007-10-17 08:16:20 +00:00
|
|
|
(Protect & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY)))
|
2005-08-07 07:30:46 +00:00
|
|
|
{
|
|
|
|
DPRINT1("Copy on write is not supported by VirtualAlloc\n");
|
|
|
|
return STATUS_INVALID_PAGE_PROTECTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
Status = ObReferenceObjectByHandle(ProcessHandle,
|
2004-04-10 22:36:07 +00:00
|
|
|
PROCESS_VM_OPERATION,
|
2007-10-17 08:16:20 +00:00
|
|
|
PsProcessType,
|
|
|
|
PreviousMode,
|
2004-04-10 22:36:07 +00:00
|
|
|
(PVOID*)(&Process),
|
|
|
|
NULL);
|
2002-08-10 16:41:20 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
Type = (AllocationType & MEM_COMMIT) ? MEM_COMMIT : MEM_RESERVE;
|
|
|
|
DPRINT("Type %x\n", Type);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2009-04-27 10:12:57 +00:00
|
|
|
AddressSpace = &Process->Vm;
|
2002-08-10 16:41:20 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
if (PBaseAddress != 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-02 19:14:52 +00:00
|
|
|
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
if (MemoryArea != NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
MemoryAreaLength = (ULONG_PTR)MemoryArea->EndingAddress -
|
|
|
|
(ULONG_PTR)MemoryArea->StartingAddress;
|
2009-09-14 09:21:05 +00:00
|
|
|
|
2010-07-16 00:34:26 +00:00
|
|
|
if (((ULONG_PTR)BaseAddress + RegionSize) > (ULONG_PTR)MemoryArea->EndingAddress)
|
2009-09-14 09:21:05 +00:00
|
|
|
{
|
|
|
|
DPRINT("BaseAddress + RegionSize %x is larger than MemoryArea's EndingAddress %x\n",
|
2010-07-16 00:34:26 +00:00
|
|
|
(ULONG_PTR)BaseAddress + RegionSize, MemoryArea->EndingAddress);
|
2009-09-14 09:21:05 +00:00
|
|
|
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
ObDereferenceObject(Process);
|
|
|
|
|
|
|
|
return STATUS_MEMORY_NOT_ALLOCATED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (AllocationType == MEM_RESET)
|
|
|
|
{
|
|
|
|
if (MmIsPagePresent(Process, BaseAddress))
|
|
|
|
{
|
|
|
|
/* FIXME: mark pages as not modified */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* FIXME: if pages are in paging file discard them and bring in pages of zeros */
|
|
|
|
}
|
|
|
|
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
ObDereferenceObject(Process);
|
|
|
|
|
|
|
|
/* MEM_RESET does not modify any attributes of region */
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY &&
|
|
|
|
MemoryAreaLength >= RegionSize)
|
|
|
|
{
|
|
|
|
Status =
|
|
|
|
MmAlterRegion(AddressSpace,
|
|
|
|
MemoryArea->StartingAddress,
|
|
|
|
&MemoryArea->Data.VirtualMemoryData.RegionListHead,
|
|
|
|
BaseAddress, RegionSize,
|
|
|
|
Type, Protect, MmModifyAttributes);
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
ObDereferenceObject(Process);
|
|
|
|
DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
|
2008-09-23 12:41:02 +00:00
|
|
|
|
|
|
|
/* Give the caller rounded BaseAddress and area length */
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
*UBaseAddress = BaseAddress;
|
|
|
|
*URegionSize = RegionSize;
|
|
|
|
DPRINT("*UBaseAddress %x *URegionSize %x\n", BaseAddress, RegionSize);
|
|
|
|
}
|
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
else if (MemoryAreaLength >= RegionSize)
|
|
|
|
{
|
2008-07-21 09:40:12 +00:00
|
|
|
/* Region list initialized? */
|
|
|
|
if (MemoryArea->Data.SectionData.RegionListHead.Flink)
|
|
|
|
{
|
|
|
|
Status =
|
|
|
|
MmAlterRegion(AddressSpace,
|
|
|
|
MemoryArea->StartingAddress,
|
|
|
|
&MemoryArea->Data.SectionData.RegionListHead,
|
|
|
|
BaseAddress, RegionSize,
|
|
|
|
Type, Protect, MmModifyAttributes);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Status = STATUS_ACCESS_VIOLATION;
|
|
|
|
}
|
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
ObDereferenceObject(Process);
|
|
|
|
DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
|
2008-09-23 12:41:02 +00:00
|
|
|
|
|
|
|
/* Give the caller rounded BaseAddress and area length */
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
*UBaseAddress = BaseAddress;
|
|
|
|
*URegionSize = RegionSize;
|
|
|
|
DPRINT("*UBaseAddress %x *URegionSize %x\n", BaseAddress, RegionSize);
|
|
|
|
}
|
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
ObDereferenceObject(Process);
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-13 17:28:24 +00:00
|
|
|
Status = MmCreateMemoryArea(AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
MEMORY_AREA_VIRTUAL_MEMORY,
|
|
|
|
&BaseAddress,
|
|
|
|
RegionSize,
|
|
|
|
Protect,
|
|
|
|
&MemoryArea,
|
|
|
|
PBaseAddress != 0,
|
2005-11-13 17:28:24 +00:00
|
|
|
AllocationType & MEM_TOP_DOWN,
|
2004-04-10 22:36:07 +00:00
|
|
|
BoundaryAddressMultiple);
|
2002-08-10 16:41:20 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
ObDereferenceObject(Process);
|
|
|
|
DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
|
|
|
|
return(Status);
|
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
|
|
|
|
MemoryAreaLength = (ULONG_PTR)MemoryArea->EndingAddress -
|
|
|
|
(ULONG_PTR)MemoryArea->StartingAddress;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-11-28 23:43:40 +00:00
|
|
|
MmInitializeRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,
|
2005-01-02 17:55:06 +00:00
|
|
|
MemoryAreaLength, Type, Protect);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
if ((AllocationType & MEM_COMMIT) &&
|
2007-10-17 08:16:20 +00:00
|
|
|
(Protect & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2007-10-17 08:16:20 +00:00
|
|
|
const ULONG nPages = PAGE_ROUND_UP(MemoryAreaLength) >> PAGE_SHIFT;
|
|
|
|
MmReserveSwapPages(nPages);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
*UBaseAddress = BaseAddress;
|
2005-01-02 17:55:06 +00:00
|
|
|
*URegionSize = MemoryAreaLength;
|
2002-08-10 16:41:20 +00:00
|
|
|
DPRINT("*UBaseAddress %x *URegionSize %x\n", BaseAddress, RegionSize);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
ObDereferenceObject(Process);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2008-12-03 17:28:59 +00:00
|
|
|
static VOID
|
2002-08-10 16:41:20 +00:00
|
|
|
MmFreeVirtualMemoryPage(PVOID Context,
|
2004-04-10 22:36:07 +00:00
|
|
|
MEMORY_AREA* MemoryArea,
|
|
|
|
PVOID Address,
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page,
|
2004-04-10 22:36:07 +00:00
|
|
|
SWAPENTRY SwapEntry,
|
|
|
|
BOOLEAN Dirty)
|
2002-08-10 16:41:20 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
PEPROCESS Process = (PEPROCESS)Context;
|
|
|
|
|
2004-08-01 07:24:59 +00:00
|
|
|
if (Page != 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2002-08-14 20:58:39 +00:00
|
|
|
SWAPENTRY SavedSwapEntry;
|
2004-08-01 07:24:59 +00:00
|
|
|
SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
|
2002-08-14 20:58:39 +00:00
|
|
|
if (SavedSwapEntry != 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
MmFreeSwapPage(SavedSwapEntry);
|
2004-08-01 07:24:59 +00:00
|
|
|
MmSetSavedSwapEntryPage(Page, 0);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2006-05-18 20:32:17 +00:00
|
|
|
MmDeleteRmap(Page, Process, Address);
|
2004-08-01 07:24:59 +00:00
|
|
|
MmReleasePageMemoryConsumer(MC_USER, Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
else if (SwapEntry != 0)
|
|
|
|
{
|
2002-08-10 16:41:20 +00:00
|
|
|
MmFreeSwapPage(SwapEntry);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2002-08-10 16:41:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2006-05-18 20:32:17 +00:00
|
|
|
MmFreeVirtualMemory(PEPROCESS Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
PMEMORY_AREA MemoryArea)
|
2002-08-10 16:41:20 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
PLIST_ENTRY current_entry;
|
|
|
|
PMM_REGION current;
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
DPRINT("MmFreeVirtualMemory(Process %p MemoryArea %p)\n", Process,
|
|
|
|
MemoryArea);
|
|
|
|
|
|
|
|
/* Mark this memory area as about to be deleted. */
|
|
|
|
MemoryArea->DeleteInProgress = TRUE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait for any ongoing paging operations. Notice that since we have
|
|
|
|
* flagged this memory area as deleted no more page ops will be added.
|
|
|
|
*/
|
|
|
|
if (MemoryArea->PageOpCount > 0)
|
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
ULONG_PTR MemoryAreaLength = (ULONG_PTR)MemoryArea->EndingAddress -
|
|
|
|
(ULONG_PTR)MemoryArea->StartingAddress;
|
2007-10-17 08:16:20 +00:00
|
|
|
const ULONG nPages = PAGE_ROUND_UP(MemoryAreaLength) >> PAGE_SHIFT;
|
2005-01-02 17:55:06 +00:00
|
|
|
|
2007-10-17 08:16:20 +00:00
|
|
|
for (i = 0; i < nPages && MemoryArea->PageOpCount != 0; ++i)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
PMM_PAGEOP PageOp;
|
|
|
|
PageOp = MmCheckForPageOp(MemoryArea, Process->UniqueProcessId,
|
2005-01-02 17:55:06 +00:00
|
|
|
(PVOID)((ULONG_PTR)MemoryArea->StartingAddress + (i * PAGE_SIZE)),
|
2004-04-10 22:36:07 +00:00
|
|
|
NULL, 0);
|
|
|
|
if (PageOp != NULL)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
2009-04-27 10:12:57 +00:00
|
|
|
MmUnlockAddressSpace(&Process->Vm);
|
2004-04-10 22:36:07 +00:00
|
|
|
Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
|
|
|
|
0,
|
|
|
|
KernelMode,
|
|
|
|
FALSE,
|
|
|
|
NULL);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
DPRINT1("Failed to wait for page op\n");
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2009-04-27 10:12:57 +00:00
|
|
|
MmLockAddressSpace(&Process->Vm);
|
2004-04-10 22:36:07 +00:00
|
|
|
MmReleasePageOp(PageOp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free all the individual segments. */
|
|
|
|
current_entry = MemoryArea->Data.VirtualMemoryData.RegionListHead.Flink;
|
|
|
|
while (current_entry != &MemoryArea->Data.VirtualMemoryData.RegionListHead)
|
|
|
|
{
|
2002-08-10 16:41:20 +00:00
|
|
|
current = CONTAINING_RECORD(current_entry, MM_REGION, RegionListEntry);
|
|
|
|
current_entry = current_entry->Flink;
|
|
|
|
ExFreePool(current);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Actually free the memory area. */
|
2009-04-27 10:12:57 +00:00
|
|
|
MmFreeMemoryArea(&Process->Vm,
|
2005-01-02 17:55:06 +00:00
|
|
|
MemoryArea,
|
2004-04-10 22:36:07 +00:00
|
|
|
MmFreeVirtualMemoryPage,
|
|
|
|
(PVOID)Process);
|
2002-08-10 16:41:20 +00:00
|
|
|
}
|
|
|
|
|
2003-07-11 01:23:16 +00:00
|
|
|
/*
|
2004-10-01 20:26:05 +00:00
|
|
|
* @implemented
|
2003-07-11 01:23:16 +00:00
|
|
|
*/
|
2008-11-29 20:47:48 +00:00
|
|
|
NTSTATUS NTAPI
|
2004-04-10 22:36:07 +00:00
|
|
|
NtFreeVirtualMemory(IN HANDLE ProcessHandle,
|
|
|
|
IN PVOID* PBaseAddress,
|
2008-08-27 20:56:16 +00:00
|
|
|
IN PSIZE_T PRegionSize,
|
2004-04-10 22:36:07 +00:00
|
|
|
IN ULONG FreeType)
|
2002-08-10 16:41:20 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Frees a range of virtual memory
|
|
|
|
* ARGUMENTS:
|
2005-05-09 01:38:29 +00:00
|
|
|
* ProcessHandle = Points to the process that allocated the virtual
|
2002-08-10 16:41:20 +00:00
|
|
|
* memory
|
2005-05-09 01:38:29 +00:00
|
|
|
* BaseAddress = Points to the memory address, rounded down to a
|
2002-09-08 10:23:54 +00:00
|
|
|
* multiple of the pagesize
|
2005-05-09 01:38:29 +00:00
|
|
|
* RegionSize = Limits the range to free, rounded up to a multiple of
|
2002-08-10 16:41:20 +00:00
|
|
|
* the paging size
|
|
|
|
* FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
|
2005-05-09 01:38:29 +00:00
|
|
|
* RETURNS: Status
|
2002-08-10 16:41:20 +00:00
|
|
|
*/
|
|
|
|
{
|
|
|
|
MEMORY_AREA* MemoryArea;
|
2009-08-24 20:39:23 +00:00
|
|
|
NTSTATUS Status;
|
2006-05-18 20:32:17 +00:00
|
|
|
PEPROCESS Process;
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace;
|
2002-08-10 16:41:20 +00:00
|
|
|
PVOID BaseAddress;
|
|
|
|
ULONG RegionSize;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2009-05-30 10:57:31 +00:00
|
|
|
PAGED_CODE();
|
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *PBaseAddress %x, "
|
2004-04-10 22:36:07 +00:00
|
|
|
"*PRegionSize %x, FreeType %x)\n",ProcessHandle,*PBaseAddress,
|
|
|
|
*PRegionSize,FreeType);
|
|
|
|
|
2009-01-19 08:02:26 +00:00
|
|
|
if (!(FreeType & (MEM_RELEASE | MEM_DECOMMIT)))
|
|
|
|
{
|
|
|
|
DPRINT1("Invalid FreeType\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_4;
|
|
|
|
}
|
|
|
|
|
2009-08-24 20:39:23 +00:00
|
|
|
if (ExGetPreviousMode() != KernelMode)
|
2009-05-30 10:57:31 +00:00
|
|
|
{
|
|
|
|
_SEH2_TRY
|
|
|
|
{
|
|
|
|
/* Probe user pointers */
|
|
|
|
ProbeForWriteSize_t(PRegionSize);
|
|
|
|
ProbeForWritePointer(PBaseAddress);
|
|
|
|
}
|
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
2009-08-24 20:39:23 +00:00
|
|
|
/* Return the exception code */
|
|
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
2009-05-30 10:57:31 +00:00
|
|
|
}
|
|
|
|
_SEH2_END;
|
|
|
|
}
|
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
BaseAddress = (PVOID)PAGE_ROUND_DOWN((*PBaseAddress));
|
2007-10-17 08:16:20 +00:00
|
|
|
RegionSize = PAGE_ROUND_UP((ULONG_PTR)(*PBaseAddress) + (*PRegionSize)) -
|
2004-04-10 22:36:07 +00:00
|
|
|
PAGE_ROUND_DOWN((*PBaseAddress));
|
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
Status = ObReferenceObjectByHandle(ProcessHandle,
|
2004-04-10 22:36:07 +00:00
|
|
|
PROCESS_VM_OPERATION,
|
|
|
|
PsProcessType,
|
|
|
|
UserMode,
|
|
|
|
(PVOID*)(&Process),
|
|
|
|
NULL);
|
2002-08-10 16:41:20 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
2009-04-27 10:12:57 +00:00
|
|
|
AddressSpace = &Process->Vm;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
MmLockAddressSpace(AddressSpace);
|
2005-01-02 19:14:52 +00:00
|
|
|
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
|
2002-08-10 16:41:20 +00:00
|
|
|
if (MemoryArea == NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2007-10-17 08:16:20 +00:00
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
|
|
goto unlock_deref_and_return;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
switch (FreeType)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2002-08-10 16:41:20 +00:00
|
|
|
case MEM_RELEASE:
|
2004-04-10 22:36:07 +00:00
|
|
|
/* We can only free a memory area in one step. */
|
2005-01-02 17:55:06 +00:00
|
|
|
if (MemoryArea->StartingAddress != BaseAddress ||
|
2004-12-19 16:16:58 +00:00
|
|
|
MemoryArea->Type != MEMORY_AREA_VIRTUAL_MEMORY)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2007-10-17 08:16:20 +00:00
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
|
|
goto unlock_deref_and_return;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2007-10-17 08:16:20 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
MmFreeVirtualMemory(Process, MemoryArea);
|
2007-10-17 08:16:20 +00:00
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
goto unlock_deref_and_return;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
case MEM_DECOMMIT:
|
2004-04-10 22:36:07 +00:00
|
|
|
Status =
|
|
|
|
MmAlterRegion(AddressSpace,
|
2005-01-02 17:55:06 +00:00
|
|
|
MemoryArea->StartingAddress,
|
2009-05-08 07:13:41 +00:00
|
|
|
(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) ?
|
|
|
|
&MemoryArea->Data.SectionData.RegionListHead :
|
|
|
|
&MemoryArea->Data.VirtualMemoryData.RegionListHead,
|
2004-04-10 22:36:07 +00:00
|
|
|
BaseAddress,
|
|
|
|
RegionSize,
|
|
|
|
MEM_RESERVE,
|
|
|
|
PAGE_NOACCESS,
|
|
|
|
MmModifyAttributes);
|
2007-10-17 08:16:20 +00:00
|
|
|
goto unlock_deref_and_return;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2007-10-17 08:16:20 +00:00
|
|
|
|
|
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
|
|
|
|
unlock_deref_and_return:
|
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
ObDereferenceObject(Process);
|
2007-10-17 08:16:20 +00:00
|
|
|
|
|
|
|
return(Status);
|
2002-08-10 16:41:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2009-04-27 10:12:57 +00:00
|
|
|
MmProtectAnonMem(PMMSUPPORT AddressSpace,
|
2004-04-10 22:36:07 +00:00
|
|
|
PMEMORY_AREA MemoryArea,
|
|
|
|
PVOID BaseAddress,
|
|
|
|
ULONG Length,
|
|
|
|
ULONG Protect,
|
|
|
|
PULONG OldProtect)
|
2002-08-10 16:41:20 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
PMM_REGION Region;
|
2009-05-09 09:54:50 +00:00
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
ULONG LengthCount = 0;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2009-05-09 09:54:50 +00:00
|
|
|
/* Search all Regions in MemoryArea up to Length */
|
|
|
|
/* Every Region up to Length must be committed for success */
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
Region = MmFindRegion(MemoryArea->StartingAddress,
|
|
|
|
&MemoryArea->Data.VirtualMemoryData.RegionListHead,
|
|
|
|
(PVOID)((ULONG_PTR)BaseAddress + (ULONG_PTR)LengthCount), NULL);
|
|
|
|
|
|
|
|
/* If a Region was found and it is committed */
|
|
|
|
if ((Region) && (Region->Type == MEM_COMMIT))
|
|
|
|
{
|
|
|
|
LengthCount += Region->Length;
|
|
|
|
if (Length <= LengthCount) break;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* If Region was found and it is not commited */
|
|
|
|
else if (Region)
|
|
|
|
{
|
|
|
|
Status = STATUS_NOT_COMMITTED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* If no Region was found at all */
|
|
|
|
else if (LengthCount == 0)
|
|
|
|
{
|
|
|
|
Status = STATUS_INVALID_ADDRESS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NT_SUCCESS(Status))
|
2009-01-19 10:27:59 +00:00
|
|
|
{
|
|
|
|
*OldProtect = Region->Protect;
|
|
|
|
Status = MmAlterRegion(AddressSpace, MemoryArea->StartingAddress,
|
|
|
|
&MemoryArea->Data.VirtualMemoryData.RegionListHead,
|
|
|
|
BaseAddress, Length, Region->Type, Protect,
|
|
|
|
MmModifyAttributes);
|
|
|
|
}
|
2009-05-09 09:54:50 +00:00
|
|
|
|
|
|
|
return (Status);
|
2002-08-10 16:41:20 +00:00
|
|
|
}
|
|
|
|
|
2008-11-29 20:47:48 +00:00
|
|
|
NTSTATUS NTAPI
|
2002-08-10 16:41:20 +00:00
|
|
|
MmQueryAnonMem(PMEMORY_AREA MemoryArea,
|
2004-04-10 22:36:07 +00:00
|
|
|
PVOID Address,
|
|
|
|
PMEMORY_BASIC_INFORMATION Info,
|
2010-07-16 00:34:26 +00:00
|
|
|
PSIZE_T ResultLength)
|
2002-08-10 16:41:20 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
PMM_REGION Region;
|
2005-11-25 21:38:37 +00:00
|
|
|
PVOID RegionBase = NULL;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
|
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
Region = MmFindRegion(MemoryArea->StartingAddress,
|
2004-04-10 22:36:07 +00:00
|
|
|
&MemoryArea->Data.VirtualMemoryData.RegionListHead,
|
|
|
|
Address, &RegionBase);
|
2004-07-10 17:01:03 +00:00
|
|
|
Info->BaseAddress = RegionBase;
|
2005-01-02 17:55:06 +00:00
|
|
|
Info->AllocationBase = MemoryArea->StartingAddress;
|
2005-11-13 17:28:24 +00:00
|
|
|
Info->AllocationProtect = MemoryArea->Protect;
|
2005-10-29 14:09:00 +00:00
|
|
|
Info->RegionSize = Region->Length;
|
2004-04-10 22:36:07 +00:00
|
|
|
Info->State = Region->Type;
|
|
|
|
Info->Protect = Region->Protect;
|
|
|
|
Info->Type = MEM_PRIVATE;
|
|
|
|
|
|
|
|
*ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
|
|
|
|
return(STATUS_SUCCESS);
|
2002-08-10 16:41:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|