-/*
- * ReactOS kernel
- * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
+/* $Id$
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * COPYRIGHT: See COPYING in the top directory
+ * PROJECT: ReactOS kernel
+ * FILE: ntoskrnl/mm/rmap.c
+ * PURPOSE: Kernel memory managment functions
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/* $Id: rmap.c,v 1.5 2002/05/14 21:19:19 dwelch Exp $
- *
- * COPYRIGHT: See COPYING in the top directory
- * PROJECT: ReactOS kernel
- * FILE: ntoskrnl/mm/rmap.c
- * PURPOSE: kernel memory managment functions
- * PROGRAMMER: David Welch (welch@cwcom.net)
- * UPDATE HISTORY:
- * Created 27/12/01
+ * PROGRAMMERS: David Welch (welch@cwcom.net)
*/
/* INCLUDES *****************************************************************/
-#include <ddk/ntddk.h>
-#include <internal/mm.h>
-#include <internal/ps.h>
-
+#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, MmInitializeRmapList)
+#endif
+
/* TYPES ********************************************************************/
typedef struct _MM_RMAP_ENTRY
{
- struct _MM_RMAP_ENTRY* Next;
- PEPROCESS Process;
- PVOID Address;
-} MM_RMAP_ENTRY, *PMM_RMAP_ENTRY;
+ struct _MM_RMAP_ENTRY* Next;
+ PEPROCESS Process;
+ PVOID Address;
+#ifdef DBG
+ PVOID Caller;
+#endif
+}
+MM_RMAP_ENTRY, *PMM_RMAP_ENTRY;
/* GLOBALS ******************************************************************/
static FAST_MUTEX RmapListLock;
+static NPAGED_LOOKASIDE_LIST RmapLookasideList;
/* FUNCTIONS ****************************************************************/
VOID
+INIT_FUNCTION
+NTAPI
MmInitializeRmapList(VOID)
{
- ExInitializeFastMutex(&RmapListLock);
+ ExInitializeFastMutex(&RmapListLock);
+ ExInitializeNPagedLookasideList (&RmapLookasideList,
+ NULL,
+ NULL,
+ 0,
+ sizeof(MM_RMAP_ENTRY),
+ TAG_RMAP,
+ 50);
}
NTSTATUS
-MmPageOutPhysicalAddress(PVOID PhysicalAddress)
+NTAPI
+MmWritePagePhysicalAddress(PFN_TYPE Page)
{
- PMM_RMAP_ENTRY entry;
- PMEMORY_AREA MemoryArea;
- ULONG Type;
- PVOID Address;
- PEPROCESS Process;
- PMM_PAGEOP PageOp;
- LARGE_INTEGER Offset;
- NTSTATUS Status;
-
- ExAcquireFastMutex(&RmapListLock);
- entry = MmGetRmapListHeadPage(PhysicalAddress);
- if (entry == NULL)
- {
+ PMM_RMAP_ENTRY entry;
+ PMEMORY_AREA MemoryArea;
+ PMADDRESS_SPACE AddressSpace;
+ ULONG Type;
+ PVOID Address;
+ PEPROCESS Process;
+ PMM_PAGEOP PageOp;
+ ULONG Offset;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ /*
+ * Check that the address still has a valid rmap; then reference the
+ * process so it isn't freed while we are working.
+ */
+ ExAcquireFastMutex(&RmapListLock);
+ entry = MmGetRmapListHeadPage(Page);
+ if (entry == NULL)
+ {
ExReleaseFastMutex(&RmapListLock);
return(STATUS_UNSUCCESSFUL);
- }
- Process = entry->Process;
- Address = entry->Address;
- if ((((ULONG)Address) & 0xFFF) != 0)
- {
- KeBugCheck(0);
- }
-
- MmLockAddressSpace(&Process->AddressSpace);
- MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace, Address);
- Type = MemoryArea->Type;
- if (Type == MEMORY_AREA_SECTION_VIEW_COMMIT)
- {
- Offset.QuadPart = (ULONG)((Address - (ULONG)MemoryArea->BaseAddress) +
- MemoryArea->Data.SectionData.ViewOffset);
+ }
+ Process = entry->Process;
+ Address = entry->Address;
+ if ((((ULONG_PTR)Address) & 0xFFF) != 0)
+ {
+ KEBUGCHECK(0);
+ }
+ if (Address < MmSystemRangeStart)
+ {
+ Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
+ ExReleaseFastMutex(&RmapListLock);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ AddressSpace = &Process->AddressSpace;
+ }
+ else
+ {
+ ExReleaseFastMutex(&RmapListLock);
+ AddressSpace = MmGetKernelAddressSpace();
+ }
+ /*
+ * Lock the address space; then check that the address we are using
+ * still corresponds to a valid memory area (the page might have been
+ * freed or paged out after we read the rmap entry.)
+ */
+ MmLockAddressSpace(AddressSpace);
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
+ if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ if (Address < MmSystemRangeStart)
+ {
+ ObDereferenceObject(Process);
+ }
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ Type = MemoryArea->Type;
+ if (Type == MEMORY_AREA_SECTION_VIEW)
+ {
+ Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
+ + MemoryArea->Data.SectionData.ViewOffset;
/*
* Get or create a pageop
*/
- PageOp = MmGetPageOp(MemoryArea, 0, 0,
- MemoryArea->Data.SectionData.Segment,
- Offset.u.LowPart, MM_PAGEOP_PAGEOUT);
+ PageOp = MmGetPageOp(MemoryArea, NULL, 0,
+ MemoryArea->Data.SectionData.Segment,
+ Offset, MM_PAGEOP_PAGEOUT, TRUE);
+
if (PageOp == NULL)
- {
- DPRINT1("MmGetPageOp failed\n");
- KeBugCheck(0);
- }
-
- if (PageOp->Thread != PsGetCurrentThread())
- {
- MmReleasePageOp(PageOp);
- MmUnlockAddressSpace(&Process->AddressSpace);
- ExReleaseFastMutex(&RmapListLock);
- return(STATUS_UNSUCCESSFUL);
- }
-
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ if (Address < MmSystemRangeStart)
+ {
+ ObDereferenceObject(Process);
+ }
+ return(STATUS_UNSUCCESSFUL);
+ }
+
/*
* Release locks now we have a page op.
*/
- MmUnlockAddressSpace(&Process->AddressSpace);
- ExReleaseFastMutex(&RmapListLock);
+ MmUnlockAddressSpace(AddressSpace);
/*
* Do the actual page out work.
*/
- Status = MmPageOutSectionView(&Process->AddressSpace, MemoryArea,
- Address, PageOp);
- }
- else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
- {
- PageOp = MmGetPageOp(MemoryArea, Process->UniqueProcessId,
- Address, NULL, 0, MM_PAGEOP_PAGEOUT);
- if (PageOp->Thread != PsGetCurrentThread())
- {
- MmReleasePageOp(PageOp);
- MmUnlockAddressSpace(&Process->AddressSpace);
- ExReleaseFastMutex(&RmapListLock);
- return(STATUS_UNSUCCESSFUL);
- }
+ Status = MmWritePageSectionView(AddressSpace, MemoryArea,
+ Address, PageOp);
+ }
+ else if ((Type == MEMORY_AREA_VIRTUAL_MEMORY) || (Type == MEMORY_AREA_PEB_OR_TEB))
+ {
+ PageOp = MmGetPageOp(MemoryArea, Address < MmSystemRangeStart ? Process->UniqueProcessId : NULL,
+ Address, NULL, 0, MM_PAGEOP_PAGEOUT, TRUE);
+
+ if (PageOp == NULL)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ if (Address < MmSystemRangeStart)
+ {
+ ObDereferenceObject(Process);
+ }
+ return(STATUS_UNSUCCESSFUL);
+ }
/*
* Release locks now we have a page op.
*/
- MmUnlockAddressSpace(&Process->AddressSpace);
+ MmUnlockAddressSpace(AddressSpace);
+
+ /*
+ * Do the actual page out work.
+ */
+ Status = MmWritePageVirtualMemory(AddressSpace, MemoryArea,
+ Address, PageOp);
+ }
+ else
+ {
+ KEBUGCHECK(0);
+ }
+ if (Address < MmSystemRangeStart)
+ {
+ ObDereferenceObject(Process);
+ }
+ return(Status);
+}
+
+NTSTATUS
+NTAPI
+MmPageOutPhysicalAddress(PFN_TYPE Page)
+{
+ PMM_RMAP_ENTRY entry;
+ PMEMORY_AREA MemoryArea;
+ PMADDRESS_SPACE AddressSpace;
+ ULONG Type;
+ PVOID Address;
+ PEPROCESS Process;
+ PMM_PAGEOP PageOp;
+ ULONG Offset;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ ExAcquireFastMutex(&RmapListLock);
+ entry = MmGetRmapListHeadPage(Page);
+ if (entry == NULL || MmGetLockCountPage(Page) != 0)
+ {
+ ExReleaseFastMutex(&RmapListLock);
+ return(STATUS_UNSUCCESSFUL);
+ }
+ Process = entry->Process;
+ Address = entry->Address;
+ if ((((ULONG_PTR)Address) & 0xFFF) != 0)
+ {
+ KEBUGCHECK(0);
+ }
+
+ if (Address < MmSystemRangeStart)
+ {
+ Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
ExReleaseFastMutex(&RmapListLock);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ AddressSpace = &Process->AddressSpace;
+ }
+ else
+ {
+ ExReleaseFastMutex(&RmapListLock);
+ AddressSpace = MmGetKernelAddressSpace();
+ }
+
+ MmLockAddressSpace(AddressSpace);
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
+ if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ if (Address < MmSystemRangeStart)
+ {
+ ObDereferenceObject(Process);
+ }
+ return(STATUS_UNSUCCESSFUL);
+ }
+ Type = MemoryArea->Type;
+ if (Type == MEMORY_AREA_SECTION_VIEW)
+ {
+ Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
+ + MemoryArea->Data.SectionData.ViewOffset;;
+
+ /*
+ * Get or create a pageop
+ */
+ PageOp = MmGetPageOp(MemoryArea, NULL, 0,
+ MemoryArea->Data.SectionData.Segment,
+ Offset, MM_PAGEOP_PAGEOUT, TRUE);
+ if (PageOp == NULL)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ if (Address < MmSystemRangeStart)
+ {
+ ObDereferenceObject(Process);
+ }
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ /*
+ * Release locks now we have a page op.
+ */
+ MmUnlockAddressSpace(AddressSpace);
+
+ /*
+ * Do the actual page out work.
+ */
+ Status = MmPageOutSectionView(AddressSpace, MemoryArea,
+ Address, PageOp);
+ }
+ else if ((Type == MEMORY_AREA_VIRTUAL_MEMORY) || (Type == MEMORY_AREA_PEB_OR_TEB))
+ {
+ PageOp = MmGetPageOp(MemoryArea, Address < MmSystemRangeStart ? Process->UniqueProcessId : NULL,
+ Address, NULL, 0, MM_PAGEOP_PAGEOUT, TRUE);
+ if (PageOp == NULL)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ if (Address < MmSystemRangeStart)
+ {
+ ObDereferenceObject(Process);
+ }
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ /*
+ * Release locks now we have a page op.
+ */
+ MmUnlockAddressSpace(AddressSpace);
/*
* Do the actual page out work.
*/
- Status = MmPageOutVirtualMemory(&Process->AddressSpace, MemoryArea,
- Address, PageOp);
- }
- else
- {
- KeBugCheck(0);
- }
- return(Status);
+ Status = MmPageOutVirtualMemory(AddressSpace, MemoryArea,
+ Address, PageOp);
+ }
+ else
+ {
+ KEBUGCHECK(0);
+ }
+ if (Address < MmSystemRangeStart)
+ {
+ ObDereferenceObject(Process);
+ }
+ return(Status);
+}
+
+VOID
+NTAPI
+MmSetCleanAllRmaps(PFN_TYPE Page)
+{
+ PMM_RMAP_ENTRY current_entry;
+
+ ExAcquireFastMutex(&RmapListLock);
+ current_entry = MmGetRmapListHeadPage(Page);
+ if (current_entry == NULL)
+ {
+ DPRINT1("MmIsDirtyRmap: No rmaps.\n");
+ KEBUGCHECK(0);
+ }
+ while (current_entry != NULL)
+ {
+ MmSetCleanPage(current_entry->Process, current_entry->Address);
+ current_entry = current_entry->Next;
+ }
+ ExReleaseFastMutex(&RmapListLock);
}
VOID
-MmInsertRmap(PVOID PhysicalAddress, PEPROCESS Process, PVOID Address)
+NTAPI
+MmSetDirtyAllRmaps(PFN_TYPE Page)
{
- PMM_RMAP_ENTRY current_entry;
- PMM_RMAP_ENTRY new_entry;
-
- Address = (PVOID)PAGE_ROUND_DOWN(Address);
-
- new_entry = ExAllocatePool(NonPagedPool, sizeof(MM_RMAP_ENTRY));
- if (new_entry == NULL)
- {
- KeBugCheck(0);
- }
- new_entry->Address = Address;
- new_entry->Process = Process;
-
- if (MmGetPhysicalAddressForProcess(Process, Address) !=
- (ULONG)PhysicalAddress)
- {
+ PMM_RMAP_ENTRY current_entry;
+
+ ExAcquireFastMutex(&RmapListLock);
+ current_entry = MmGetRmapListHeadPage(Page);
+ if (current_entry == NULL)
+ {
+ DPRINT1("MmIsDirtyRmap: No rmaps.\n");
+ KEBUGCHECK(0);
+ }
+ while (current_entry != NULL)
+ {
+ MmSetDirtyPage(current_entry->Process, current_entry->Address);
+ current_entry = current_entry->Next;
+ }
+ ExReleaseFastMutex(&RmapListLock);
+}
+
+BOOL
+NTAPI
+MmIsDirtyPageRmap(PFN_TYPE Page)
+{
+ PMM_RMAP_ENTRY current_entry;
+
+ ExAcquireFastMutex(&RmapListLock);
+ current_entry = MmGetRmapListHeadPage(Page);
+ if (current_entry == NULL)
+ {
+ ExReleaseFastMutex(&RmapListLock);
+ return(FALSE);
+ }
+ while (current_entry != NULL)
+ {
+ if (MmIsDirtyPage(current_entry->Process, current_entry->Address))
+ {
+ ExReleaseFastMutex(&RmapListLock);
+ return(TRUE);
+ }
+ current_entry = current_entry->Next;
+ }
+ ExReleaseFastMutex(&RmapListLock);
+ return(FALSE);
+}
+
+VOID
+NTAPI
+MmInsertRmap(PFN_TYPE Page, PEPROCESS Process,
+ PVOID Address)
+{
+ PMM_RMAP_ENTRY current_entry;
+ PMM_RMAP_ENTRY new_entry;
+ ULONG PrevSize;
+
+ Address = (PVOID)PAGE_ROUND_DOWN(Address);
+
+ new_entry = ExAllocateFromNPagedLookasideList(&RmapLookasideList);
+ if (new_entry == NULL)
+ {
+ KEBUGCHECK(0);
+ }
+ new_entry->Address = Address;
+ new_entry->Process = Process;
+#ifdef DBG
+ new_entry->Caller = __builtin_return_address(0);
+#endif
+
+ if (MmGetPfnForProcess(Process, Address) != Page)
+ {
DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
- "address 0x%.8X\n", Process->UniqueProcessId, Address,
- MmGetPhysicalAddressForProcess(Process, Address),
- PhysicalAddress)
- KeBugCheck(0);
- }
-
- ExAcquireFastMutex(&RmapListLock);
- current_entry = MmGetRmapListHeadPage(PhysicalAddress);
- new_entry->Next = current_entry;
- MmSetRmapListHeadPage(PhysicalAddress, new_entry);
- ExReleaseFastMutex(&RmapListLock);
+ "address 0x%.8X\n", Process->UniqueProcessId, Address,
+ MmGetPfnForProcess(Process, Address) << PAGE_SHIFT,
+ Page << PAGE_SHIFT);
+ KEBUGCHECK(0);
+ }
+
+ ExAcquireFastMutex(&RmapListLock);
+ current_entry = MmGetRmapListHeadPage(Page);
+ new_entry->Next = current_entry;
+#ifdef DBG
+ while (current_entry)
+ {
+ if (current_entry->Address == new_entry->Address && current_entry->Process == new_entry->Process)
+ {
+ DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n current caller ",
+ current_entry->Address);
+ KeRosPrintAddress(new_entry->Caller);
+ DbgPrint("\n previous caller ");
+ KeRosPrintAddress(current_entry->Caller);
+ DbgPrint("\n");
+ KeBugCheck(0);
+ }
+ current_entry = current_entry->Next;
+ }
+#endif
+ MmSetRmapListHeadPage(Page, new_entry);
+ ExReleaseFastMutex(&RmapListLock);
+ if (Process == NULL)
+ {
+ Process = PsInitialSystemProcess;
+ }
+ if (Process)
+ {
+ PrevSize = InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, PAGE_SIZE);
+ if (PrevSize >= Process->Vm.PeakWorkingSetSize)
+ {
+ Process->Vm.PeakWorkingSetSize = PrevSize + PAGE_SIZE;
+ }
+ }
}
VOID
-MmDeleteAllRmaps(PVOID PhysicalAddress, PVOID Context,
- VOID (*DeleteMapping)(PVOID Context, PEPROCESS Process,
- PVOID Address))
+NTAPI
+MmDeleteAllRmaps(PFN_TYPE Page, PVOID Context,
+ VOID (*DeleteMapping)(PVOID Context, PEPROCESS Process,
+ PVOID Address))
{
- PMM_RMAP_ENTRY current_entry;
- PMM_RMAP_ENTRY previous_entry;
+ PMM_RMAP_ENTRY current_entry;
+ PMM_RMAP_ENTRY previous_entry;
+ PEPROCESS Process;
- ExAcquireFastMutex(&RmapListLock);
- current_entry = MmGetRmapListHeadPage(PhysicalAddress);
- if (current_entry == NULL)
- {
+ ExAcquireFastMutex(&RmapListLock);
+ current_entry = MmGetRmapListHeadPage(Page);
+ if (current_entry == NULL)
+ {
DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
- KeBugCheck(0);
- }
- while (current_entry != NULL)
- {
+ KEBUGCHECK(0);
+ }
+ MmSetRmapListHeadPage(Page, NULL);
+ ExReleaseFastMutex(&RmapListLock);
+ while (current_entry != NULL)
+ {
previous_entry = current_entry;
current_entry = current_entry->Next;
if (DeleteMapping)
- {
- DeleteMapping(Context, previous_entry->Process,
- previous_entry->Address);
- }
- ExFreePool(previous_entry);
- }
- MmSetRmapListHeadPage(PhysicalAddress, NULL);
- ExReleaseFastMutex(&RmapListLock);
+ {
+ DeleteMapping(Context, previous_entry->Process,
+ previous_entry->Address);
+ }
+ Process = previous_entry->Process;
+ ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
+ if (Process == NULL)
+ {
+ Process = PsInitialSystemProcess;
+ }
+ if (Process)
+ {
+ InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
+ }
+ }
}
VOID
-MmDeleteRmap(PVOID PhysicalAddress, PEPROCESS Process, PVOID Address)
+NTAPI
+MmDeleteRmap(PFN_TYPE Page, PEPROCESS Process,
+ PVOID Address)
{
- PMM_RMAP_ENTRY current_entry, previous_entry;
-
- ExAcquireFastMutex(&RmapListLock);
- previous_entry = NULL;
- current_entry = MmGetRmapListHeadPage(PhysicalAddress);
- while (current_entry != NULL)
- {
- if (current_entry->Process == Process &&
- current_entry->Address == Address)
- {
- if (previous_entry == NULL)
- {
- MmSetRmapListHeadPage(PhysicalAddress, current_entry->Next);
- ExReleaseFastMutex(&RmapListLock);
- ExFreePool(current_entry);
- }
- else
- {
- previous_entry->Next = current_entry->Next;
- ExReleaseFastMutex(&RmapListLock);
- ExFreePool(current_entry);
- }
- return;
- }
+ PMM_RMAP_ENTRY current_entry, previous_entry;
+
+ ExAcquireFastMutex(&RmapListLock);
+ previous_entry = NULL;
+ current_entry = MmGetRmapListHeadPage(Page);
+ while (current_entry != NULL)
+ {
+ if (current_entry->Process == Process &&
+ current_entry->Address == Address)
+ {
+ if (previous_entry == NULL)
+ {
+ MmSetRmapListHeadPage(Page, current_entry->Next);
+ }
+ else
+ {
+ previous_entry->Next = current_entry->Next;
+ }
+ ExReleaseFastMutex(&RmapListLock);
+ ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
+ if (Process == NULL)
+ {
+ Process = PsInitialSystemProcess;
+ }
+ if (Process)
+ {
+ InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
+ }
+ return;
+ }
previous_entry = current_entry;
current_entry = current_entry->Next;
- }
- KeBugCheck(0);
+ }
+ KEBUGCHECK(0);
}