reactos/reactos/ntoskrnl/mm/anonmem.c
David Welch 383eddd11e 2002-08-10 David Welch <welch@computer2.darkstar.org>
* ntoskrnl/mm/i386/page.c (MmSetPageProtect): Fixed
	behaviour when called on the system address space.

2002-08-10  David Welch  <welch@computer2.darkstar.org>

	* ntoskrnl/mm/virtual.c (MmQueryAnonMem, MmProtectAnonMem,
	NtAllocateVirtualMemory, NtFreeVirtualMemory): Renamed
	segments to regions; moved region code to seperate file.
	Implemented NtQueryVirtualMemory and NtProtectVirtualMemory
	for anonymous memory areas.

2002-08-10  David Welch  <welch@computer2.darkstar.org>

	* ntoskrnl/mm/anonmem.c: Moved functions relating to
	areas created with NtAllocateVirtualMemory to a
	seperate file.

2002-08-10  David Welch  <welch@computer2.darkstar.org>

	* ntoskrnl/mm/section.c (MmQuerySectionView): Implemented
	NtQueryVirtualMemory for section views.

2002-08-10  David Welch  <welch@computer2.darkstar.org>

	* ntoskrnl/mm/section.c (MmAccessFaultSectionView,
	MmNotPresentFaultSectionView, MmProtectSectionView,
	MmMapViewOfSegment, MmAlterViewAttributes): Implemented
	NtProtectVirtualMemory for section views.

2002-08-10  David Welch  <welch@computer2.darkstar.org>

	* ntoskrnl/ke/main.c: Removed SEH test code.

2002-08-10  David Welch  <welch@computer2.darkstar.org>

	* lib/ntdll/ldr/utils.c (LdrFixupImports): Remove the readonly
	protection from the IAT before writing to it.

2002-08-10  David Welch  <welch@computer2.darkstar.org>

	* lib/ntdll/ldr/utils.c (LdrAdjustDllName): Properly null terminate
	the base name of the DLL.

2002-08-10  David Welch  <welch@computer2.darkstar.org>

	* ntoskrnl/ldr/loader.c (LdrPEProcessModule): Set the text segment
	of modules to readonly after loading.

svn path=/trunk/; revision=3327
2002-08-10 16:41:20 +00:00

809 lines
22 KiB
C

