mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
[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:
parent
103fbf8518
commit
7d21cf7abd
12 changed files with 1188 additions and 2505 deletions
|
@ -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
|
||||
);
|
||||
|
||||
|
|
|
@ -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 ***********************************************************/
|
||||
|
||||
/*
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue