[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()
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 NP
92 MiCreateArm3StaticMemoryArea(MmNonPagedSystemStart, MiNonPagedSystemSize, FALSE);
93
94 // System view space
95 MiCreateArm3StaticMemoryArea(MiSystemViewStart, MmSystemViewSize, FALSE);
96
97 // Session space
98 MiCreateArm3StaticMemoryArea(MmSessionBase, (ULONG_PTR)MiSessionSpaceEnd - (ULONG_PTR)MmSessionBase, FALSE);
99
100 // Paged pool
101 MiCreateArm3StaticMemoryArea(MmPagedPoolStart, MmSizeOfPagedPoolInBytes, FALSE);
102
103 #ifndef _M_AMD64
104 // KPCR, one page per CPU. Only for 32-bit kernel.
105 MiCreateArm3StaticMemoryArea(PCR, PAGE_SIZE * KeNumberProcessors, FALSE);
106 #endif
107
108 // KUSER_SHARED_DATA
109 MiCreateArm3StaticMemoryArea((PVOID)KI_USER_SHARED_DATA, PAGE_SIZE, FALSE);
110
111 // Debugger mapping
112 MiCreateArm3StaticMemoryArea(MI_DEBUG_MAPPING, PAGE_SIZE, FALSE);
113
114 #if defined(_X86_)
115 // Reserve the 2 pages we currently make use of for HAL mappings.
116 // TODO: Remove hard-coded constant and replace with a define.
117 MiCreateArm3StaticMemoryArea((PVOID)0xFFC00000, PAGE_SIZE * 2, FALSE);
118 #endif
119 }
120
121 VOID
122 NTAPI
123 INIT_FUNCTION
124 MiDbgDumpAddressSpace(VOID)
125 {
126 //
127 // Print the memory layout
128 //
129 DPRINT1(" 0x%p - 0x%p\t%s\n",
130 KSEG0_BASE,
131 (ULONG_PTR)KSEG0_BASE + MmBootImageSize,
132 "Boot Loaded Image");
133 DPRINT1(" 0x%p - 0x%p\t%s\n",
134 MmPfnDatabase,
135 (ULONG_PTR)MmPfnDatabase + (MxPfnAllocation << PAGE_SHIFT),
136 "PFN Database");
137 DPRINT1(" 0x%p - 0x%p\t%s\n",
138 MmNonPagedPoolStart,
139 (ULONG_PTR)MmNonPagedPoolStart + MmSizeOfNonPagedPoolInBytes,
140 "ARM3 Non Paged Pool");
141 DPRINT1(" 0x%p - 0x%p\t%s\n",
142 MiSystemViewStart,
143 (ULONG_PTR)MiSystemViewStart + MmSystemViewSize,
144 "System View Space");
145 DPRINT1(" 0x%p - 0x%p\t%s\n",
146 MmSessionBase,
147 MiSessionSpaceEnd,
148 "Session Space");
149 DPRINT1(" 0x%p - 0x%p\t%s\n",
150 PTE_BASE, PTE_TOP,
151 "Page Tables");
152 DPRINT1(" 0x%p - 0x%p\t%s\n",
153 PDE_BASE, PDE_TOP,
154 "Page Directories");
155 DPRINT1(" 0x%p - 0x%p\t%s\n",
156 HYPER_SPACE, HYPER_SPACE_END,
157 "Hyperspace");
158 DPRINT1(" 0x%p - 0x%p\t%s\n",
159 MmPagedPoolStart,
160 (ULONG_PTR)MmPagedPoolStart + MmSizeOfPagedPoolInBytes,
161 "ARM3 Paged Pool");
162 DPRINT1(" 0x%p - 0x%p\t%s\n",
163 MmNonPagedSystemStart, MmNonPagedPoolExpansionStart,
164 "System PTE Space");
165 DPRINT1(" 0x%p - 0x%p\t%s\n",
166 MmNonPagedPoolExpansionStart, MmNonPagedPoolEnd,
167 "Non Paged Pool Expansion PTE Space");
168 }
169
170 VOID
171 NTAPI
172 MmMpwThreadMain(PVOID Parameter)
173 {
174 NTSTATUS Status;
175 #ifndef NEWCC
176 ULONG PagesWritten;
177 #endif
178 LARGE_INTEGER Timeout;
179
180 UNREFERENCED_PARAMETER(Parameter);
181
182 Timeout.QuadPart = -50000000;
183
184 for(;;)
185 {
186 Status = KeWaitForSingleObject(&MpwThreadEvent,
187 0,
188 KernelMode,
189 FALSE,
190 &Timeout);
191 if (!NT_SUCCESS(Status))
192 {
193 DbgPrint("MpwThread: Wait failed\n");
194 KeBugCheck(MEMORY_MANAGEMENT);
195 return;
196 }
197
198 #ifndef NEWCC
199 PagesWritten = 0;
200
201 // XXX arty -- we flush when evicting pages or destorying cache
202 // sections.
203 CcRosFlushDirtyPages(128, &PagesWritten, FALSE);
204 #endif
205 }
206 }
207
208 NTSTATUS
209 NTAPI
210 INIT_FUNCTION
211 MmInitMpwThread(VOID)
212 {
213 KPRIORITY Priority;
214 NTSTATUS Status;
215 CLIENT_ID MpwThreadId;
216
217 KeInitializeEvent(&MpwThreadEvent, SynchronizationEvent, FALSE);
218
219 Status = PsCreateSystemThread(&MpwThreadHandle,
220 THREAD_ALL_ACCESS,
221 NULL,
222 NULL,
223 &MpwThreadId,
224 MmMpwThreadMain,
225 NULL);
226 if (!NT_SUCCESS(Status))
227 {
228 return(Status);
229 }
230
231 Priority = 27;
232 NtSetInformationThread(MpwThreadHandle,
233 ThreadPriority,
234 &Priority,
235 sizeof(Priority));
236
237 return(STATUS_SUCCESS);
238 }
239
240 NTSTATUS
241 NTAPI
242 INIT_FUNCTION
243 MmInitBsmThread(VOID)
244 {
245 NTSTATUS Status;
246 OBJECT_ATTRIBUTES ObjectAttributes;
247 HANDLE ThreadHandle;
248
249 /* Create the thread */
250 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
251 Status = PsCreateSystemThread(&ThreadHandle,
252 THREAD_ALL_ACCESS,
253 &ObjectAttributes,
254 NULL,
255 NULL,
256 KeBalanceSetManager,
257 NULL);
258
259 /* Close the handle and return status */
260 ZwClose(ThreadHandle);
261 return Status;
262 }
263
264 BOOLEAN
265 NTAPI
266 INIT_FUNCTION
267 MmInitSystem(IN ULONG Phase,
268 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
269 {
270 extern MMPTE ValidKernelPte;
271 PMMPTE PointerPte;
272 MMPTE TempPte = ValidKernelPte;
273 PFN_NUMBER PageFrameNumber;
274
275 /* Initialize the kernel address space */
276 ASSERT(Phase == 1);
277
278 InitializeListHead(&MiSegmentList);
279 ExInitializeFastMutex(&MiGlobalPageOperation);
280 KeInitializeEvent(&MmWaitPageEvent, SynchronizationEvent, FALSE);
281 // Until we're fully demand paged, we can do things the old way through
282 // the balance manager
283 MmInitializeMemoryConsumer(MC_CACHE, MiRosTrimCache);
284
285 MmKernelAddressSpace = &PsIdleProcess->Vm;
286
287 /* Intialize system memory areas */
288 MiInitSystemMemoryAreas();
289
290 /* Dump the address space */
291 MiDbgDumpAddressSpace();
292
293 MmInitGlobalKernelPageDirectory();
294 MiInitializeUserPfnBitmap();
295 MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
296 MmInitializeRmapList();
297 MmInitSectionImplementation();
298 MmInitPagingFile();
299
300 //
301 // Create a PTE to double-map the shared data section. We allocate it
302 // from paged pool so that we can't fault when trying to touch the PTE
303 // itself (to map it), since paged pool addresses will already be mapped
304 // by the fault handler.
305 //
306 MmSharedUserDataPte = ExAllocatePoolWithTag(PagedPool,
307 sizeof(MMPTE),
308 ' mM');
309 if (!MmSharedUserDataPte) return FALSE;
310
311 //
312 // Now get the PTE for shared data, and read the PFN that holds it
313 //
314 PointerPte = MiAddressToPte((PVOID)KI_USER_SHARED_DATA);
315 ASSERT(PointerPte->u.Hard.Valid == 1);
316 PageFrameNumber = PFN_FROM_PTE(PointerPte);
317
318 /* Build the PTE and write it */
319 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte,
320 PointerPte,
321 MM_READONLY,
322 PageFrameNumber);
323 *MmSharedUserDataPte = TempPte;
324
325 /* Initialize session working set support */
326 MiInitializeSessionWsSupport();
327
328 /* Setup session IDs */
329 MiInitializeSessionIds();
330
331 /* Setup the memory threshold events */
332 if (!MiInitializeMemoryEvents()) return FALSE;
333
334 /*
335 * Unmap low memory
336 */
337 MiInitBalancerThread();
338
339 /*
340 * Initialise the modified page writer.
341 */
342 MmInitMpwThread();
343
344 /* Initialize the balance set manager */
345 MmInitBsmThread();
346
347 return TRUE;
348 }
349