[NTOS]: Delete a bunch of junk, 5 less files in Mm now (also moved some functions around). Delete unused functions where found.

[NTOS]: The modified page writer should run at a high priority such as 27, not in idle mode at priority 1 -- otherwise dirty pages never get flushed out.
[NTOS]: Reimplement MmGetFileNameForAddress, MmGetFileNameForSection, MmGetFileObjectForSection to also support ARM3 sections. Shouldn't affect anything other than the user-mode debugging support.

svn path=/trunk/; revision=48999
This commit is contained in:
Sir Richard 2010-10-05 15:55:52 +00:00
parent 103fbf8518
commit 7d21cf7abd
12 changed files with 1188 additions and 2505 deletions

View file

@ -1503,7 +1503,7 @@ MmFindRegion(
PFILE_OBJECT
NTAPI
MmGetFileObjectForSection(
IN PROS_SECTION_OBJECT Section
IN PVOID Section
);
NTSTATUS
NTAPI
@ -1515,7 +1515,7 @@ MmGetFileNameForAddress(
NTSTATUS
NTAPI
MmGetFileNameForSection(
IN PROS_SECTION_OBJECT Section,
IN PVOID Section,
OUT POBJECT_NAME_INFORMATION *ModuleName
);

View file

@ -717,6 +717,184 @@ MiCreatePagingFileMap(OUT PSEGMENT *Segment,
return STATUS_SUCCESS;
}
PFILE_OBJECT
NTAPI
MmGetFileObjectForSection(IN PVOID SectionObject)
{
PSECTION_OBJECT Section;
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
ASSERT(SectionObject != NULL);
/* Check if it's an ARM3, or ReactOS section */
if ((ULONG_PTR)SectionObject & 1)
{
/* Return the file pointer stored in the control area */
Section = (PVOID)((ULONG_PTR)SectionObject & ~1);
return Section->Segment->ControlArea->FilePointer;
}
/* Return the file object */
return ((PROS_SECTION_OBJECT)SectionObject)->FileObject;
}
NTSTATUS
NTAPI
MmGetFileNameForFileObject(IN PFILE_OBJECT FileObject,
OUT POBJECT_NAME_INFORMATION *ModuleName)
{
POBJECT_NAME_INFORMATION ObjectNameInfo;
NTSTATUS Status;
ULONG ReturnLength;
/* Allocate memory for our structure */
ObjectNameInfo = ExAllocatePoolWithTag(PagedPool, 1024, ' mM');
if (!ObjectNameInfo) return STATUS_NO_MEMORY;
/* Query the name */
Status = ObQueryNameString(FileObject,
ObjectNameInfo,
1024,
&ReturnLength);
if (!NT_SUCCESS(Status))
{
/* Failed, free memory */
DPRINT1("Name query failed\n");
ExFreePoolWithTag(ObjectNameInfo, ' mM');
*ModuleName = NULL;
return Status;
}
/* Success */
*ModuleName = ObjectNameInfo;
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
MmGetFileNameForSection(IN PVOID Section,
OUT POBJECT_NAME_INFORMATION *ModuleName)
{
PFILE_OBJECT FileObject;
/* Make sure it's an image section */
if ((ULONG_PTR)Section & 1)
{
/* Check ARM3 Section flag */
if (((PSECTION)((ULONG_PTR)Section & ~1))->u.Flags.Image == 0)
{
/* It's not, fail */
DPRINT1("Not an image section\n");
return STATUS_SECTION_NOT_IMAGE;
}
}
else if (!(((PROS_SECTION_OBJECT)Section)->AllocationAttributes & SEC_IMAGE))
{
/* It's not, fail */
DPRINT1("Not an image section\n");
return STATUS_SECTION_NOT_IMAGE;
}
/* Get the file object */
FileObject = MmGetFileObjectForSection(Section);
return MmGetFileNameForFileObject(FileObject, ModuleName);
}
NTSTATUS
NTAPI
MmGetFileNameForAddress(IN PVOID Address,
OUT PUNICODE_STRING ModuleName)
{
PVOID Section;
PMEMORY_AREA MemoryArea;
POBJECT_NAME_INFORMATION ModuleNameInformation;
PVOID AddressSpace;
NTSTATUS Status;
PFILE_OBJECT FileObject = NULL;
PMMVAD Vad;
PCONTROL_AREA ControlArea;
/* Lock address space */
AddressSpace = MmGetCurrentAddressSpace();
MmLockAddressSpace(AddressSpace);
/* Locate the memory area for the process by address */
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
if (!MemoryArea)
{
/* Fail, the address does not exist */
InvalidAddress:
DPRINT1("Invalid address\n");
MmUnlockAddressSpace(AddressSpace);
return STATUS_INVALID_ADDRESS;
}
/* Check if it's a section view (RosMm section) or ARM3 section */
if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
{
/* Get the section pointer to the SECTION_OBJECT */
Section = MemoryArea->Data.SectionData.Section;
/* Unlock address space */
MmUnlockAddressSpace(AddressSpace);
/* Get the filename of the section */
Status = MmGetFileNameForSection(Section, &ModuleNameInformation);
}
else if (MemoryArea->Type == MEMORY_AREA_OWNED_BY_ARM3)
{
/* Get the VAD */
Vad = MiLocateAddress(Address);
if (!Vad) goto InvalidAddress;
/* Make sure it's not a VM VAD */
if (Vad->u.VadFlags.PrivateMemory == 1)
{
NotSection:
DPRINT1("Address is not a section\n");
MmUnlockAddressSpace(AddressSpace);
return STATUS_SECTION_NOT_IMAGE;
}
/* Get the control area */
ControlArea = Vad->ControlArea;
if (!(ControlArea) || !(ControlArea->u.Flags.Image)) goto NotSection;
/* Get the file object */
FileObject = ControlArea->FilePointer;
ASSERT(FileObject != NULL);
ObReferenceObject(FileObject);
/* Unlock address space */
MmUnlockAddressSpace(AddressSpace);
/* Get the filename of the file object */
Status = MmGetFileNameForFileObject(FileObject, &ModuleNameInformation);
/* Dereference it */
ObDereferenceObject(FileObject);
}
else
{
/* Trying to access virtual memory or something */
goto InvalidAddress;
}
/* Check if we were able to get the file object name */
if (NT_SUCCESS(Status))
{
/* Init modulename */
RtlCreateUnicodeString(ModuleName,
ModuleNameInformation->Name.Buffer);
/* Free temp taged buffer from MmGetFileNameForFileObject() */
ExFreePoolWithTag(ModuleNameInformation, ' mM');
DPRINT("Found ModuleName %S by address %p\n", ModuleName->Buffer, Address);
}
/* Return status */
return Status;
}
/* PUBLIC FUNCTIONS ***********************************************************/
/*

View file

@ -513,6 +513,153 @@ MmModifyAttributes(PMMSUPPORT AddressSpace,
}
}
NTSTATUS FASTCALL
MiQueryVirtualMemory(IN HANDLE ProcessHandle,
IN PVOID Address,
IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass,
OUT PVOID VirtualMemoryInformation,
IN SIZE_T Length,
OUT PSIZE_T ResultLength)
{
NTSTATUS Status;
PEPROCESS Process;
MEMORY_AREA* MemoryArea;
PMMSUPPORT AddressSpace;
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_QUERY_INFORMATION,
NULL,
UserMode,
(PVOID*)(&Process),
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("NtQueryVirtualMemory() = %x\n",Status);
return(Status);
}
AddressSpace = &Process->Vm;
MmLockAddressSpace(AddressSpace);
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
switch(VirtualMemoryInformationClass)
{
case MemoryBasicInformation:
{
PMEMORY_BASIC_INFORMATION Info =
(PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
if (Length != sizeof(MEMORY_BASIC_INFORMATION))
{
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
return(STATUS_INFO_LENGTH_MISMATCH);
}
if (MemoryArea == NULL)
{
Info->Type = 0;
Info->State = MEM_FREE;
Info->Protect = PAGE_NOACCESS;
Info->AllocationProtect = 0;
Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
Info->AllocationBase = NULL;
Info->RegionSize = MmFindGapAtAddress(AddressSpace, Info->BaseAddress);
Status = STATUS_SUCCESS;
*ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
}
else
{
switch(MemoryArea->Type)
{
case MEMORY_AREA_VIRTUAL_MEMORY:
Status = MmQueryAnonMem(MemoryArea, Address, Info,
ResultLength);
break;
case MEMORY_AREA_SECTION_VIEW:
Status = MmQuerySectionView(MemoryArea, Address, Info,
ResultLength);
break;
default:
DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea->Type);
Status = STATUS_UNSUCCESSFUL;
*ResultLength = 0;
}
}
break;
}
default:
{
DPRINT1("Unsupported or unimplemented class: %lx\n", VirtualMemoryInformationClass);
Status = STATUS_INVALID_INFO_CLASS;
*ResultLength = 0;
break;
}
}
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
return Status;
}
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;
}
/*
* @implemented
*/
@ -849,6 +996,171 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
return(STATUS_SUCCESS);
}
NTSTATUS NTAPI
NtQueryVirtualMemory(IN HANDLE ProcessHandle,
IN PVOID Address,
IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass,
OUT PVOID VirtualMemoryInformation,
IN SIZE_T Length,
OUT PSIZE_T UnsafeResultLength)
{
NTSTATUS Status;
SIZE_T ResultLength = 0;
KPROCESSOR_MODE PreviousMode;
WCHAR ModuleFileNameBuffer[MAX_PATH] = {0};
UNICODE_STRING ModuleFileName;
PMEMORY_SECTION_NAME SectionName = NULL;
PEPROCESS Process;
union
{
MEMORY_BASIC_INFORMATION BasicInfo;
}
VirtualMemoryInfo;
DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
"VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
"Length %lu ResultLength %x)\n",ProcessHandle,Address,
VirtualMemoryInformationClass,VirtualMemoryInformation,
Length,ResultLength);
PreviousMode = ExGetPreviousMode();
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
ProbeForWrite(VirtualMemoryInformation,
Length,
sizeof(ULONG_PTR));
if (UnsafeResultLength) ProbeForWriteSize_t(UnsafeResultLength);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
if (Address >= MmSystemRangeStart)
{
DPRINT1("Invalid parameter\n");
return STATUS_INVALID_PARAMETER;
}
/* FIXME: Move this inside MiQueryVirtualMemory */
if (VirtualMemoryInformationClass == MemorySectionName)
{
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_QUERY_INFORMATION,
NULL,
PreviousMode,
(PVOID*)(&Process),
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("NtQueryVirtualMemory() = %x\n",Status);
return(Status);
}
RtlInitEmptyUnicodeString(&ModuleFileName, ModuleFileNameBuffer, sizeof(ModuleFileNameBuffer));
Status = MmGetFileNameForAddress(Address, &ModuleFileName);
if (NT_SUCCESS(Status))
{
SectionName = VirtualMemoryInformation;
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
RtlInitUnicodeString(&SectionName->SectionFileName, SectionName->NameBuffer);
SectionName->SectionFileName.MaximumLength = Length;
RtlCopyUnicodeString(&SectionName->SectionFileName, &ModuleFileName);
if (UnsafeResultLength != NULL)
{
*UnsafeResultLength = ModuleFileName.Length;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
else
{
RtlInitUnicodeString(&SectionName->SectionFileName, SectionName->NameBuffer);
SectionName->SectionFileName.MaximumLength = Length;
RtlCopyUnicodeString(&SectionName->SectionFileName, &ModuleFileName);
if (UnsafeResultLength != NULL)
{
*UnsafeResultLength = ModuleFileName.Length;
}
}
}
ObDereferenceObject(Process);
return Status;
}
else
{
Status = MiQueryVirtualMemory(ProcessHandle,
Address,
VirtualMemoryInformationClass,
&VirtualMemoryInfo,
Length,
&ResultLength);
}
if (NT_SUCCESS(Status))
{
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
if (ResultLength > 0)
{
ProbeForWrite(VirtualMemoryInformation,
ResultLength,
1);
RtlCopyMemory(VirtualMemoryInformation,
&VirtualMemoryInfo,
ResultLength);
}
if (UnsafeResultLength != NULL)
{
*UnsafeResultLength = ResultLength;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
else
{
if (ResultLength > 0)
{
RtlCopyMemory(VirtualMemoryInformation,
&VirtualMemoryInfo,
ResultLength);
}
if (UnsafeResultLength != NULL)
{
*UnsafeResultLength = ResultLength;
}
}
}
return(Status);
}
static VOID
MmFreeVirtualMemoryPage(PVOID Context,
MEMORY_AREA* MemoryArea,

View file

@ -48,8 +48,6 @@
MEMORY_AREA MiStaticMemoryAreas[MI_STATIC_MEMORY_AREAS];
ULONG MiStaticMemoryAreaCount;
/* #define VALIDATE_MEMORY_AREAS */
/* FUNCTIONS *****************************************************************/
/**
@ -158,56 +156,6 @@ static PMEMORY_AREA MmIteratePrevNode(PMEMORY_AREA Node)
return Node;
}
#ifdef VALIDATE_MEMORY_AREAS
static VOID MmVerifyMemoryAreas(PMMSUPPORT AddressSpace)
{
PMEMORY_AREA Node;
ASSERT(AddressSpace != NULL);
/* Special case for empty tree. */
if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
return;
/* Traverse the tree from left to right. */
for (Node = MmIterateFirstNode(AddressSpace->WorkingSetExpansionLinks.Flink);
Node != NULL;
Node = MmIterateNextNode(Node))
{
/* FiN: The starting address can be NULL if someone explicitely asks
* for NULL address. */
ASSERT(Node->StartingAddress == NULL);
ASSERT(Node->EndingAddress >= Node->StartingAddress);
}
}
#else
#define MmVerifyMemoryAreas(x)
#endif
VOID NTAPI
MmDumpMemoryAreas(PMMSUPPORT AddressSpace)
{
PMEMORY_AREA Node;
DbgPrint("MmDumpMemoryAreas()\n");
/* Special case for empty tree. */
if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
return;
/* Traverse the tree from left to right. */
for (Node = MmIterateFirstNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink);
Node != NULL;
Node = MmIterateNextNode(Node))
{
DbgPrint("Start %p End %p Protect %x Flags %x\n",
Node->StartingAddress, Node->EndingAddress,
Node->Protect, Node->Flags);
}
DbgPrint("Finished MmDumpMemoryAreas()\n");
}
PMEMORY_AREA NTAPI
MmLocateMemoryAreaByAddress(
PMMSUPPORT AddressSpace,
@ -218,8 +166,6 @@ MmLocateMemoryAreaByAddress(
DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n",
AddressSpace, Address);
MmVerifyMemoryAreas(AddressSpace);
while (Node != NULL)
{
if (Address < Node->StartingAddress)
@ -247,8 +193,6 @@ MmLocateMemoryAreaByRegion(
PMEMORY_AREA Node;
PVOID Extent = (PVOID)((ULONG_PTR)Address + Length);
MmVerifyMemoryAreas(AddressSpace);
/* Special case for empty tree. */
if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
return NULL;
@ -421,8 +365,6 @@ MmInsertMemoryArea(
PMEMORY_AREA PreviousNode;
ULONG Depth = 0;
MmVerifyMemoryAreas(AddressSpace);
/* Build a lame VAD if this is a user-space allocation */
if ((marea->EndingAddress < MmSystemRangeStart) && (marea->Type != MEMORY_AREA_OWNED_BY_ARM3))
{
@ -502,8 +444,6 @@ MmFindGapBottomUp(
PMEMORY_AREA FirstNode;
PMEMORY_AREA PreviousNode;
MmVerifyMemoryAreas(AddressSpace);
DPRINT("LowestAddress: %p HighestAddress: %p\n",
LowestAddress, HighestAddress);
@ -579,8 +519,6 @@ MmFindGapTopDown(
PMEMORY_AREA Node;
PMEMORY_AREA PreviousNode;
MmVerifyMemoryAreas(AddressSpace);
DPRINT("LowestAddress: %p HighestAddress: %p\n",
LowestAddress, HighestAddress);
@ -676,8 +614,6 @@ MmFindGapAtAddress(
PVOID HighestAddress = MmGetAddressSpaceOwner(AddressSpace) ?
(PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
MmVerifyMemoryAreas(AddressSpace);
Address = MM_ROUND_DOWN(Address, PAGE_SIZE);
if (LowestAddress < MmSystemRangeStart)
@ -881,57 +817,6 @@ MmFreeMemoryArea(
return STATUS_SUCCESS;
}
/**
* @name MmFreeMemoryAreaByPtr
*
* Free an existing memory area given a pointer inside it.
*
* @param AddressSpace
* Address space to free the area from.
* @param BaseAddress
* Address in the memory area we're about to free.
* @param FreePage
* Callback function for each freed page.
* @param FreePageContext
* Context passed to the callback function.
*
* @return Status
*
* @see MmFreeMemoryArea
*
* @todo Should we require the BaseAddress to be really the starting
* address of the memory area or is the current relaxed check
* (BaseAddress can point anywhere in the memory area) acceptable?
*
* @remarks Lock the address space before calling this function.
*/
NTSTATUS NTAPI
MmFreeMemoryAreaByPtr(
PMMSUPPORT AddressSpace,
PVOID BaseAddress,
PMM_FREE_PAGE_FUNC FreePage,
PVOID FreePageContext)
{
PMEMORY_AREA MemoryArea;
DPRINT("MmFreeMemoryArea(AddressSpace %p, BaseAddress %p, "
"FreePageContext %p)\n", AddressSpace, BaseAddress,
FreePageContext);
MmVerifyMemoryAreas(AddressSpace);
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
BaseAddress);
if (MemoryArea == NULL)
{
KeBugCheck(MEMORY_MANAGEMENT);
return(STATUS_UNSUCCESSFUL);
}
return MmFreeMemoryArea(AddressSpace, MemoryArea, FreePage, FreePageContext);
}
/**
* @name MmCreateMemoryArea
*
@ -980,8 +865,6 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
Type, BaseAddress, *BaseAddress, Length, AllocationFlags,
FixedAddress, Result);
MmVerifyMemoryAreas(AddressSpace);
Granularity = (MEMORY_AREA_VIRTUAL_MEMORY == Type ? MM_VIRTMEM_GRANULARITY : PAGE_SIZE);
if ((*BaseAddress) == 0 && !FixedAddress)
{
@ -1102,36 +985,51 @@ MmMapMemoryArea(PVOID BaseAddress,
}
}
VOID NTAPI
MmReleaseMemoryAreaIfDecommitted(PEPROCESS Process,
PMMSUPPORT AddressSpace,
PVOID BaseAddress)
NTSTATUS
NTAPI
MmDeleteProcessAddressSpace(PEPROCESS Process)
{
PVOID Address;
PMEMORY_AREA MemoryArea;
PLIST_ENTRY Entry;
PMM_REGION Region;
BOOLEAN Reserved;
MmVerifyMemoryAreas(AddressSpace);
DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process,
Process->ImageFileName);
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
if (MemoryArea != NULL)
RemoveEntryList(&Process->MmProcessLinks);
MmLockAddressSpace(&Process->Vm);
while ((MemoryArea = (PMEMORY_AREA)Process->Vm.WorkingSetExpansionLinks.Flink) != NULL)
{
Entry = MemoryArea->Data.VirtualMemoryData.RegionListHead.Flink;
Reserved = TRUE;
while (Reserved && Entry != &MemoryArea->Data.VirtualMemoryData.RegionListHead)
switch (MemoryArea->Type)
{
Region = CONTAINING_RECORD(Entry, MM_REGION, RegionListEntry);
Reserved = (MEM_RESERVE == Region->Type);
Entry = Entry->Flink;
}
case MEMORY_AREA_SECTION_VIEW:
Address = (PVOID)MemoryArea->StartingAddress;
MmUnlockAddressSpace(&Process->Vm);
MmUnmapViewOfSection(Process, Address);
MmLockAddressSpace(&Process->Vm);
break;
if (Reserved)
{
MmFreeVirtualMemory(Process, MemoryArea);
case MEMORY_AREA_VIRTUAL_MEMORY:
MmFreeVirtualMemory(Process, MemoryArea);
break;
case MEMORY_AREA_OWNED_BY_ARM3:
MmFreeMemoryArea(&Process->Vm,
MemoryArea,
NULL,
NULL);
break;
default:
KeBugCheck(MEMORY_MANAGEMENT);
}
}
MmUnlockAddressSpace(&Process->Vm);
DPRINT("Finished MmReleaseMmInfo()\n");
return(STATUS_SUCCESS);
}
/* EOF */

View file

@ -17,6 +17,8 @@
/* GLOBALS *******************************************************************/
VOID NTAPI MiInitializeUserPfnBitmap(VOID);
PCHAR
MemType[] =
{
@ -48,6 +50,9 @@ MemType[] =
"LoaderXIPRom "
};
HANDLE MpwThreadHandle;
KEVENT MpwThreadEvent;
BOOLEAN Mm64BitPhysicalAddress = FALSE;
ULONG MmReadClusterSize;
//
@ -330,7 +335,88 @@ MiDbgDumpMemoryDescriptors(VOID)
DPRINT1("Total: %08lX (%d MB)\n", TotalPages, (TotalPages * PAGE_SIZE) / 1024 / 1024);
}
VOID NTAPI MiInitializeUserPfnBitmap(VOID);
NTSTATUS NTAPI
MmMpwThreadMain(PVOID Ignored)
{
NTSTATUS Status;
ULONG PagesWritten;
LARGE_INTEGER Timeout;
Timeout.QuadPart = -50000000;
for(;;)
{
Status = KeWaitForSingleObject(&MpwThreadEvent,
0,
KernelMode,
FALSE,
&Timeout);
if (!NT_SUCCESS(Status))
{
DbgPrint("MpwThread: Wait failed\n");
KeBugCheck(MEMORY_MANAGEMENT);
return(STATUS_UNSUCCESSFUL);
}
PagesWritten = 0;
CcRosFlushDirtyPages(128, &PagesWritten);
}
}
NTSTATUS
NTAPI
MmInitMpwThread(VOID)
{
KPRIORITY Priority;
NTSTATUS Status;
CLIENT_ID MpwThreadId;
KeInitializeEvent(&MpwThreadEvent, SynchronizationEvent, FALSE);
Status = PsCreateSystemThread(&MpwThreadHandle,
THREAD_ALL_ACCESS,
NULL,
NULL,
&MpwThreadId,
(PKSTART_ROUTINE) MmMpwThreadMain,
NULL);
if (!NT_SUCCESS(Status))
{
return(Status);
}
Priority = 27;
NtSetInformationThread(MpwThreadHandle,
ThreadPriority,
&Priority,
sizeof(Priority));
return(STATUS_SUCCESS);
}
NTSTATUS
NTAPI
MmInitBsmThread(VOID)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE ThreadHandle;
/* Create the thread */
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
Status = PsCreateSystemThread(&ThreadHandle,
THREAD_ALL_ACCESS,
&ObjectAttributes,
NULL,
NULL,
KeBalanceSetManager,
NULL);
/* Close the handle and return status */
ZwClose(ThreadHandle);
return Status;
}
BOOLEAN
NTAPI

View file

@ -1,112 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/mpw.c
* PURPOSE: Writes data that has been modified in memory but not on
* the disk
*
* PROGRAMMERS: David Welch (welch@cwcom.net)
*/
/* INCLUDES ****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
HANDLE MpwThreadHandle;
static CLIENT_ID MpwThreadId;
KEVENT MpwThreadEvent;
BOOLEAN MpwThreadShouldTerminate;
/* FUNCTIONS *****************************************************************/
NTSTATUS NTAPI
MmMpwThreadMain(PVOID Ignored)
{
NTSTATUS Status;
ULONG PagesWritten;
LARGE_INTEGER Timeout;
Timeout.QuadPart = -50000000;
for(;;)
{
Status = KeWaitForSingleObject(&MpwThreadEvent,
0,
KernelMode,
FALSE,
&Timeout);
if (!NT_SUCCESS(Status))
{
DbgPrint("MpwThread: Wait failed\n");
KeBugCheck(MEMORY_MANAGEMENT);
return(STATUS_UNSUCCESSFUL);
}
if (MpwThreadShouldTerminate)
{
DbgPrint("MpwThread: Terminating\n");
return(STATUS_SUCCESS);
}
PagesWritten = 0;
CcRosFlushDirtyPages(128, &PagesWritten);
}
}
NTSTATUS
NTAPI
MmInitMpwThread(VOID)
{
KPRIORITY Priority;
NTSTATUS Status;
MpwThreadShouldTerminate = FALSE;
KeInitializeEvent(&MpwThreadEvent, SynchronizationEvent, FALSE);
Status = PsCreateSystemThread(&MpwThreadHandle,
THREAD_ALL_ACCESS,
NULL,
NULL,
&MpwThreadId,
(PKSTART_ROUTINE) MmMpwThreadMain,
NULL);
if (!NT_SUCCESS(Status))
{
return(Status);
}
Priority = 1;
NtSetInformationThread(MpwThreadHandle,
ThreadPriority,
&Priority,
sizeof(Priority));
return(STATUS_SUCCESS);
}
NTSTATUS
NTAPI
MmInitBsmThread(VOID)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE ThreadHandle;
/* Create the thread */
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
Status = PsCreateSystemThread(&ThreadHandle,
THREAD_ALL_ACCESS,
&ObjectAttributes,
NULL,
NULL,
KeBalanceSetManager,
NULL);
/* Close the handle and return status */
ZwClose(ThreadHandle);
return Status;
}

View file

@ -1,745 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/pe.c
* PURPOSE: Loader for PE executables
*
* PROGRAMMERS: KJK::Hyperion <hackbunny@reactos.com>
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
//#define NDEBUG
#include <debug.h>
#include <reactos/exeformat.h>
static ULONG SectionCharacteristicsToProtect[16] =
{
PAGE_NOACCESS, /* 0 = NONE */
PAGE_NOACCESS, /* 1 = SHARED */
PAGE_EXECUTE, /* 2 = EXECUTABLE */
PAGE_EXECUTE, /* 3 = EXECUTABLE, SHARED */
PAGE_READONLY, /* 4 = READABLE */
PAGE_READONLY, /* 5 = READABLE, SHARED */
PAGE_EXECUTE_READ, /* 6 = READABLE, EXECUTABLE */
PAGE_EXECUTE_READ, /* 7 = READABLE, EXECUTABLE, SHARED */
/*
* FIXME? do we really need the WriteCopy field in segments? can't we use
* PAGE_WRITECOPY here?
*/
PAGE_READWRITE, /* 8 = WRITABLE */
PAGE_READWRITE, /* 9 = WRITABLE, SHARED */
PAGE_EXECUTE_READWRITE, /* 10 = WRITABLE, EXECUTABLE */
PAGE_EXECUTE_READWRITE, /* 11 = WRITABLE, EXECUTABLE, SHARED */
PAGE_READWRITE, /* 12 = WRITABLE, READABLE */
PAGE_READWRITE, /* 13 = WRITABLE, READABLE, SHARED */
PAGE_EXECUTE_READWRITE, /* 14 = WRITABLE, READABLE, EXECUTABLE */
PAGE_EXECUTE_READWRITE, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
};
/* TODO: Intsafe should be made into a library, as it's generally useful */
static __inline BOOLEAN Intsafe_CanAddULongPtr(IN ULONG_PTR Addend1, IN ULONG_PTR Addend2)
{
return Addend1 <= (MAXULONG_PTR - Addend2);
}
static __inline BOOLEAN Intsafe_CanAddLong64(IN LONG64 Addend1, IN LONG64 Addend2)
{
return Addend1 <= (MAXLONGLONG - Addend2);
}
static __inline BOOLEAN Intsafe_CanAddULong32(IN ULONG Addend1, IN ULONG Addend2)
{
return Addend1 <= (MAXULONG - Addend2);
}
static __inline BOOLEAN Intsafe_AddULong32(OUT PULONG Result, IN ULONG Addend1, IN ULONG Addend2)
{
if(!Intsafe_CanAddULong32(Addend1, Addend2))
return FALSE;
*Result = Addend1 + Addend2;
return TRUE;
}
static __inline BOOLEAN Intsafe_CanMulULong32(IN ULONG Factor1, IN ULONG Factor2)
{
return Factor1 <= (MAXULONG / Factor2);
}
static __inline BOOLEAN Intsafe_CanOffsetPointer(IN CONST VOID * Pointer, IN SIZE_T Offset)
{
/* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */
return Intsafe_CanAddULongPtr((ULONG_PTR)Pointer, Offset);
}
/* TODO: these are standard DDK/PSDK macros */
#ifndef RTL_FIELD_SIZE
#define RTL_FIELD_SIZE(TYPE_, FIELD_) (sizeof(((TYPE_ *)0)->FIELD_))
#endif
#ifndef RTL_SIZEOF_THROUGH_FIELD
#define RTL_SIZEOF_THROUGH_FIELD(TYPE_, FIELD_) \
(FIELD_OFFSET(TYPE_, FIELD_) + RTL_FIELD_SIZE(TYPE_, FIELD_))
#endif
#ifndef RTL_CONTAINS_FIELD
#define RTL_CONTAINS_FIELD(P_, SIZE_, FIELD_) \
((ULONG_PTR)(P_) + (ULONG_PTR)(SIZE_) > (ULONG_PTR)&((P_)->FIELD_) + sizeof((P_)->FIELD_))
#endif
static __inline BOOLEAN IsPowerOf2(IN ULONG Number)
{
if(Number == 0)
return FALSE;
return (Number & (Number - 1)) == 0;
}
static __inline ULONG ModPow2(IN ULONG Address, IN ULONG Alignment)
{
ASSERT(IsPowerOf2(Alignment));
return Address & (Alignment - 1);
}
static __inline BOOLEAN IsAligned(IN ULONG Address, IN ULONG Alignment)
{
return ModPow2(Address, Alignment) == 0;
}
static __inline BOOLEAN AlignUp(OUT PULONG AlignedAddress, IN ULONG Address, IN ULONG Alignment)
{
ULONG nExcess = ModPow2(Address, Alignment);
if(nExcess == 0)
{
*AlignedAddress = Address;
return nExcess == 0;
}
else
return Intsafe_AddULong32(AlignedAddress, Address, Alignment - nExcess);
}
#define PEFMT_FIELDS_EQUAL(TYPE1_, TYPE2_, FIELD_) \
( \
(FIELD_OFFSET(TYPE1_, FIELD_) == FIELD_OFFSET(TYPE2_, FIELD_)) && \
(RTL_FIELD_SIZE(TYPE1_, FIELD_) == RTL_FIELD_SIZE(TYPE2_, FIELD_)) \
)
//
// FIXME: All this whitespace is "padding" so the C_ASSERTs aren't on the same lines as asserts in other headers.
// This is necessary because of the way we define C_ASSERT in a gcc compatible way.
// This can be removed once we upgrade to gcc 4.3.x or later (which implements __COUNTER__).
//
//
// PeFmtCreateSection depends on the following:
//
C_ASSERT(EXEFMT_LOAD_HEADER_SIZE >= sizeof(IMAGE_DOS_HEADER));
C_ASSERT(sizeof(IMAGE_NT_HEADERS32) <= sizeof(IMAGE_NT_HEADERS64));
C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64));
C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64, FileHeader));
C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader) == FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Magic));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SectionAlignment));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, FileAlignment));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Subsystem));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MinorSubsystemVersion));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MajorSubsystemVersion));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfHeaders));
/*
References:
[1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
File Format Specification", revision 6.0 (February 1999)
*/
NTSTATUS NTAPI PeFmtCreateSection(IN CONST VOID * FileHeader,
IN SIZE_T FileHeaderSize,
IN PVOID File,
OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
OUT PULONG Flags,
IN PEXEFMT_CB_READ_FILE ReadFileCb,
IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb)
{
NTSTATUS nStatus;
ULONG cbFileHeaderOffsetSize = 0;
ULONG cbSectionHeadersOffset = 0;
ULONG cbSectionHeadersSize;
ULONG cbSectionHeadersOffsetSize = 0;
ULONG cbOptHeaderSize;
ULONG cbHeadersSize = 0;
ULONG nSectionAlignment;
ULONG nFileAlignment;
const IMAGE_DOS_HEADER * pidhDosHeader;
const IMAGE_NT_HEADERS32 * pinhNtHeader;
const IMAGE_OPTIONAL_HEADER32 * piohOptHeader;
const IMAGE_SECTION_HEADER * pishSectionHeaders;
PMM_SECTION_SEGMENT pssSegments;
LARGE_INTEGER lnOffset;
PVOID pBuffer;
ULONG nPrevVirtualEndOfSegment = 0;
ULONG nFileSizeOfHeaders = 0;
ULONG i;
ASSERT(FileHeader);
ASSERT(FileHeaderSize > 0);
ASSERT(File);
ASSERT(ImageSectionObject);
ASSERT(ReadFileCb);
ASSERT(AllocateSegmentsCb);
ASSERT(Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize));
ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_DOS_HEADER)) == 0);
#define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
pBuffer = NULL;
pidhDosHeader = FileHeader;
/* DOS HEADER */
nStatus = STATUS_ROS_EXEFMT_UNKNOWN_FORMAT;
/* image too small to be an MZ executable */
if(FileHeaderSize < sizeof(IMAGE_DOS_HEADER))
DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize));
/* no MZ signature */
if(pidhDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader->e_magic));
/* not a Windows executable */
if(pidhDosHeader->e_lfanew <= 0)
DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew));
/* NT HEADER */
nStatus = STATUS_INVALID_IMAGE_FORMAT;
if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize, pidhDosHeader->e_lfanew, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader)))
DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
if(FileHeaderSize < cbFileHeaderOffsetSize)
pinhNtHeader = NULL;
else
{
/*
* we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
* and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
*/
ASSERT(Intsafe_CanOffsetPointer(FileHeader, pidhDosHeader->e_lfanew));
pinhNtHeader = (PVOID)((UINT_PTR)FileHeader + pidhDosHeader->e_lfanew);
}
/*
* the buffer doesn't contain the NT file header, or the alignment is wrong: we
* need to read the header from the file
*/
if(FileHeaderSize < cbFileHeaderOffsetSize ||
(UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
{
ULONG cbNtHeaderSize;
ULONG cbReadSize;
PVOID pData;
l_ReadHeaderFromFile:
cbNtHeaderSize = 0;
lnOffset.QuadPart = pidhDosHeader->e_lfanew;
/* read the header from the file */
nStatus = ReadFileCb(File, &lnOffset, sizeof(IMAGE_NT_HEADERS64), &pData, &pBuffer, &cbReadSize);
if(!NT_SUCCESS(nStatus))
DIE(("ReadFile failed, status %08X\n", nStatus));
ASSERT(pData);
ASSERT(pBuffer);
ASSERT(cbReadSize > 0);
nStatus = STATUS_INVALID_IMAGE_FORMAT;
/* the buffer doesn't contain the file header */
if(cbReadSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader))
DIE(("The file doesn't contain the PE file header\n"));
pinhNtHeader = pData;
/* object still not aligned: copy it to the beginning of the buffer */
if((UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
{
ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == 0);
RtlMoveMemory(pBuffer, pData, cbReadSize);
pinhNtHeader = pBuffer;
}
/* invalid NT header */
nStatus = STATUS_INVALID_IMAGE_PROTECT;
if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
nStatus = STATUS_INVALID_IMAGE_FORMAT;
if(!Intsafe_AddULong32(&cbNtHeaderSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
DIE(("The full NT header is too large\n"));
/* the buffer doesn't contain the whole NT header */
if(cbReadSize < cbNtHeaderSize)
DIE(("The file doesn't contain the full NT header\n"));
}
else
{
ULONG cbOptHeaderOffsetSize = 0;
nStatus = STATUS_INVALID_IMAGE_FORMAT;
/* don't trust an invalid NT header */
if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, cbOptHeaderOffsetSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader->FileHeader.SizeOfOptionalHeader));
/* the buffer doesn't contain the whole NT header: read it from the file */
if(cbOptHeaderOffsetSize > FileHeaderSize)
goto l_ReadHeaderFromFile;
}
/* read information from the NT header */
piohOptHeader = &pinhNtHeader->OptionalHeader;
cbOptHeaderSize = pinhNtHeader->FileHeader.SizeOfOptionalHeader;
nStatus = STATUS_INVALID_IMAGE_FORMAT;
if(!RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Magic))
DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize));
/* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
switch(piohOptHeader->Magic)
{
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
break;
default:
DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader->Magic));
}
if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SectionAlignment) &&
RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, FileAlignment))
{
/* See [1], section 3.4.2 */
if(piohOptHeader->SectionAlignment < PAGE_SIZE)
{
if(piohOptHeader->FileAlignment != piohOptHeader->SectionAlignment)
DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
}
else if(piohOptHeader->SectionAlignment < piohOptHeader->FileAlignment)
DIE(("The section alignment is smaller than the file alignment\n"));
nSectionAlignment = piohOptHeader->SectionAlignment;
nFileAlignment = piohOptHeader->FileAlignment;
if(!IsPowerOf2(nSectionAlignment) || !IsPowerOf2(nFileAlignment))
DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment, nFileAlignment));
}
else
{
nSectionAlignment = PAGE_SIZE;
nFileAlignment = PAGE_SIZE;
}
ASSERT(IsPowerOf2(nSectionAlignment));
ASSERT(IsPowerOf2(nFileAlignment));
switch(piohOptHeader->Magic)
{
/* PE32 */
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
{
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, ImageBase))
ImageSectionObject->ImageBase = piohOptHeader->ImageBase;
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfImage))
ImageSectionObject->ImageSize = piohOptHeader->SizeOfImage;
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackReserve))
ImageSectionObject->StackReserve = piohOptHeader->SizeOfStackReserve;
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackCommit))
ImageSectionObject->StackCommit = piohOptHeader->SizeOfStackCommit;
break;
}
/* PE32+ */
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
{
const IMAGE_OPTIONAL_HEADER64 * pioh64OptHeader;
pioh64OptHeader = (const IMAGE_OPTIONAL_HEADER64 *)piohOptHeader;
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, ImageBase))
{
if(pioh64OptHeader->ImageBase > MAXULONG_PTR)
DIE(("ImageBase exceeds the address space\n"));
ImageSectionObject->ImageBase = (ULONG_PTR)pioh64OptHeader->ImageBase;
}
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfImage))
{
if(pioh64OptHeader->SizeOfImage > MAXULONG_PTR)
DIE(("SizeOfImage exceeds the address space\n"));
ImageSectionObject->ImageSize = pioh64OptHeader->SizeOfImage;
}
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackReserve))
{
if(pioh64OptHeader->SizeOfStackReserve > MAXULONG_PTR)
DIE(("SizeOfStackReserve exceeds the address space\n"));
ImageSectionObject->StackReserve = pioh64OptHeader->SizeOfStackReserve;
}
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackCommit))
{
if(pioh64OptHeader->SizeOfStackCommit > MAXULONG_PTR)
DIE(("SizeOfStackCommit exceeds the address space\n"));
ImageSectionObject->StackCommit = pioh64OptHeader->SizeOfStackCommit;
}
break;
}
}
/* [1], section 3.4.2 */
if((ULONG_PTR)ImageSectionObject->ImageBase % 0x10000)
DIE(("ImageBase is not aligned on a 64KB boundary"));
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Subsystem))
{
ImageSectionObject->Subsystem = piohOptHeader->Subsystem;
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MinorSubsystemVersion) &&
RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MajorSubsystemVersion))
{
ImageSectionObject->MinorSubsystemVersion = piohOptHeader->MinorSubsystemVersion;
ImageSectionObject->MajorSubsystemVersion = piohOptHeader->MajorSubsystemVersion;
}
}
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint))
{
ImageSectionObject->EntryPoint = piohOptHeader->ImageBase +
piohOptHeader->AddressOfEntryPoint;
}
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfCode))
ImageSectionObject->Executable = piohOptHeader->SizeOfCode != 0;
else
ImageSectionObject->Executable = TRUE;
ImageSectionObject->ImageCharacteristics = pinhNtHeader->FileHeader.Characteristics;
ImageSectionObject->Machine = pinhNtHeader->FileHeader.Machine;
/* SECTION HEADERS */
nStatus = STATUS_INVALID_IMAGE_FORMAT;
/* see [1], section 3.3 */
if(pinhNtHeader->FileHeader.NumberOfSections > 96)
DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader->FileHeader.NumberOfSections));
/*
* the additional segment is for the file's headers. They need to be present for
* the benefit of the dynamic loader (to locate exports, defaults for thread
* parameters, resources, etc.)
*/
ImageSectionObject->NrSegments = pinhNtHeader->FileHeader.NumberOfSections + 1;
/* file offset for the section headers */
if(!Intsafe_AddULong32(&cbSectionHeadersOffset, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
DIE(("Offset overflow\n"));
if(!Intsafe_AddULong32(&cbSectionHeadersOffset, cbSectionHeadersOffset, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
DIE(("Offset overflow\n"));
/* size of the section headers */
ASSERT(Intsafe_CanMulULong32(pinhNtHeader->FileHeader.NumberOfSections, sizeof(IMAGE_SECTION_HEADER)));
cbSectionHeadersSize = pinhNtHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize, cbSectionHeadersOffset, cbSectionHeadersSize))
DIE(("Section headers too large\n"));
/* size of the executable's headers */
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfHeaders))
{
// if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
// DIE(("SizeOfHeaders is not aligned\n"));
if(cbSectionHeadersSize > piohOptHeader->SizeOfHeaders)
DIE(("The section headers overflow SizeOfHeaders\n"));
cbHeadersSize = piohOptHeader->SizeOfHeaders;
}
else if(!AlignUp(&cbHeadersSize, cbSectionHeadersOffsetSize, nFileAlignment))
DIE(("Overflow aligning the size of headers\n"));
if(pBuffer)
{
ExFreePool(pBuffer);
pBuffer = NULL;
}
/* WARNING: pinhNtHeader IS NO LONGER USABLE */
/* WARNING: piohOptHeader IS NO LONGER USABLE */
/* WARNING: pioh64OptHeader IS NO LONGER USABLE */
if(FileHeaderSize < cbSectionHeadersOffsetSize)
pishSectionHeaders = NULL;
else
{
/*
* we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
* and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
*/
ASSERT(Intsafe_CanOffsetPointer(FileHeader, cbSectionHeadersOffset));
pishSectionHeaders = (PVOID)((UINT_PTR)FileHeader + cbSectionHeadersOffset);
}
/*
* the buffer doesn't contain the section headers, or the alignment is wrong:
* read the headers from the file
*/
if(FileHeaderSize < cbSectionHeadersOffsetSize ||
(UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
{
PVOID pData;
ULONG cbReadSize;
lnOffset.QuadPart = cbSectionHeadersOffset;
/* read the header from the file */
nStatus = ReadFileCb(File, &lnOffset, cbSectionHeadersSize, &pData, &pBuffer, &cbReadSize);
if(!NT_SUCCESS(nStatus))
DIE(("ReadFile failed with status %08X\n", nStatus));
ASSERT(pData);
ASSERT(pBuffer);
ASSERT(cbReadSize > 0);
nStatus = STATUS_INVALID_IMAGE_FORMAT;
/* the buffer doesn't contain all the section headers */
if(cbReadSize < cbSectionHeadersSize)
DIE(("The file doesn't contain all of the section headers\n"));
pishSectionHeaders = pData;
/* object still not aligned: copy it to the beginning of the buffer */
if((UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
{
ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) == 0);
RtlMoveMemory(pBuffer, pData, cbReadSize);
pishSectionHeaders = pBuffer;
}
}
/* SEGMENTS */
/* allocate the segments */
nStatus = STATUS_INSUFFICIENT_RESOURCES;
ImageSectionObject->Segments = AllocateSegmentsCb(ImageSectionObject->NrSegments);
if(ImageSectionObject->Segments == NULL)
DIE(("AllocateSegments failed\n"));
/* initialize the headers segment */
pssSegments = ImageSectionObject->Segments;
// ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
if(!AlignUp(&nFileSizeOfHeaders, cbHeadersSize, nFileAlignment))
DIE(("Cannot align the size of the section headers\n"));
if(!AlignUp(&nPrevVirtualEndOfSegment, cbHeadersSize, nSectionAlignment))
DIE(("Cannot align the size of the section headers\n"));
pssSegments[0].FileOffset = 0;
pssSegments[0].Protection = PAGE_READONLY;
pssSegments[0].Length = nPrevVirtualEndOfSegment;
pssSegments[0].RawLength = nFileSizeOfHeaders;
pssSegments[0].VirtualAddress = 0;
pssSegments[0].Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA;
pssSegments[0].WriteCopy = TRUE;
/* skip the headers segment */
++ pssSegments;
nStatus = STATUS_INVALID_IMAGE_FORMAT;
/* convert the executable sections into segments. See also [1], section 4 */
for(i = 0; i < ImageSectionObject->NrSegments - 1; ++ i)
{
ULONG nCharacteristics;
/* validate the alignment */
if(!IsAligned(pishSectionHeaders[i].VirtualAddress, nSectionAlignment))
DIE(("VirtualAddress[%u] is not aligned\n", i));
/* sections must be contiguous, ordered by base address and non-overlapping */
if(pishSectionHeaders[i].VirtualAddress != nPrevVirtualEndOfSegment)
DIE(("Memory gap between section %u and the previous\n", i));
/* ignore explicit BSS sections */
if(pishSectionHeaders[i].SizeOfRawData != 0)
{
/* validate the alignment */
#if 0
/* Yes, this should be a multiple of FileAlignment, but there's
* stuff out there that isn't. We can cope with that
*/
if(!IsAligned(pishSectionHeaders[i].SizeOfRawData, nFileAlignment))
DIE(("SizeOfRawData[%u] is not aligned\n", i));
#endif
// if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
// DIE(("PointerToRawData[%u] is not aligned\n", i));
/* conversion */
pssSegments[i].FileOffset = pishSectionHeaders[i].PointerToRawData;
pssSegments[i].RawLength = pishSectionHeaders[i].SizeOfRawData;
}
else
{
ASSERT(pssSegments[i].FileOffset == 0);
ASSERT(pssSegments[i].RawLength == 0);
}
ASSERT(Intsafe_CanAddLong64(pssSegments[i].FileOffset, pssSegments[i].RawLength));
nCharacteristics = pishSectionHeaders[i].Characteristics;
/* no explicit protection */
if((nCharacteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == 0)
{
if(nCharacteristics & IMAGE_SCN_CNT_CODE)
nCharacteristics |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
if(nCharacteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
if(nCharacteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
}
/* see table above */
pssSegments[i].Protection = SectionCharacteristicsToProtect[nCharacteristics >> 28];
pssSegments[i].WriteCopy = !(nCharacteristics & IMAGE_SCN_MEM_SHARED);
if(pishSectionHeaders[i].Misc.VirtualSize == 0 || pishSectionHeaders[i].Misc.VirtualSize < pishSectionHeaders[i].SizeOfRawData)
pssSegments[i].Length = pishSectionHeaders[i].SizeOfRawData;
else
pssSegments[i].Length = pishSectionHeaders[i].Misc.VirtualSize;
if(!AlignUp(&pssSegments[i].Length, pssSegments[i].Length, nSectionAlignment))
DIE(("Cannot align the virtual size of section %u\n", i));
ASSERT(IsAligned(pssSegments[i].Length, nSectionAlignment));
if(pssSegments[i].Length == 0)
DIE(("Virtual size of section %u is null\n", i));
pssSegments[i].VirtualAddress = pishSectionHeaders[i].VirtualAddress;
pssSegments[i].Characteristics = pishSectionHeaders[i].Characteristics;
/* ensure the memory image is no larger than 4GB */
if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment, pssSegments[i].VirtualAddress, pssSegments[i].Length))
DIE(("The image is larger than 4GB\n"));
}
/* spare our caller some work in validating the segments */
*Flags = EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED | EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP;
if(nSectionAlignment >= PAGE_SIZE)
*Flags |= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED;
/* Success */
nStatus = STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
l_Return:
if(pBuffer)
ExFreePool(pBuffer);
return nStatus;
}
/* EOF */

View file

@ -1,992 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/ppool.c
* PURPOSE: Implements the paged pool
*
* PROGRAMMERS: David Welch (welch@mcmail.com)
* Royce Mitchell III
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
#undef ASSERT
#define ASSERT(x) if (!(x)) {DbgPrint("Assertion "#x" failed at %s:%d\n", __FILE__,__LINE__); DbgBreakPoint(); }
// enable "magic"
//#define R_MAGIC
#define R_MUTEX FAST_MUTEX
#define R_ACQUIRE_MUTEX(pool) /*DPRINT1("Acquiring PPool Mutex\n");*/ ExAcquireFastMutex(&pool->Mutex)
#define R_RELEASE_MUTEX(pool) /*DPRINT1("Releasing PPool Mutex\n");*/ ExReleaseFastMutex(&pool->Mutex)
#define R_PRINT_ADDRESS(addr) KeRosPrintAddress(addr)
#define R_PANIC() KeBugCheck(MEMORY_MANAGEMENT)
#define R_DEBUG DbgPrint
#ifdef _ARM_
#define R_GET_STACK_FRAMES(ptr,cnt)
#else
#define R_GET_STACK_FRAMES(ptr,cnt) RtlWalkFrameChain((PVOID*)ptr,cnt, 0)
#endif
/* GLOBALS ********************************************************************/
typedef unsigned long rulong;
#define R_IS_POOL_PTR(pool,ptr) (((void*)(ULONG_PTR)(ptr) >= pool->UserBase) && ((ULONG_PTR)(ptr) < ((ULONG_PTR)pool->UserBase + pool->UserSize)))
#define R_ASSERT_PTR(pool,ptr) ASSERT( R_IS_POOL_PTR(pool,ptr) )
#define R_ASSERT_SIZE(pool,sz) ASSERT( sz > (sizeof(R_USED)+2*R_RZ) && sz >= sizeof(R_FREE) && sz < pool->UserSize )
#ifndef R_ROUND_UP
#define R_ROUND_UP(x,s) ((PVOID)(((ULONG_PTR)(x)+(s)-1) & ~((ULONG_PTR)(s)-1)))
#endif//R_ROUND_UP
#ifndef R_ROUND_DOWN
#define R_ROUND_DOWN(x,s) ((PVOID)(((ULONG_PTR)(x)) & ~((ULONG_PTR)(s)-1)))
#endif//R_ROUND_DOWN
#ifndef R_QUEMIN
// R_QUEMIN is the minimum number of entries to keep in a que
#define R_QUEMIN 0
#endif//R_QUEMIN
#ifndef R_QUECOUNT
// 16, 32, 64, 128, 256, 512
#define R_QUECOUNT 6
#endif//R_QUECOUNT
#ifndef R_RZ
// R_RZ is the redzone size
#define R_RZ 4
#endif//R_RZ
#ifndef R_RZ_LOVALUE
#define R_RZ_LOVALUE 0x87
#endif//R_RZ_LOVALUE
#ifndef R_RZ_HIVALUE
#define R_RZ_HIVALUE 0xA5
#endif//R_RZ_HIVALUE
#ifndef R_STACK
// R_STACK is the number of stack entries to store in blocks for debug purposes
#define R_STACK 6
#else // R_STACK
#if R_STACK > 0 && R_STACK < 6
/* Increase the frame depth to get a reasonable back trace */
#undef R_STACK
#define R_STACK 6
#endif // R_STACK > 0 && R_STACK < 6
#endif//R_STACK
#ifndef R_TAG
// R_TAG do we keep track of tags on a per-memory block basis?
#define R_TAG 0
#endif//R_TAG
#ifdef R_MAGIC
# ifndef R_FREE_MAGIC
# define R_FREE_MAGIC (rulong)(('F'<<0) + ('r'<<8) + ('E'<<16) + ('e'<<24))
# endif//R_FREE_MAGIC
# ifndef R_USED_MAGIC
# define R_USED_MAGIC (rulong)(('u'<<0) + ('S'<<8) + ('e'<<16) + ('D'<<24))
# endif//R_USED_MAGIC
#endif//R_MAGIC
// **IMPORTANT NOTE** Magic, PrevSize, Size and Status must be at same offset
// in both the R_FREE and R_USED structures
typedef struct _R_FREE
{
#ifdef R_MAGIC
rulong FreeMagic;
#endif//R_MAGIC
rulong PrevSize : 30;
rulong Status : 2;
rulong Size;
#if R_STACK
ULONG_PTR LastOwnerStack[R_STACK];
#endif//R_STACK
struct _R_FREE* NextFree;
struct _R_FREE* PrevFree;
}
R_FREE, *PR_FREE;
typedef struct _R_USED
{
#ifdef R_MAGIC
rulong UsedMagic;
#endif//R_MAGIC
rulong PrevSize : 30;
rulong Status : 2;
rulong Size;
#if R_STACK
ULONG_PTR LastOwnerStack[R_STACK];
#endif//R_STACK
struct _R_USED* NextUsed;
#if R_RZ
rulong UserSize; // how many bytes the user actually asked for...
#endif//R_RZ
rulong Tag;
}
R_USED, *PR_USED;
typedef struct _R_QUE
{
rulong Count;
PR_USED First, Last;
}
R_QUE, *PR_QUE;
typedef struct _R_POOL
{
void* PoolBase;
rulong PoolSize;
void* UserBase;
rulong UserSize;
rulong Alignments[3];
PR_FREE FirstFree, LastFree;
R_QUE Que[R_QUECOUNT][3];
R_MUTEX Mutex;
}
R_POOL, *PR_POOL;
PVOID MmPagedPoolBase;
SIZE_T MmPagedPoolSize;
SIZE_T MmTotalPagedPoolQuota = 0; // TODO FIXME commented out until we use it
static PR_POOL MmPagedPool = NULL;
/* FUNCTIONS*******************************************************************/
#if !R_STACK
#define RiPrintLastOwner(Block)
#else
static void
RiPrintLastOwner ( PR_USED Block )
{
int i;
for ( i = 0; i < R_STACK; i++ )
{
if ( Block->LastOwnerStack[i] != 0xDEADBEEF )
{
R_DEBUG(" ");
//if (!R_PRINT_ADDRESS ((PVOID)Block->LastOwnerStack[i]) )
{
R_DEBUG("<%X>", Block->LastOwnerStack[i] );
}
}
}
}
#endif//R_STACK
static int
RQueWhich ( rulong size )
{
rulong que, quesize;
for ( que=0, quesize=16; que < R_QUECOUNT; que++, quesize<<=1 )
{
if ( quesize >= size )
{
return que;
}
}
return -1;
}
static void
RQueInit ( PR_QUE que )
{
que->Count = 0;
que->First = NULL;
que->Last = NULL;
}
static void
RQueAdd ( PR_QUE que, PR_USED Item )
{
ASSERT(Item);
Item->Status = 2;
Item->NextUsed = NULL;
++que->Count;
if ( !que->Last )
{
que->First = que->Last = Item;
return;
}
ASSERT(!que->Last->NextUsed);
que->Last->NextUsed = Item;
que->Last = Item;
}
static PR_USED
RQueRemove ( PR_QUE que )
{
PR_USED Item;
#if R_QUEMIN
if ( que->count < R_QUEMIN )
return NULL;
#endif
if ( !que->First )
return NULL;
Item = que->First;
que->First = Item->NextUsed;
if ( !--que->Count )
{
ASSERT ( !que->First );
que->Last = NULL;
}
Item->Status = 0;
return Item;
}
static void
RPoolAddFree ( PR_POOL pool, PR_FREE Item )
{
ASSERT(pool);
ASSERT(Item);
if ( !pool->FirstFree )
{
pool->FirstFree = pool->LastFree = Item;
Item->NextFree = NULL;
}
else
{
pool->FirstFree->PrevFree = Item;
Item->NextFree = pool->FirstFree;
pool->FirstFree = Item;
}
Item->PrevFree = NULL;
}
static void
RPoolRemoveFree ( PR_POOL pool, PR_FREE Item )
{
ASSERT(pool);
ASSERT(Item);
if ( Item->NextFree )
Item->NextFree->PrevFree = Item->PrevFree;
else
{
ASSERT ( pool->LastFree == Item );
pool->LastFree = Item->PrevFree;
}
if ( Item->PrevFree )
Item->PrevFree->NextFree = Item->NextFree;
else
{
ASSERT ( pool->FirstFree == Item );
pool->FirstFree = Item->NextFree;
}
#if DBG
Item->NextFree = Item->PrevFree = (PR_FREE)(ULONG_PTR)0xDEADBEEF;
#endif//DBG
}
#if !R_STACK
#define RFreeFillStack(free)
#define RUsedFillStack(used)
#else
static void
RFreeFillStack ( PR_FREE free )
{
int i;
ULONG stack[R_STACK+3]; // need to skip 3 known levels of stack trace
memset ( stack, 0xCD, sizeof(stack) );
R_GET_STACK_FRAMES ( stack, R_STACK+3 );
for ( i = 0; i < R_STACK; i++ )
free->LastOwnerStack[i] = stack[i+3];
}
static void
RUsedFillStack ( PR_USED used )
{
int i;
ULONG stack[R_STACK+2]; // need to skip 2 known levels of stack trace
memset ( stack, 0xCD, sizeof(stack) );
R_GET_STACK_FRAMES ( stack, R_STACK+2 );
for ( i = 0; i < R_STACK; i++ )
used->LastOwnerStack[i] = stack[i+2];
}
#endif
static PR_FREE
RFreeInit ( void* memory )
{
PR_FREE block = (PR_FREE)memory;
#if R_FREEMAGIC
block->FreeMagic = R_FREE_MAGIC;
#endif//R_FREEMAGIC
block->Status = 0;
RFreeFillStack ( block );
#if DBG
block->PrevFree = block->NextFree = (PR_FREE)(ULONG_PTR)0xDEADBEEF;
#endif//DBG
return block;
}
PR_POOL
RPoolInit ( void* PoolBase, rulong PoolSize, int align1, int align2, int align3 )
{
int align, que;
PR_POOL pool = (PR_POOL)PoolBase;
pool->PoolBase = PoolBase;
pool->PoolSize = PoolSize;
pool->UserBase = (char*)pool->PoolBase + sizeof(R_POOL);
pool->UserSize = PoolSize - sizeof(R_POOL);
pool->Alignments[0] = align1;
pool->Alignments[1] = align2;
pool->Alignments[2] = align3;
pool->FirstFree = pool->LastFree = NULL;
RPoolAddFree ( pool,
RFreeInit ( pool->UserBase ));
pool->FirstFree->PrevSize = 0;
pool->FirstFree->Size = pool->UserSize;
for ( que = 0; que < R_QUECOUNT; que++ )
{
for ( align = 0; align < 3; align++ )
{
RQueInit ( &pool->Que[que][align] );
}
}
return pool;
}
#if R_RZ
static const char*
RFormatTag ( rulong Tag, char* buf )
{
int i;
*(rulong*)&buf[0] = Tag;
buf[4] = 0;
for ( i = 0; i < 4; i++ )
{
if ( !buf[i] )
buf[i] = ' ';
}
return buf;
}
#endif
#if !R_RZ
#define RUsedRedZoneCheck(pUsed,Addr,file,line, printzone)
#else//R_RZ
static void
RiBadBlock ( PR_USED pUsed, char* Addr, const char* violation, const char* file, int line, int printzone )
{
char tag[5];
unsigned int i;
R_DEBUG("%s(%i): %s detected for paged pool address 0x%x\n",
file, line, violation, Addr );
#ifdef R_MAGIC
R_DEBUG ( "UsedMagic 0x%x, ", pUsed->UsedMagic );
#endif//R_MAGIC
R_DEBUG ( "Tag %s(%X), Size %i, UserSize %i",
RFormatTag(pUsed->Tag,tag),
pUsed->Tag,
pUsed->Size,
pUsed->UserSize );
if ( printzone )
{
unsigned char* HiZone = (unsigned char*)Addr + pUsed->UserSize;
unsigned char* LoZone = (unsigned char*)Addr - R_RZ; // this is to simplify indexing below...
R_DEBUG ( ", LoZone " );
for ( i = 0; i < R_RZ; i++ )
R_DEBUG ( "%02x", LoZone[i] );
R_DEBUG ( ", HiZone " );
for ( i = 0; i < R_RZ; i++ )
R_DEBUG ( "%02x", HiZone[i] );
}
R_DEBUG ( "\n" );
R_DEBUG ( "First few Stack Frames:" );
RiPrintLastOwner ( pUsed );
R_DEBUG ( "\n" );
R_DEBUG ( "Contents of Block:\n" );
for ( i = 0; i < 8*16 && i < pUsed->UserSize; i += 16 )
{
int j;
R_DEBUG ( "%04X ", i );
for ( j = 0; j < 16; j++ )
{
if ( i+j < pUsed->UserSize )
{
R_DEBUG ( "%02X ", (unsigned)(unsigned char)Addr[i+j] );
}
else
{
R_DEBUG ( " " );
}
}
R_DEBUG(" ");
for ( j = 0; j < 16; j++ )
{
if ( i+j < pUsed->UserSize )
{
char c = Addr[i+j];
if ( c < 0x20 || c > 0x7E )
c = '.';
R_DEBUG ( "%c", c );
}
else
{
R_DEBUG ( " " );
}
}
R_DEBUG("\n");
}
R_PANIC();
}
static void
RUsedRedZoneCheck ( PR_POOL pool, PR_USED pUsed, char* Addr, const char* file, int line )
{
int i;
unsigned char *LoZone, *HiZone;
int bLow = 1;
int bHigh = 1;
ASSERT ( Addr >= (char*)pool->UserBase && Addr < ((char*)pool->UserBase + pool->UserSize - 16) );
#ifdef R_MAGIC
if ( pUsed->UsedMagic == R_FREE_MAGIC )
{
pUsed->UserSize = 0; // just to keep from confusion, MmpBadBlock() doesn't return...
RiBadBlock ( pUsed, Addr, "double-free", file, line, 0 );
}
if ( pUsed->UsedMagic != R_USED_MAGIC )
{
RiBadBlock ( pUsed, Addr, "bad magic", file, line, 0 );
}
#endif//R_MAGIC
switch ( pUsed->Status )
{
case 0: // freed into main pool
case 2: // in ques
RiBadBlock ( pUsed, Addr, "double-free", file, line, 0 );
// no need for break here - RiBadBlock doesn't return
case 1: // allocated - this is okay
break;
default:
RiBadBlock ( pUsed, Addr, "corrupt status", file, line, 0 );
}
if ( pUsed->Status != 1 )
{
RiBadBlock ( pUsed, Addr, "double-free", file, line, 0 );
}
if ( pUsed->Size > pool->PoolSize || pUsed->Size == 0 )
{
RiBadBlock ( pUsed, Addr, "invalid size", file, line, 0 );
}
if ( pUsed->UserSize > pool->PoolSize || pUsed->UserSize == 0 )
{
RiBadBlock ( pUsed, Addr, "invalid user size", file, line, 0 );
}
HiZone = (unsigned char*)Addr + pUsed->UserSize;
LoZone = (unsigned char*)Addr - R_RZ; // this is to simplify indexing below...
for ( i = 0; i < R_RZ && bLow && bHigh; i++ )
{
bLow = bLow && ( LoZone[i] == R_RZ_LOVALUE );
bHigh = bHigh && ( HiZone[i] == R_RZ_HIVALUE );
}
if ( !bLow || !bHigh )
{
const char* violation = "High and Low-side redzone overwrite";
if ( bHigh ) // high is okay, so it was just low failed
violation = "Low-side redzone overwrite";
else if ( bLow ) // low side is okay, so it was just high failed
violation = "High-side redzone overwrite";
RiBadBlock ( pUsed, Addr, violation, file, line, 1 );
}
}
#endif//R_RZ
PR_FREE
RPreviousBlock ( PR_FREE Block )
{
if ( Block->PrevSize > 0 )
return (PR_FREE)( (char*)Block - Block->PrevSize );
return NULL;
}
PR_FREE
RNextBlock ( PR_POOL pool, PR_FREE Block )
{
PR_FREE NextBlock = (PR_FREE)( (char*)Block + Block->Size );
if ( (char*)NextBlock >= (char*)pool->UserBase + pool->UserSize )
NextBlock = NULL;
return NextBlock;
}
static __inline void*
RHdrToBody ( void* blk )
/*
* FUNCTION: Translate a block header address to the corresponding block
* address (internal)
*/
{
return ( (void *) ((char*)blk + sizeof(R_USED) + R_RZ) );
}
static __inline PR_USED
RBodyToHdr ( void* addr )
{
return (PR_USED)
( ((char*)addr) - sizeof(R_USED) - R_RZ );
}
static int
RiInFreeChain ( PR_POOL pool, PR_FREE Block )
{
PR_FREE Free;
Free = pool->FirstFree;
if ( Free == Block )
return 1;
while ( Free != Block )
{
Free = Free->NextFree;
if ( !Free )
return 0;
}
return 1;
}
static void
RPoolRedZoneCheck ( PR_POOL pool, const char* file, int line )
{
{
PR_USED Block = (PR_USED)pool->UserBase;
PR_USED NextBlock;
for ( ;; )
{
switch ( Block->Status )
{
case 0: // block is in chain
ASSERT ( RiInFreeChain ( pool, (PR_FREE)Block ) );
break;
case 1: // block is allocated
RUsedRedZoneCheck ( pool, Block, RHdrToBody(Block), file, line );
break;
case 2: // block is in que
// nothing to verify here yet
break;
default:
ASSERT ( !"invalid status in memory block found in pool!" );
}
NextBlock = (PR_USED)RNextBlock(pool,(PR_FREE)Block);
if ( !NextBlock )
break;
ASSERT ( NextBlock->PrevSize == Block->Size );
Block = NextBlock;
}
}
{
// now let's step through the list of free pointers and verify
// each one can be found by size-jumping...
PR_FREE Free = (PR_FREE)pool->FirstFree;
while ( Free )
{
PR_FREE NextFree = (PR_FREE)pool->UserBase;
if ( Free != NextFree )
{
while ( NextFree != Free )
{
NextFree = RNextBlock ( pool, NextFree );
ASSERT(NextFree);
}
}
Free = Free->NextFree;
}
}
}
static void
RSetSize ( PR_POOL pool, PR_FREE Block, rulong NewSize, PR_FREE NextBlock )
{
R_ASSERT_PTR(pool,Block);
ASSERT ( NewSize < pool->UserSize );
ASSERT ( NewSize >= sizeof(R_FREE) );
Block->Size = NewSize;
if ( !NextBlock )
NextBlock = RNextBlock ( pool, Block );
if ( NextBlock )
NextBlock->PrevSize = NewSize;
}
static PR_FREE
RFreeSplit ( PR_POOL pool, PR_FREE Block, rulong NewSize )
{
PR_FREE NewBlock = (PR_FREE)((char*)Block + NewSize);
RSetSize ( pool, NewBlock, Block->Size - NewSize, NULL );
RSetSize ( pool, Block, NewSize, NewBlock );
RFreeInit ( NewBlock );
RPoolAddFree ( pool, NewBlock );
return NewBlock;
}
static void
RFreeMerge ( PR_POOL pool, PR_FREE First, PR_FREE Second )
{
ASSERT ( RPreviousBlock(Second) == First );
ASSERT ( First->Size == Second->PrevSize );
RPoolRemoveFree ( pool, Second );
RSetSize ( pool, First, First->Size + Second->Size, NULL );
}
static void
RPoolReclaim ( PR_POOL pool, PR_FREE FreeBlock )
{
PR_FREE NextBlock, PreviousBlock;
RFreeInit ( FreeBlock );
RPoolAddFree ( pool, FreeBlock );
// TODO FIXME - don't merge and always insert freed blocks at the end for debugging purposes...
/*
* If the next block is immediately adjacent to the newly freed one then
* merge them.
* PLEASE DO NOT WIPE OUT 'MAGIC' OR 'LASTOWNER' DATA FOR MERGED FREE BLOCKS
*/
NextBlock = RNextBlock ( pool, FreeBlock );
if ( NextBlock != NULL && !NextBlock->Status )
{
RFreeMerge ( pool, FreeBlock, NextBlock );
}
/*
* If the previous block is adjacent to the newly freed one then
* merge them.
* PLEASE DO NOT WIPE OUT 'MAGIC' OR 'LASTOWNER' DATA FOR MERGED FREE BLOCKS
*/
PreviousBlock = RPreviousBlock ( FreeBlock );
if ( PreviousBlock != NULL && !PreviousBlock->Status )
{
RFreeMerge ( pool, PreviousBlock, FreeBlock );
}
}
static void
RiUsedInit ( PR_USED Block, rulong Tag )
{
Block->Status = 1;
RUsedFillStack ( Block );
#ifdef R_MAGIC
Block->UsedMagic = R_USED_MAGIC;
#endif//R_MAGIC
//ASSERT_SIZE ( Block->Size );
// now add the block to the used block list
#if DBG
Block->NextUsed = (PR_USED)(ULONG_PTR)0xDEADBEEF;
#endif//R_USED_LIST
Block->Tag = Tag;
}
#if !R_RZ
#define RiUsedInitRedZone(Block,UserSize)
#else//R_RZ
static void
RiUsedInitRedZone ( PR_USED Block, rulong UserSize )
{
// write out buffer-overrun detection bytes
char* Addr = (char*)RHdrToBody(Block);
Block->UserSize = UserSize;
memset ( Addr - R_RZ, R_RZ_LOVALUE, R_RZ );
memset ( Addr + Block->UserSize, R_RZ_HIVALUE, R_RZ );
#if DBG
memset ( Addr, 0xCD, UserSize );
#endif//DBG
}
#endif//R_RZ
static void*
RPoolAlloc ( PR_POOL pool, rulong NumberOfBytes, rulong Tag, rulong align )
{
PR_USED NewBlock;
PR_FREE BestBlock,
CurrentBlock;
void* BestAlignedAddr;
int que,
queBytes = NumberOfBytes;
rulong BlockSize,
Alignment;
int que_reclaimed = 0;
ASSERT ( pool );
ASSERT ( align < 3 );
R_ACQUIRE_MUTEX(pool);
if ( !NumberOfBytes )
{
R_DEBUG("0 bytes requested - initiating pool verification\n");
RPoolRedZoneCheck ( pool, __FILE__, __LINE__ );
R_RELEASE_MUTEX(pool);
return NULL;
}
if ( NumberOfBytes > pool->PoolSize )
{
if ( R_IS_POOL_PTR(pool,NumberOfBytes) )
{
R_DEBUG("red zone verification requested for block 0x%X\n", NumberOfBytes );
RUsedRedZoneCheck(pool,RBodyToHdr((void*)(ULONG_PTR)NumberOfBytes), (char*)(ULONG_PTR)NumberOfBytes, __FILE__, __LINE__ );
R_RELEASE_MUTEX(pool);
return NULL;
}
R_DEBUG("Invalid allocation request: %i bytes\n", NumberOfBytes );
R_RELEASE_MUTEX(pool);
return NULL;
}
que = RQueWhich ( NumberOfBytes );
if ( que >= 0 )
{
if ( (NewBlock = RQueRemove ( &pool->Que[que][align] )) )
{
RiUsedInit ( NewBlock, Tag );
RiUsedInitRedZone ( NewBlock, NumberOfBytes );
R_RELEASE_MUTEX(pool);
return RHdrToBody(NewBlock);
}
queBytes = 16 << que;
}
/*
* Calculate the total number of bytes we will need.
*/
BlockSize = queBytes + sizeof(R_USED) + 2*R_RZ;
if (BlockSize < sizeof(R_FREE))
{
/* At least we need the size of the free block header. */
BlockSize = sizeof(R_FREE);
}
try_again:
/*
* Find the best-fitting block.
*/
BestBlock = NULL;
Alignment = pool->Alignments[align];
CurrentBlock = pool->FirstFree;
BestAlignedAddr = NULL;
while ( CurrentBlock != NULL )
{
PVOID Addr = RHdrToBody(CurrentBlock);
PVOID CurrentBlockEnd = (char*)CurrentBlock + CurrentBlock->Size;
/* calculate last size-aligned address available within this block */
PVOID AlignedAddr = R_ROUND_DOWN((char*)CurrentBlockEnd-queBytes-R_RZ, Alignment);
ASSERT ( (char*)AlignedAddr+queBytes+R_RZ <= (char*)CurrentBlockEnd );
/* special case, this address is already size-aligned, and the right size */
if ( Addr == AlignedAddr )
{
BestAlignedAddr = AlignedAddr;
BestBlock = CurrentBlock;
break;
}
// if we carve out a size-aligned block... is it still past the end of this
// block's free header?
else if ( (char*)RBodyToHdr(AlignedAddr)
>= (char*)CurrentBlock+sizeof(R_FREE) )
{
/*
* there's enough room to allocate our size-aligned memory out
* of this block, see if it's a better choice than any previous
* finds
*/
if ( BestBlock == NULL
|| BestBlock->Size > CurrentBlock->Size )
{
BestAlignedAddr = AlignedAddr;
BestBlock = CurrentBlock;
}
}
CurrentBlock = CurrentBlock->NextFree;
}
/*
* We didn't find anything suitable at all.
*/
if (BestBlock == NULL)
{
if ( !que_reclaimed )
{
// reclaim que
int i, j;
for ( i = 0; i < R_QUECOUNT; i++ )
{
for ( j = 0; j < 3; j++ )
{
while ( (BestBlock = (PR_FREE)RQueRemove ( &pool->Que[i][j] )) )
{
RPoolReclaim ( pool, BestBlock );
}
}
}
que_reclaimed = 1;
goto try_again;
}
DPRINT1("Trying to allocate %lu bytes from paged pool - nothing suitable found, returning NULL\n",
queBytes );
R_RELEASE_MUTEX(pool);
return NULL;
}
/*
* we found a best block. If Addr isn't already aligned, we've pre-qualified that
* there's room at the beginning of the block for a free block...
*/
{
void* Addr = RHdrToBody(BestBlock);
if ( BestAlignedAddr != Addr )
{
PR_FREE NewFreeBlock = RFreeSplit (
pool,
BestBlock,
(char*)RBodyToHdr(BestAlignedAddr) - (char*)BestBlock );
ASSERT ( BestAlignedAddr > Addr );
//DPRINT ( "breaking off preceding bytes into their own block...\n" );
/*DPRINT ( "NewFreeBlock 0x%x Size %lu (Old Block's new size %lu) NextFree 0x%x\n",
NewFreeBlock, NewFreeBlock->Size, BestBlock->Size, BestBlock->NextFree );*/
/* we want the following code to use our size-aligned block */
BestBlock = NewFreeBlock;
//VerifyPagedPool();
}
}
/*
* Is there enough space to create a second block from the unused portion.
*/
if ( (BestBlock->Size - BlockSize) > sizeof(R_FREE) )
{
/*DPRINT("BestBlock 0x%x Size 0x%x BlockSize 0x%x NewSize 0x%x\n",
BestBlock, BestBlock->Size, BlockSize, NewSize );*/
/*
* Create the new free block.
*/
RFreeSplit ( pool, BestBlock, BlockSize );
//ASSERT_SIZE ( NextBlock->Size );
}
/*
* Remove the selected block from the list of free blocks.
*/
//DPRINT ( "Removing selected block from free block list\n" );
RPoolRemoveFree ( pool, BestBlock );
/*
* Create the new used block header.
*/
NewBlock = (PR_USED)BestBlock;
RiUsedInit ( NewBlock, Tag );
/* RtlZeroMemory(RHdrToBody(NewBlock), NumberOfBytes);*/
RiUsedInitRedZone ( NewBlock, NumberOfBytes );
R_RELEASE_MUTEX(pool);
return RHdrToBody(NewBlock);
}
static void
RPoolFree ( PR_POOL pool, void* Addr )
{
PR_USED UsedBlock;
#if !R_RZ
rulong UsedSize;
#endif
PR_FREE FreeBlock;
rulong UserSize;
int que;
ASSERT(pool);
if ( !Addr )
{
R_DEBUG("Attempt to free NULL ptr, initiating Red Zone Check\n" );
R_ACQUIRE_MUTEX(pool);
RPoolRedZoneCheck ( pool, __FILE__, __LINE__ );
R_RELEASE_MUTEX(pool);
return;
}
R_ASSERT_PTR(pool,Addr);
UsedBlock = RBodyToHdr(Addr);
FreeBlock = (PR_FREE)UsedBlock;
#if R_RZ
UserSize = UsedBlock->UserSize;
#else
UsedSize = UsedBlock->Size;
UserSize = UsedSize - sizeof(R_USED) - 2*R_RZ;
#endif//R_RZ
RUsedRedZoneCheck ( pool, UsedBlock, Addr, __FILE__, __LINE__ );
#if R_RZ
memset ( Addr, 0xCD, UsedBlock->UserSize );
#endif
que = RQueWhich ( UserSize );
if ( que >= 0 )
{
int queBytes = 16 << que;
ASSERT( (rulong)queBytes >= UserSize );
if ( que >= 0 )
{
int align = 0;
if ( R_ROUND_UP(Addr,pool->Alignments[2]) == Addr )
align = 2;
else if ( R_ROUND_UP(Addr,pool->Alignments[1]) == Addr )
align = 1;
R_ACQUIRE_MUTEX(pool);
RQueAdd ( &pool->Que[que][align], UsedBlock );
R_RELEASE_MUTEX(pool);
return;
}
}
R_ACQUIRE_MUTEX(pool);
RPoolReclaim ( pool, FreeBlock );
R_RELEASE_MUTEX(pool);
}
PVOID NTAPI
ExAllocatePagedPoolWithTag (IN POOL_TYPE PoolType,
IN ULONG NumberOfBytes,
IN ULONG Tag)
{
int align;
if ( NumberOfBytes >= PAGE_SIZE )
align = 2;
else if ( PoolType & CACHE_ALIGNED_POOL_MASK )
align = 1;
else
align = 0;
ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL);
return RPoolAlloc ( MmPagedPool, NumberOfBytes, Tag, align );
}
VOID NTAPI
ExFreePagedPool(IN PVOID Block)
{
ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL);
RPoolFree ( MmPagedPool, Block );
}
/* EOF */

