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
|
|
|
|
2010-10-05 20:00:32 +00:00
|
|
|
#define MODULE_INVOLVED_IN_ARM3
|
|
|
|
#include "ARM3/miarm.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
|
|
|
}
|
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
NTSTATUS NTAPI
|
|
|
|
MiProtectVirtualMemory(IN PEPROCESS Process,
|
|
|
|
IN OUT PVOID *BaseAddress,
|
|
|
|
IN OUT PSIZE_T NumberOfBytesToProtect,
|
|
|
|
IN ULONG NewAccessProtection,
|
|
|
|
OUT PULONG OldAccessProtection OPTIONAL)
|
|
|
|
{
|
|
|
|
PMEMORY_AREA MemoryArea;
|
|
|
|
PMMSUPPORT AddressSpace;
|
|
|
|
ULONG OldAccessProtection_;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
*NumberOfBytesToProtect =
|
|
|
|
PAGE_ROUND_UP((ULONG_PTR)(*BaseAddress) + (*NumberOfBytesToProtect)) -
|
|
|
|
PAGE_ROUND_DOWN(*BaseAddress);
|
|
|
|
*BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress);
|
|
|
|
|
|
|
|
AddressSpace = &Process->Vm;
|
|
|
|
|
|
|
|
MmLockAddressSpace(AddressSpace);
|
|
|
|
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress);
|
|
|
|
if (MemoryArea == NULL)
|
|
|
|
{
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (OldAccessProtection == NULL)
|
|
|
|
OldAccessProtection = &OldAccessProtection_;
|
|
|
|
|
|
|
|
if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
|
|
|
|
{
|
|
|
|
Status = MmProtectAnonMem(AddressSpace, MemoryArea, *BaseAddress,
|
|
|
|
*NumberOfBytesToProtect, NewAccessProtection,
|
|
|
|
OldAccessProtection);
|
|
|
|
}
|
|
|
|
else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
|
|
|
|
{
|
|
|
|
Status = MmProtectSectionView(AddressSpace, MemoryArea, *BaseAddress,
|
|
|
|
*NumberOfBytesToProtect,
|
|
|
|
NewAccessProtection,
|
|
|
|
OldAccessProtection);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* FIXME: Should we return failure or success in this case? */
|
|
|
|
Status = STATUS_CONFLICTING_ADDRESSES;
|
|
|
|
}
|
|
|
|
|
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2003-07-10 21:05:04 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2010-10-05 20:00:32 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
|
2007-10-17 08:16:20 +00:00
|
|
|
IN OUT PVOID* UBaseAddress,
|
2010-10-05 20:00:32 +00:00
|
|
|
IN ULONG_PTR ZeroBits,
|
2008-08-27 20:56:16 +00:00
|
|
|
IN OUT PSIZE_T URegionSize,
|
2010-10-05 20:00:32 +00:00
|
|
|
IN ULONG AllocationType,
|
|
|
|
IN ULONG Protect)
|
2002-08-10 16:41:20 +00:00
|
|
|
{
|
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;
|
2003-12-31 05:33:04 +00:00
|
|
|
PHYSICAL_ADDRESS BoundaryAddressMultiple;
|
2010-10-05 20:00:32 +00:00
|
|
|
PEPROCESS CurrentProcess = PsGetCurrentProcess();
|
|
|
|
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
|
|
|
|
KAPC_STATE ApcState;
|
|
|
|
ULONG ProtectionMask;
|
|
|
|
BOOLEAN Attached = FALSE;
|
|
|
|
BoundaryAddressMultiple.QuadPart = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
2010-10-05 20:00:32 +00:00
|
|
|
/* Check for valid Allocation Types */
|
|
|
|
if ((AllocationType & ~(MEM_COMMIT | MEM_RESERVE | MEM_RESET | MEM_PHYSICAL |
|
|
|
|
MEM_TOP_DOWN | MEM_WRITE_WATCH)))
|
|
|
|
{
|
|
|
|
DPRINT1("Invalid Allocation Type\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_5;
|
|
|
|
}
|
2005-08-07 07:14:52 +00:00
|
|
|
|
2010-10-05 20:00:32 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
2005-08-07 07:11:03 +00:00
|
|
|
|
2010-10-05 20:00:32 +00:00
|
|
|
/* MEM_RESET is an exclusive flag, make sure that is valid too */
|
|
|
|
if ((AllocationType & MEM_RESET) && (AllocationType != MEM_RESET))
|
|
|
|
{
|
|
|
|
DPRINT1("Invalid use of MEM_RESET\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_5;
|
|
|
|
}
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2010-10-05 20:00:32 +00:00
|
|
|
/* Check if large pages are being used */
|
|
|
|
if (AllocationType & MEM_LARGE_PAGES)
|
|
|
|
{
|
|
|
|
/* Large page allocations MUST be committed */
|
|
|
|
if (!(AllocationType & MEM_COMMIT))
|
|
|
|
{
|
|
|
|
DPRINT1("Must supply MEM_COMMIT with MEM_LARGE_PAGES\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_5;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* These flags are not allowed with large page allocations */
|
|
|
|
if (AllocationType & (MEM_PHYSICAL | MEM_RESET | MEM_WRITE_WATCH))
|
|
|
|
{
|
|
|
|
DPRINT1("Using illegal flags with MEM_LARGE_PAGES\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_5;
|
|
|
|
}
|
|
|
|
}
|
2005-08-07 07:11:03 +00:00
|
|
|
|
2010-10-05 20:00:32 +00:00
|
|
|
/* MEM_WRITE_WATCH can only be used if MEM_RESERVE is also used */
|
|
|
|
if ((AllocationType & MEM_WRITE_WATCH) && !(AllocationType & MEM_RESERVE))
|
|
|
|
{
|
|
|
|
DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_5;
|
|
|
|
}
|
2005-08-07 07:11:03 +00:00
|
|
|
|
2010-10-05 20:00:32 +00:00
|
|
|
/* MEM_PHYSICAL can only be used if MEM_RESERVE is also used */
|
|
|
|
if ((AllocationType & MEM_PHYSICAL) && !(AllocationType & MEM_RESERVE))
|
|
|
|
{
|
|
|
|
DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_5;
|
|
|
|
}
|
2005-08-07 07:11:03 +00:00
|
|
|
|
2010-10-05 20:00:32 +00:00
|
|
|
/* Check for valid MEM_PHYSICAL usage */
|
|
|
|
if (AllocationType & MEM_PHYSICAL)
|
|
|
|
{
|
|
|
|
/* Only these flags are allowed with MEM_PHYSIAL */
|
|
|
|
if (AllocationType & ~(MEM_RESERVE | MEM_TOP_DOWN | MEM_PHYSICAL))
|
|
|
|
{
|
|
|
|
DPRINT1("Using illegal flags with MEM_PHYSICAL\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_5;
|
|
|
|
}
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2010-10-05 20:00:32 +00:00
|
|
|
/* Then make sure PAGE_READWRITE is used */
|
|
|
|
if (Protect != PAGE_READWRITE)
|
|
|
|
{
|
|
|
|
DPRINT1("MEM_PHYSICAL used without PAGE_READWRITE\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_6;
|
|
|
|
}
|
|
|
|
}
|
2007-10-17 08:16:20 +00:00
|
|
|
|
2010-10-05 20:00:32 +00:00
|
|
|
/* Calculate the protection mask and make sure it's valid */
|
|
|
|
ProtectionMask = MiMakeProtectionMask(Protect);
|
|
|
|
if (ProtectionMask == MM_INVALID_PROTECTION)
|
|
|
|
{
|
|
|
|
DPRINT1("Invalid protection mask\n");
|
|
|
|
return STATUS_INVALID_PAGE_PROTECTION;
|
|
|
|
}
|
2007-10-17 08:16:20 +00:00
|
|
|
|
2010-10-05 20:00:32 +00:00
|
|
|
/* Enter SEH */
|
|
|
|
_SEH2_TRY
|
|
|
|
{
|
|
|
|
/* Check for user-mode parameters */
|
|
|
|
if (PreviousMode != KernelMode)
|
|
|
|
{
|
|
|
|
/* Make sure they are writable */
|
|
|
|
ProbeForWritePointer(UBaseAddress);
|
|
|
|
ProbeForWriteUlong(URegionSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Capture their values */
|
|
|
|
PBaseAddress = *UBaseAddress;
|
|
|
|
PRegionSize = *URegionSize;
|
|
|
|
}
|
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
/* Return the exception code */
|
|
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
|
|
}
|
|
|
|
_SEH2_END;
|
|
|
|
|
|
|
|
/* Make sure the allocation isn't past the VAD area */
|
|
|
|
if (PBaseAddress >= MM_HIGHEST_VAD_ADDRESS)
|
|
|
|
{
|
|
|
|
DPRINT1("Virtual allocation base above User Space\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure the allocation wouldn't overflow past the VAD area */
|
|
|
|
if ((((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) - (ULONG_PTR)PBaseAddress) < PRegionSize)
|
|
|
|
{
|
|
|
|
DPRINT1("Region size would overflow into kernel-memory\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_4;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure there's a size specified */
|
|
|
|
if (!PRegionSize)
|
|
|
|
{
|
|
|
|
DPRINT1("Region size is invalid (zero)\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_4;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if this is for the current process */
|
|
|
|
if (ProcessHandle == NtCurrentProcess())
|
|
|
|
{
|
|
|
|
/* We already have the current process, no need to go through Ob */
|
|
|
|
Process = CurrentProcess;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Reference the handle for correct permissions */
|
|
|
|
Status = ObReferenceObjectByHandle(ProcessHandle,
|
|
|
|
PROCESS_VM_OPERATION,
|
|
|
|
PsProcessType,
|
|
|
|
PreviousMode,
|
|
|
|
(PVOID*)&Process,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
|
|
|
|
/* Check if not running in the current process */
|
|
|
|
if (CurrentProcess != Process)
|
|
|
|
{
|
|
|
|
/* Attach to it */
|
|
|
|
KeStackAttachProcess(&Process->Pcb, &ApcState);
|
|
|
|
Attached = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for large page allocations */
|
|
|
|
if (AllocationType & MEM_LARGE_PAGES)
|
|
|
|
{
|
|
|
|
/* The lock memory privilege is required */
|
|
|
|
if (!SeSinglePrivilegeCheck(SeLockMemoryPrivilege, PreviousMode))
|
|
|
|
{
|
|
|
|
/* Fail without it */
|
|
|
|
DPRINT1("Privilege not held for MEM_LARGE_PAGES\n");
|
|
|
|
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
|
|
|
|
return STATUS_PRIVILEGE_NOT_HELD;
|
|
|
|
}
|
|
|
|
}
|
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);
|
|
|
|
|
2005-08-07 07:11:03 +00:00
|
|
|
|
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
|
|
|
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);
|
2010-10-05 20:00:32 +00:00
|
|
|
if (Attached) KeUnstackDetachProcess(&ApcState);
|
|
|
|
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
|
2009-09-14 09:21:05 +00:00
|
|
|
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);
|
2010-10-05 20:00:32 +00:00
|
|
|
if (Attached) KeUnstackDetachProcess(&ApcState);
|
|
|
|
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
|
2009-09-14 09:21:05 +00:00
|
|
|
|
|
|
|
/* 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);
|
2010-10-05 20:00:32 +00:00
|
|
|
if (Attached) KeUnstackDetachProcess(&ApcState);
|
|
|
|
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
|
2005-01-02 17:55:06 +00:00
|
|
|
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);
|
2010-10-05 20:00:32 +00:00
|
|
|
if (Attached) KeUnstackDetachProcess(&ApcState);
|
|
|
|
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
|
2005-01-02 17:55:06 +00:00
|
|
|
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);
|
2010-10-05 20:00:32 +00:00
|
|
|
if (Attached) KeUnstackDetachProcess(&ApcState);
|
|
|
|
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
|
2005-01-02 17:55:06 +00:00
|
|
|
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);
|
2010-10-05 20:00:32 +00:00
|
|
|
if (Attached) KeUnstackDetachProcess(&ApcState);
|
|
|
|
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
|
2004-04-10 22:36:07 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2010-10-05 20:00:32 +00:00
|
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
|
|
if (Attached) KeUnstackDetachProcess(&ApcState);
|
|
|
|
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
|
|
|
|
|
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
|
|
|
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,
|
2010-10-05 20:00:32 +00:00
|
|
|
IN PVOID* UBaseAddress,
|
|
|
|
IN PSIZE_T URegionSize,
|
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;
|
2010-10-05 20:00:32 +00:00
|
|
|
PVOID BaseAddress, PBaseAddress;
|
|
|
|
ULONG RegionSize, PRegionSize;
|
|
|
|
PEPROCESS CurrentProcess = PsGetCurrentProcess();
|
|
|
|
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
|
|
|
|
KAPC_STATE ApcState;
|
|
|
|
BOOLEAN Attached = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
/* Only two flags are supported */
|
2009-01-19 08:02:26 +00:00
|
|
|
if (!(FreeType & (MEM_RELEASE | MEM_DECOMMIT)))
|
|
|
|
{
|
|
|
|
DPRINT1("Invalid FreeType\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_4;
|
|
|
|
}
|
2010-10-05 20:00:32 +00:00
|
|
|
|
|
|
|
/* Check if no flag was used, or if both flags were used */
|
|
|
|
if (!((FreeType & (MEM_DECOMMIT | MEM_RELEASE))) ||
|
|
|
|
((FreeType & (MEM_DECOMMIT | MEM_RELEASE)) == (MEM_DECOMMIT | MEM_RELEASE)))
|
2009-05-30 10:57:31 +00:00
|
|
|
{
|
2010-10-05 20:00:32 +00:00
|
|
|
DPRINT1("Invalid FreeType combination\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_4;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enter SEH */
|
|
|
|
_SEH2_TRY
|
|
|
|
{
|
|
|
|
/* Check for user-mode parameters */
|
|
|
|
if (PreviousMode != KernelMode)
|
2009-05-30 10:57:31 +00:00
|
|
|
{
|
2010-10-05 20:00:32 +00:00
|
|
|
/* Make sure they are writable */
|
|
|
|
ProbeForWritePointer(UBaseAddress);
|
|
|
|
ProbeForWriteUlong(URegionSize);
|
2009-05-30 10:57:31 +00:00
|
|
|
}
|
2010-10-05 20:00:32 +00:00
|
|
|
|
|
|
|
/* Capture their values */
|
|
|
|
PBaseAddress = *UBaseAddress;
|
|
|
|
PRegionSize = *URegionSize;
|
2009-05-30 10:57:31 +00:00
|
|
|
}
|
2010-10-05 20:00:32 +00:00
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
/* Return the exception code */
|
|
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
|
|
}
|
|
|
|
_SEH2_END;
|
|
|
|
|
|
|
|
/* Make sure the allocation isn't past the user area */
|
|
|
|
if (PBaseAddress >= MM_HIGHEST_USER_ADDRESS)
|
|
|
|
{
|
|
|
|
DPRINT1("Virtual free base above User Space\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure the allocation wouldn't overflow past the user area */
|
|
|
|
if (((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (ULONG_PTR)PBaseAddress) < PRegionSize)
|
|
|
|
{
|
|
|
|
DPRINT1("Region size would overflow into kernel-memory\n");
|
|
|
|
return STATUS_INVALID_PARAMETER_3;
|
|
|
|
}
|
2009-05-30 10:57:31 +00:00
|
|
|
|
2010-10-05 20:00:32 +00:00
|
|
|
/* Check if this is for the current process */
|
|
|
|
if (ProcessHandle == NtCurrentProcess())
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2010-10-05 20:00:32 +00:00
|
|
|
/* We already have the current process, no need to go through Ob */
|
|
|
|
Process = CurrentProcess;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Reference the handle for correct permissions */
|
|
|
|
Status = ObReferenceObjectByHandle(ProcessHandle,
|
|
|
|
PROCESS_VM_OPERATION,
|
|
|
|
PsProcessType,
|
|
|
|
PreviousMode,
|
|
|
|
(PVOID*)&Process,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
|
|
|
|
/* Check if not running in the current process */
|
|
|
|
if (CurrentProcess != Process)
|
|
|
|
{
|
|
|
|
/* Attach to it */
|
|
|
|
KeStackAttachProcess(&Process->Pcb, &ApcState);
|
|
|
|
Attached = TRUE;
|
|
|
|
}
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
2010-10-05 20:00:32 +00:00
|
|
|
BaseAddress = (PVOID)PAGE_ROUND_DOWN((PBaseAddress));
|
|
|
|
RegionSize = PAGE_ROUND_UP((ULONG_PTR)(PBaseAddress) + (PRegionSize)) -
|
|
|
|
PAGE_ROUND_DOWN((PBaseAddress));
|
|
|
|
|
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);
|
2010-10-05 20:00:32 +00:00
|
|
|
if (Attached) KeUnstackDetachProcess(&ApcState);
|
|
|
|
if (ProcessHandle != NtCurrentProcess()) 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 */
|