- Implemented a kernel mapping region which is process local.
[reactos.git] / reactos / ntoskrnl / mm / mminit.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/mminit.c
6 * PURPOSE: kernel memory managment initialization functions
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * UPDATE HISTORY:
9 * Created 9/4/98
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* GLOBALS *****************************************************************/
19
20 /*
21 * Compiler defined symbols
22 */
23 extern unsigned int _text_start__;
24 extern unsigned int _text_end__;
25
26 extern unsigned int _init_start__;
27 extern unsigned int _init_end__;
28
29 extern unsigned int _bss_end__;
30
31
32 static BOOLEAN IsThisAnNtAsSystem = FALSE;
33 static MM_SYSTEM_SIZE MmSystemSize = MmSmallSystem;
34
35 static MEMORY_AREA* kernel_text_desc = NULL;
36 static MEMORY_AREA* kernel_init_desc = NULL;
37 static MEMORY_AREA* kernel_kpcr_desc = NULL;
38 static MEMORY_AREA* kernel_data_desc = NULL;
39 static MEMORY_AREA* kernel_param_desc = NULL;
40 static MEMORY_AREA* kernel_pool_desc = NULL;
41 static MEMORY_AREA* kernel_shared_data_desc = NULL;
42 static MEMORY_AREA* kernel_mapped_vga_framebuffer_desc = NULL;
43 static MEMORY_AREA* MiKernelMapDescriptor = NULL;
44 static MEMORY_AREA* MiPagedPoolDescriptor = NULL;
45
46 PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress;
47
48 PVOID MiNonPagedPoolStart;
49 ULONG MiNonPagedPoolLength;
50 //PVOID MiKernelMapStart;
51
52
53 /* FUNCTIONS ****************************************************************/
54
55 /*
56 * @implemented
57 */
58 BOOLEAN STDCALL MmIsThisAnNtAsSystem(VOID)
59 {
60 return(IsThisAnNtAsSystem);
61 }
62
63 /*
64 * @implemented
65 */
66 MM_SYSTEM_SIZE STDCALL MmQuerySystemSize(VOID)
67 {
68 return(MmSystemSize);
69 }
70
71 VOID MiShutdownMemoryManager(VOID)
72 {}
73
74 VOID INIT_FUNCTION
75 MmInitVirtualMemory(ULONG_PTR LastKernelAddress,
76 ULONG KernelLength)
77 /*
78 * FUNCTION: Intialize the memory areas list
79 * ARGUMENTS:
80 * bp = Pointer to the boot parameters
81 * kernel_len = Length of the kernel
82 */
83 {
84 PVOID BaseAddress;
85 ULONG Length;
86 ULONG ParamLength = KernelLength;
87 NTSTATUS Status;
88 PHYSICAL_ADDRESS BoundaryAddressMultiple;
89 PFN_TYPE Pfn;
90
91 DPRINT("MmInitVirtualMemory(%x, %x)\n",LastKernelAddress, KernelLength);
92
93 BoundaryAddressMultiple.QuadPart = 0;
94 LastKernelAddress = PAGE_ROUND_UP(LastKernelAddress);
95
96 MmInitMemoryAreas();
97
98 MiNonPagedPoolStart = (char*)LastKernelAddress + PAGE_SIZE;
99 MiNonPagedPoolLength = MM_NONPAGED_POOL_SIZE;
100
101 MmPagedPoolBase = (char*)MiNonPagedPoolStart + MiNonPagedPoolLength + PAGE_SIZE;
102 MmPagedPoolSize = MM_PAGED_POOL_SIZE;
103
104 MiInitializeNonPagedPool();
105
106 /*
107 * Setup the system area descriptor list
108 */
109 MiInitPageDirectoryMap();
110
111 BaseAddress = (PVOID)KPCR_BASE;
112 MmCreateMemoryArea(NULL,
113 MmGetKernelAddressSpace(),
114 MEMORY_AREA_SYSTEM,
115 &BaseAddress,
116 PAGE_SIZE * MAXIMUM_PROCESSORS,
117 0,
118 &kernel_kpcr_desc,
119 TRUE,
120 FALSE,
121 BoundaryAddressMultiple);
122
123 BaseAddress = (PVOID)0xFF3A0000;
124 MmCreateMemoryArea(NULL,
125 MmGetKernelAddressSpace(),
126 MEMORY_AREA_SYSTEM,
127 &BaseAddress,
128 0x20000,
129 0,
130 &kernel_mapped_vga_framebuffer_desc,
131 TRUE,
132 FALSE,
133 BoundaryAddressMultiple);
134
135 BaseAddress = (PVOID)KERNEL_BASE;
136 Length = PAGE_ROUND_UP(((ULONG_PTR)&_text_end__)) - KERNEL_BASE;
137 ParamLength = ParamLength - Length;
138
139 /*
140 * No need to lock the address space at this point since no
141 * other threads are running.
142 */
143 MmCreateMemoryArea(NULL,
144 MmGetKernelAddressSpace(),
145 MEMORY_AREA_SYSTEM,
146 &BaseAddress,
147 Length,
148 0,
149 &kernel_text_desc,
150 TRUE,
151 FALSE,
152 BoundaryAddressMultiple);
153
154 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG_PTR)&_text_end__));
155 ASSERT(BaseAddress == (PVOID)&_init_start__);
156 Length = PAGE_ROUND_UP(((ULONG_PTR)&_init_end__)) -
157 PAGE_ROUND_UP(((ULONG_PTR)&_text_end__));
158 ParamLength = ParamLength - Length;
159
160 MmCreateMemoryArea(NULL,
161 MmGetKernelAddressSpace(),
162 MEMORY_AREA_SYSTEM,
163 &BaseAddress,
164 Length,
165 0,
166 &kernel_init_desc,
167 TRUE,
168 FALSE,
169 BoundaryAddressMultiple);
170
171 Length = PAGE_ROUND_UP(((ULONG_PTR)&_bss_end__)) -
172 PAGE_ROUND_UP(((ULONG_PTR)&_init_end__));
173 ParamLength = ParamLength - Length;
174 DPRINT("Length %x\n",Length);
175 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG_PTR)&_init_end__));
176 DPRINT("BaseAddress %x\n",BaseAddress);
177
178 /*
179 * No need to lock the address space at this point since we are
180 * the only thread running.
181 */
182 MmCreateMemoryArea(NULL,
183 MmGetKernelAddressSpace(),
184 MEMORY_AREA_SYSTEM,
185 &BaseAddress,
186 Length,
187 0,
188 &kernel_data_desc,
189 TRUE,
190 FALSE,
191 BoundaryAddressMultiple);
192
193 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG_PTR)&_bss_end__));
194 Length = LastKernelAddress - (ULONG_PTR)BaseAddress;
195 MmCreateMemoryArea(NULL,
196 MmGetKernelAddressSpace(),
197 MEMORY_AREA_SYSTEM,
198 &BaseAddress,
199 Length,
200 0,
201 &kernel_param_desc,
202 TRUE,
203 FALSE,
204 BoundaryAddressMultiple);
205
206 BaseAddress = MiNonPagedPoolStart;
207 MmCreateMemoryArea(NULL,
208 MmGetKernelAddressSpace(),
209 MEMORY_AREA_SYSTEM,
210 &BaseAddress,
211 MiNonPagedPoolLength,
212 0,
213 &kernel_pool_desc,
214 TRUE,
215 FALSE,
216 BoundaryAddressMultiple);
217
218 BaseAddress = (PVOID)MM_KERNEL_MAP_BASE;
219 Status = MmCreateMemoryArea(NULL,
220 MmGetKernelAddressSpace(),
221 MEMORY_AREA_SYSTEM,
222 &BaseAddress,
223 MM_KERNEL_MAP_SIZE,
224 0,
225 &MiKernelMapDescriptor,
226 TRUE,
227 FALSE,
228 BoundaryAddressMultiple);
229
230 BaseAddress = MmPagedPoolBase;
231 Status = MmCreateMemoryArea(NULL,
232 MmGetKernelAddressSpace(),
233 MEMORY_AREA_PAGED_POOL,
234 &BaseAddress,
235 MmPagedPoolSize,
236 0,
237 &MiPagedPoolDescriptor,
238 TRUE,
239 FALSE,
240 BoundaryAddressMultiple);
241
242 MmInitializePagedPool();
243
244 /*
245 * Create the kernel mapping of the user/kernel shared memory.
246 */
247 BaseAddress = (PVOID)KI_USER_SHARED_DATA;
248 Length = PAGE_SIZE;
249 MmCreateMemoryArea(NULL,
250 MmGetKernelAddressSpace(),
251 MEMORY_AREA_SYSTEM,
252 &BaseAddress,
253 Length,
254 0,
255 &kernel_shared_data_desc,
256 TRUE,
257 FALSE,
258 BoundaryAddressMultiple);
259 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Pfn);
260 MmSharedDataPagePhysicalAddress.QuadPart = Pfn << PAGE_SHIFT;
261 Status = MmCreateVirtualMapping(NULL,
262 (PVOID)KI_USER_SHARED_DATA,
263 PAGE_READWRITE,
264 &Pfn,
265 1);
266 if (!NT_SUCCESS(Status))
267 {
268 DbgPrint("Unable to create virtual mapping\n");
269 KEBUGCHECK(0);
270 }
271 RtlZeroMemory(BaseAddress, Length);
272
273 /*
274 *
275 */
276 MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
277 }
278
279 VOID INIT_FUNCTION
280 MmInit1(ULONG_PTR FirstKrnlPhysAddr,
281 ULONG_PTR LastKrnlPhysAddr,
282 ULONG_PTR LastKernelAddress,
283 PADDRESS_RANGE BIOSMemoryMap,
284 ULONG AddressRangeCount,
285 ULONG MaxMem)
286 /*
287 * FUNCTION: Initalize memory managment
288 */
289 {
290 ULONG i;
291 ULONG kernel_len;
292 ULONG_PTR MappingAddress;
293 #ifndef CONFIG_SMP
294 extern unsigned int unmap_me, unmap_me2, unmap_me3;
295 #endif
296 extern unsigned int pagetable_start, pagetable_end;
297
298 DPRINT("MmInit1(FirstKrnlPhysAddr, %p, LastKrnlPhysAddr %p, LastKernelAddress %p)\n",
299 FirstKrnlPhysAddr,
300 LastKrnlPhysAddr,
301 LastKernelAddress);
302
303
304 if ((BIOSMemoryMap != NULL) && (AddressRangeCount > 0))
305 {
306 // If we have a bios memory map, recalulate the memory size
307 ULONG last = 0;
308 for (i = 0; i < AddressRangeCount; i++)
309 {
310 if (BIOSMemoryMap[i].Type == 1
311 && (BIOSMemoryMap[i].BaseAddrLow + BIOSMemoryMap[i].LengthLow + PAGE_SIZE -1) / PAGE_SIZE > last)
312 {
313 last = (BIOSMemoryMap[i].BaseAddrLow + BIOSMemoryMap[i].LengthLow + PAGE_SIZE -1) / PAGE_SIZE;
314 }
315 }
316 if ((last - 256) * 4 > KeLoaderBlock.MemHigher)
317 {
318 KeLoaderBlock.MemHigher = (last - 256) * 4;
319 }
320 }
321
322 if (KeLoaderBlock.MemHigher >= (MaxMem - 1) * 1024)
323 {
324 KeLoaderBlock.MemHigher = (MaxMem - 1) * 1024;
325 }
326
327 /*
328 * FIXME: Set this based on the system command line
329 */
330 MmSystemRangeStart = (PVOID)KERNEL_BASE; // 0xC0000000
331 MmUserProbeAddress = 0x7fff0000;
332 MmHighestUserAddress = (PVOID)0x7ffeffff;
333
334 /*
335 * Initialize memory managment statistics
336 */
337 MmStats.NrTotalPages = 0;
338 MmStats.NrSystemPages = 0;
339 MmStats.NrUserPages = 0;
340 MmStats.NrReservedPages = 0;
341 MmStats.NrUserPages = 0;
342 MmStats.NrFreePages = 0;
343 MmStats.NrLockedPages = 0;
344 MmStats.PagingRequestsInLastMinute = 0;
345 MmStats.PagingRequestsInLastFiveMinutes = 0;
346 MmStats.PagingRequestsInLastFifteenMinutes = 0;
347
348 /*
349 * Free all pages not used for kernel memory
350 * (we assume the kernel occupies a continuous range of physical
351 * memory)
352 */
353 DPRINT("first krnl %x\nlast krnl %x\n",FirstKrnlPhysAddr,
354 LastKrnlPhysAddr);
355
356 /*
357 * Free physical memory not used by the kernel
358 */
359 MmStats.NrTotalPages = KeLoaderBlock.MemHigher/4;
360 if (!MmStats.NrTotalPages)
361 {
362 DbgPrint("Memory not detected, default to 8 MB\n");
363 MmStats.NrTotalPages = 2048;
364 }
365 else
366 {
367 /* add 1MB for standard memory (not extended) */
368 MmStats.NrTotalPages += 256;
369 }
370 #ifdef BIOS_MEM_FIX
371 MmStats.NrTotalPages += 16;
372 #endif
373
374 /*
375 * Initialize the kernel address space
376 */
377 MmInitializeKernelAddressSpace();
378
379 MmInitGlobalKernelPageDirectory();
380
381 DbgPrint("Used memory %dKb\n", (MmStats.NrTotalPages * PAGE_SIZE) / 1024);
382
383 LastKernelAddress = (ULONG_PTR)MmInitializePageList(
384 FirstKrnlPhysAddr,
385 LastKrnlPhysAddr,
386 MmStats.NrTotalPages,
387 PAGE_ROUND_UP(LastKernelAddress),
388 BIOSMemoryMap,
389 AddressRangeCount);
390 kernel_len = LastKrnlPhysAddr - FirstKrnlPhysAddr;
391
392 /*
393 * Unmap low memory
394 */
395 #ifndef CONFIG_SMP
396 /* In SMP mode we unmap the low memory in MmInit3.
397 The APIC needs the mapping of the first pages
398 while the processors are starting up. */
399 MmDeletePageTable(NULL, 0);
400 #endif
401
402
403
404 DPRINT("Invalidating between %x and %x\n",
405 LastKernelAddress, KERNEL_BASE + 0x00600000);
406 for (MappingAddress = LastKernelAddress;
407 MappingAddress < KERNEL_BASE + 0x00600000;
408 MappingAddress += PAGE_SIZE)
409 {
410 MmRawDeleteVirtualMapping((PVOID)MappingAddress);
411 }
412
413 for (MappingAddress = (ULONG_PTR)&pagetable_start;
414 MappingAddress < (ULONG_PTR)&pagetable_end;
415 MappingAddress += PAGE_SIZE)
416 {
417 MmDeleteVirtualMapping(NULL, (PVOID)MappingAddress, FALSE, NULL, NULL);
418 }
419
420 DPRINT("Almost done MmInit()\n");
421 #ifndef CONFIG_SMP
422 /* FIXME: This is broken in SMP mode */
423 MmDeleteVirtualMapping(NULL, (PVOID)&unmap_me, TRUE, NULL, NULL);
424 MmDeleteVirtualMapping(NULL, (PVOID)&unmap_me2, TRUE, NULL, NULL);
425 MmDeleteVirtualMapping(NULL, (PVOID)&unmap_me3, TRUE, NULL, NULL);
426 #endif
427 /*
428 * Intialize memory areas
429 */
430 MmInitVirtualMemory(LastKernelAddress, kernel_len);
431
432 MmInitializeMdlImplementation();
433 }
434
435 VOID INIT_FUNCTION
436 MmInit2(VOID)
437 {
438 MmInitializeRmapList();
439 MmInitializePageOp();
440 MmInitSectionImplementation();
441 MmInitPagingFile();
442 }
443
444 VOID INIT_FUNCTION
445 MmInit3(VOID)
446 {
447 /*
448 * Unmap low memory
449 */
450 #ifdef CONFIG_SMP
451 /* In SMP mode we can unmap the low memory
452 if all processors are started. */
453 MmDeletePageTable(NULL, 0);
454 #endif
455
456 MmInitZeroPageThread();
457 MmCreatePhysicalMemorySection();
458 MiInitBalancerThread();
459
460 /*
461 * Initialise the modified page writer.
462 */
463 MmInitMpwThread();
464
465 /* FIXME: Read parameters from memory */
466 }
467
468 VOID STATIC
469 MiFreeInitMemoryPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
470 PFN_TYPE Page, SWAPENTRY SwapEntry,
471 BOOLEAN Dirty)
472 {
473 ASSERT(SwapEntry == 0);
474 if (Page != 0)
475 {
476 MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
477 }
478 }
479
480 VOID
481 MiFreeInitMemory(VOID)
482 {
483 MmLockAddressSpace(MmGetKernelAddressSpace());
484 MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
485 (PVOID)&_init_start__,
486 MiFreeInitMemoryPage,
487 NULL);
488 MmUnlockAddressSpace(MmGetKernelAddressSpace());
489 }