-/*
- * ReactOS kernel
- * Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
+/* $Id$
*
- * 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.
+ * Copyright (C) 2002-2005 ReactOS Team (and the authors from the programmers section)
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * 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.
*
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/* $Id$
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * PROJECT: ReactOS kernel
+ * FILE: ntoskrnl/mm/anonmem.c
+ * PURPOSE: Implementing anonymous memory.
*
- * PROJECT: ReactOS kernel
- * FILE: ntoskrnl/mm/anonmem.c
- * PURPOSE: Implementing anonymous memory.
- * PROGRAMMER: David Welch
+ * PROGRAMMERS: David Welch
+ * Casper Hornstrup
+ * KJK::Hyperion
+ * Ge van Geldorp
+ * Eric Kohl
+ * Royce Mitchell III
+ * Aleksey Bragin
+ * Jason Filby
+ * Art Yerkes
+ * Gunnar Andre' Dalsnes
+ * Filip Navara
+ * Thomas Weidenmueller
+ * Alex Ionescu
+ * Trevor McCort
+ * Steven Edwards
*/
/* INCLUDE *****************************************************************/
/* FUNCTIONS *****************************************************************/
NTSTATUS
+NTAPI
MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
PMEMORY_AREA MemoryArea,
PVOID Address,
/*
* Get that the page actually is dirty.
*/
- if (!MmIsDirtyPage(MemoryArea->Process, Address))
+ if (!MmIsDirtyPage(AddressSpace->Process, Address))
{
PageOp->Status = STATUS_SUCCESS;
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
/*
* Speculatively set the mapping to clean.
*/
- MmSetCleanPage(MemoryArea->Process, Address);
+ MmSetCleanPage(AddressSpace->Process, Address);
/*
* If necessary, allocate an entry in the paging file for this page
SwapEntry = MmAllocSwapPage();
if (SwapEntry == 0)
{
- MmSetDirtyPage(MemoryArea->Process, Address);
+ MmSetDirtyPage(AddressSpace->Process, Address);
PageOp->Status = STATUS_PAGEFILE_QUOTA_EXCEEDED;
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
MmReleasePageOp(PageOp);
{
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
Status);
- MmSetDirtyPage(MemoryArea->Process, Address);
+ MmSetDirtyPage(AddressSpace->Process, Address);
PageOp->Status = STATUS_UNSUCCESSFUL;
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
MmReleasePageOp(PageOp);
}
NTSTATUS
+NTAPI
MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
PMEMORY_AREA MemoryArea,
PVOID Address,
PMM_PAGEOP PageOp)
{
PFN_TYPE Page;
- BOOL WasDirty;
+ BOOLEAN WasDirty;
SWAPENTRY SwapEntry;
NTSTATUS Status;
DPRINT("MmPageOutVirtualMemory(Address 0x%.8X) PID %d\n",
- Address, MemoryArea->Process->UniqueProcessId);
+ Address, AddressSpace->Process->UniqueProcessId);
/*
* Check for paging out from a deleted virtual memory area.
/*
* Disable the virtual mapping.
*/
- MmDisableVirtualMapping(MemoryArea->Process, Address,
+ MmDisableVirtualMapping(AddressSpace->Process, Address,
&WasDirty, &Page);
if (Page == 0)
}
/*
- * Paging out non-dirty data is easy.
+ * Paging out non-dirty data is easy.
*/
if (!WasDirty)
{
- MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, NULL, NULL);
+ MmLockAddressSpace(AddressSpace);
+ MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);
MmDeleteAllRmaps(Page, NULL, NULL);
if ((SwapEntry = MmGetSavedSwapEntryPage(Page)) != 0)
{
- MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry);
+ MmCreatePageFileMapping(AddressSpace->Process, Address, SwapEntry);
MmSetSavedSwapEntryPage(Page, 0);
}
+ MmUnlockAddressSpace(AddressSpace);
MmReleasePageMemoryConsumer(MC_USER, Page);
PageOp->Status = STATUS_SUCCESS;
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
if (SwapEntry == 0)
{
MmShowOutOfSpaceMessagePagingFile();
- MmEnableVirtualMapping(MemoryArea->Process, Address);
+ MmEnableVirtualMapping(AddressSpace->Process, Address);
PageOp->Status = STATUS_UNSUCCESSFUL;
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
MmReleasePageOp(PageOp);
{
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
Status);
- MmEnableVirtualMapping(MemoryArea->Process, Address);
+ MmEnableVirtualMapping(AddressSpace->Process, Address);
PageOp->Status = STATUS_UNSUCCESSFUL;
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
MmReleasePageOp(PageOp);
* Otherwise we have succeeded, free the page
*/
DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", Page << PAGE_SHIFT);
- MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, NULL, NULL);
- MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry);
+ MmLockAddressSpace(AddressSpace);
+ MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);
+ MmCreatePageFileMapping(AddressSpace->Process, Address, SwapEntry);
+ MmUnlockAddressSpace(AddressSpace);
MmDeleteAllRmaps(Page, NULL, NULL);
MmSetSavedSwapEntryPage(Page, 0);
MmReleasePageMemoryConsumer(MC_USER, Page);
}
NTSTATUS
+NTAPI
MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
MEMORY_AREA* MemoryArea,
PVOID Address,
/*
* Get or create a page operation
*/
- PageOp = MmGetPageOp(MemoryArea, (ULONG)MemoryArea->Process->UniqueProcessId,
+ PageOp = MmGetPageOp(MemoryArea, AddressSpace->Process->UniqueProcessId,
(PVOID)PAGE_ROUND_DOWN(Address), NULL, 0,
MM_PAGEOP_PAGEIN, FALSE);
if (PageOp == NULL)
{
SWAPENTRY SwapEntry;
- MmDeletePageFileMapping(MemoryArea->Process, Address, &SwapEntry);
+ MmDeletePageFileMapping(AddressSpace->Process, Address, &SwapEntry);
Status = MmReadFromSwapPage(SwapEntry, Page);
if (!NT_SUCCESS(Status))
{
* Set the page. If we fail because we are out of memory then
* try again
*/
- Status = MmCreateVirtualMapping(MemoryArea->Process,
+ Status = MmCreateVirtualMapping(AddressSpace->Process,
(PVOID)PAGE_ROUND_DOWN(Address),
Region->Protect,
&Page,
while (Status == STATUS_NO_MEMORY)
{
MmUnlockAddressSpace(AddressSpace);
- Status = MmCreateVirtualMapping(MemoryArea->Process,
+ Status = MmCreateVirtualMapping(AddressSpace->Process,
Address,
Region->Protect,
&Page,
/*
* Add the page to the process's working set
*/
- MmInsertRmap(Page, MemoryArea->Process, (PVOID)PAGE_ROUND_DOWN(Address));
+ MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAGE_ROUND_DOWN(Address));
/*
* Finish the operation
* FUNCTION: Allocates a block of virtual memory in the process address space
* ARGUMENTS:
* ProcessHandle = The handle of the process which owns the virtual memory
- * 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
+ * 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
* it down to a multiple of the page size.
- * ZeroBits = (OPTIONAL) You can specify the number of high order bits
- * that must be zero, ensuring that the memory will be
+ * ZeroBits = (OPTIONAL) You can specify the number of high order bits
+ * that must be zero, ensuring that the memory will be
* allocated at a address below a certain value.
* RegionSize = The number of bytes to allocate
- * AllocationType = Indicates the type of virtual memory you like to
- * allocated, can be a combination of MEM_COMMIT,
+ * AllocationType = Indicates the type of virtual memory you like to
+ * allocated, can be a combination of MEM_COMMIT,
* MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN.
* Protect = Indicates the protection type of the pages allocated, can be
- * a combination of PAGE_READONLY, PAGE_READWRITE,
- * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
+ * a combination of PAGE_READONLY, PAGE_READWRITE,
+ * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
* PAGE_NOACCESS
* RETURNS: Status
*/
{
- PEPROCESS Process;
+ PROS_EPROCESS Process;
MEMORY_AREA* MemoryArea;
ULONG_PTR MemoryAreaLength;
ULONG Type;
*UBaseAddress,ZeroBits,*URegionSize,AllocationType,
Protect);
- /*
- * Check the validity of the parameters
- */
+ /* Check for valid protection flags */
if ((Protect & PAGE_FLAGS_VALID_FROM_USER_MODE) != Protect)
{
- return(STATUS_INVALID_PAGE_PROTECTION);
+ DPRINT1("Invalid page protection\n");
+ return STATUS_INVALID_PAGE_PROTECTION;
+ }
+
+ /* Check for valid Zero bits */
+ if (ZeroBits > 21)
+ {
+ DPRINT1("Too many zero bits\n");
+ return STATUS_INVALID_PARAMETER_3;
+ }
+
+ /* 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;
+ }
+
+ /* 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;
+ }
+
+ /* MEM_RESET is an exclusive flag, make sure that is valid too */
+ if ((AllocationType & MEM_RESET) && (AllocationType != MEM_RESET))
+ {
+ DPRINT1("MEM_RESET used illegaly\n");
+ return STATUS_INVALID_PARAMETER_5;
}
- if ((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == 0)
+
+ /* MEM_WRITE_WATCH can only be used if MEM_RESERVE is also used */
+ if ((AllocationType & MEM_WRITE_WATCH) && !(AllocationType & MEM_RESERVE))
{
- return(STATUS_INVALID_PARAMETER);
+ 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;
+ }
}
PBaseAddress = *UBaseAddress;
RegionSize = PAGE_ROUND_UP(PBaseAddress + PRegionSize) -
PAGE_ROUND_DOWN(PBaseAddress);
+ /*
+ * 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.
+ */
+ if (BaseAddress >= MM_HIGHEST_USER_ADDRESS)
+ {
+ DPRINT1("Virtual allocation above User Space\n");
+ return STATUS_INVALID_PARAMETER_2;
+ }
+ if (!RegionSize)
+ {
+ DPRINT1("Region size is invalid\n");
+ return STATUS_INVALID_PARAMETER_4;
+ }
+ if (((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (ULONG_PTR)BaseAddress) < RegionSize)
+ {
+ DPRINT1("Region size would overflow into kernel-memory\n");
+ return STATUS_INVALID_PARAMETER_4;
+ }
+
+ /*
+ * Copy on Write is reserved for system use. This case is a certain failure
+ * but there may be other cases...needs more testing
+ */
+ if ((!BaseAddress || (AllocationType & MEM_RESERVE)) &&
+ ((Protect & PAGE_WRITECOPY) || (Protect & PAGE_EXECUTE_WRITECOPY)))
+ {
+ DPRINT1("Copy on write is not supported by VirtualAlloc\n");
+ return STATUS_INVALID_PAGE_PROTECTION;
+ }
+
+
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_VM_OPERATION,
NULL,
}
}
- Status = MmCreateMemoryArea(Process,
- AddressSpace,
+ Status = MmCreateMemoryArea(AddressSpace,
MEMORY_AREA_VIRTUAL_MEMORY,
&BaseAddress,
RegionSize,
Protect,
&MemoryArea,
PBaseAddress != 0,
- (AllocationType & MEM_TOP_DOWN) == MEM_TOP_DOWN,
+ AllocationType & MEM_TOP_DOWN,
BoundaryAddressMultiple);
if (!NT_SUCCESS(Status))
{
MemoryAreaLength = (ULONG_PTR)MemoryArea->EndingAddress -
(ULONG_PTR)MemoryArea->StartingAddress;
-
- MmInitialiseRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,
+
+ MmInitializeRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,
MemoryAreaLength, Type, Protect);
if ((AllocationType & MEM_COMMIT) &&
MmFreeSwapPage(SavedSwapEntry);
MmSetSavedSwapEntryPage(Page, 0);
}
- MmDeleteRmap(Page, Process, Address);
+ MmDeleteRmap(Page, (PROS_EPROCESS)Process, Address);
MmReleasePageMemoryConsumer(MC_USER, Page);
}
else if (SwapEntry != 0)
}
VOID
-MmFreeVirtualMemory(PEPROCESS Process,
+NTAPI
+MmFreeVirtualMemory(PROS_EPROCESS Process,
PMEMORY_AREA MemoryArea)
{
PLIST_ENTRY current_entry;
/*
* FUNCTION: Frees a range of virtual memory
* ARGUMENTS:
- * ProcessHandle = Points to the process that allocated the virtual
+ * ProcessHandle = Points to the process that allocated the virtual
* memory
- * BaseAddress = Points to the memory address, rounded down to a
+ * BaseAddress = Points to the memory address, rounded down to a
* multiple of the pagesize
- * RegionSize = Limits the range to free, rounded up to a multiple of
+ * RegionSize = Limits the range to free, rounded up to a multiple of
* the paging size
* FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
- * RETURNS: Status
+ * RETURNS: Status
*/
{
MEMORY_AREA* MemoryArea;
NTSTATUS Status;
- PEPROCESS Process;
+ PROS_EPROCESS Process;
PMADDRESS_SPACE AddressSpace;
PVOID BaseAddress;
ULONG RegionSize;
}
NTSTATUS
+NTAPI
MmProtectAnonMem(PMADDRESS_SPACE AddressSpace,
PMEMORY_AREA MemoryArea,
PVOID BaseAddress,
PULONG ResultLength)
{
PMM_REGION Region;
- PVOID RegionBase;
+ PVOID RegionBase = NULL;
Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
Address, &RegionBase);
Info->BaseAddress = RegionBase;
Info->AllocationBase = MemoryArea->StartingAddress;
- Info->AllocationProtect = MemoryArea->Attributes;
- Info->RegionSize = (char*)RegionBase + Region->Length - (char*)Info->BaseAddress;
+ Info->AllocationProtect = MemoryArea->Protect;
+ Info->RegionSize = Region->Length;
Info->State = Region->Type;
Info->Protect = Region->Protect;
Info->Type = MEM_PRIVATE;