[NTOS:MM]
[reactos.git] / reactos / ntoskrnl / mm / mminit.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/mm/mminit.c
5 * PURPOSE: Memory Manager Initialization
6 * PROGRAMMERS:
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #define MODULE_INVOLVED_IN_ARM3
16 #include "ARM3/miarm.h"
17
18 /* GLOBALS *******************************************************************/
19
20 VOID NTAPI MiInitializeUserPfnBitmap(VOID);
21
22 HANDLE MpwThreadHandle;
23 KEVENT MpwThreadEvent;
24
25 BOOLEAN Mm64BitPhysicalAddress = FALSE;
26 ULONG MmReadClusterSize;
27 //
28 // 0 | 1 is on/off paging, 2 is undocumented
29 //
30 UCHAR MmDisablePagingExecutive = 1; // Forced to off
31 PMMPTE MmSharedUserDataPte;
32 PMMSUPPORT MmKernelAddressSpace;
33
34 extern KEVENT MmWaitPageEvent;
35 extern FAST_MUTEX MiGlobalPageOperation;
36 extern LIST_ENTRY MiSegmentList;
37 extern NTSTATUS MiRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed);
38
39 /* PRIVATE FUNCTIONS *********************************************************/
40
41 //
42 // Helper function to create initial memory areas.
43 // The created area is always read/write.
44 //
45 VOID
46 INIT_FUNCTION
47 NTAPI
48 MiCreateArm3StaticMemoryArea(PVOID BaseAddress, ULONG Size, BOOLEAN Executable)
49 {
50 const ULONG Protection = Executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
51 PVOID pBaseAddress = BaseAddress;
52 PMEMORY_AREA MArea;
53 NTSTATUS Status;
54
55 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
56 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
57 &pBaseAddress,
58 Size,
59 Protection,
60 &MArea,
61 0,
62 PAGE_SIZE);
63 ASSERT(Status == STATUS_SUCCESS);
64 // TODO: Perhaps it would be prudent to bugcheck here, not only assert?
65 }
66
67 VOID
68 INIT_FUNCTION
69 NTAPI
70 MiInitSystemMemoryAreas(VOID)
71 {
72 //
73 // Create all the static memory areas.
74 //
75
76 // The loader mappings. The only Executable area.
77 MiCreateArm3StaticMemoryArea((PVOID)KSEG0_BASE, MmBootImageSize, TRUE);
78
79 // The PTE base
80 MiCreateArm3StaticMemoryArea((PVOID)PTE_BASE, PTE_TOP - PTE_BASE + 1, FALSE);
81
82 // Hyperspace
83 MiCreateArm3StaticMemoryArea((PVOID)HYPER_SPACE, HYPER_SPACE_END - HYPER_SPACE + 1, FALSE);
84
85 // Protect the PFN database
86 MiCreateArm3StaticMemoryArea(MmPfnDatabase, (MxPfnAllocation << PAGE_SHIFT), FALSE);
87
88 // ReactOS requires a memory area to keep the initial NP area off-bounds
89 MiCreateArm3StaticMemoryArea(MmNonPagedPoolStart, MmSizeOfNonPagedPoolInBytes, FALSE);
90
91 // System PTE space
92 MiCreateArm3StaticMemoryArea(MmNonPagedSystemStart, (MmNumberOfSystemPtes + 1) * PAGE_SIZE, FALSE);
93
94 // Nonpaged pool expansion space
95 MiCreateArm3StaticMemoryArea(MmNonPagedPoolExpansionStart, (ULONG_PTR)MmNonPagedPoolEnd - (ULONG_PTR)MmNonPagedPoolExpansionStart, FALSE);
96
97 // System view space
98 MiCreateArm3StaticMemoryArea(MiSystemViewStart, MmSystemViewSize, FALSE);
99
100 // Session space
101 MiCreateArm3StaticMemoryArea(MmSessionBase, (ULONG_PTR)MiSessionSpaceEnd - (ULONG_PTR)MmSessionBase, FALSE);
102
103 // Paged pool
104 MiCreateArm3StaticMemoryArea(MmPagedPoolStart, MmSizeOfPagedPoolInBytes, FALSE);
105
106 // Debugger mapping
107 MiCreateArm3StaticMemoryArea(MI_DEBUG_MAPPING, PAGE_SIZE, FALSE);
108
109 #if defined(_X86_)
110 // Reserved HAL area (includes KUSER_SHARED_DATA and KPCR)
111 MiCreateArm3StaticMemoryArea((PVOID)MM_HAL_VA_START, MM_HAL_VA_END - MM_HAL_VA_START + 1, FALSE);
112 #else /* _X86_ */
113 #ifndef _M_AMD64
114 // KPCR, one page per CPU. Only for 32-bit kernel.
115 MiCreateArm3StaticMemoryArea(PCR, PAGE_SIZE * KeNumberProcessors, FALSE);
116 #endif /* _M_AMD64 */
117
118 // KUSER_SHARED_DATA
119 MiCreateArm3StaticMemoryArea((PVOID)KI_USER_SHARED_DATA, PAGE_SIZE, FALSE);
120 #endif /* _X86_ */
121 }
122
123 VOID
124 NTAPI
125 INIT_FUNCTION
126 MiDbgDumpAddressSpace(VOID)
127 {
128 //
129 // Print the memory layout
130 //
131 DPRINT1(" 0x%p - 0x%p\t%s\n",
132 KSEG0_BASE,
133 (ULONG_PTR)KSEG0_BASE + MmBootImageSize,
134 "Boot Loaded Image");
135 DPRINT1(" 0x%p - 0x%p\t%s\n",
136 MmPfnDatabase,
137 (ULONG_PTR)MmPfnDatabase + (MxPfnAllocation << PAGE_SHIFT),
138 "PFN Database");
139 DPRINT1(" 0x%p - 0x%p\t%s\n",
140 MmNonPagedPoolStart,
141 (ULONG_PTR)MmNonPagedPoolStart + MmSizeOfNonPagedPoolInBytes,
142 "ARM3 Non Paged Pool");
143 DPRINT1(" 0x%p - 0x%p\t%s\n",
144 MiSystemViewStart,
145 (ULONG_PTR)MiSystemViewStart + MmSystemViewSize,
146 "System View Space");
147 DPRINT1(" 0x%p - 0x%p\t%s\n",
148 MmSessionBase,
149 MiSessionSpaceEnd,
150 "Session Space");
151 DPRINT1(" 0x%p - 0x%p\t%s\n",
152 PTE_BASE, PTE_TOP,
153 "Page Tables");
154 DPRINT1(" 0x%p - 0x%p\t%s\n",
155 PDE_BASE, PDE_TOP,
156 "Page Directories");
157 DPRINT1(" 0x%p - 0x%p\t%s\n",
158 HYPER_SPACE, HYPER_SPACE_END,
159 "Hyperspace");
160 DPRINT1(" 0x%p - 0x%p\t%s\n",
161 MmPagedPoolStart,
162 (ULONG_PTR)MmPagedPoolStart + MmSizeOfPagedPoolInBytes,
163 "ARM3 Paged Pool");
164 DPRINT1(" 0x%p - 0x%p\t%s\n",
165 MmNonPagedSystemStart, MmNonPagedPoolExpansionStart,
166 "System PTE Space");
167 DPRINT1(" 0x%p - 0x%p\t%s\n",
168 MmNonPagedPoolExpansionStart, MmNonPagedPoolEnd,
169 "Non Paged Pool Expansion PTE Space");
170 }
171
172 VOID
173 NTAPI
174 MmMpwThreadMain(PVOID Parameter)
175 {
176 NTSTATUS Status;
177 #ifndef NEWCC
178 ULONG PagesWritten;
179 #endif
180 LARGE_INTEGER Timeout;
181
182 UNREFERENCED_PARAMETER(Parameter);
183
184 Timeout.QuadPart = -50000000;
185
186 for(;;)
187 {
188 Status = KeWaitForSingleObject(&MpwThreadEvent,
189 0,
190 KernelMode,
191 FALSE,
192 &Timeout);
193 if (!NT_SUCCESS(Status))
194 {
195 DbgPrint("MpwThread: Wait failed\n");
196 KeBugCheck(MEMORY_MANAGEMENT);
197 return;
198 }
199
200 #ifndef NEWCC
201 PagesWritten = 0;
202
203 // XXX arty -- we flush when evicting pages or destorying cache
204 // sections.
205 CcRosFlushDirtyPages(128, &PagesWritten, FALSE);
206 #endif
207 }
208 }
209
210 NTSTATUS
211 NTAPI
212 INIT_FUNCTION
213 MmInitMpwThread(VOID)
214 {
215 KPRIORITY Priority;
216 NTSTATUS Status;
217 CLIENT_ID MpwThreadId;
218
219 KeInitializeEvent(&MpwThreadEvent, SynchronizationEvent, FALSE);
220
221 Status = PsCreateSystemThread(&MpwThreadHandle,
222 THREAD_ALL_ACCESS,
223 NULL,
224 NULL,
225 &MpwThreadId,
226 MmMpwThreadMain,
227 NULL);
228 if (!NT_SUCCESS(Status))
229 {
230 return(Status);
231 }
232
233 Priority = 27;
234 NtSetInformationThread(MpwThreadHandle,
235 ThreadPriority,
236 &Priority,
237 sizeof(Priority));
238
239 return(STATUS_SUCCESS);
240 }
241
242 NTSTATUS
243 NTAPI
244 INIT_FUNCTION
245 MmInitBsmThread(VOID)
246 {
247 NTSTATUS Status;
248 OBJECT_ATTRIBUTES ObjectAttributes;
249 HANDLE ThreadHandle;
250
251 /* Create the thread */
252 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
253 Status = PsCreateSystemThread(&ThreadHandle,
254 THREAD_ALL_ACCESS,
255 &ObjectAttributes,
256 NULL,
257 NULL,
258 KeBalanceSetManager,
259 NULL);
260
261 /* Close the handle and return status */
262 ZwClose(ThreadHandle);
263 return Status;
264 }
265
266 BOOLEAN
267 NTAPI
268 INIT_FUNCTION
269 MmInitSystem(IN ULONG Phase,
270 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
271 {
272 extern MMPTE ValidKernelPte;
273 PMMPTE PointerPte;
274 MMPTE TempPte = ValidKernelPte;
275 PFN_NUMBER PageFrameNumber;
276
277 /* Initialize the kernel address space */
278 ASSERT(Phase == 1);
279
280 InitializeListHead(&MiSegmentList);
281 ExInitializeFastMutex(&MiGlobalPageOperation);
282 KeInitializeEvent(&MmWaitPageEvent, SynchronizationEvent, FALSE);
283 // Until we're fully demand paged, we can do things the old way through
284 // the balance manager
285 MmInitializeMemoryConsumer(MC_CACHE, MiRosTrimCache);
286
287 MmKernelAddressSpace = &PsIdleProcess->Vm;
288
289 /* Intialize system memory areas */
290 MiInitSystemMemoryAreas();
291
292 /* Dump the address space */
293 MiDbgDumpAddressSpace();
294
295 MmInitGlobalKernelPageDirectory();
296 MiInitializeUserPfnBitmap();
297 MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
298 MmInitializeRmapList();
299 MmInitSectionImplementation();
300 MmInitPagingFile();
301
302 //
303 // Create a PTE to double-map the shared data section. We allocate it
304 // from paged pool so that we can't fault when trying to touch the PTE
305 // itself (to map it), since paged pool addresses will already be mapped
306 // by the fault handler.
307 //
308 MmSharedUserDataPte = ExAllocatePoolWithTag(PagedPool,
309 sizeof(MMPTE),
310 TAG_MM);
311 if (!MmSharedUserDataPte) return FALSE;
312
313 //
314 // Now get the PTE for shared data, and read the PFN that holds it
315 //
316 PointerPte = MiAddressToPte((PVOID)KI_USER_SHARED_DATA);
317 ASSERT(PointerPte->u.Hard.Valid == 1);
318 PageFrameNumber = PFN_FROM_PTE(PointerPte);
319
320 /* Build the PTE and write it */
321 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte,
322 PointerPte,
323 MM_READONLY,
324 PageFrameNumber);
325 *MmSharedUserDataPte = TempPte;
326
327 /* Initialize session working set support */
328 MiInitializeSessionWsSupport();
329
330 /* Setup session IDs */
331 MiInitializeSessionIds();
332
333 /* Setup the memory threshold events */
334 if (!MiInitializeMemoryEvents()) return FALSE;
335
336 /*
337 * Unmap low memory
338 */
339 MiInitBalancerThread();
340
341 /*
342 * Initialise the modified page writer.
343 */
344 MmInitMpwThread();
345
346 /* Initialize the balance set manager */
347 MmInitBsmThread();
348
349 return TRUE;
350 }
351