reactos/ntoskrnl/mm/mmfault.c
Timo Kreuzer a662bedab8 [NTOS:MM] Fix bugs in MmAccessFault
- 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
2023-10-24 21:45:27 +03:00

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;
}