reactos/ntoskrnl/mm/mminit.c
Pierre Schweitzer c7ad200f8b
[NTOSKRNL] Reimplement the lazy writer in Cc and remove the "basic" one in Mm.
This removes the "modified page writer" thread in Mm that was regularly blindly
attempting to flush dirty pages to the disk.
Instead, this commit introduces a lazy writer that will monitor dirty pages count
and will flush them to disk when this count is above a threshold. The threshold is
computed on Cc init.
Compared to what was done previously, this lazy writer will only write down files
that are not marked as temporary.
The mechanisms involved in this lazy writer worker are well described in Windows
Internals 4th editions (constants are coming from it ;-)).
Also fixed a bad (and old!) bug in CcRosFlushDirtyPages() where target count could
be overflow and the function would spin forever while holding the VACBs lock. This is
mandatory as now lazy writer will call it with "random" values.
This also allows implementing CcWaitForCurrentLazyWriterActivity() :-).
Also renamed DirtyPageCount to its MS equivalent.

CORE-14235
2018-01-23 19:33:59 +01:00

274 lines
8.5 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/mm/mminit.c
* PURPOSE: Memory Manager Initialization
* PROGRAMMERS:
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
#define MODULE_INVOLVED_IN_ARM3
#include "ARM3/miarm.h"
/* GLOBALS *******************************************************************/
VOID NTAPI MiInitializeUserPfnBitmap(VOID);
BOOLEAN Mm64BitPhysicalAddress = FALSE;
ULONG MmReadClusterSize;
//
// 0 | 1 is on/off paging, 2 is undocumented
//
UCHAR MmDisablePagingExecutive = 1; // Forced to off
PMMPTE MmSharedUserDataPte;
PMMSUPPORT MmKernelAddressSpace;
extern KEVENT MmWaitPageEvent;
extern FAST_MUTEX MiGlobalPageOperation;
extern LIST_ENTRY MiSegmentList;
extern NTSTATUS MiRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed);
/* PRIVATE FUNCTIONS *********************************************************/
//
// Helper function to create initial memory areas.
// The created area is always read/write.
//
VOID
INIT_FUNCTION
NTAPI
MiCreateArm3StaticMemoryArea(PVOID BaseAddress, SIZE_T Size, BOOLEAN Executable)
{
const ULONG Protection = Executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
PVOID pBaseAddress = BaseAddress;
PMEMORY_AREA MArea;
NTSTATUS Status;
Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
&pBaseAddress,
Size,
Protection,
&MArea,
0,
PAGE_SIZE);
ASSERT(Status == STATUS_SUCCESS);
// TODO: Perhaps it would be prudent to bugcheck here, not only assert?
}
VOID
INIT_FUNCTION
NTAPI
MiInitSystemMemoryAreas(VOID)
{
//
// Create all the static memory areas.
//
// The loader mappings. The only Executable area.
MiCreateArm3StaticMemoryArea((PVOID)KSEG0_BASE, MmBootImageSize, TRUE);
// The PTE base
MiCreateArm3StaticMemoryArea((PVOID)PTE_BASE, PTE_TOP - PTE_BASE + 1, FALSE);
// Hyperspace
MiCreateArm3StaticMemoryArea((PVOID)HYPER_SPACE, HYPER_SPACE_END - HYPER_SPACE + 1, FALSE);
// Protect the PFN database
MiCreateArm3StaticMemoryArea(MmPfnDatabase, (MxPfnAllocation << PAGE_SHIFT), FALSE);
// ReactOS requires a memory area to keep the initial NP area off-bounds
MiCreateArm3StaticMemoryArea(MmNonPagedPoolStart, MmSizeOfNonPagedPoolInBytes, FALSE);
// System PTE space
MiCreateArm3StaticMemoryArea(MmNonPagedSystemStart, (MmNumberOfSystemPtes + 1) * PAGE_SIZE, FALSE);
// Nonpaged pool expansion space
MiCreateArm3StaticMemoryArea(MmNonPagedPoolExpansionStart, (ULONG_PTR)MmNonPagedPoolEnd - (ULONG_PTR)MmNonPagedPoolExpansionStart, FALSE);
// System view space
MiCreateArm3StaticMemoryArea(MiSystemViewStart, MmSystemViewSize, FALSE);
// Session space
MiCreateArm3StaticMemoryArea(MmSessionBase, (ULONG_PTR)MiSessionSpaceEnd - (ULONG_PTR)MmSessionBase, FALSE);
// Paged pool
MiCreateArm3StaticMemoryArea(MmPagedPoolStart, MmSizeOfPagedPoolInBytes, FALSE);
// Debugger mapping
MiCreateArm3StaticMemoryArea(MI_DEBUG_MAPPING, PAGE_SIZE, FALSE);
#if defined(_X86_)
// Reserved HAL area (includes KUSER_SHARED_DATA and KPCR)
MiCreateArm3StaticMemoryArea((PVOID)MM_HAL_VA_START, MM_HAL_VA_END - MM_HAL_VA_START + 1, FALSE);
#else /* _X86_ */
#ifndef _M_AMD64
// KPCR, one page per CPU. Only for 32-bit kernel.
MiCreateArm3StaticMemoryArea(PCR, PAGE_SIZE * KeNumberProcessors, FALSE);
#endif /* _M_AMD64 */
// KUSER_SHARED_DATA
MiCreateArm3StaticMemoryArea((PVOID)KI_USER_SHARED_DATA, PAGE_SIZE, FALSE);
#endif /* _X86_ */
}
VOID
NTAPI
INIT_FUNCTION
MiDbgDumpAddressSpace(VOID)
{
//
// Print the memory layout
//
DPRINT1(" 0x%p - 0x%p\t%s\n",
KSEG0_BASE,
(ULONG_PTR)KSEG0_BASE + MmBootImageSize,
"Boot Loaded Image");
DPRINT1(" 0x%p - 0x%p\t%s\n",
MmPfnDatabase,
(ULONG_PTR)MmPfnDatabase + (MxPfnAllocation << PAGE_SHIFT),
"PFN Database");
DPRINT1(" 0x%p - 0x%p\t%s\n",
MmNonPagedPoolStart,
(ULONG_PTR)MmNonPagedPoolStart + MmSizeOfNonPagedPoolInBytes,
"ARM3 Non Paged Pool");
DPRINT1(" 0x%p - 0x%p\t%s\n",
MiSystemViewStart,
(ULONG_PTR)MiSystemViewStart + MmSystemViewSize,
"System View Space");
DPRINT1(" 0x%p - 0x%p\t%s\n",
MmSessionBase,
MiSessionSpaceEnd,
"Session Space");
DPRINT1(" 0x%p - 0x%p\t%s\n",
PTE_BASE, PTE_TOP,
"Page Tables");
DPRINT1(" 0x%p - 0x%p\t%s\n",
PDE_BASE, PDE_TOP,
"Page Directories");
DPRINT1(" 0x%p - 0x%p\t%s\n",
HYPER_SPACE, HYPER_SPACE_END,
"Hyperspace");
DPRINT1(" 0x%p - 0x%p\t%s\n",
MmPagedPoolStart,
(ULONG_PTR)MmPagedPoolStart + MmSizeOfPagedPoolInBytes,
"ARM3 Paged Pool");
DPRINT1(" 0x%p - 0x%p\t%s\n",
MmNonPagedSystemStart, MmNonPagedPoolExpansionStart,
"System PTE Space");
DPRINT1(" 0x%p - 0x%p\t%s\n",
MmNonPagedPoolExpansionStart, MmNonPagedPoolEnd,
"Non Paged Pool Expansion PTE Space");
}
NTSTATUS
NTAPI
INIT_FUNCTION
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
INIT_FUNCTION
MmInitSystem(IN ULONG Phase,
IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
extern MMPTE ValidKernelPte;
PMMPTE PointerPte;
MMPTE TempPte = ValidKernelPte;
PFN_NUMBER PageFrameNumber;
/* Initialize the kernel address space */
ASSERT(Phase == 1);
InitializeListHead(&MiSegmentList);
ExInitializeFastMutex(&MiGlobalPageOperation);
KeInitializeEvent(&MmWaitPageEvent, SynchronizationEvent, FALSE);
// Until we're fully demand paged, we can do things the old way through
// the balance manager
MmInitializeMemoryConsumer(MC_CACHE, MiRosTrimCache);
MmKernelAddressSpace = &PsIdleProcess->Vm;
/* Intialize system memory areas */
MiInitSystemMemoryAreas();
/* Dump the address space */
MiDbgDumpAddressSpace();
MmInitGlobalKernelPageDirectory();
MiInitializeUserPfnBitmap();
MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
MmInitializeRmapList();
MmInitSectionImplementation();
MmInitPagingFile();
//
// Create a PTE to double-map the shared data section. We allocate it
// from paged pool so that we can't fault when trying to touch the PTE
// itself (to map it), since paged pool addresses will already be mapped
// by the fault handler.
//
MmSharedUserDataPte = ExAllocatePoolWithTag(PagedPool,
sizeof(MMPTE),
TAG_MM);
if (!MmSharedUserDataPte) return FALSE;
//
// Now get the PTE for shared data, and read the PFN that holds it
//
PointerPte = MiAddressToPte((PVOID)KI_USER_SHARED_DATA);
ASSERT(PointerPte->u.Hard.Valid == 1);
PageFrameNumber = PFN_FROM_PTE(PointerPte);
/* Build the PTE and write it */
MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte,
PointerPte,
MM_READONLY,
PageFrameNumber);
*MmSharedUserDataPte = TempPte;
/* Initialize session working set support */
MiInitializeSessionWsSupport();
/* Setup session IDs */
MiInitializeSessionIds();
/* Setup the memory threshold events */
if (!MiInitializeMemoryEvents()) return FALSE;
/*
* Unmap low memory
*/
MiInitBalancerThread();
/* Initialize the balance set manager */
MmInitBsmThread();
return TRUE;
}