[NTOS]
[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 VOID
42 INIT_FUNCTION
43 NTAPI
44 MiInitSystemMemoryAreas()
45 {
46 PVOID BaseAddress;
47 PHYSICAL_ADDRESS BoundaryAddressMultiple;
48 PMEMORY_AREA MArea;
49 NTSTATUS Status;
50 BoundaryAddressMultiple.QuadPart = 0;
51
52 //
53 // Create the memory area to define the loader mappings
54 //
55 BaseAddress = (PVOID)KSEG0_BASE;
56 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
57 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
58 &BaseAddress,
59 MmBootImageSize,
60 PAGE_EXECUTE_READWRITE,
61 &MArea,
62 TRUE,
63 0,
64 BoundaryAddressMultiple);
65 ASSERT(Status == STATUS_SUCCESS);
66
67 //
68 // Create the memory area to define the PTE base
69 //
70 BaseAddress = (PVOID)PTE_BASE;
71 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
72 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
73 &BaseAddress,
74 PTE_TOP - PTE_BASE + 1,
75 PAGE_READWRITE,
76 &MArea,
77 TRUE,
78 0,
79 BoundaryAddressMultiple);
80 ASSERT(Status == STATUS_SUCCESS);
81
82 //
83 // Create the memory area to define Hyperspace
84 //
85 BaseAddress = (PVOID)HYPER_SPACE;
86 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
87 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
88 &BaseAddress,
89 HYPER_SPACE_END - HYPER_SPACE + 1,
90 PAGE_READWRITE,
91 &MArea,
92 TRUE,
93 0,
94 BoundaryAddressMultiple);
95 ASSERT(Status == STATUS_SUCCESS);
96
97 //
98 // Protect the PFN database
99 //
100 BaseAddress = MmPfnDatabase;
101 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
102 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
103 &BaseAddress,
104 (MxPfnAllocation << PAGE_SHIFT),
105 PAGE_READWRITE,
106 &MArea,
107 TRUE,
108 0,
109 BoundaryAddressMultiple);
110 ASSERT(Status == STATUS_SUCCESS);
111
112 //
113 // ReactOS requires a memory area to keep the initial NP area off-bounds
114 //
115 BaseAddress = MmNonPagedPoolStart;
116 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
117 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
118 &BaseAddress,
119 MmSizeOfNonPagedPoolInBytes,
120 PAGE_READWRITE,
121 &MArea,
122 TRUE,
123 0,
124 BoundaryAddressMultiple);
125 ASSERT(Status == STATUS_SUCCESS);
126
127 //
128 // And we need one more for the system NP
129 //
130 BaseAddress = MmNonPagedSystemStart;
131 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
132 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
133 &BaseAddress,
134 MiNonPagedSystemSize,
135 PAGE_READWRITE,
136 &MArea,
137 TRUE,
138 0,
139 BoundaryAddressMultiple);
140 ASSERT(Status == STATUS_SUCCESS);
141
142 //
143 // We also need one for system view space
144 //
145 BaseAddress = MiSystemViewStart;
146 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
147 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
148 &BaseAddress,
149 MmSystemViewSize,
150 PAGE_READWRITE,
151 &MArea,
152 TRUE,
153 0,
154 BoundaryAddressMultiple);
155 ASSERT(Status == STATUS_SUCCESS);
156
157 //
158 // And another for session space
159 //
160 BaseAddress = MmSessionBase;
161 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
162 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
163 &BaseAddress,
164 (ULONG_PTR)MiSessionSpaceEnd -
165 (ULONG_PTR)MmSessionBase,
166 PAGE_READWRITE,
167 &MArea,
168 TRUE,
169 0,
170 BoundaryAddressMultiple);
171 ASSERT(Status == STATUS_SUCCESS);
172
173 //
174 // One more for ARM paged pool
175 //
176 BaseAddress = MmPagedPoolStart;
177 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
178 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
179 &BaseAddress,
180 MmSizeOfPagedPoolInBytes,
181 PAGE_READWRITE,
182 &MArea,
183 TRUE,
184 0,
185 BoundaryAddressMultiple);
186 ASSERT(Status == STATUS_SUCCESS);
187 #ifndef _M_AMD64
188 //
189 // Next, the KPCR
190 //
191 BaseAddress = (PVOID)PCR;
192 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
193 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
194 &BaseAddress,
195 PAGE_SIZE * KeNumberProcessors,
196 PAGE_READWRITE,
197 &MArea,
198 TRUE,
199 0,
200 BoundaryAddressMultiple);
201 ASSERT(Status == STATUS_SUCCESS);
202 #endif
203 //
204 // Now the KUSER_SHARED_DATA
205 //
206 BaseAddress = (PVOID)KI_USER_SHARED_DATA;
207 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
208 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
209 &BaseAddress,
210 PAGE_SIZE,
211 PAGE_READWRITE,
212 &MArea,
213 TRUE,
214 0,
215 BoundaryAddressMultiple);
216 ASSERT(Status == STATUS_SUCCESS);
217
218 //
219 // And the debugger mapping
220 //
221 BaseAddress = MI_DEBUG_MAPPING;
222 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
223 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
224 &BaseAddress,
225 PAGE_SIZE,
226 PAGE_READWRITE,
227 &MArea,
228 TRUE,
229 0,
230 BoundaryAddressMultiple);
231 ASSERT(Status == STATUS_SUCCESS);
232
233 #if defined(_X86_)
234 //
235 // Finally, reserve the 2 pages we currently make use of for HAL mappings
236 //
237 BaseAddress = (PVOID)0xFFC00000;
238 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
239 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
240 &BaseAddress,
241 PAGE_SIZE * 2,
242 PAGE_READWRITE,
243 &MArea,
244 TRUE,
245 0,
246 BoundaryAddressMultiple);
247 ASSERT(Status == STATUS_SUCCESS);
248 #endif
249 }
250
251 VOID
252 NTAPI
253 INIT_FUNCTION
254 MiDbgDumpAddressSpace(VOID)
255 {
256 //
257 // Print the memory layout
258 //
259 DPRINT1(" 0x%p - 0x%p\t%s\n",
260 KSEG0_BASE,
261 (ULONG_PTR)KSEG0_BASE + MmBootImageSize,
262 "Boot Loaded Image");
263 DPRINT1(" 0x%p - 0x%p\t%s\n",
264 MmPfnDatabase,
265 (ULONG_PTR)MmPfnDatabase + (MxPfnAllocation << PAGE_SHIFT),
266 "PFN Database");
267 DPRINT1(" 0x%p - 0x%p\t%s\n",
268 MmNonPagedPoolStart,
269 (ULONG_PTR)MmNonPagedPoolStart + MmSizeOfNonPagedPoolInBytes,
270 "ARM3 Non Paged Pool");
271 DPRINT1(" 0x%p - 0x%p\t%s\n",
272 MiSystemViewStart,
273 (ULONG_PTR)MiSystemViewStart + MmSystemViewSize,
274 "System View Space");
275 DPRINT1(" 0x%p - 0x%p\t%s\n",
276 MmSessionBase,
277 MiSessionSpaceEnd,
278 "Session Space");
279 DPRINT1(" 0x%p - 0x%p\t%s\n",
280 PTE_BASE, PTE_TOP,
281 "Page Tables");
282 DPRINT1(" 0x%p - 0x%p\t%s\n",
283 PDE_BASE, PDE_TOP,
284 "Page Directories");
285 DPRINT1(" 0x%p - 0x%p\t%s\n",
286 HYPER_SPACE, HYPER_SPACE_END,
287 "Hyperspace");
288 DPRINT1(" 0x%p - 0x%p\t%s\n",
289 MmPagedPoolStart,
290 (ULONG_PTR)MmPagedPoolStart + MmSizeOfPagedPoolInBytes,
291 "ARM3 Paged Pool");
292 DPRINT1(" 0x%p - 0x%p\t%s\n",
293 MmNonPagedSystemStart, MmNonPagedPoolExpansionStart,
294 "System PTE Space");
295 DPRINT1(" 0x%p - 0x%p\t%s\n",
296 MmNonPagedPoolExpansionStart, MmNonPagedPoolEnd,
297 "Non Paged Pool Expansion PTE Space");
298 }
299
300 VOID
301 NTAPI
302 MmMpwThreadMain(PVOID Parameter)
303 {
304 NTSTATUS Status;
305 ULONG PagesWritten;
306 LARGE_INTEGER Timeout;
307
308 UNREFERENCED_PARAMETER(Parameter);
309
310 Timeout.QuadPart = -50000000;
311
312 for(;;)
313 {
314 Status = KeWaitForSingleObject(&MpwThreadEvent,
315 0,
316 KernelMode,
317 FALSE,
318 &Timeout);
319 if (!NT_SUCCESS(Status))
320 {
321 DbgPrint("MpwThread: Wait failed\n");
322 KeBugCheck(MEMORY_MANAGEMENT);
323 return;
324 }
325
326 PagesWritten = 0;
327
328 #ifndef NEWCC
329 // XXX arty -- we flush when evicting pages or destorying cache
330 // sections.
331 CcRosFlushDirtyPages(128, &PagesWritten, FALSE);
332 #endif
333 }
334 }
335
336 NTSTATUS
337 NTAPI
338 INIT_FUNCTION
339 MmInitMpwThread(VOID)
340 {
341 KPRIORITY Priority;
342 NTSTATUS Status;
343 CLIENT_ID MpwThreadId;
344
345 KeInitializeEvent(&MpwThreadEvent, SynchronizationEvent, FALSE);
346
347 Status = PsCreateSystemThread(&MpwThreadHandle,
348 THREAD_ALL_ACCESS,
349 NULL,
350 NULL,
351 &MpwThreadId,
352 MmMpwThreadMain,
353 NULL);
354 if (!NT_SUCCESS(Status))
355 {
356 return(Status);
357 }
358
359 Priority = 27;
360 NtSetInformationThread(MpwThreadHandle,
361 ThreadPriority,
362 &Priority,
363 sizeof(Priority));
364
365 return(STATUS_SUCCESS);
366 }
367
368 NTSTATUS
369 NTAPI
370 INIT_FUNCTION
371 MmInitBsmThread(VOID)
372 {
373 NTSTATUS Status;
374 OBJECT_ATTRIBUTES ObjectAttributes;
375 HANDLE ThreadHandle;
376
377 /* Create the thread */
378 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
379 Status = PsCreateSystemThread(&ThreadHandle,
380 THREAD_ALL_ACCESS,
381 &ObjectAttributes,
382 NULL,
383 NULL,
384 KeBalanceSetManager,
385 NULL);
386
387 /* Close the handle and return status */
388 ZwClose(ThreadHandle);
389 return Status;
390 }
391
392 BOOLEAN
393 NTAPI
394 INIT_FUNCTION
395 MmInitSystem(IN ULONG Phase,
396 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
397 {
398 extern MMPTE ValidKernelPte;
399 PMMPTE PointerPte;
400 MMPTE TempPte = ValidKernelPte;
401 PFN_NUMBER PageFrameNumber;
402
403 /* Initialize the kernel address space */
404 ASSERT(Phase == 1);
405
406 InitializeListHead(&MiSegmentList);
407 ExInitializeFastMutex(&MiGlobalPageOperation);
408 KeInitializeEvent(&MmWaitPageEvent, SynchronizationEvent, FALSE);
409 // Until we're fully demand paged, we can do things the old way through
410 // the balance manager
411 MmInitializeMemoryConsumer(MC_CACHE, MiRosTrimCache);
412
413 MmKernelAddressSpace = &PsIdleProcess->Vm;
414
415 /* Intialize system memory areas */
416 MiInitSystemMemoryAreas();
417
418 /* Dump the address space */
419 MiDbgDumpAddressSpace();
420
421 MmInitGlobalKernelPageDirectory();
422 MiInitializeUserPfnBitmap();
423 MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
424 MmInitializeRmapList();
425 MmInitSectionImplementation();
426 MmInitPagingFile();
427
428 //
429 // Create a PTE to double-map the shared data section. We allocate it
430 // from paged pool so that we can't fault when trying to touch the PTE
431 // itself (to map it), since paged pool addresses will already be mapped
432 // by the fault handler.
433 //
434 MmSharedUserDataPte = ExAllocatePoolWithTag(PagedPool,
435 sizeof(MMPTE),
436 ' mM');
437 if (!MmSharedUserDataPte) return FALSE;
438
439 //
440 // Now get the PTE for shared data, and read the PFN that holds it
441 //
442 PointerPte = MiAddressToPte((PVOID)KI_USER_SHARED_DATA);
443 ASSERT(PointerPte->u.Hard.Valid == 1);
444 PageFrameNumber = PFN_FROM_PTE(PointerPte);
445
446 /* Build the PTE and write it */
447 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte,
448 PointerPte,
449 MM_READONLY,
450 PageFrameNumber);
451 *MmSharedUserDataPte = TempPte;
452
453 /* Setup session IDs */
454 MiInitializeSessionIds();
455
456 /* Setup the memory threshold events */
457 if (!MiInitializeMemoryEvents()) return FALSE;
458
459 /*
460 * Unmap low memory
461 */
462 MiInitBalancerThread();
463
464 /*
465 * Initialise the modified page writer.
466 */
467 MmInitMpwThread();
468
469 /* Initialize the balance set manager */
470 MmInitBsmThread();
471
472 return TRUE;
473 }
474