raddr2line utility
[reactos.git] / msvc6 / ntoskrnl / mm_mminit_msvc.c
1 /* $Id: mm_mminit_msvc.c,v 1.1 2004/02/06 08:22:01 fireball Exp $
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 <ddk/ntddk.h>
15 #include <roscfg.h>
16 #include <internal/i386/segment.h>
17 #include <internal/mm.h>
18 #include <internal/ntoskrnl.h>
19 #include <internal/io.h>
20 #include <internal/ps.h>
21 #include <internal/pool.h>
22
23 #define NDEBUG
24 #include <internal/debug.h>
25
26 /* GLOBALS *****************************************************************/
27
28 /*
29 * Size of extended memory (kb) (fixed for now)
30 */
31 #define EXTENDED_MEMORY_SIZE (3*1024*1024)
32
33 /*
34 * Compiler defined symbols
35 */
36
37 #if defined(_MSC_VER)
38
39 #pragma intrinsic(strcmp)
40
41 static PIMAGE_SECTION_HEADER FindSection(const char* szSeg)
42 {
43 PIMAGE_NT_HEADERS NtHeader = RtlImageNtHeader((PVOID)KERNEL_BASE);
44 PIMAGE_SECTION_HEADER Section = IMAGE_FIRST_SECTION(NtHeader);
45 const int count = NtHeader->FileHeader.NumberOfSections;
46 int i;
47 for (i = 0; i < count; ++i, ++Section)
48 {
49 if (!strcmp(szSeg, Section->Name))
50 {
51 return Section;
52 }
53 }
54 return NULL;
55 }
56
57 static void* FindSegmentStart(const char* szSeg)
58 {
59 PIMAGE_SECTION_HEADER Section = FindSection(szSeg);
60 if (Section)
61 {
62 return (void*)(KERNEL_BASE + Section->VirtualAddress);
63 }
64 return NULL;
65 }
66
67 static void* FindSegmentEnd(const char* szSeg)
68 {
69 PIMAGE_SECTION_HEADER Section = FindSection(szSeg);
70 if (Section)
71 {
72 return (void*)(KERNEL_BASE + Section->VirtualAddress + Section->Misc.VirtualSize);
73 }
74 return NULL;
75 }
76
77 #endif // defined(_MSC_VER)
78
79
80 static BOOLEAN IsThisAnNtAsSystem = FALSE;
81 static MM_SYSTEM_SIZE MmSystemSize = MmSmallSystem;
82
83 static MEMORY_AREA* kernel_text_desc = NULL;
84 static MEMORY_AREA* kernel_init_desc = NULL;
85 static MEMORY_AREA* kernel_map_desc = NULL;
86 static MEMORY_AREA* kernel_kpcr_desc = NULL;
87 static MEMORY_AREA* kernel_data_desc = NULL;
88 static MEMORY_AREA* kernel_param_desc = NULL;
89 static MEMORY_AREA* kernel_pool_desc = NULL;
90 static MEMORY_AREA* kernel_shared_data_desc = NULL;
91 static MEMORY_AREA* kernel_mapped_low_mem_desc = NULL;
92 static MEMORY_AREA* MiKernelMapDescriptor = NULL;
93 static MEMORY_AREA* MiPagedPoolDescriptor = NULL;
94
95 PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress;
96
97 PVOID MiNonPagedPoolStart;
98 ULONG MiNonPagedPoolLength;
99 PVOID MiKernelMapStart;
100 ULONG MiKernelMapLength;
101
102 /* FUNCTIONS ****************************************************************/
103
104 /*
105 * @implemented
106 */
107 BOOLEAN STDCALL MmIsThisAnNtAsSystem(VOID)
108 {
109 return(IsThisAnNtAsSystem);
110 }
111
112 /*
113 * @implemented
114 */
115 MM_SYSTEM_SIZE STDCALL MmQuerySystemSize(VOID)
116 {
117 return(MmSystemSize);
118 }
119
120 VOID MiShutdownMemoryManager(VOID)
121 {
122 }
123
124 VOID INIT_FUNCTION
125 MmInitVirtualMemory(ULONG LastKernelAddress,
126 ULONG KernelLength)
127 /*
128 * FUNCTION: Intialize the memory areas list
129 * ARGUMENTS:
130 * bp = Pointer to the boot parameters
131 * kernel_len = Length of the kernel
132 */
133 {
134 PVOID BaseAddress;
135 ULONG Length;
136 ULONG ParamLength = KernelLength;
137 NTSTATUS Status;
138 PHYSICAL_ADDRESS BoundaryAddressMultiple;
139 //ULONG i;
140
141 DPRINT("MmInitVirtualMemory(%x, %x)\n",LastKernelAddress, KernelLength);
142
143 BoundaryAddressMultiple.QuadPart = 0;
144 LastKernelAddress = PAGE_ROUND_UP(LastKernelAddress);
145
146 MmInitMemoryAreas();
147
148 /* Don't change the start of kernel map. Pte's must always exist for this region. */
149 MiKernelMapStart = (char*)LastKernelAddress + PAGE_SIZE;
150 MiKernelMapLength = MM_KERNEL_MAP_SIZE;
151
152 MiNonPagedPoolStart = (char*)MiKernelMapStart + MiKernelMapLength + PAGE_SIZE;
153 MiNonPagedPoolLength = MM_NONPAGED_POOL_SIZE;
154
155 MmPagedPoolBase = (char*)MiNonPagedPoolStart + MiNonPagedPoolLength + PAGE_SIZE;
156 MmPagedPoolSize = MM_PAGED_POOL_SIZE;
157
158 MiInitKernelMap();
159 MiInitializeNonPagedPool();
160
161 /*
162 * Setup the system area descriptor list
163 */
164 BaseAddress = (PVOID)0xf0000000;
165 MmCreateMemoryArea(NULL,
166 MmGetKernelAddressSpace(),
167 MEMORY_AREA_SYSTEM,
168 &BaseAddress,
169 0x400000,
170 0,
171 &kernel_map_desc,
172 FALSE,
173 FALSE,
174 BoundaryAddressMultiple);
175
176 BaseAddress = (PVOID)KPCR_BASE;
177 MmCreateMemoryArea(NULL,
178 MmGetKernelAddressSpace(),
179 MEMORY_AREA_SYSTEM,
180 &BaseAddress,
181 PAGE_SIZE * MAXIMUM_PROCESSORS,
182 0,
183 &kernel_kpcr_desc,
184 FALSE,
185 FALSE,
186 BoundaryAddressMultiple);
187
188 BaseAddress = (PVOID)0xd0000000;
189 MmCreateMemoryArea(NULL,
190 MmGetKernelAddressSpace(),
191 MEMORY_AREA_SYSTEM,
192 &BaseAddress,
193 0x100000,
194 0,
195 &kernel_mapped_low_mem_desc,
196 FALSE,
197 FALSE,
198 BoundaryAddressMultiple);
199
200 BaseAddress = (PVOID)KERNEL_BASE;
201 Length = PAGE_ROUND_UP(((ULONG)FindSegmentEnd(".text"))) - KERNEL_BASE;
202 ParamLength = ParamLength - Length;
203
204 /*
205 * No need to lock the address space at this point since no
206 * other threads are running.
207 */
208 MmCreateMemoryArea(NULL,
209 MmGetKernelAddressSpace(),
210 MEMORY_AREA_SYSTEM,
211 &BaseAddress,
212 Length,
213 0,
214 &kernel_text_desc,
215 FALSE,
216 FALSE,
217 BoundaryAddressMultiple);
218 // TODO: Here we REALLY should iterate the PE's sections and set protection
219 // accordingly for each and every one of them.
220
221 // NOTE This code ONLY works because of the assumption that the .text
222 // segment is the first in the PE, and the .reloc segment is the last.
223 // Link in a way to make this assumtion false, and the kernel won't work.
224 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)FindSegmentEnd(".text")));
225 Length = PAGE_ROUND_UP(((ULONG)FindSegmentStart(".reloc"))) - (ULONG_PTR)BaseAddress;
226 ParamLength = ParamLength - Length;
227 DPRINT1("Data Length %x\n",Length);
228 DPRINT1("Data BaseAddress %x\n",BaseAddress);
229
230 /*
231 * No need to lock the address space at this point since we are
232 * the only thread running.
233 */
234 // For GCC-compiled, kernel_data_desc contains:
235 // .data, .edata, .idata, .bss and .rsrc. E.i. all but .text and .reloc
236 MmCreateMemoryArea(NULL,
237 MmGetKernelAddressSpace(),
238 MEMORY_AREA_SYSTEM,
239 &BaseAddress,
240 Length,
241 0,
242 &kernel_data_desc,
243 FALSE,
244 FALSE,
245 BoundaryAddressMultiple);
246
247 // BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)FindSegmentEnd(".edata")));
248 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)FindSegmentStart(".reloc")));
249 Length = LastKernelAddress - (ULONG)BaseAddress;
250 // For GCC-compiled, kernel_param_desc contains .reloc
251 MmCreateMemoryArea(NULL,
252 MmGetKernelAddressSpace(),
253 MEMORY_AREA_SYSTEM,
254 &BaseAddress,
255 Length,
256 0,
257 &kernel_param_desc,
258 FALSE,
259 FALSE,
260 BoundaryAddressMultiple);
261
262 BaseAddress = MiNonPagedPoolStart;
263 MmCreateMemoryArea(NULL,
264 MmGetKernelAddressSpace(),
265 MEMORY_AREA_SYSTEM,
266 &BaseAddress,
267 MiNonPagedPoolLength,
268 0,
269 &kernel_pool_desc,
270 FALSE,
271 FALSE,
272 BoundaryAddressMultiple);
273
274 BaseAddress = MiKernelMapStart;
275 Status = MmCreateMemoryArea(NULL,
276 MmGetKernelAddressSpace(),
277 MEMORY_AREA_SYSTEM,
278 &BaseAddress,
279 MiKernelMapLength,
280 0,
281 &MiKernelMapDescriptor,
282 FALSE,
283 FALSE,
284 BoundaryAddressMultiple);
285
286 BaseAddress = MmPagedPoolBase;
287 Status = MmCreateMemoryArea(NULL,
288 MmGetKernelAddressSpace(),
289 MEMORY_AREA_PAGED_POOL,
290 &BaseAddress,
291 MmPagedPoolSize,
292 0,
293 &MiPagedPoolDescriptor,
294 FALSE,
295 FALSE,
296 BoundaryAddressMultiple);
297
298 MmInitializePagedPool();
299
300 /*
301 * Create the kernel mapping of the user/kernel shared memory.
302 */
303 BaseAddress = (PVOID)KI_USER_SHARED_DATA;
304 Length = PAGE_SIZE;
305 MmCreateMemoryArea(NULL,
306 MmGetKernelAddressSpace(),
307 MEMORY_AREA_SYSTEM,
308 &BaseAddress,
309 Length,
310 0,
311 &kernel_shared_data_desc,
312 FALSE,
313 FALSE,
314 BoundaryAddressMultiple);
315
316 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE,
317 &MmSharedDataPagePhysicalAddress);
318 Status = MmCreateVirtualMapping(NULL,
319 (PVOID)KI_USER_SHARED_DATA,
320 PAGE_READWRITE,
321 MmSharedDataPagePhysicalAddress,
322 TRUE);
323 if (!NT_SUCCESS(Status))
324 {
325 DbgPrint("Unable to create virtual mapping\n");
326 KEBUGCHECK(0);
327 }
328 RtlZeroMemory(BaseAddress, Length);
329
330 /*
331 *
332 */
333 MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
334 }
335
336
337 VOID INIT_FUNCTION
338 MmInit1(ULONG FirstKrnlPhysAddr,
339 ULONG LastKrnlPhysAddr,
340 ULONG LastKernelAddress,
341 PADDRESS_RANGE BIOSMemoryMap,
342 ULONG AddressRangeCount,
343 ULONG MaxMem)
344 /*
345 * FUNCTION: Initalize memory managment
346 */
347 {
348 ULONG i;
349 ULONG kernel_len;
350 #ifndef MP
351 extern unsigned int unmap_me, unmap_me2, unmap_me3;
352 #endif
353
354 DPRINT("MmInit1(FirstKrnlPhysAddr, %x, LastKrnlPhysAddr %x, LastKernelAddress %x)\n",
355 FirstKrnlPhysAddr,
356 LastKrnlPhysAddr,
357 LastKernelAddress);
358
359
360 if ((BIOSMemoryMap != NULL) && (AddressRangeCount > 0))
361 {
362 // If we have a bios memory map, recalulate the memory size
363 ULONG last = 0;
364 for (i = 0; i < AddressRangeCount; i++)
365 {
366 if (BIOSMemoryMap[i].Type == 1
367 && (BIOSMemoryMap[i].BaseAddrLow + BIOSMemoryMap[i].LengthLow + PAGE_SIZE -1) / PAGE_SIZE > last)
368 {
369 last = (BIOSMemoryMap[i].BaseAddrLow + BIOSMemoryMap[i].LengthLow + PAGE_SIZE -1) / PAGE_SIZE;
370 }
371 }
372 if ((last - 256) * 4 > KeLoaderBlock.MemHigher)
373 {
374 KeLoaderBlock.MemHigher = (last - 256) * 4;
375 }
376 }
377
378 if (KeLoaderBlock.MemHigher >= (MaxMem - 1) * 1024)
379 {
380 KeLoaderBlock.MemHigher = (MaxMem - 1) * 1024;
381 }
382
383 /*
384 * FIXME: Set this based on the system command line
385 */
386 MmSystemRangeStart = (PVOID)KERNEL_BASE; // 0xC0000000
387 MmUserProbeAddress = (PVOID)0x7fff0000;
388 MmHighestUserAddress = (PVOID)0x7ffeffff;
389
390 MmInitGlobalKernelPageDirectory();
391
392 /*
393 * Initialize memory managment statistics
394 */
395 MmStats.NrTotalPages = 0;
396 MmStats.NrSystemPages = 0;
397 MmStats.NrUserPages = 0;
398 MmStats.NrReservedPages = 0;
399 MmStats.NrUserPages = 0;
400 MmStats.NrFreePages = 0;
401 MmStats.NrLockedPages = 0;
402 MmStats.PagingRequestsInLastMinute = 0;
403 MmStats.PagingRequestsInLastFiveMinutes = 0;
404 MmStats.PagingRequestsInLastFifteenMinutes = 0;
405
406 /*
407 * Initialize the kernel address space
408 */
409 MmInitializeKernelAddressSpace();
410
411 /*
412 * Unmap low memory
413 */
414 #ifndef MP
415 /* In SMP mode we unmap the low memory in MmInit3.
416 The APIC needs the mapping of the first pages
417 while the processors are starting up. */
418 MmDeletePageTable(NULL, 0);
419 #endif
420 /*
421 * Free all pages not used for kernel memory
422 * (we assume the kernel occupies a continuous range of physical
423 * memory)
424 */
425 DPRINT("first krnl %x\nlast krnl %x\n",FirstKrnlPhysAddr,
426 LastKrnlPhysAddr);
427
428 /*
429 * Free physical memory not used by the kernel
430 */
431 MmStats.NrTotalPages = KeLoaderBlock.MemHigher/4;
432 if (!MmStats.NrTotalPages)
433 {
434 DbgPrint("Memory not detected, default to 8 MB\n");
435 MmStats.NrTotalPages = 2048;
436 }
437 else
438 {
439 /* add 1MB for standard memory (not extended) */
440 MmStats.NrTotalPages += 256;
441 }
442 #ifdef BIOS_MEM_FIX
443 MmStats.NrTotalPages += 16;
444 #endif
445 DbgPrint("Used memory %dKb\n", (MmStats.NrTotalPages * PAGE_SIZE) / 1024);
446
447 LastKernelAddress = (ULONG)MmInitializePageList((PVOID)FirstKrnlPhysAddr,
448 (PVOID)LastKrnlPhysAddr,
449 MmStats.NrTotalPages,
450 PAGE_ROUND_UP(LastKernelAddress),
451 BIOSMemoryMap,
452 AddressRangeCount);
453 kernel_len = LastKrnlPhysAddr - FirstKrnlPhysAddr;
454
455 /*
456 * Create a trap for null pointer references and protect text
457 * segment
458 */
459 CHECKPOINT;
460 #if defined(_MSC_VER)
461 DPRINT(".text start: %x, .data start: %x\n",
462 (int)FindSegmentStart(".text"),
463 (int)FindSegmentStart(".data"));
464
465 {
466 const char* pCode = FindSegmentStart(".text");
467 const char* pData = FindSegmentEnd(".text");
468 while (pCode < pData)
469 {
470 MmSetPageProtect(NULL, (PVOID)pCode, PAGE_EXECUTE_READ);
471 pCode += PAGE_SIZE;
472 }
473 }
474 #else
475 DPRINT("_text_start__ %x _init_end__ %x\n",(int)&_text_start__,(int)&_init_end__);
476 for (i=PAGE_ROUND_DOWN(((int)&_text_start__));
477 i<PAGE_ROUND_UP(((int)&_init_end__));i=i+PAGE_SIZE)
478 {
479 MmSetPageProtect(NULL,
480 (PVOID)i,
481 PAGE_EXECUTE_READ);
482 }
483 #endif
484
485 DPRINT("Invalidating between %x and %x\n",
486 LastKernelAddress, 0xc0600000);
487 for (i=(LastKernelAddress); i<0xc0600000; i+=PAGE_SIZE)
488 {
489 MmRawDeleteVirtualMapping((PVOID)(i));
490 }
491
492 DPRINT("Invalidating between %x and %x\n",
493 0xd0100000, 0xd0400000);
494 for (i=0xd0100000; i<0xd0400000; i+=PAGE_SIZE)
495 {
496 MmRawDeleteVirtualMapping((PVOID)(i));
497 }
498
499 DPRINT("Almost done MmInit()\n");
500 #ifndef MP
501 /* FIXME: This is broken in SMP mode */
502 #if !defined(_MSC_VER) // FIXME: I don't trust using this from MSVC yet!
503 MmDeleteVirtualMapping(NULL, (PVOID)&unmap_me, TRUE, NULL, NULL);
504 MmDeleteVirtualMapping(NULL, (PVOID)&unmap_me2, TRUE, NULL, NULL);
505 MmDeleteVirtualMapping(NULL, (PVOID)&unmap_me3, TRUE, NULL, NULL);
506 #endif // _MSC_VER
507 #endif
508 /*
509 * Intialize memory areas
510 */
511 MmInitVirtualMemory(LastKernelAddress, kernel_len);
512
513 MmInitializeMdlImplementation();
514 }
515
516 VOID INIT_FUNCTION
517 MmInit2(VOID)
518 {
519 MmInitializeRmapList();
520 MmInitializePageOp();
521 MmInitSectionImplementation();
522 MmInitPagingFile();
523 }
524
525 VOID INIT_FUNCTION
526 MmInit3(VOID)
527 {
528 /*
529 * Unmap low memory
530 */
531 #ifdef MP
532 /* In SMP mode we can unmap the low memory
533 if all processors are started. */
534 MmDeletePageTable(NULL, 0);
535 #endif
536 MmInitZeroPageThread();
537 MmCreatePhysicalMemorySection();
538 MiInitBalancerThread();
539
540 /*
541 * Initialise the modified page writer.
542 */
543 MmInitMpwThread();
544
545 /* FIXME: Read parameters from memory */
546 }
547
548 VOID STATIC
549 MiFreeInitMemoryPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
550 PHYSICAL_ADDRESS PhysAddr, SWAPENTRY SwapEntry,
551 BOOLEAN Dirty)
552 {
553 assert(SwapEntry == 0);
554 if (PhysAddr.QuadPart != 0)
555 {
556 MmReleasePageMemoryConsumer(MC_NPPOOL, PhysAddr);
557 }
558 }
559
560 VOID
561 MiFreeInitMemory(VOID)
562 {
563 #if defined(_MSC_VER)
564 DPRINT1("Can not yet free .init memory for MSVC compiled kernel\n");
565 #else
566 MmLockAddressSpace(MmGetKernelAddressSpace());
567 MmFreeMemoryArea(MmGetKernelAddressSpace(),
568 (PVOID)&_init_start__,
569 PAGE_ROUND_UP((ULONG)&_init_end__) - (ULONG)_init_start__,
570 MiFreeInitMemoryPage,
571 NULL);
572 MmUnlockAddressSpace(MmGetKernelAddressSpace());
573 #endif
574 }