/*
* ReactOS kernel
* Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
*
* 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.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: anonmem.c,v 1.1 2002/08/10 16:41:19 dwelch Exp $
*
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/anonmem.c
* PURPOSE: Implementing anonymous memory.
* PROGRAMMER: David Welch
*/
/* INCLUDE *****************************************************************/
#include <ddk/ntddk.h>
#include <internal/mm.h>
#include <internal/ob.h>
#include <internal/io.h>
#include <internal/ps.h>
#include <internal/pool.h>
#define NDEBUG
#include <internal/debug.h>
/* FUNCTIONS *****************************************************************/
NTSTATUS
MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
PMEMORY_AREA MArea,
PVOID Address)
{
return(STATUS_UNSUCCESSFUL);
}
NTSTATUS
MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
PMEMORY_AREA MemoryArea,
PVOID Address,
PMM_PAGEOP PageOp)
{
PHYSICAL_ADDRESS PhysicalAddress;
BOOL WasDirty;
SWAPENTRY SwapEntry;
NTSTATUS Status;
PMDL Mdl;
DPRINT("MmPageOutVirtualMemory(Address 0x%.8X) PID %d\n",
Address, MemoryArea->Process->UniqueProcessId);
/*
* Check for paging out from a deleted virtual memory area.
*/
if (MemoryArea->DeleteInProgress)
{
return(STATUS_UNSUCCESSFUL);
}
/*
* Paging out code or readonly data is easy.
*/
if ((MemoryArea->Attributes & PAGE_READONLY) ||
(MemoryArea->Attributes & PAGE_EXECUTE_READ))
{
MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE,
NULL, &PhysicalAddress);
MmDeleteAllRmaps(PhysicalAddress, NULL, NULL);
if (MmGetSavedSwapEntryPage(PhysicalAddress) != 0)
{
DPRINT1("Read-only page was swapped out.\n");
KeBugCheck(0);
}
MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
PageOp->Status = STATUS_SUCCESS;
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
MmReleasePageOp(PageOp);
return(STATUS_SUCCESS);
}
/*
* Otherwise this is read-write data
*/
MmDisableVirtualMapping(MemoryArea->Process, Address,
&WasDirty, (PULONG)&PhysicalAddress);
if (PhysicalAddress.QuadPart == 0)
{
KeBugCheck(0);
}
if (!WasDirty)
{
MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, NULL, NULL);
MmDeleteAllRmaps(PhysicalAddress, NULL, NULL);
if ((SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress)) != 0)
{
MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry);
MmSetSavedSwapEntryPage(PhysicalAddress, 0);
}
MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
PageOp->Status = STATUS_SUCCESS;
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
MmReleasePageOp(PageOp);
return(STATUS_SUCCESS);
}
/*
* If necessary, allocate an entry in the paging file for this page
*/
SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
if (SwapEntry == 0)
{
SwapEntry = MmAllocSwapPage();
if (SwapEntry == 0)
{
MmEnableVirtualMapping(MemoryArea->Process, Address);
PageOp->Status = STATUS_UNSUCCESSFUL;
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
MmReleasePageOp(PageOp);
return(STATUS_UNSUCCESSFUL);
}
}
/*
* Write the page to the pagefile
*/
Mdl = MmCreateMdl(NULL, NULL, PAGESIZE);
MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
Status = MmWriteToSwapPage(SwapEntry, Mdl);
if (!NT_SUCCESS(Status))
{
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
Status);
MmEnableVirtualMapping(MemoryArea->Process, Address);
PageOp->Status = STATUS_UNSUCCESSFUL;
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
MmReleasePageOp(PageOp);
return(STATUS_UNSUCCESSFUL);
}
/*
* Otherwise we have succeeded, free the page
*/
DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", PhysicalAddress);
MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, NULL, NULL);
MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry);
MmDeleteAllRmaps(PhysicalAddress, NULL, NULL);
MmSetSavedSwapEntryPage(PhysicalAddress, 0);
MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
PageOp->Status = STATUS_SUCCESS;
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
MmReleasePageOp(PageOp);
return(STATUS_SUCCESS);
}
NTSTATUS
MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
MEMORY_AREA* MemoryArea,
PVOID Address,
BOOLEAN Locked)
/*
* 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.
*/
{
PHYSICAL_ADDRESS Page;
NTSTATUS Status;
PMM_REGION Region;
PMM_PAGEOP PageOp;
/*
* 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))
{
if (Locked)
{
MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
}
return(STATUS_SUCCESS);
}
/*
* Check for the virtual memory area being deleted.
*/
if (MemoryArea->DeleteInProgress)
{
return(STATUS_UNSUCCESSFUL);
}
/*
* Get the segment corresponding to the virtual address
*/
Region = MmFindRegion(MemoryArea->BaseAddress,
&MemoryArea->Data.VirtualMemoryData.RegionListHead,
Address, NULL);
if (Region->Type == MEM_RESERVE)
{
return(STATUS_UNSUCCESSFUL);
}
/*
* Get or create a page operation
*/
PageOp = MmGetPageOp(MemoryArea, (ULONG)PsGetCurrentProcessId(),
(PVOID)PAGE_ROUND_DOWN(Address), NULL, 0,
MM_PAGEOP_PAGEIN);
if (PageOp == NULL)
{
DPRINT1("MmGetPageOp failed");
KeBugCheck(0);
}
/*
* Check if someone else is already handling this fault, if so wait
* for them
*/
if (PageOp->Thread != PsGetCurrentThread())
{
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");
KeBugCheck(0);
}
if (PageOp->Status == STATUS_PENDING)
{
DPRINT1("Woke for page op before completion\n");
KeBugCheck(0);
}
/*
* If this wasn't a pagein then we need to restart the handling
*/
if (PageOp->OpType != MM_PAGEOP_PAGEIN)
{
MmLockAddressSpace(AddressSpace);
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);
MmReleasePageOp(PageOp);
return(Status);
}
MmLockAddressSpace(AddressSpace);
if (Locked)
{
MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
}
MmReleasePageOp(PageOp);
return(STATUS_SUCCESS);
}
/*
* Try to allocate a page
*/
Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
if (Status == STATUS_NO_MEMORY)
{
MmUnlockAddressSpace(AddressSpace);
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
MmLockAddressSpace(AddressSpace);
}
/*
* Handle swapped out pages.
*/
if (MmIsPageSwapEntry(NULL, Address))
{
SWAPENTRY SwapEntry;
PMDL Mdl;
MmDeletePageFileMapping(NULL, Address, &SwapEntry);
Mdl = MmCreateMdl(NULL, NULL, PAGESIZE);
MmBuildMdlFromPages(Mdl, (PULONG)&Page);
Status = MmReadFromSwapPage(SwapEntry, Mdl);
if (!NT_SUCCESS(Status))
{
KeBugCheck(0);
}
MmSetSavedSwapEntryPage(Page, SwapEntry);
}
/*
* Set the page. If we fail because we are out of memory then
* try again
*/
Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
Address,
MemoryArea->Attributes,
Page,
FALSE);
while (Status == STATUS_NO_MEMORY)
{
MmUnlockAddressSpace(AddressSpace);
Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
Address,
MemoryArea->Attributes,
Page,
TRUE);
MmLockAddressSpace(AddressSpace);
}
if (!NT_SUCCESS(Status))
{
DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
KeBugCheck(0);
return(Status);
}
/*
* Add the page to the process's working set
*/
MmInsertRmap(Page, PsGetCurrentProcess(), (PVOID)PAGE_ROUND_DOWN(Address));
/*
* Finish the operation
*/
if (Locked)
{
MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
}
PageOp->Status = STATUS_SUCCESS;
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
MmReleasePageOp(PageOp);
return(STATUS_SUCCESS);
}
VOID STATIC
MmModifyAttributes(PMADDRESS_SPACE AddressSpace,
PVOID BaseAddress,
ULONG RegionSize,
ULONG OldType,
ULONG OldProtect,
ULONG NewType,
ULONG NewProtect)
/*
* FUNCTION: Modify the attributes of a memory region
*/
{
/*
* 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)
{
ULONG i;
for (i=0; i <= (RegionSize/PAGESIZE); i++)
{
LARGE_INTEGER PhysicalAddr;
if (MmIsPageSwapEntry(AddressSpace->Process,
BaseAddress + (i * PAGESIZE)))
{
SWAPENTRY SwapEntry;
MmDeletePageFileMapping(AddressSpace->Process,
BaseAddress + (i * PAGESIZE),
&SwapEntry);
MmFreeSwapPage(SwapEntry);
}
else
{
PhysicalAddr = MmGetPhysicalAddress(BaseAddress + (i*PAGESIZE));
MmDeleteVirtualMapping(AddressSpace->Process,
BaseAddress + (i*PAGESIZE),
FALSE, NULL, NULL);
if (PhysicalAddr.QuadPart != 0)
{
MmDeleteRmap(PhysicalAddr, AddressSpace->Process,
BaseAddress + (i * PAGESIZE));
MmReleasePageMemoryConsumer(MC_USER, PhysicalAddr);
}
}
}
}
/*
* 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 &&
OldProtect != NewProtect)
{
ULONG i;
for (i=0; i <= (RegionSize/PAGESIZE); i++)
{
if (MmIsPagePresent(AddressSpace->Process,
BaseAddress + (i*PAGESIZE)))
{
MmSetPageProtect(AddressSpace->Process,
BaseAddress + (i*PAGESIZE),
NewProtect);
}
}
}
}
NTSTATUS STDCALL
NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
IN OUT PVOID* UBaseAddress,
IN ULONG ZeroBits,
IN OUT PULONG URegionSize,
IN ULONG AllocationType,
IN ULONG Protect)
/*
* 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
* 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
* 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,
* 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,
* PAGE_NOACCESS
* REMARKS:
* This function maps to the win32 VirtualAllocEx. Virtual memory is
* process based so the protocol starts with a ProcessHandle. I
* splitted the functionality of obtaining the actual address and
* specifying the start address in two parameters ( BaseAddress and
* StartAddress ) The NumberOfBytesAllocated specify the range and the
* AllocationType and ProctectionType map to the other two parameters.
* RETURNS: Status
*/
{
PEPROCESS Process;
MEMORY_AREA* MemoryArea;
ULONG Type;
NTSTATUS Status;
PMADDRESS_SPACE AddressSpace;
PVOID BaseAddress;
ULONG RegionSize;
PVOID PBaseAddress;
ULONG PRegionSize;
DPRINT("NtAllocateVirtualMemory(*UBaseAddress %x, "
"ZeroBits %d, *URegionSize %x, AllocationType %x, Protect %x)\n",
*UBaseAddress,ZeroBits,*URegionSize,AllocationType,
Protect);
/*
* Check the validity of the parameters
*/
if ((Protect & PAGE_FLAGS_VALID_FROM_USER_MODE) != Protect)
{
return(STATUS_INVALID_PAGE_PROTECTION);
}
if ((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == 0)
{
return(STATUS_INVALID_PARAMETER);
}
PBaseAddress = *UBaseAddress;
PRegionSize = *URegionSize;
BaseAddress = (PVOID)PAGE_ROUND_DOWN(PBaseAddress);
RegionSize = PAGE_ROUND_UP(PBaseAddress + PRegionSize) -
PAGE_ROUND_DOWN(PBaseAddress);
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_VM_OPERATION,
NULL,
UserMode,
(PVOID*)(&Process),
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
return(Status);
}
Type = (AllocationType & MEM_COMMIT) ? MEM_COMMIT : MEM_RESERVE;
DPRINT("Type %x\n", Type);
AddressSpace = &Process->AddressSpace;
MmLockAddressSpace(AddressSpace);
if (PBaseAddress != 0)
{
MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace,
BaseAddress);
if (MemoryArea != NULL &&
MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY &&
MemoryArea->Length >= RegionSize)
{
Status =
MmAlterRegion(&Process->AddressSpace,
MemoryArea->BaseAddress,
&MemoryArea->Data.VirtualMemoryData.RegionListHead,
PBaseAddress, RegionSize,
Type, Protect, MmModifyAttributes);
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
return(Status);
}
else if (MemoryArea != NULL)
{
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
return(STATUS_UNSUCCESSFUL);
}
}
Status = MmCreateMemoryArea(Process,
&Process->AddressSpace,
MEMORY_AREA_VIRTUAL_MEMORY,
&BaseAddress,
RegionSize,
Protect,
&MemoryArea,
PBaseAddress != 0);
if (!NT_SUCCESS(Status))
{
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
return(Status);
}
MmInitialiseRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,
RegionSize, Type, Protect);
if ((AllocationType & MEM_COMMIT) &&
((Protect & PAGE_READWRITE) ||
(Protect & PAGE_EXECUTE_READWRITE)))
{
MmReserveSwapPages(RegionSize);
}
*UBaseAddress = BaseAddress;
*URegionSize = RegionSize;
DPRINT("*UBaseAddress %x *URegionSize %x\n", BaseAddress, RegionSize);
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
return(STATUS_SUCCESS);
}
VOID STATIC
MmFreeVirtualMemoryPage(PVOID Context,
MEMORY_AREA* MemoryArea,
PVOID Address,
PHYSICAL_ADDRESS PhysicalAddr,
SWAPENTRY SwapEntry,
BOOLEAN Dirty)
{
PEPROCESS Process = (PEPROCESS)Context;
if (PhysicalAddr.QuadPart != 0)
{
MmDeleteRmap(PhysicalAddr, Process, Address);
MmReleasePageMemoryConsumer(MC_USER, PhysicalAddr);
}
else if (SwapEntry != 0)
{
MmFreeSwapPage(SwapEntry);
}
}
VOID
MmFreeVirtualMemory(PEPROCESS Process,
PMEMORY_AREA MemoryArea)
{
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)
{
for (i = 0; i < (PAGE_ROUND_UP(MemoryArea->Length) / PAGESIZE); i++)
{
PMM_PAGEOP PageOp;
if (MemoryArea->PageOpCount == 0)
{
break;
}
PageOp = MmCheckForPageOp(MemoryArea, Process->UniqueProcessId,
MemoryArea->BaseAddress + (i * PAGESIZE),
NULL, 0);
if (PageOp != NULL)
{
NTSTATUS Status;
MmUnlockAddressSpace(&Process->AddressSpace);
Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
0,
KernelMode,
FALSE,
NULL);
if (Status != STATUS_SUCCESS)
{
DPRINT1("Failed to wait for page op\n");
KeBugCheck(0);
}
MmLockAddressSpace(&Process->AddressSpace);
MmReleasePageOp(PageOp);
}
}
}
/* Free all the individual segments. */
current_entry = MemoryArea->Data.VirtualMemoryData.RegionListHead.Flink;
while (current_entry != &MemoryArea->Data.VirtualMemoryData.RegionListHead)
{
current = CONTAINING_RECORD(current_entry, MM_REGION, RegionListEntry);
current_entry = current_entry->Flink;
ExFreePool(current);
}
/* Actually free the memory area. */
MmFreeMemoryArea(&Process->AddressSpace,
MemoryArea->BaseAddress,
0,
MmFreeVirtualMemoryPage,
(PVOID)Process);
}
NTSTATUS STDCALL
NtFreeVirtualMemory(IN HANDLE ProcessHandle,
IN PVOID* PBaseAddress,
IN PULONG PRegionSize,
IN ULONG FreeType)
/*
* FUNCTION: Frees a range of virtual memory
* ARGUMENTS:
* ProcessHandle = Points to the process that allocated the virtual
* memory
* 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
* the paging size
* FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
* RETURNS: Status
*/
{
MEMORY_AREA* MemoryArea;
NTSTATUS Status;
PEPROCESS Process;
PMADDRESS_SPACE AddressSpace;
PVOID BaseAddress;
ULONG RegionSize;
DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *PBaseAddress %x, "
"*PRegionSize %x, FreeType %x)\n",ProcessHandle,*PBaseAddress,
*PRegionSize,FreeType);
BaseAddress = (PVOID)PAGE_ROUND_DOWN((*PBaseAddress));
RegionSize = PAGE_ROUND_UP((*PBaseAddress) + (*PRegionSize)) -
PAGE_ROUND_DOWN((*PBaseAddress));
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_VM_OPERATION,
PsProcessType,
UserMode,
(PVOID*)(&Process),
NULL);
if (!NT_SUCCESS(Status))
{
return(Status);
}
AddressSpace = &Process->AddressSpace;
MmLockAddressSpace(AddressSpace);
MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
BaseAddress);
if (MemoryArea == NULL)
{
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
return(STATUS_UNSUCCESSFUL);
}
switch (FreeType)
{
case MEM_RELEASE:
/* We can only free a memory area in one step. */
if (MemoryArea->BaseAddress != BaseAddress)
{
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
return(STATUS_UNSUCCESSFUL);
}
MmFreeVirtualMemory(Process, MemoryArea);
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
return(STATUS_SUCCESS);
case MEM_DECOMMIT:
Status =
MmAlterRegion(AddressSpace,
MemoryArea->BaseAddress,
&MemoryArea->Data.VirtualMemoryData.RegionListHead,
BaseAddress,
RegionSize,
MEM_RESERVE,
PAGE_NOACCESS,
MmModifyAttributes);
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
return(Status);
}
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
return(STATUS_NOT_IMPLEMENTED);
}
NTSTATUS
MmProtectAnonMem(PMADDRESS_SPACE AddressSpace,
PMEMORY_AREA MemoryArea,
PVOID BaseAddress,
ULONG Length,
ULONG Protect,
PULONG OldProtect)
{
PMM_REGION Region;
NTSTATUS Status;
Region = MmFindRegion(MemoryArea->BaseAddress,
&MemoryArea->Data.VirtualMemoryData.RegionListHead,
BaseAddress, NULL);
*OldProtect = Region->Protect;
Status = MmAlterRegion(AddressSpace, MemoryArea->BaseAddress,
&MemoryArea->Data.VirtualMemoryData.RegionListHead,
BaseAddress, Length, Region->Type, Protect,
MmModifyAttributes);
return(Status);
}
NTSTATUS STDCALL
MmQueryAnonMem(PMEMORY_AREA MemoryArea,
PVOID Address,
PMEMORY_BASIC_INFORMATION Info,
PULONG ResultLength)
{
PMM_REGION Region;
PVOID RegionBase;
Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
Region = MmFindRegion(MemoryArea->BaseAddress,
&MemoryArea->Data.VirtualMemoryData.RegionListHead,
Address, &RegionBase);
Info->AllocationBase = RegionBase;
Info->AllocationProtect = Region->Protect; /* FIXME */
Info->RegionSize = Region->Length;
Info->State = Region->Type;
Info->Protect = Region->Protect;
Info->Type = MEM_PRIVATE;
return(STATUS_SUCCESS);
}
/* EOF */