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