diff --git a/reactos/ntoskrnl/include/internal/mm.h b/reactos/ntoskrnl/include/internal/mm.h index 647d392583e..a384d14de06 100644 --- a/reactos/ntoskrnl/include/internal/mm.h +++ b/reactos/ntoskrnl/include/internal/mm.h @@ -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 ); diff --git a/reactos/ntoskrnl/mm/ARM3/section.c b/reactos/ntoskrnl/mm/ARM3/section.c index 9c7902084f2..4a1b3cd7404 100644 --- a/reactos/ntoskrnl/mm/ARM3/section.c +++ b/reactos/ntoskrnl/mm/ARM3/section.c @@ -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 ***********************************************************/ /* diff --git a/reactos/ntoskrnl/mm/anonmem.c b/reactos/ntoskrnl/mm/anonmem.c index 56453521d3a..531cd8f98a0 100644 --- a/reactos/ntoskrnl/mm/anonmem.c +++ b/reactos/ntoskrnl/mm/anonmem.c @@ -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, diff --git a/reactos/ntoskrnl/mm/marea.c b/reactos/ntoskrnl/mm/marea.c index fc5f474c666..823cbedf969 100644 --- a/reactos/ntoskrnl/mm/marea.c +++ b/reactos/ntoskrnl/mm/marea.c @@ -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 */ diff --git a/reactos/ntoskrnl/mm/mminit.c b/reactos/ntoskrnl/mm/mminit.c index edc770df944..72a671856e3 100644 --- a/reactos/ntoskrnl/mm/mminit.c +++ b/reactos/ntoskrnl/mm/mminit.c @@ -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 diff --git a/reactos/ntoskrnl/mm/mpw.c b/reactos/ntoskrnl/mm/mpw.c deleted file mode 100644 index 89fba8d6e1e..00000000000 --- a/reactos/ntoskrnl/mm/mpw.c +++ /dev/null @@ -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 -#define NDEBUG -#include - -/* 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; -} diff --git a/reactos/ntoskrnl/mm/pe.c b/reactos/ntoskrnl/mm/pe.c deleted file mode 100644 index ae80234bebd..00000000000 --- a/reactos/ntoskrnl/mm/pe.c +++ /dev/null @@ -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 - */ - -/* INCLUDES *****************************************************************/ - -#include - -//#define NDEBUG -#include - -#include - -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 */ diff --git a/reactos/ntoskrnl/mm/ppool.c b/reactos/ntoskrnl/mm/ppool.c deleted file mode 100644 index 49cc12b215a..00000000000 --- a/reactos/ntoskrnl/mm/ppool.c +++ /dev/null @@ -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 -#define NDEBUG -#include - -#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 */ diff --git a/reactos/ntoskrnl/mm/procsup.c b/reactos/ntoskrnl/mm/procsup.c deleted file mode 100644 index 7ed23748dc6..00000000000 --- a/reactos/ntoskrnl/mm/procsup.c +++ /dev/null @@ -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 -#define NDEBUG -#include - -/* 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); -} - diff --git a/reactos/ntoskrnl/mm/section.c b/reactos/ntoskrnl/mm/section.c index f5bc663fdb5..3b00025d6d1 100644 --- a/reactos/ntoskrnl/mm/section.c +++ b/reactos/ntoskrnl/mm/section.c @@ -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 diff --git a/reactos/ntoskrnl/mm/virtual.c b/reactos/ntoskrnl/mm/virtual.c deleted file mode 100644 index 92d56c9f0b8..00000000000 --- a/reactos/ntoskrnl/mm/virtual.c +++ /dev/null @@ -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 -#define NDEBUG -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/ntoskrnl-generic.rbuild b/reactos/ntoskrnl/ntoskrnl-generic.rbuild index abbcc9d0481..74fdf0b4531 100644 --- a/reactos/ntoskrnl/ntoskrnl-generic.rbuild +++ b/reactos/ntoskrnl/ntoskrnl-generic.rbuild @@ -472,20 +472,11 @@ marea.c mmfault.c mminit.c - mpw.c pagefile.c pageop.c - pe.c - ppool.c - procsup.c region.c rmap.c section.c - virtual.c - - elf32.c - elf64.c - obdir.c