mirror of
https://github.com/reactos/reactos.git
synced 2024-09-03 17:19:20 +00:00
![Timo Kreuzer](/assets/img/avatar_default.png)
- Acquire the appropriate working set lock when calling MmLocateMemoryAreaByAddress - Do not access MemoryArea without holding the lock (otherwise it can be pulled away under our feet) - Fix range check for paged pool
305 lines
8.3 KiB
C
305 lines
8.3 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: ntoskrnl/mm/mmfault.c
|
|
* PURPOSE: Kernel memory management functions
|
|
* PROGRAMMERS: David Welch (welch@cwcom.net)
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#include <cache/section/newmm.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#define MODULE_INVOLVED_IN_ARM3
|
|
#include "ARM3/miarm.h"
|
|
|
|
/* PRIVATE FUNCTIONS **********************************************************/
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
MmpAccessFault(KPROCESSOR_MODE Mode,
|
|
ULONG_PTR Address,
|
|
BOOLEAN FromMdl)
|
|
{
|
|
PMMSUPPORT AddressSpace;
|
|
MEMORY_AREA* MemoryArea;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
|
|
|
|
if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
|
|
{
|
|
DPRINT1("Page fault at high IRQL was %u\n", KeGetCurrentIrql());
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
/*
|
|
* Find the memory area for the faulting address
|
|
*/
|
|
if (Address >= (ULONG_PTR)MmSystemRangeStart)
|
|
{
|
|
/*
|
|
* Check permissions
|
|
*/
|
|
if (Mode != KernelMode)
|
|
{
|
|
DPRINT1("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
|
|
return(STATUS_ACCESS_VIOLATION);
|
|
}
|
|
AddressSpace = MmGetKernelAddressSpace();
|
|
}
|
|
else
|
|
{
|
|
AddressSpace = &PsGetCurrentProcess()->Vm;
|
|
}
|
|
|
|
if (!FromMdl)
|
|
{
|
|
MmLockAddressSpace(AddressSpace);
|
|
}
|
|
do
|
|
{
|
|
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
|
|
if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
|
|
{
|
|
if (!FromMdl)
|
|
{
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
}
|
|
return (STATUS_ACCESS_VIOLATION);
|
|
}
|
|
|
|
switch (MemoryArea->Type)
|
|
{
|
|
case MEMORY_AREA_SECTION_VIEW:
|
|
Status = MmAccessFaultSectionView(AddressSpace,
|
|
MemoryArea,
|
|
(PVOID)Address,
|
|
!FromMdl);
|
|
break;
|
|
#ifdef NEWCC
|
|
case MEMORY_AREA_CACHE:
|
|
// This code locks for itself to keep from having to break a lock
|
|
// passed in.
|
|
if (!FromMdl)
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
Status = MmAccessFaultCacheSection(Mode, Address, FromMdl);
|
|
if (!FromMdl)
|
|
MmLockAddressSpace(AddressSpace);
|
|
break;
|
|
#endif
|
|
default:
|
|
Status = STATUS_ACCESS_VIOLATION;
|
|
break;
|
|
}
|
|
}
|
|
while (Status == STATUS_MM_RESTART_OPERATION);
|
|
|
|
DPRINT("Completed page fault handling\n");
|
|
if (!FromMdl)
|
|
{
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
MmNotPresentFault(KPROCESSOR_MODE Mode,
|
|
ULONG_PTR Address,
|
|
BOOLEAN FromMdl)
|
|
{
|
|
PMMSUPPORT AddressSpace;
|
|
MEMORY_AREA* MemoryArea;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("MmNotPresentFault(Mode %d, Address %x)\n", Mode, Address);
|
|
|
|
if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
|
|
{
|
|
DPRINT1("Page fault at high IRQL was %u, address %x\n", KeGetCurrentIrql(), Address);
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
/*
|
|
* Find the memory area for the faulting address
|
|
*/
|
|
if (Address >= (ULONG_PTR)MmSystemRangeStart)
|
|
{
|
|
/*
|
|
* Check permissions
|
|
*/
|
|
if (Mode != KernelMode)
|
|
{
|
|
DPRINT1("Address: %x\n", Address);
|
|
return(STATUS_ACCESS_VIOLATION);
|
|
}
|
|
AddressSpace = MmGetKernelAddressSpace();
|
|
}
|
|
else
|
|
{
|
|
AddressSpace = &PsGetCurrentProcess()->Vm;
|
|
}
|
|
|
|
if (!FromMdl)
|
|
{
|
|
MmLockAddressSpace(AddressSpace);
|
|
}
|
|
|
|
/*
|
|
* Call the memory area specific fault handler
|
|
*/
|
|
do
|
|
{
|
|
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
|
|
if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
|
|
{
|
|
if (!FromMdl)
|
|
{
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
}
|
|
return (STATUS_ACCESS_VIOLATION);
|
|
}
|
|
|
|
switch (MemoryArea->Type)
|
|
{
|
|
case MEMORY_AREA_SECTION_VIEW:
|
|
Status = MmNotPresentFaultSectionView(AddressSpace,
|
|
MemoryArea,
|
|
(PVOID)Address,
|
|
!FromMdl);
|
|
break;
|
|
#ifdef NEWCC
|
|
case MEMORY_AREA_CACHE:
|
|
// This code locks for itself to keep from having to break a lock
|
|
// passed in.
|
|
if (!FromMdl)
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
Status = MmNotPresentFaultCacheSection(Mode, Address, FromMdl);
|
|
if (!FromMdl)
|
|
MmLockAddressSpace(AddressSpace);
|
|
break;
|
|
#endif
|
|
default:
|
|
Status = STATUS_ACCESS_VIOLATION;
|
|
break;
|
|
}
|
|
}
|
|
while (Status == STATUS_MM_RESTART_OPERATION);
|
|
|
|
DPRINT("Completed page fault handling\n");
|
|
if (!FromMdl)
|
|
{
|
|
MmUnlockAddressSpace(AddressSpace);
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
extern BOOLEAN Mmi386MakeKernelPageTableGlobal(PVOID Address);
|
|
|
|
VOID
|
|
NTAPI
|
|
MmRebalanceMemoryConsumersAndWait(VOID);
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
MmAccessFault(IN ULONG FaultCode,
|
|
IN PVOID Address,
|
|
IN KPROCESSOR_MODE Mode,
|
|
IN PVOID TrapInformation)
|
|
{
|
|
PMEMORY_AREA MemoryArea = NULL;
|
|
NTSTATUS Status;
|
|
BOOLEAN IsArm3Fault = FALSE;
|
|
|
|
/* Cute little hack for ROS */
|
|
if ((ULONG_PTR)Address >= (ULONG_PTR)MmSystemRangeStart)
|
|
{
|
|
#ifdef _M_IX86
|
|
/* Check for an invalid page directory in kernel mode */
|
|
if (Mmi386MakeKernelPageTableGlobal(Address))
|
|
{
|
|
/* All is well with the world */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Handle shared user page / page table, which don't have a VAD / MemoryArea */
|
|
if ((PAGE_ALIGN(Address) == (PVOID)MM_SHARED_USER_DATA_VA) ||
|
|
MI_IS_PAGE_TABLE_ADDRESS(Address))
|
|
{
|
|
/* This is an ARM3 fault */
|
|
DPRINT("ARM3 fault %p\n", Address);
|
|
return MmArmAccessFault(FaultCode, Address, Mode, TrapInformation);
|
|
}
|
|
|
|
/* Is there a ReactOS address space yet? */
|
|
if (MmGetKernelAddressSpace())
|
|
{
|
|
if (Address > MM_HIGHEST_USER_ADDRESS)
|
|
{
|
|
/* Check if this is an ARM3 memory area */
|
|
MiLockWorkingSetShared(PsGetCurrentThread(), &MmSystemCacheWs);
|
|
MemoryArea = MmLocateMemoryAreaByAddress(MmGetKernelAddressSpace(), Address);
|
|
|
|
if ((MemoryArea != NULL) && (MemoryArea->Type == MEMORY_AREA_OWNED_BY_ARM3))
|
|
{
|
|
IsArm3Fault = TRUE;
|
|
}
|
|
|
|
MiUnlockWorkingSetShared(PsGetCurrentThread(), &MmSystemCacheWs);
|
|
}
|
|
else
|
|
{
|
|
/* Could this be a VAD fault from user-mode? */
|
|
MiLockProcessWorkingSetShared(PsGetCurrentProcess(), PsGetCurrentThread());
|
|
MemoryArea = MmLocateMemoryAreaByAddress(MmGetCurrentAddressSpace(), Address);
|
|
|
|
if ((MemoryArea != NULL) && (MemoryArea->Type == MEMORY_AREA_OWNED_BY_ARM3))
|
|
{
|
|
IsArm3Fault = TRUE;
|
|
}
|
|
|
|
MiUnlockProcessWorkingSetShared(PsGetCurrentProcess(), PsGetCurrentThread());
|
|
}
|
|
}
|
|
|
|
/* Is this an ARM3 memory area, or is there no address space yet? */
|
|
if (IsArm3Fault ||
|
|
((MemoryArea == NULL) &&
|
|
((ULONG_PTR)Address >= (ULONG_PTR)MmPagedPoolStart) &&
|
|
((ULONG_PTR)Address < (ULONG_PTR)MmPagedPoolEnd)) ||
|
|
(!MmGetKernelAddressSpace()))
|
|
{
|
|
/* This is an ARM3 fault */
|
|
DPRINT("ARM3 fault %p\n", MemoryArea);
|
|
return MmArmAccessFault(FaultCode, Address, Mode, TrapInformation);
|
|
}
|
|
|
|
Retry:
|
|
/* Keep same old ReactOS Behaviour */
|
|
if (!MI_IS_NOT_PRESENT_FAULT(FaultCode))
|
|
{
|
|
/* Call access fault */
|
|
Status = MmpAccessFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE);
|
|
}
|
|
else
|
|
{
|
|
/* Call not present */
|
|
Status = MmNotPresentFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE);
|
|
}
|
|
|
|
if (Status == STATUS_NO_MEMORY)
|
|
{
|
|
MmRebalanceMemoryConsumersAndWait();
|
|
goto Retry;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|