View file

@ -1,64 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/procsup.c
* PURPOSE: Memory functions related to Processes
*
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* FUNCTIONS *****************************************************************/
NTSTATUS
NTAPI
MmDeleteProcessAddressSpace(PEPROCESS Process)
{
PVOID Address;
PMEMORY_AREA MemoryArea;
DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process,
Process->ImageFileName);
RemoveEntryList(&Process->MmProcessLinks);
MmLockAddressSpace(&Process->Vm);
while ((MemoryArea = (PMEMORY_AREA)Process->Vm.WorkingSetExpansionLinks.Flink) != NULL)
{
switch (MemoryArea->Type)
{
case MEMORY_AREA_SECTION_VIEW:
Address = (PVOID)MemoryArea->StartingAddress;
MmUnlockAddressSpace(&Process->Vm);
MmUnmapViewOfSection(Process, Address);
MmLockAddressSpace(&Process->Vm);
break;
case MEMORY_AREA_VIRTUAL_MEMORY:
MmFreeVirtualMemory(Process, MemoryArea);
break;
case MEMORY_AREA_OWNED_BY_ARM3:
MmFreeMemoryArea(&Process->Vm,
MemoryArea,
NULL,
NULL);
break;
default:
KeBugCheck(MEMORY_MANAGEMENT);
}
}
MmUnlockAddressSpace(&Process->Vm);
DPRINT("Finished MmReleaseMmInfo()\n");
return(STATUS_SUCCESS);
}

