Author: sir_richard
Date: Tue Oct 5 20:00:32 2010
New Revision: 49004
URL: http://svn.reactos.org/svn/reactos?rev=49004&view=rev
Log:
[NTOS]: High-level interface fixes to NtAllocateVirtualMemory/NtFreeVirtualMemory:
- Validate MEM_LARGE_PAGES, MEM_PHYSICAL flags. Check for permission to use MEM_LARGE_PAGES.
- Validate protection mask.
- Validate MEM_RELEASE and MEM_DECOMMIT.
- Perform correct SEH in NtFreeVirtualMemory.
- Protect against overflows past VAD/User address ranegs.
- Only reference the process by handle if this isn't already the current process.
- If this isn't the current process, attach to it during the duration of the VM operation.
Modified:
trunk/reactos/ntoskrnl/mm/anonmem.c
Modified: trunk/reactos/ntoskrnl/mm/anonmem.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/anonmem.c?rev=…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/anonmem.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/anonmem.c [iso-8859-1] Tue Oct 5 20:00:32 2010
@@ -42,6 +42,9 @@
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
+
+#define MODULE_INVOLVED_IN_ARM3
+#include "ARM3/miarm.h"
/* FUNCTIONS *****************************************************************/
@@ -663,31 +666,14 @@
/*
* @implemented
*/
-NTSTATUS NTAPI
-NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
+NTSTATUS
+NTAPI
+NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
IN OUT PVOID* UBaseAddress,
- IN ULONG_PTR ZeroBits,
+ IN ULONG_PTR ZeroBits,
IN OUT PSIZE_T URegionSize,
- IN ULONG AllocationType,
- IN ULONG Protect)
-/*
- * FUNCTION: Allocates a block of virtual memory in the process address space
- * ARGUMENTS:
- * ProcessHandle = The handle of the process which owns the virtual memory
- * BaseAddress = A pointer to the virtual memory allocated. If you
- * supply a non zero value the system will try to
- * allocate the memory at the address supplied. It round
- * it down to a multiple of the page size.
- * ZeroBits = (OPTIONAL) You can specify the number of high order bits
- * that must be zero, ensuring that the memory will be
- * allocated at a address below a certain value.
- * RegionSize = The number of bytes to allocate
- * AllocationType = Indicates the type of virtual memory you like to
- * allocated, can be a combination of MEM_COMMIT,
- * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN.
- * Protect = Indicates the protection type of the pages allocated.
- * RETURNS: Status
- */
+ IN ULONG AllocationType,
+ IN ULONG Protect)
{
PEPROCESS Process;
MEMORY_AREA* MemoryArea;
@@ -699,132 +685,188 @@
ULONG RegionSize;
PVOID PBaseAddress;
ULONG PRegionSize;
- ULONG MemProtection;
PHYSICAL_ADDRESS BoundaryAddressMultiple;
- KPROCESSOR_MODE PreviousMode;
-
- PAGED_CODE();
-
- DPRINT("NtAllocateVirtualMemory(*UBaseAddress %x, "
- "ZeroBits %d, *URegionSize %x, AllocationType %x, Protect %x)\n",
- *UBaseAddress,ZeroBits,*URegionSize,AllocationType,
- Protect);
-
- /* Check for valid protection flags */
- MemProtection = Protect & ~(PAGE_GUARD|PAGE_NOCACHE);
- if (MemProtection != PAGE_NOACCESS &&
- MemProtection != PAGE_READONLY &&
- MemProtection != PAGE_READWRITE &&
- MemProtection != PAGE_WRITECOPY &&
- MemProtection != PAGE_EXECUTE &&
- MemProtection != PAGE_EXECUTE_READ &&
- MemProtection != PAGE_EXECUTE_READWRITE &&
- MemProtection != PAGE_EXECUTE_WRITECOPY)
- {
- DPRINT1("Invalid page protection\n");
- return STATUS_INVALID_PAGE_PROTECTION;
- }
-
- /* Check for valid Zero bits */
- if (ZeroBits > 21)
- {
- DPRINT1("Too many zero bits\n");
- return STATUS_INVALID_PARAMETER_3;
- }
-
- /* Check for valid Allocation Types */
- if ((AllocationType & ~(MEM_COMMIT | MEM_RESERVE | MEM_RESET | MEM_PHYSICAL |
- MEM_TOP_DOWN | MEM_WRITE_WATCH)))
- {
- DPRINT1("Invalid Allocation Type\n");
- return STATUS_INVALID_PARAMETER_5;
- }
-
- /* Check for at least one of these Allocation Types to be set */
- if (!(AllocationType & (MEM_COMMIT | MEM_RESERVE | MEM_RESET)))
- {
- DPRINT1("No memory allocation base type\n");
- return STATUS_INVALID_PARAMETER_5;
- }
-
- /* MEM_RESET is an exclusive flag, make sure that is valid too */
- if ((AllocationType & MEM_RESET) && (AllocationType != MEM_RESET))
- {
- DPRINT1("Invalid use of MEM_RESET\n");
- return STATUS_INVALID_PARAMETER_5;
- }
-
- /* MEM_WRITE_WATCH can only be used if MEM_RESERVE is also used */
- if ((AllocationType & MEM_WRITE_WATCH) && !(AllocationType & MEM_RESERVE))
- {
- DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n");
- return STATUS_INVALID_PARAMETER_5;
- }
-
- /* MEM_PHYSICAL can only be used with MEM_RESERVE, and can only be R/W */
- if (AllocationType & MEM_PHYSICAL)
- {
- /* First check for MEM_RESERVE exclusivity */
- if (AllocationType != (MEM_RESERVE | MEM_PHYSICAL))
- {
- DPRINT1("MEM_PHYSICAL used with other flags then MEM_RESERVE or"
- "MEM_RESERVE was not present at all\n");
- return STATUS_INVALID_PARAMETER_5;
- }
-
- /* Then make sure PAGE_READWRITE is used */
- if (Protect != PAGE_READWRITE)
- {
- DPRINT1("MEM_PHYSICAL used without PAGE_READWRITE\n");
- return STATUS_INVALID_PAGE_PROTECTION;
- }
- }
-
- PreviousMode = KeGetPreviousMode();
-
- _SEH2_TRY
- {
- if (PreviousMode != KernelMode)
- {
- ProbeForWritePointer(UBaseAddress);
- ProbeForWriteUlong(URegionSize);
- }
- PBaseAddress = *UBaseAddress;
- PRegionSize = *URegionSize;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- /* Return the exception code */
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
-
- BoundaryAddressMultiple.QuadPart = 0;
+ PEPROCESS CurrentProcess = PsGetCurrentProcess();
+ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+ KAPC_STATE ApcState;
+ ULONG ProtectionMask;
+ BOOLEAN Attached = FALSE;
+ BoundaryAddressMultiple.QuadPart = 0;
+ PAGED_CODE();
+
+ /* Check for valid Zero bits */
+ if (ZeroBits > 21)
+ {
+ DPRINT1("Too many zero bits\n");
+ return STATUS_INVALID_PARAMETER_3;
+ }
+
+ /* Check for valid Allocation Types */
+ if ((AllocationType & ~(MEM_COMMIT | MEM_RESERVE | MEM_RESET | MEM_PHYSICAL |
+ MEM_TOP_DOWN | MEM_WRITE_WATCH)))
+ {
+ DPRINT1("Invalid Allocation Type\n");
+ return STATUS_INVALID_PARAMETER_5;
+ }
+
+ /* Check for at least one of these Allocation Types to be set */
+ if (!(AllocationType & (MEM_COMMIT | MEM_RESERVE | MEM_RESET)))
+ {
+ DPRINT1("No memory allocation base type\n");
+ return STATUS_INVALID_PARAMETER_5;
+ }
+
+ /* MEM_RESET is an exclusive flag, make sure that is valid too */
+ if ((AllocationType & MEM_RESET) && (AllocationType != MEM_RESET))
+ {
+ DPRINT1("Invalid use of MEM_RESET\n");
+ return STATUS_INVALID_PARAMETER_5;
+ }
+
+ /* Check if large pages are being used */
+ if (AllocationType & MEM_LARGE_PAGES)
+ {
+ /* Large page allocations MUST be committed */
+ if (!(AllocationType & MEM_COMMIT))
+ {
+ DPRINT1("Must supply MEM_COMMIT with MEM_LARGE_PAGES\n");
+ return STATUS_INVALID_PARAMETER_5;
+ }
+
+ /* These flags are not allowed with large page allocations */
+ if (AllocationType & (MEM_PHYSICAL | MEM_RESET | MEM_WRITE_WATCH))
+ {
+ DPRINT1("Using illegal flags with MEM_LARGE_PAGES\n");
+ return STATUS_INVALID_PARAMETER_5;
+ }
+ }
+
+ /* MEM_WRITE_WATCH can only be used if MEM_RESERVE is also used */
+ if ((AllocationType & MEM_WRITE_WATCH) && !(AllocationType & MEM_RESERVE))
+ {
+ DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n");
+ return STATUS_INVALID_PARAMETER_5;
+ }
+
+ /* MEM_PHYSICAL can only be used if MEM_RESERVE is also used */
+ if ((AllocationType & MEM_PHYSICAL) && !(AllocationType & MEM_RESERVE))
+ {
+ DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n");
+ return STATUS_INVALID_PARAMETER_5;
+ }
+
+ /* Check for valid MEM_PHYSICAL usage */
+ if (AllocationType & MEM_PHYSICAL)
+ {
+ /* Only these flags are allowed with MEM_PHYSIAL */
+ if (AllocationType & ~(MEM_RESERVE | MEM_TOP_DOWN | MEM_PHYSICAL))
+ {
+ DPRINT1("Using illegal flags with MEM_PHYSICAL\n");
+ return STATUS_INVALID_PARAMETER_5;
+ }
+
+ /* Then make sure PAGE_READWRITE is used */
+ if (Protect != PAGE_READWRITE)
+ {
+ DPRINT1("MEM_PHYSICAL used without PAGE_READWRITE\n");
+ return STATUS_INVALID_PARAMETER_6;
+ }
+ }
+
+ /* Calculate the protection mask and make sure it's valid */
+ ProtectionMask = MiMakeProtectionMask(Protect);
+ if (ProtectionMask == MM_INVALID_PROTECTION)
+ {
+ DPRINT1("Invalid protection mask\n");
+ return STATUS_INVALID_PAGE_PROTECTION;
+ }
+
+ /* Enter SEH */
+ _SEH2_TRY
+ {
+ /* Check for user-mode parameters */
+ if (PreviousMode != KernelMode)
+ {
+ /* Make sure they are writable */
+ ProbeForWritePointer(UBaseAddress);
+ ProbeForWriteUlong(URegionSize);
+ }
+
+ /* Capture their values */
+ PBaseAddress = *UBaseAddress;
+ PRegionSize = *URegionSize;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Return the exception code */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ /* Make sure the allocation isn't past the VAD area */
+ if (PBaseAddress >= MM_HIGHEST_VAD_ADDRESS)
+ {
+ DPRINT1("Virtual allocation base above User Space\n");
+ return STATUS_INVALID_PARAMETER_2;
+ }
+
+ /* Make sure the allocation wouldn't overflow past the VAD area */
+ if ((((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) - (ULONG_PTR)PBaseAddress) < PRegionSize)
+ {
+ DPRINT1("Region size would overflow into kernel-memory\n");
+ return STATUS_INVALID_PARAMETER_4;
+ }
+
+ /* Make sure there's a size specified */
+ if (!PRegionSize)
+ {
+ DPRINT1("Region size is invalid (zero)\n");
+ return STATUS_INVALID_PARAMETER_4;
+ }
+
+ /* Check if this is for the current process */
+ if (ProcessHandle == NtCurrentProcess())
+ {
+ /* We already have the current process, no need to go through Ob */
+ Process = CurrentProcess;
+ }
+ else
+ {
+ /* Reference the handle for correct permissions */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_VM_OPERATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Check if not running in the current process */
+ if (CurrentProcess != Process)
+ {
+ /* Attach to it */
+ KeStackAttachProcess(&Process->Pcb, &ApcState);
+ Attached = TRUE;
+ }
+ }
+
+ /* Check for large page allocations */
+ if (AllocationType & MEM_LARGE_PAGES)
+ {
+ /* The lock memory privilege is required */
+ if (!SeSinglePrivilegeCheck(SeLockMemoryPrivilege, PreviousMode))
+ {
+ /* Fail without it */
+ DPRINT1("Privilege not held for MEM_LARGE_PAGES\n");
+ if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
+ return STATUS_PRIVILEGE_NOT_HELD;
+ }
+ }
BaseAddress = (PVOID)PAGE_ROUND_DOWN(PBaseAddress);
RegionSize = PAGE_ROUND_UP((ULONG_PTR)PBaseAddress + PRegionSize) -
PAGE_ROUND_DOWN(PBaseAddress);
- /*
- * We've captured and calculated the data, now do more checks
- * Yes, MmCreateMemoryArea does similar checks, but they don't return
- * the right status codes that a caller of this routine would expect.
- */
- if ((ULONG_PTR)BaseAddress >= USER_SHARED_DATA)
- {
- DPRINT1("Virtual allocation base above User Space\n");
- return STATUS_INVALID_PARAMETER_2;
- }
- if (!RegionSize)
- {
- DPRINT1("Region size is invalid (zero)\n");
- return STATUS_INVALID_PARAMETER_4;
- }
- if ((USER_SHARED_DATA - (ULONG_PTR)BaseAddress) < RegionSize)
- {
- DPRINT1("Region size would overflow into kernel-memory\n");
- return STATUS_INVALID_PARAMETER_4;
- }
/*
* Copy on Write is reserved for system use. This case is a certain failure
@@ -835,19 +877,6 @@
{
DPRINT1("Copy on write is not supported by VirtualAlloc\n");
return STATUS_INVALID_PAGE_PROTECTION;
- }
-
-
- Status = ObReferenceObjectByHandle(ProcessHandle,
- PROCESS_VM_OPERATION,
- PsProcessType,
- PreviousMode,
- (PVOID*)(&Process),
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
- return(Status);
}
Type = (AllocationType & MEM_COMMIT) ? MEM_COMMIT : MEM_RESERVE;
@@ -871,8 +900,8 @@
(ULONG_PTR)BaseAddress + RegionSize, MemoryArea->EndingAddress);
MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
-
+ if (Attached) KeUnstackDetachProcess(&ApcState);
+ if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
return STATUS_MEMORY_NOT_ALLOCATED;
}
@@ -888,7 +917,8 @@
}
MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
+ if (Attached) KeUnstackDetachProcess(&ApcState);
+ if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
/* MEM_RESET does not modify any attributes of region */
return STATUS_SUCCESS;
@@ -904,7 +934,8 @@
BaseAddress, RegionSize,
Type, Protect, MmModifyAttributes);
MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
+ if (Attached) KeUnstackDetachProcess(&ApcState);
+ if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
/* Give the caller rounded BaseAddress and area length */
@@ -935,7 +966,8 @@
}
MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
+ if (Attached) KeUnstackDetachProcess(&ApcState);
+ if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
/* Give the caller rounded BaseAddress and area length */
@@ -951,7 +983,8 @@
else
{
MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
+ if (Attached) KeUnstackDetachProcess(&ApcState);
+ if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
return(STATUS_UNSUCCESSFUL);
}
}
@@ -969,7 +1002,8 @@
if (!NT_SUCCESS(Status))
{
MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
+ if (Attached) KeUnstackDetachProcess(&ApcState);
+ if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
return(Status);
}
@@ -986,13 +1020,15 @@
const ULONG nPages = PAGE_ROUND_UP(MemoryAreaLength) >> PAGE_SHIFT;
MmReserveSwapPages(nPages);
}
+
+ MmUnlockAddressSpace(AddressSpace);
+ if (Attached) KeUnstackDetachProcess(&ApcState);
+ if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
*UBaseAddress = BaseAddress;
*URegionSize = MemoryAreaLength;
DPRINT("*UBaseAddress %x *URegionSize %x\n", BaseAddress, RegionSize);
- MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
return(STATUS_SUCCESS);
}
@@ -1261,8 +1297,8 @@
*/
NTSTATUS NTAPI
NtFreeVirtualMemory(IN HANDLE ProcessHandle,
- IN PVOID* PBaseAddress,
- IN PSIZE_T PRegionSize,
+ IN PVOID* UBaseAddress,
+ IN PSIZE_T URegionSize,
IN ULONG FreeType)
/*
* FUNCTION: Frees a range of virtual memory
@@ -1281,51 +1317,94 @@
NTSTATUS Status;
PEPROCESS Process;
PMMSUPPORT AddressSpace;
- PVOID BaseAddress;
- ULONG RegionSize;
-
- PAGED_CODE();
-
- DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *PBaseAddress %x, "
- "*PRegionSize %x, FreeType %x)\n",ProcessHandle,*PBaseAddress,
- *PRegionSize,FreeType);
-
+ PVOID BaseAddress, PBaseAddress;
+ ULONG RegionSize, PRegionSize;
+ PEPROCESS CurrentProcess = PsGetCurrentProcess();
+ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+ KAPC_STATE ApcState;
+ BOOLEAN Attached = FALSE;
+ PAGED_CODE();
+
+ /* Only two flags are supported */
if (!(FreeType & (MEM_RELEASE | MEM_DECOMMIT)))
{
DPRINT1("Invalid FreeType\n");
return STATUS_INVALID_PARAMETER_4;
}
-
- if (ExGetPreviousMode() != KernelMode)
- {
- _SEH2_TRY
+
+ /* Check if no flag was used, or if both flags were used */
+ if (!((FreeType & (MEM_DECOMMIT | MEM_RELEASE))) ||
+ ((FreeType & (MEM_DECOMMIT | MEM_RELEASE)) == (MEM_DECOMMIT | MEM_RELEASE)))
+ {
+ DPRINT1("Invalid FreeType combination\n");
+ return STATUS_INVALID_PARAMETER_4;
+ }
+
+ /* Enter SEH */
+ _SEH2_TRY
+ {
+ /* Check for user-mode parameters */
+ if (PreviousMode != KernelMode)
{
- /* Probe user pointers */
- ProbeForWriteSize_t(PRegionSize);
- ProbeForWritePointer(PBaseAddress);
+ /* Make sure they are writable */
+ ProbeForWritePointer(UBaseAddress);
+ ProbeForWriteUlong(URegionSize);
}
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- /* Return the exception code */
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
- }
-
- BaseAddress = (PVOID)PAGE_ROUND_DOWN((*PBaseAddress));
- RegionSize = PAGE_ROUND_UP((ULONG_PTR)(*PBaseAddress) + (*PRegionSize)) -
- PAGE_ROUND_DOWN((*PBaseAddress));
-
- Status = ObReferenceObjectByHandle(ProcessHandle,
- PROCESS_VM_OPERATION,
- PsProcessType,
- UserMode,
- (PVOID*)(&Process),
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
+
+ /* Capture their values */
+ PBaseAddress = *UBaseAddress;
+ PRegionSize = *URegionSize;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Return the exception code */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ /* Make sure the allocation isn't past the user area */
+ if (PBaseAddress >= MM_HIGHEST_USER_ADDRESS)
+ {
+ DPRINT1("Virtual free base above User Space\n");
+ return STATUS_INVALID_PARAMETER_2;
+ }
+
+ /* Make sure the allocation wouldn't overflow past the user area */
+ if (((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (ULONG_PTR)PBaseAddress) < PRegionSize)
+ {
+ DPRINT1("Region size would overflow into kernel-memory\n");
+ return STATUS_INVALID_PARAMETER_3;
+ }
+
+ /* Check if this is for the current process */
+ if (ProcessHandle == NtCurrentProcess())
+ {
+ /* We already have the current process, no need to go through Ob */
+ Process = CurrentProcess;
+ }
+ else
+ {
+ /* Reference the handle for correct permissions */
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_VM_OPERATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&Process,
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Check if not running in the current process */
+ if (CurrentProcess != Process)
+ {
+ /* Attach to it */
+ KeStackAttachProcess(&Process->Pcb, &ApcState);
+ Attached = TRUE;
+ }
+ }
+
+ BaseAddress = (PVOID)PAGE_ROUND_DOWN((PBaseAddress));
+ RegionSize = PAGE_ROUND_UP((ULONG_PTR)(PBaseAddress) + (PRegionSize)) -
+ PAGE_ROUND_DOWN((PBaseAddress));
AddressSpace = &Process->Vm;
@@ -1372,7 +1451,8 @@
unlock_deref_and_return:
MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
+ if (Attached) KeUnstackDetachProcess(&ApcState);
+ if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
return(Status);
}
Author: sir_richard
Date: Tue Oct 5 15:59:47 2010
New Revision: 49000
URL: http://svn.reactos.org/svn/reactos?rev=49000&view=rev
Log:
[NTOS]: Fix whitespace typo in comment (two spaces instead of one).
That's right. I'm not a fun person.
Modified:
trunk/reactos/ntoskrnl/mm/mminit.c
Modified: trunk/reactos/ntoskrnl/mm/mminit.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/mminit.c?rev=4…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/mminit.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/mminit.c [iso-8859-1] Tue Oct 5 15:59:47 2010
@@ -250,7 +250,7 @@
#if defined(_X86_)
//
- // Finally, reserve the 2 pages we currently make use of for HAL mappings
+ // Finally, reserve the 2 pages we currently make use of for HAL mappings
//
BaseAddress = (PVOID)0xFFC00000;
Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
Author: sir_richard
Date: Tue Oct 5 14:36:09 2010
New Revision: 48997
URL: http://svn.reactos.org/svn/reactos?rev=48997&view=rev
Log:
[NTOS]: Implement ARM3 version of MmMapViewOfSection, only for ARM3 pagefile-backed sections, and without any special flag support. Tested and works great, with the new pagefault code correctly finding the Prototype PTE for the VAD.
[NTOS]: Make every VAD insert also create a MEMORY_AREA. Now the two address space views should be completely synchronized and we can try removing the hack that was done for PEB/TEB support (which will remove the 200 thread regression).
[NTOS]: Implement MiGetNextNode and MiFindEmptyAddressRangeInTree.
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/section.c
trunk/reactos/ntoskrnl/mm/ARM3/vadnode.c
trunk/reactos/ntoskrnl/mm/section.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/section.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/section.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/section.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/section.c [iso-8859-1] Tue Oct 5 14:36:09 2010
@@ -460,6 +460,159 @@
/* Return the base adress of the mapping and success */
*MappedBase = Base;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
+ IN PEPROCESS Process,
+ IN PVOID *BaseAddress,
+ IN PLARGE_INTEGER SectionOffset,
+ IN PSIZE_T ViewSize,
+ IN PSECTION Section,
+ IN SECTION_INHERIT InheritDisposition,
+ IN ULONG ProtectionMask,
+ IN ULONG CommitSize,
+ IN ULONG_PTR ZeroBits,
+ IN ULONG AllocationType)
+{
+ PMMVAD Vad;
+ PETHREAD Thread = PsGetCurrentThread();
+ ULONG_PTR StartAddress, EndingAddress;
+ PSUBSECTION Subsection;
+ PSEGMENT Segment;
+ PFN_NUMBER PteOffset;
+ NTSTATUS Status;
+
+ /* Get the segment and subection for this section */
+ Segment = ControlArea->Segment;
+ Subsection = (PSUBSECTION)(ControlArea + 1);
+
+ /* Non-pagefile-backed sections not supported */
+ ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
+ ASSERT(ControlArea->u.Flags.Rom == 0);
+ ASSERT(ControlArea->FilePointer == NULL);
+ ASSERT(Segment->SegmentFlags.TotalNumberOfPtes4132 == 0);
+
+ /* Based sections not supported */
+ ASSERT(Section->Address.StartingVpn == 0);
+
+ /* These flags/parameters are not supported */
+ ASSERT((AllocationType & MEM_DOS_LIM) == 0);
+ ASSERT((AllocationType & MEM_RESERVE) == 0);
+ ASSERT((AllocationType & MEM_TOP_DOWN) == 0);
+ ASSERT(Process->VmTopDown == 0);
+ ASSERT(Section->u.Flags.CopyOnWrite == FALSE);
+ ASSERT(ZeroBits == 0);
+
+ /* First, increase the map count. No purging is supported yet */
+ Status = MiCheckPurgeAndUpMapCount(ControlArea, FALSE);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Check if the caller specified the view size */
+ if (!(*ViewSize))
+ {
+ /* The caller did not, so pick a 64K aligned view size based on the offset */
+ SectionOffset->LowPart &= ~(_64K - 1);
+ *ViewSize = Section->SizeOfSection.QuadPart - SectionOffset->QuadPart;
+ }
+ else
+ {
+ /* A size was specified, align it to a 64K boundary */
+ *ViewSize += SectionOffset->LowPart & (_64K - 1);
+
+ /* Align the offset as well to make this an aligned map */
+ SectionOffset->LowPart &= ~((ULONG)_64K - 1);
+ }
+
+ /* We must be dealing with a 64KB aligned offset */
+ ASSERT((SectionOffset->LowPart & ((ULONG)_64K - 1)) == 0);
+
+ /* It's illegal to try to map more than 2GB */
+ if (*ViewSize >= 0x80000000) return STATUS_INVALID_VIEW_SIZE;
+
+ /* Within this section, figure out which PTEs will describe the view */
+ PteOffset = SectionOffset->QuadPart >> PAGE_SHIFT;
+
+ /* The offset must be in this segment's PTE chunk and it must be valid */
+ ASSERT(PteOffset < Segment->TotalNumberOfPtes);
+ ASSERT(((SectionOffset->QuadPart + *ViewSize + PAGE_SIZE - 1) >> PAGE_SHIFT) >= PteOffset);
+
+ /* In ARM3, only one subsection is used for now. It must contain these PTEs */
+ ASSERT(PteOffset < Subsection->PtesInSubsection);
+ ASSERT(Subsection->SubsectionBase != NULL);
+
+ /* In ARM3, only MEM_COMMIT is supported for now. The PTEs must've been committed */
+ ASSERT(Segment->NumberOfCommittedPages >= Segment->TotalNumberOfPtes);
+
+ /* Did the caller specify an address? */
+ if (!(*BaseAddress))
+ {
+ /* No, find an address bottom-up */
+ Status = MiFindEmptyAddressRangeInTree(*ViewSize,
+ _64K,
+ &Process->VadRoot,
+ (PMMADDRESS_NODE*)&Process->VadFreeHint,
+ &StartAddress);
+ ASSERT(NT_SUCCESS(Status));
+ }
+ else
+ {
+ /* This (rather easy) code path is not yet implemented */
+ UNIMPLEMENTED;
+ while (TRUE);
+ }
+
+ /* Get the ending address, which is the last piece we need for the VAD */
+ EndingAddress = (StartAddress + *ViewSize - 1) | (PAGE_SIZE - 1);
+
+ /* A VAD can now be allocated. Do so and zero it out */
+ Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD), 'ldaV');
+ ASSERT(Vad);
+ RtlZeroMemory(Vad, sizeof(MMVAD));
+
+ /* Write all the data required in the VAD for handling a fault */
+ Vad->StartingVpn = StartAddress >> PAGE_SHIFT;
+ Vad->EndingVpn = EndingAddress >> PAGE_SHIFT;
+ Vad->ControlArea = ControlArea;
+ Vad->u.VadFlags.Protection = ProtectionMask;
+ Vad->u2.VadFlags2.FileOffset = SectionOffset->QuadPart >> 16;
+ Vad->u2.VadFlags2.Inherit = (InheritDisposition == ViewShare);
+ if ((AllocationType & SEC_NO_CHANGE) || (Section->u.Flags.NoChange))
+ {
+ /* This isn't really implemented yet, but handle setting the flag */
+ Vad->u.VadFlags.NoChange = 1;
+ Vad->u2.VadFlags2.SecNoChange = 1;
+ }
+
+ /* Finally, write down the first and last prototype PTE */
+ Vad->FirstPrototypePte = &Subsection->SubsectionBase[PteOffset];
+ PteOffset += (Vad->EndingVpn - Vad->StartingVpn);
+ Vad->LastContiguousPte = &Subsection->SubsectionBase[PteOffset];
+
+ /* Make sure the last PTE is valid and still within the subsection */
+ ASSERT(PteOffset < Subsection->PtesInSubsection);
+ ASSERT(Vad->FirstPrototypePte <= Vad->LastContiguousPte);
+
+ /* FIXME: Should setup VAD bitmap */
+ Status = STATUS_SUCCESS;
+
+ /* Pretend as if we own the working set */
+ MiLockProcessWorkingSet(Process, Thread);
+
+ /* Insert the VAD */
+ MiInsertVad(Vad, Process);
+
+ /* Release the working set */
+ MiUnlockProcessWorkingSet(Process, Thread);
+
+ /* Windows stores this for accounting purposes, do so as well */
+ if (!Segment->u2.FirstMappedVa) Segment->u2.FirstMappedVa = (PVOID)StartAddress;
+
+ /* Finally, let the caller know where, and for what size, the view was mapped */
+ *ViewSize = (ULONG_PTR)EndingAddress - (ULONG_PTR)StartAddress + 1;
+ *BaseAddress = (PVOID)StartAddress;
return STATUS_SUCCESS;
}
@@ -668,6 +821,146 @@
return Status;
}
+/*
+ * @implemented
+ */
+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)
+{
+ KAPC_STATE ApcState;
+ BOOLEAN Attached = FALSE;
+ PSECTION Section;
+ PCONTROL_AREA ControlArea;
+ ULONG ProtectionMask;
+ NTSTATUS Status;
+ PAGED_CODE();
+
+ /* Get the segment and control area */
+ Section = (PSECTION)SectionObject;
+ ControlArea = Section->Segment->ControlArea;
+
+ /* These flags/states are not yet supported by ARM3 */
+ ASSERT(Section->u.Flags.Image == 0);
+ ASSERT(Section->u.Flags.NoCache == 0);
+ ASSERT(Section->u.Flags.WriteCombined == 0);
+ ASSERT((AllocationType & MEM_RESERVE) == 0);
+ ASSERT(ControlArea->u.Flags.PhysicalMemory == 0);
+
+
+#if 0
+ /* FIXME: Check if the mapping protection is compatible with the create */
+ if (!MiIsProtectionCompatible(Section->InitialPageProtection, Protect))
+ {
+ DPRINT1("Mapping protection is incompatible\n");
+ return STATUS_SECTION_PROTECTION;
+ }
+#endif
+
+ /* Check if the offset and size would cause an overflow */
+ if ((SectionOffset->QuadPart + *ViewSize) < SectionOffset->QuadPart)
+ {
+ DPRINT1("Section offset overflows\n");
+ return STATUS_INVALID_VIEW_SIZE;
+ }
+
+ /* Check if the offset and size are bigger than the section itself */
+ if ((SectionOffset->QuadPart + *ViewSize) > Section->SizeOfSection.QuadPart)
+ {
+ DPRINT1("Section offset is larger than section\n");
+ return STATUS_INVALID_VIEW_SIZE;
+ }
+
+ /* Check if the caller did not specify a view size */
+ if (!(*ViewSize))
+ {
+ /* Compute it for the caller */
+ *ViewSize = Section->SizeOfSection.QuadPart - SectionOffset->QuadPart;
+
+ /* Check if it's larger than 4GB or overflows into kernel-mode */
+ if ((*ViewSize > 0xFFFFFFFF) ||
+ (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - (ULONG_PTR)*BaseAddress) < *ViewSize))
+ {
+ DPRINT1("Section view won't fit\n");
+ return STATUS_INVALID_VIEW_SIZE;
+ }
+ }
+
+ /* Check if the commit size is larger than the view size */
+ if (CommitSize > *ViewSize)
+ {
+ DPRINT1("Attempting to commit more than the view itself\n");
+ return STATUS_INVALID_PARAMETER_5;
+ }
+
+ /* Check if the view size is larger than the section */
+ if (*ViewSize > Section->SizeOfSection.QuadPart)
+ {
+ DPRINT1("The view is larger than the section\n");
+ return STATUS_INVALID_VIEW_SIZE;
+ }
+
+ /* Compute and validate the protection mask */
+ ProtectionMask = MiMakeProtectionMask(Protect);
+ if (ProtectionMask == MM_INVALID_PROTECTION)
+ {
+ DPRINT1("The protection is invalid\n");
+ return STATUS_INVALID_PAGE_PROTECTION;
+ }
+
+ /* We only handle pagefile-backed sections, which cannot be writecombined */
+ if (Protect & PAGE_WRITECOMBINE)
+ {
+ DPRINT1("Cannot write combine a pagefile-backed section\n");
+ return STATUS_INVALID_PARAMETER_10;
+ }
+
+ /* Start by attaching to the current process if needed */
+ if (PsGetCurrentProcess() != Process)
+ {
+ KeStackAttachProcess(&Process->Pcb, &ApcState);
+ Attached = TRUE;
+ }
+
+ /* Lock the address space and make sure the process is alive */
+ MmLockAddressSpace(&Process->Vm);
+ if (!Process->VmDeleted)
+ {
+ /* Do the actual mapping */
+ Status = MiMapViewOfDataSection(ControlArea,
+ Process,
+ BaseAddress,
+ SectionOffset,
+ ViewSize,
+ Section,
+ InheritDisposition,
+ ProtectionMask,
+ CommitSize,
+ ZeroBits,
+ AllocationType);
+ }
+ else
+ {
+ /* The process is being terminated, fail */
+ DPRINT1("The process is dying\n");
+ Status = STATUS_PROCESS_IS_TERMINATING;
+ }
+
+ /* Unlock the address space and detatch if needed, then return status */
+ MmUnlockAddressSpace(&Process->Vm);
+ if (Attached) KeUnstackDetachProcess(&ApcState);
+ return Status;
+}
+
/* SYSTEM CALLS ***************************************************************/
NTSTATUS
Modified: trunk/reactos/ntoskrnl/mm/ARM3/vadnode.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/vadnode.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/vadnode.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/vadnode.c [iso-8859-1] Tue Oct 5 14:36:09 2010
@@ -121,6 +121,28 @@
/* Do the actual insert operation */
MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
+
+ /* Now insert an ARM3 MEMORY_AREA for this node, unless the insert was already from the MEMORY_AREA code */
+ if (Vad->u.VadFlags.Spare == 0)
+ {
+ NTSTATUS Status;
+ PMEMORY_AREA MemoryArea;
+ PHYSICAL_ADDRESS BoundaryAddressMultiple;
+ SIZE_T Size;
+ PVOID AllocatedBase = (PVOID)(Vad->StartingVpn << PAGE_SHIFT);
+ BoundaryAddressMultiple.QuadPart = 0;
+ Size = ((Vad->EndingVpn + 1) - Vad->StartingVpn) << PAGE_SHIFT;
+ Status = MmCreateMemoryArea(&Process->Vm,
+ MEMORY_AREA_OWNED_BY_ARM3,
+ &AllocatedBase,
+ Size,
+ PAGE_READWRITE,
+ &MemoryArea,
+ TRUE,
+ 0,
+ BoundaryAddressMultiple);
+ ASSERT(NT_SUCCESS(Status));
+ }
}
VOID
@@ -179,6 +201,112 @@
/* Nothing found */
return NULL;
+}
+
+PMMADDRESS_NODE
+NTAPI
+MiGetNextNode(IN PMMADDRESS_NODE Node)
+{
+ PMMADDRESS_NODE Parent;
+
+ /* Get the right child */
+ if (RtlRightChildAvl(Node))
+ {
+ /* Get left-most child */
+ Node = RtlRightChildAvl(Node);
+ while (RtlLeftChildAvl(Node)) Node = RtlLeftChildAvl(Node);
+ return Node;
+ }
+
+ Parent = RtlParentAvl(Node);
+ ASSERT(Parent != NULL);
+ while (Parent != Node)
+ {
+ /* The parent should be a left child, return the real predecessor */
+ if (RtlIsLeftChildAvl(Node))
+ {
+ /* Return it */
+ return Parent;
+ }
+
+ /* Keep lopping until we find our parent */
+ Node = Parent;
+ Parent = RtlParentAvl(Node);
+ }
+
+ /* Nothing found */
+ return NULL;
+}
+
+NTSTATUS
+NTAPI
+MiFindEmptyAddressRangeInTree(IN SIZE_T Length,
+ IN ULONG_PTR Alignment,
+ IN PMM_AVL_TABLE Table,
+ OUT PMMADDRESS_NODE *PreviousVad,
+ OUT PULONG_PTR Base)
+{
+ PMMADDRESS_NODE Node;
+ PMMADDRESS_NODE NextNode;
+ ULONG_PTR StartingVpn, HighestVpn, AlignmentVpn, LengthVpn, LowVpn;
+ ASSERT(Length != 0);
+
+ /* Precompute page numbers for the length, alignment, and starting address */
+ LengthVpn = (Length + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ AlignmentVpn = Alignment >> PAGE_SHIFT;
+ StartingVpn = ROUND_DOWN((ULONG_PTR)MM_LOWEST_USER_ADDRESS >> PAGE_SHIFT,
+ AlignmentVpn);
+
+ /* Check if the table is free, so the lowest possible address is available */
+ if (!Table->NumberGenericTableElements) goto FoundAtBottom;
+
+ /* Otherwise, follow the leftmost child of the right root node's child */
+ Node = RtlRightChildAvl(&Table->BalancedRoot);
+ while (RtlLeftChildAvl(Node)) Node = RtlLeftChildAvl(Node);
+
+ /* This is the node for the remaining gap at the bottom, can it be used? */
+ if ((Node->StartingVpn > StartingVpn) &&
+ (LengthVpn < Node->StartingVpn - StartingVpn))
+ {
+FoundAtBottom:
+ /* Use this VAD to store the allocation */
+ *PreviousVad = NULL;
+ *Base = StartingVpn << PAGE_SHIFT;
+ return STATUS_SUCCESS;
+ }
+
+ /* Otherwise, we start a search to find a gap */
+ while (TRUE)
+ {
+ /* The last aligned page number in this entry */
+ LowVpn = ROUND_DOWN(Node->EndingVpn + 1, AlignmentVpn);
+
+ /* Keep going as long as there's still a next node */
+ NextNode = MiGetNextNode(Node);
+ if (!NextNode) break;
+
+ /* Can this allocation fit in this node? */
+ if ((LengthVpn <= (NextNode->StartingVpn - LowVpn)) &&
+ (NextNode->StartingVpn > LowVpn))
+ {
+Found:
+ /* Yes! Use this VAD to store the allocation */
+ *PreviousVad = Node;
+ *Base = ROUND_DOWN((Node->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1),
+ Alignment);
+ return STATUS_SUCCESS;
+ }
+
+ /* Try the next node */
+ Node = NextNode;
+ }
+
+ /* We're down to the last (top) VAD, will this allocation fit inside it? */
+ HighestVpn = ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) >> PAGE_SHIFT;
+ if ((HighestVpn > LowVpn) && (LengthVpn <= HighestVpn - LowVpn)) goto Found;
+
+ /* Nyet, there's no free address space for this allocation, so we'll fail */
+ return STATUS_NO_MEMORY;
}
TABLE_SEARCH_RESULT
Modified: trunk/reactos/ntoskrnl/mm/section.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/section.c?rev=…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/section.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/section.c [iso-8859-1] Tue Oct 5 14:36:09 2010
@@ -3956,7 +3956,19 @@
-
+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
* MmMapViewOfSection
@@ -4023,6 +4035,20 @@
ULONG ViewOffset;
NTSTATUS Status = STATUS_SUCCESS;
+ if ((ULONG_PTR)SectionObject & 1)
+ {
+ return MmMapViewOfArm3Section((PVOID)((ULONG_PTR)SectionObject & ~1),
+ Process,
+ BaseAddress,
+ ZeroBits,
+ CommitSize,
+ SectionOffset,
+ ViewSize,
+ InheritDisposition,
+ AllocationType,
+ Protect);
+ }
+
ASSERT(Process);
if (!Protect || Protect & ~PAGE_FLAGS_VALID_FOR_SECTION)
@@ -4280,10 +4306,10 @@
PROS_SECTION_OBJECT Section;
PMMSUPPORT AddressSpace;
NTSTATUS Status;
-
+ PAGED_CODE();
+
if ((ULONG_PTR)SectionObject & 1)
{
- PAGED_CODE();
extern PVOID MmSession;
return MiMapViewInSystemSpace((PVOID)((ULONG_PTR)SectionObject & ~1),
&MmSession,