View file

@ -72,6 +72,39 @@ IN ULONG AllocationAttributes,
IN HANDLE FileHandle OPTIONAL,
IN PFILE_OBJECT FileObject OPTIONAL);
NTSTATUS
NTAPI
MmMapViewOfArm3Section(IN PVOID SectionObject,
IN PEPROCESS Process,
IN OUT PVOID *BaseAddress,
IN ULONG_PTR ZeroBits,
IN SIZE_T CommitSize,
IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
IN OUT PSIZE_T ViewSize,
IN SECTION_INHERIT InheritDisposition,
IN ULONG AllocationType,
IN ULONG Protect);
//
// PeFmtCreateSection depends on the following:
//
C_ASSERT(EXEFMT_LOAD_HEADER_SIZE >= sizeof(IMAGE_DOS_HEADER));
C_ASSERT(sizeof(IMAGE_NT_HEADERS32) <= sizeof(IMAGE_NT_HEADERS64));
C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64));
C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64, FileHeader));
C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader) == FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Magic));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SectionAlignment));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, FileAlignment));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Subsystem));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MinorSubsystemVersion));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MajorSubsystemVersion));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode));
C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfHeaders));
/* TYPES *********************************************************************/
typedef struct
@ -92,6 +125,30 @@ SIZE_T MmAllocationFragment;
ULONG_PTR MmSubsectionBase;
static ULONG SectionCharacteristicsToProtect[16] =
{
PAGE_NOACCESS, /* 0 = NONE */
PAGE_NOACCESS, /* 1 = SHARED */
PAGE_EXECUTE, /* 2 = EXECUTABLE */
PAGE_EXECUTE, /* 3 = EXECUTABLE, SHARED */
PAGE_READONLY, /* 4 = READABLE */
PAGE_READONLY, /* 5 = READABLE, SHARED */
PAGE_EXECUTE_READ, /* 6 = READABLE, EXECUTABLE */
PAGE_EXECUTE_READ, /* 7 = READABLE, EXECUTABLE, SHARED */
/*
* FIXME? do we really need the WriteCopy field in segments? can't we use
* PAGE_WRITECOPY here?
*/
PAGE_READWRITE, /* 8 = WRITABLE */
PAGE_READWRITE, /* 9 = WRITABLE, SHARED */
PAGE_EXECUTE_READWRITE, /* 10 = WRITABLE, EXECUTABLE */
PAGE_EXECUTE_READWRITE, /* 11 = WRITABLE, EXECUTABLE, SHARED */
PAGE_READWRITE, /* 12 = WRITABLE, READABLE */
PAGE_READWRITE, /* 13 = WRITABLE, READABLE, SHARED */
PAGE_EXECUTE_READWRITE, /* 14 = WRITABLE, READABLE, EXECUTABLE */
PAGE_EXECUTE_READWRITE, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
};
static GENERIC_MAPPING MmpSectionMapping = {
STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY,
STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE,
@ -115,115 +172,535 @@ static const INFORMATION_CLASS_INFO ExSectionInfoClass[] =
/* FUNCTIONS *****************************************************************/
PFILE_OBJECT
NTAPI
MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section)
/*
References:
[1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
File Format Specification", revision 6.0 (February 1999)
*/
NTSTATUS NTAPI PeFmtCreateSection(IN CONST VOID * FileHeader,
IN SIZE_T FileHeaderSize,
IN PVOID File,
OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
OUT PULONG Flags,
IN PEXEFMT_CB_READ_FILE ReadFileCb,
IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb)
{
PAGED_CODE();
ASSERT(Section);
NTSTATUS nStatus;
ULONG cbFileHeaderOffsetSize = 0;
ULONG cbSectionHeadersOffset = 0;
ULONG cbSectionHeadersSize;
ULONG cbSectionHeadersOffsetSize = 0;
ULONG cbOptHeaderSize;
ULONG cbHeadersSize = 0;
ULONG nSectionAlignment;
ULONG nFileAlignment;
const IMAGE_DOS_HEADER * pidhDosHeader;
const IMAGE_NT_HEADERS32 * pinhNtHeader;
const IMAGE_OPTIONAL_HEADER32 * piohOptHeader;
const IMAGE_SECTION_HEADER * pishSectionHeaders;
PMM_SECTION_SEGMENT pssSegments;
LARGE_INTEGER lnOffset;
PVOID pBuffer;
ULONG nPrevVirtualEndOfSegment = 0;
ULONG nFileSizeOfHeaders = 0;
ULONG i;
/* Return the file object */
return Section->FileObject; // Section->ControlArea->FileObject on NT
}
ASSERT(FileHeader);
ASSERT(FileHeaderSize > 0);
ASSERT(File);
ASSERT(ImageSectionObject);
ASSERT(ReadFileCb);
ASSERT(AllocateSegmentsCb);
NTSTATUS
NTAPI
MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section,
OUT POBJECT_NAME_INFORMATION *ModuleName)
{
POBJECT_NAME_INFORMATION ObjectNameInfo;
NTSTATUS Status;
ULONG ReturnLength;
ASSERT(Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize));
/* Make sure it's an image section */
*ModuleName = NULL;
if (!(Section->AllocationAttributes & SEC_IMAGE))
ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_DOS_HEADER)) == 0);
#define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
pBuffer = NULL;
pidhDosHeader = FileHeader;
/* DOS HEADER */
nStatus = STATUS_ROS_EXEFMT_UNKNOWN_FORMAT;
/* image too small to be an MZ executable */
if(FileHeaderSize < sizeof(IMAGE_DOS_HEADER))
DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize));
/* no MZ signature */
if(pidhDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader->e_magic));
/* not a Windows executable */
if(pidhDosHeader->e_lfanew <= 0)
DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew));
/* NT HEADER */
nStatus = STATUS_INVALID_IMAGE_FORMAT;
if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize, pidhDosHeader->e_lfanew, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader)))
DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
if(FileHeaderSize < cbFileHeaderOffsetSize)
pinhNtHeader = NULL;
else
{
/* It's not, fail */
return STATUS_SECTION_NOT_IMAGE;
/*
* we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
* and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
*/
ASSERT(Intsafe_CanOffsetPointer(FileHeader, pidhDosHeader->e_lfanew));
pinhNtHeader = (PVOID)((UINT_PTR)FileHeader + pidhDosHeader->e_lfanew);
}
/* Allocate memory for our structure */
ObjectNameInfo = ExAllocatePoolWithTag(PagedPool,
1024,
' mM');
if (!ObjectNameInfo) return STATUS_NO_MEMORY;
/* Query the name */
Status = ObQueryNameString(Section->FileObject,
ObjectNameInfo,
1024,
&ReturnLength);
if (!NT_SUCCESS(Status))
/*
* the buffer doesn't contain the NT file header, or the alignment is wrong: we
* need to read the header from the file
*/
if(FileHeaderSize < cbFileHeaderOffsetSize ||
(UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
{
/* Failed, free memory */
ExFreePoolWithTag(ObjectNameInfo, ' mM');
return Status;
ULONG cbNtHeaderSize;
ULONG cbReadSize;
PVOID pData;
l_ReadHeaderFromFile:
cbNtHeaderSize = 0;
lnOffset.QuadPart = pidhDosHeader->e_lfanew;
/* read the header from the file */
nStatus = ReadFileCb(File, &lnOffset, sizeof(IMAGE_NT_HEADERS64), &pData, &pBuffer, &cbReadSize);
if(!NT_SUCCESS(nStatus))
DIE(("ReadFile failed, status %08X\n", nStatus));
ASSERT(pData);
ASSERT(pBuffer);
ASSERT(cbReadSize > 0);
nStatus = STATUS_INVALID_IMAGE_FORMAT;
/* the buffer doesn't contain the file header */
if(cbReadSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader))
DIE(("The file doesn't contain the PE file header\n"));
pinhNtHeader = pData;
/* object still not aligned: copy it to the beginning of the buffer */
if((UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
{
ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == 0);
RtlMoveMemory(pBuffer, pData, cbReadSize);
pinhNtHeader = pBuffer;
}
/* invalid NT header */
nStatus = STATUS_INVALID_IMAGE_PROTECT;
if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
nStatus = STATUS_INVALID_IMAGE_FORMAT;
if(!Intsafe_AddULong32(&cbNtHeaderSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
DIE(("The full NT header is too large\n"));
/* the buffer doesn't contain the whole NT header */
if(cbReadSize < cbNtHeaderSize)
DIE(("The file doesn't contain the full NT header\n"));
}
else
{
ULONG cbOptHeaderOffsetSize = 0;
nStatus = STATUS_INVALID_IMAGE_FORMAT;
/* don't trust an invalid NT header */
if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, cbOptHeaderOffsetSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader->FileHeader.SizeOfOptionalHeader));
/* the buffer doesn't contain the whole NT header: read it from the file */
if(cbOptHeaderOffsetSize > FileHeaderSize)
goto l_ReadHeaderFromFile;
}
/* read information from the NT header */
piohOptHeader = &pinhNtHeader->OptionalHeader;
cbOptHeaderSize = pinhNtHeader->FileHeader.SizeOfOptionalHeader;
nStatus = STATUS_INVALID_IMAGE_FORMAT;
if(!RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Magic))
DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize));
/* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
switch(piohOptHeader->Magic)
{
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
break;
default:
DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader->Magic));
}
if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SectionAlignment) &&
RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, FileAlignment))
{
/* See [1], section 3.4.2 */
if(piohOptHeader->SectionAlignment < PAGE_SIZE)
{
if(piohOptHeader->FileAlignment != piohOptHeader->SectionAlignment)
DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
}
else if(piohOptHeader->SectionAlignment < piohOptHeader->FileAlignment)
DIE(("The section alignment is smaller than the file alignment\n"));
nSectionAlignment = piohOptHeader->SectionAlignment;
nFileAlignment = piohOptHeader->FileAlignment;
if(!IsPowerOf2(nSectionAlignment) || !IsPowerOf2(nFileAlignment))
DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment, nFileAlignment));
}
else
{
nSectionAlignment = PAGE_SIZE;
nFileAlignment = PAGE_SIZE;
}
ASSERT(IsPowerOf2(nSectionAlignment));
ASSERT(IsPowerOf2(nFileAlignment));
switch(piohOptHeader->Magic)
{
/* PE32 */
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
{
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, ImageBase))
ImageSectionObject->ImageBase = piohOptHeader->ImageBase;
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfImage))
ImageSectionObject->ImageSize = piohOptHeader->SizeOfImage;
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackReserve))
ImageSectionObject->StackReserve = piohOptHeader->SizeOfStackReserve;
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackCommit))
ImageSectionObject->StackCommit = piohOptHeader->SizeOfStackCommit;
break;
}
/* PE32+ */
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
{
const IMAGE_OPTIONAL_HEADER64 * pioh64OptHeader;
pioh64OptHeader = (const IMAGE_OPTIONAL_HEADER64 *)piohOptHeader;
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, ImageBase))
{
if(pioh64OptHeader->ImageBase > MAXULONG_PTR)
DIE(("ImageBase exceeds the address space\n"));
ImageSectionObject->ImageBase = (ULONG_PTR)pioh64OptHeader->ImageBase;
}
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfImage))
{
if(pioh64OptHeader->SizeOfImage > MAXULONG_PTR)
DIE(("SizeOfImage exceeds the address space\n"));
ImageSectionObject->ImageSize = pioh64OptHeader->SizeOfImage;
}
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackReserve))
{
if(pioh64OptHeader->SizeOfStackReserve > MAXULONG_PTR)
DIE(("SizeOfStackReserve exceeds the address space\n"));
ImageSectionObject->StackReserve = pioh64OptHeader->SizeOfStackReserve;
}
if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackCommit))
{
if(pioh64OptHeader->SizeOfStackCommit > MAXULONG_PTR)
DIE(("SizeOfStackCommit exceeds the address space\n"));
ImageSectionObject->StackCommit = pioh64OptHeader->SizeOfStackCommit;
}
break;
}
}
/* [1], section 3.4.2 */
if((ULONG_PTR)ImageSectionObject->ImageBase % 0x10000)
DIE(("ImageBase is not aligned on a 64KB boundary"));
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Subsystem))
{
ImageSectionObject->Subsystem = piohOptHeader->Subsystem;
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MinorSubsystemVersion) &&
RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MajorSubsystemVersion))
{
ImageSectionObject->MinorSubsystemVersion = piohOptHeader->MinorSubsystemVersion;
ImageSectionObject->MajorSubsystemVersion = piohOptHeader->MajorSubsystemVersion;
}
}
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint))
{
ImageSectionObject->EntryPoint = piohOptHeader->ImageBase +
piohOptHeader->AddressOfEntryPoint;
}
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfCode))
ImageSectionObject->Executable = piohOptHeader->SizeOfCode != 0;
else
ImageSectionObject->Executable = TRUE;
ImageSectionObject->ImageCharacteristics = pinhNtHeader->FileHeader.Characteristics;
ImageSectionObject->Machine = pinhNtHeader->FileHeader.Machine;
/* SECTION HEADERS */
nStatus = STATUS_INVALID_IMAGE_FORMAT;
/* see [1], section 3.3 */
if(pinhNtHeader->FileHeader.NumberOfSections > 96)
DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader->FileHeader.NumberOfSections));
/*
* the additional segment is for the file's headers. They need to be present for
* the benefit of the dynamic loader (to locate exports, defaults for thread
* parameters, resources, etc.)
*/
ImageSectionObject->NrSegments = pinhNtHeader->FileHeader.NumberOfSections + 1;
/* file offset for the section headers */
if(!Intsafe_AddULong32(&cbSectionHeadersOffset, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
DIE(("Offset overflow\n"));
if(!Intsafe_AddULong32(&cbSectionHeadersOffset, cbSectionHeadersOffset, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
DIE(("Offset overflow\n"));
/* size of the section headers */
ASSERT(Intsafe_CanMulULong32(pinhNtHeader->FileHeader.NumberOfSections, sizeof(IMAGE_SECTION_HEADER)));
cbSectionHeadersSize = pinhNtHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize, cbSectionHeadersOffset, cbSectionHeadersSize))
DIE(("Section headers too large\n"));
/* size of the executable's headers */
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfHeaders))
{
// if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
// DIE(("SizeOfHeaders is not aligned\n"));
if(cbSectionHeadersSize > piohOptHeader->SizeOfHeaders)
DIE(("The section headers overflow SizeOfHeaders\n"));
cbHeadersSize = piohOptHeader->SizeOfHeaders;
}
else if(!AlignUp(&cbHeadersSize, cbSectionHeadersOffsetSize, nFileAlignment))
DIE(("Overflow aligning the size of headers\n"));
if(pBuffer)
{
ExFreePool(pBuffer);
pBuffer = NULL;
}
/* WARNING: pinhNtHeader IS NO LONGER USABLE */
/* WARNING: piohOptHeader IS NO LONGER USABLE */
/* WARNING: pioh64OptHeader IS NO LONGER USABLE */
if(FileHeaderSize < cbSectionHeadersOffsetSize)
pishSectionHeaders = NULL;
else
{
/*
* we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
* and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
*/
ASSERT(Intsafe_CanOffsetPointer(FileHeader, cbSectionHeadersOffset));
pishSectionHeaders = (PVOID)((UINT_PTR)FileHeader + cbSectionHeadersOffset);
}
/*
* the buffer doesn't contain the section headers, or the alignment is wrong:
* read the headers from the file
*/
if(FileHeaderSize < cbSectionHeadersOffsetSize ||
(UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
{
PVOID pData;
ULONG cbReadSize;
lnOffset.QuadPart = cbSectionHeadersOffset;
/* read the header from the file */
nStatus = ReadFileCb(File, &lnOffset, cbSectionHeadersSize, &pData, &pBuffer, &cbReadSize);
if(!NT_SUCCESS(nStatus))
DIE(("ReadFile failed with status %08X\n", nStatus));
ASSERT(pData);
ASSERT(pBuffer);
ASSERT(cbReadSize > 0);
nStatus = STATUS_INVALID_IMAGE_FORMAT;
/* the buffer doesn't contain all the section headers */
if(cbReadSize < cbSectionHeadersSize)
DIE(("The file doesn't contain all of the section headers\n"));
pishSectionHeaders = pData;
/* object still not aligned: copy it to the beginning of the buffer */
if((UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
{
ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) == 0);
RtlMoveMemory(pBuffer, pData, cbReadSize);
pishSectionHeaders = pBuffer;
}
}
/* SEGMENTS */
/* allocate the segments */
nStatus = STATUS_INSUFFICIENT_RESOURCES;
ImageSectionObject->Segments = AllocateSegmentsCb(ImageSectionObject->NrSegments);
if(ImageSectionObject->Segments == NULL)
DIE(("AllocateSegments failed\n"));
/* initialize the headers segment */
pssSegments = ImageSectionObject->Segments;
// ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
if(!AlignUp(&nFileSizeOfHeaders, cbHeadersSize, nFileAlignment))
DIE(("Cannot align the size of the section headers\n"));
if(!AlignUp(&nPrevVirtualEndOfSegment, cbHeadersSize, nSectionAlignment))
DIE(("Cannot align the size of the section headers\n"));
pssSegments[0].FileOffset = 0;
pssSegments[0].Protection = PAGE_READONLY;
pssSegments[0].Length = nPrevVirtualEndOfSegment;
pssSegments[0].RawLength = nFileSizeOfHeaders;
pssSegments[0].VirtualAddress = 0;
pssSegments[0].Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA;
pssSegments[0].WriteCopy = TRUE;
/* skip the headers segment */
++ pssSegments;
nStatus = STATUS_INVALID_IMAGE_FORMAT;
/* convert the executable sections into segments. See also [1], section 4 */
for(i = 0; i < ImageSectionObject->NrSegments - 1; ++ i)
{
ULONG nCharacteristics;
/* validate the alignment */
if(!IsAligned(pishSectionHeaders[i].VirtualAddress, nSectionAlignment))
DIE(("VirtualAddress[%u] is not aligned\n", i));
/* sections must be contiguous, ordered by base address and non-overlapping */
if(pishSectionHeaders[i].VirtualAddress != nPrevVirtualEndOfSegment)
DIE(("Memory gap between section %u and the previous\n", i));
/* ignore explicit BSS sections */
if(pishSectionHeaders[i].SizeOfRawData != 0)
{
/* validate the alignment */
#if 0
/* Yes, this should be a multiple of FileAlignment, but there's
* stuff out there that isn't. We can cope with that
*/
if(!IsAligned(pishSectionHeaders[i].SizeOfRawData, nFileAlignment))
DIE(("SizeOfRawData[%u] is not aligned\n", i));
#endif
// if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
// DIE(("PointerToRawData[%u] is not aligned\n", i));
/* conversion */
pssSegments[i].FileOffset = pishSectionHeaders[i].PointerToRawData;
pssSegments[i].RawLength = pishSectionHeaders[i].SizeOfRawData;
}
else
{
ASSERT(pssSegments[i].FileOffset == 0);
ASSERT(pssSegments[i].RawLength == 0);
}
ASSERT(Intsafe_CanAddLong64(pssSegments[i].FileOffset, pssSegments[i].RawLength));
nCharacteristics = pishSectionHeaders[i].Characteristics;
/* no explicit protection */
if((nCharacteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == 0)
{
if(nCharacteristics & IMAGE_SCN_CNT_CODE)
nCharacteristics |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
if(nCharacteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
if(nCharacteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
}
/* see table above */
pssSegments[i].Protection = SectionCharacteristicsToProtect[nCharacteristics >> 28];
pssSegments[i].WriteCopy = !(nCharacteristics & IMAGE_SCN_MEM_SHARED);
if(pishSectionHeaders[i].Misc.VirtualSize == 0 || pishSectionHeaders[i].Misc.VirtualSize < pishSectionHeaders[i].SizeOfRawData)
pssSegments[i].Length = pishSectionHeaders[i].SizeOfRawData;
else
pssSegments[i].Length = pishSectionHeaders[i].Misc.VirtualSize;
if(!AlignUp(&pssSegments[i].Length, pssSegments[i].Length, nSectionAlignment))
DIE(("Cannot align the virtual size of section %u\n", i));
ASSERT(IsAligned(pssSegments[i].Length, nSectionAlignment));
if(pssSegments[i].Length == 0)
DIE(("Virtual size of section %u is null\n", i));
pssSegments[i].VirtualAddress = pishSectionHeaders[i].VirtualAddress;
pssSegments[i].Characteristics = pishSectionHeaders[i].Characteristics;
/* ensure the memory image is no larger than 4GB */
if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment, pssSegments[i].VirtualAddress, pssSegments[i].Length))
DIE(("The image is larger than 4GB\n"));
}
/* spare our caller some work in validating the segments */
*Flags = EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED | EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP;
if(nSectionAlignment >= PAGE_SIZE)
*Flags |= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED;
/* Success */
*ModuleName = ObjectNameInfo;
return STATUS_SUCCESS;
}
nStatus = STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
NTSTATUS
NTAPI
MmGetFileNameForAddress(IN PVOID Address,
OUT PUNICODE_STRING ModuleName)
{
PROS_SECTION_OBJECT Section;
PMEMORY_AREA MemoryArea;
PMMSUPPORT AddressSpace;
POBJECT_NAME_INFORMATION ModuleNameInformation;
NTSTATUS Status = STATUS_ADDRESS_NOT_ASSOCIATED;
l_Return:
if(pBuffer)
ExFreePool(pBuffer);
/* Get the MM_AVL_TABLE from EPROCESS */
if (Address >= MmSystemRangeStart)
{
AddressSpace = MmGetKernelAddressSpace();
}
else
{
AddressSpace = &PsGetCurrentProcess()->Vm;
}
/* Lock address space */
MmLockAddressSpace(AddressSpace);
/* Locate the memory area for the process by address */
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
/* Make sure it's a section view type */
if ((MemoryArea != NULL) && (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW))
{
/* Get the section pointer to the SECTION_OBJECT */
Section = MemoryArea->Data.SectionData.Section;
/* Unlock address space */
MmUnlockAddressSpace(AddressSpace);
/* Get the filename of the section */
Status = MmGetFileNameForSection(Section,&ModuleNameInformation);
if (NT_SUCCESS(Status))
{
/* Init modulename */
RtlCreateUnicodeString(ModuleName,
ModuleNameInformation->Name.Buffer);
/* Free temp taged buffer from MmGetFileNameForSection() */
ExFreePoolWithTag(ModuleNameInformation, ' mM');
DPRINT("Found ModuleName %S by address %p\n",
ModuleName->Buffer,Address);
}
}
else
{
/* Unlock address space */
MmUnlockAddressSpace(AddressSpace);
}
return Status;
return nStatus;
}
/* Note: Mmsp prefix denotes "Memory Manager Section Private". */
@ -3953,21 +4430,6 @@ NtQuerySection(IN HANDLE SectionHandle,
return(Status);
}
NTSTATUS
NTAPI
MmMapViewOfArm3Section(IN PVOID SectionObject,
IN PEPROCESS Process,
IN OUT PVOID *BaseAddress,
IN ULONG_PTR ZeroBits,
IN SIZE_T CommitSize,
IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
IN OUT PSIZE_T ViewSize,
IN SECTION_INHERIT InheritDisposition,
IN ULONG AllocationType,
IN ULONG Protect);
/**********************************************************************
* NAME EXPORTED

View file

@ -1,331 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/virtual.c
* PURPOSE: Implementing operations on virtual memory.
*
* PROGRAMMERS: David Welch
*/
/* INCLUDE ********************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* PRIVATE FUNCTIONS **********************************************************/
NTSTATUS FASTCALL
MiQueryVirtualMemory(IN HANDLE ProcessHandle,
IN PVOID Address,
IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass,
OUT PVOID VirtualMemoryInformation,
IN SIZE_T Length,
OUT PSIZE_T ResultLength)
{
NTSTATUS Status;
PEPROCESS Process;
MEMORY_AREA* MemoryArea;
PMMSUPPORT AddressSpace;
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_QUERY_INFORMATION,
NULL,
UserMode,
(PVOID*)(&Process),
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("NtQueryVirtualMemory() = %x\n",Status);
return(Status);
}
AddressSpace = &Process->Vm;
MmLockAddressSpace(AddressSpace);
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
switch(VirtualMemoryInformationClass)
{
case MemoryBasicInformation:
{
PMEMORY_BASIC_INFORMATION Info =
(PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
if (Length != sizeof(MEMORY_BASIC_INFORMATION))
{
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
return(STATUS_INFO_LENGTH_MISMATCH);
}
if (MemoryArea == NULL)
{
Info->Type = 0;
Info->State = MEM_FREE;
Info->Protect = PAGE_NOACCESS;
Info->AllocationProtect = 0;
Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
Info->AllocationBase = NULL;
Info->RegionSize = MmFindGapAtAddress(AddressSpace, Info->BaseAddress);
Status = STATUS_SUCCESS;
*ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
}
else
{
switch(MemoryArea->Type)
{
case MEMORY_AREA_VIRTUAL_MEMORY:
Status = MmQueryAnonMem(MemoryArea, Address, Info,
ResultLength);
break;
case MEMORY_AREA_SECTION_VIEW:
Status = MmQuerySectionView(MemoryArea, Address, Info,
ResultLength);
break;
default:
DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea->Type);
Status = STATUS_UNSUCCESSFUL;
*ResultLength = 0;
}
}
break;
}
default:
{
DPRINT1("Unsupported or unimplemented class: %lx\n", VirtualMemoryInformationClass);
Status = STATUS_INVALID_INFO_CLASS;
*ResultLength = 0;
break;
}
}
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
return Status;
}
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;
}
/* SYSTEM CALLS ***************************************************************/
NTSTATUS NTAPI
NtQueryVirtualMemory(IN HANDLE ProcessHandle,
IN PVOID Address,
IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass,
OUT PVOID VirtualMemoryInformation,
IN SIZE_T Length,
OUT PSIZE_T UnsafeResultLength)
{
NTSTATUS Status;
SIZE_T ResultLength = 0;
KPROCESSOR_MODE PreviousMode;
WCHAR ModuleFileNameBuffer[MAX_PATH] = {0};
UNICODE_STRING ModuleFileName;
PMEMORY_SECTION_NAME SectionName = NULL;
PEPROCESS Process;
union
{
MEMORY_BASIC_INFORMATION BasicInfo;
}
VirtualMemoryInfo;
DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
"VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
"Length %lu ResultLength %x)\n",ProcessHandle,Address,
VirtualMemoryInformationClass,VirtualMemoryInformation,
Length,ResultLength);
PreviousMode = ExGetPreviousMode();
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
ProbeForWrite(VirtualMemoryInformation,
Length,
sizeof(ULONG_PTR));
if (UnsafeResultLength) ProbeForWriteSize_t(UnsafeResultLength);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
if (Address >= MmSystemRangeStart)
{
DPRINT1("Invalid parameter\n");
return STATUS_INVALID_PARAMETER;
}
/* FIXME: Move this inside MiQueryVirtualMemory */
if (VirtualMemoryInformationClass == MemorySectionName)
{
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_QUERY_INFORMATION,
NULL,
PreviousMode,
(PVOID*)(&Process),
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("NtQueryVirtualMemory() = %x\n",Status);
return(Status);
}
RtlInitEmptyUnicodeString(&ModuleFileName, ModuleFileNameBuffer, sizeof(ModuleFileNameBuffer));
Status = MmGetFileNameForAddress(Address, &ModuleFileName);
if (NT_SUCCESS(Status))
{
SectionName = VirtualMemoryInformation;
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
RtlInitUnicodeString(&SectionName->SectionFileName, SectionName->NameBuffer);
SectionName->SectionFileName.MaximumLength = Length;
RtlCopyUnicodeString(&SectionName->SectionFileName, &ModuleFileName);
if (UnsafeResultLength != NULL)
{
*UnsafeResultLength = ModuleFileName.Length;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
else
{
RtlInitUnicodeString(&SectionName->SectionFileName, SectionName->NameBuffer);
SectionName->SectionFileName.MaximumLength = Length;
RtlCopyUnicodeString(&SectionName->SectionFileName, &ModuleFileName);
if (UnsafeResultLength != NULL)
{
*UnsafeResultLength = ModuleFileName.Length;
}
}
}
ObDereferenceObject(Process);
return Status;
}
else
{
Status = MiQueryVirtualMemory(ProcessHandle,
Address,
VirtualMemoryInformationClass,
&VirtualMemoryInfo,
Length,
&ResultLength);
}
if (NT_SUCCESS(Status))
{
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
if (ResultLength > 0)
{
ProbeForWrite(VirtualMemoryInformation,
ResultLength,
1);
RtlCopyMemory(VirtualMemoryInformation,
&VirtualMemoryInfo,
ResultLength);
}
if (UnsafeResultLength != NULL)
{
*UnsafeResultLength = ResultLength;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
else
{
if (ResultLength > 0)
{
RtlCopyMemory(VirtualMemoryInformation,
&VirtualMemoryInfo,
ResultLength);
}
if (UnsafeResultLength != NULL)
{
*UnsafeResultLength = ResultLength;
}
}
}
return(Status);
}
/* EOF */

View file

@ -472,20 +472,11 @@
<file>marea.c</file>
<file>mmfault.c</file>
<file>mminit.c</file>
<file>mpw.c</file>
<file>pagefile.c</file>
<file>pageop.c</file>
<file>pe.c</file>
<file>ppool.c</file>
<file>procsup.c</file>
<file>region.c</file>
<file>rmap.c</file>
<file>section.c</file>
<file>virtual.c</file>
<if property="_ELF_" value="1">
<file>elf32.c</file>
<file>elf64.c</file>
</if>
</directory>
<directory name="ob">
<file>obdir.c</file>