1 /* $Id: mm_mminit_msvc.c,v 1.1 2004/02/06 08:22:01 fireball Exp $
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)
12 /* INCLUDES *****************************************************************/
14 #include <ddk/ntddk.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>
24 #include <internal/debug.h>
26 /* GLOBALS *****************************************************************/
29 * Size of extended memory (kb) (fixed for now)
31 #define EXTENDED_MEMORY_SIZE (3*1024*1024)
34 * Compiler defined symbols
39 #pragma intrinsic(strcmp)
41 static PIMAGE_SECTION_HEADER
FindSection(const char* szSeg
)
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
;
47 for (i
= 0; i
< count
; ++i
, ++Section
)
49 if (!strcmp(szSeg
, Section
->Name
))
57 static void* FindSegmentStart(const char* szSeg
)
59 PIMAGE_SECTION_HEADER Section
= FindSection(szSeg
);
62 return (void*)(KERNEL_BASE
+ Section
->VirtualAddress
);
67 static void* FindSegmentEnd(const char* szSeg
)
69 PIMAGE_SECTION_HEADER Section
= FindSection(szSeg
);
72 return (void*)(KERNEL_BASE
+ Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
);
77 #endif // defined(_MSC_VER)
80 static BOOLEAN IsThisAnNtAsSystem
= FALSE
;
81 static MM_SYSTEM_SIZE MmSystemSize
= MmSmallSystem
;
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
;
95 PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress
;
97 PVOID MiNonPagedPoolStart
;
98 ULONG MiNonPagedPoolLength
;
99 PVOID MiKernelMapStart
;
100 ULONG MiKernelMapLength
;
102 /* FUNCTIONS ****************************************************************/
107 BOOLEAN STDCALL
MmIsThisAnNtAsSystem(VOID
)
109 return(IsThisAnNtAsSystem
);
115 MM_SYSTEM_SIZE STDCALL
MmQuerySystemSize(VOID
)
117 return(MmSystemSize
);
120 VOID
MiShutdownMemoryManager(VOID
)
125 MmInitVirtualMemory(ULONG LastKernelAddress
,
128 * FUNCTION: Intialize the memory areas list
130 * bp = Pointer to the boot parameters
131 * kernel_len = Length of the kernel
136 ULONG ParamLength
= KernelLength
;
138 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
141 DPRINT("MmInitVirtualMemory(%x, %x)\n",LastKernelAddress
, KernelLength
);
143 BoundaryAddressMultiple
.QuadPart
= 0;
144 LastKernelAddress
= PAGE_ROUND_UP(LastKernelAddress
);
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
;
152 MiNonPagedPoolStart
= (char*)MiKernelMapStart
+ MiKernelMapLength
+ PAGE_SIZE
;
153 MiNonPagedPoolLength
= MM_NONPAGED_POOL_SIZE
;
155 MmPagedPoolBase
= (char*)MiNonPagedPoolStart
+ MiNonPagedPoolLength
+ PAGE_SIZE
;
156 MmPagedPoolSize
= MM_PAGED_POOL_SIZE
;
159 MiInitializeNonPagedPool();
162 * Setup the system area descriptor list
164 BaseAddress
= (PVOID
)0xf0000000;
165 MmCreateMemoryArea(NULL
,
166 MmGetKernelAddressSpace(),
174 BoundaryAddressMultiple
);
176 BaseAddress
= (PVOID
)KPCR_BASE
;
177 MmCreateMemoryArea(NULL
,
178 MmGetKernelAddressSpace(),
181 PAGE_SIZE
* MAXIMUM_PROCESSORS
,
186 BoundaryAddressMultiple
);
188 BaseAddress
= (PVOID
)0xd0000000;
189 MmCreateMemoryArea(NULL
,
190 MmGetKernelAddressSpace(),
195 &kernel_mapped_low_mem_desc
,
198 BoundaryAddressMultiple
);
200 BaseAddress
= (PVOID
)KERNEL_BASE
;
201 Length
= PAGE_ROUND_UP(((ULONG
)FindSegmentEnd(".text"))) - KERNEL_BASE
;
202 ParamLength
= ParamLength
- Length
;
205 * No need to lock the address space at this point since no
206 * other threads are running.
208 MmCreateMemoryArea(NULL
,
209 MmGetKernelAddressSpace(),
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.
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
);
231 * No need to lock the address space at this point since we are
232 * the only thread running.
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(),
245 BoundaryAddressMultiple
);
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(),
260 BoundaryAddressMultiple
);
262 BaseAddress
= MiNonPagedPoolStart
;
263 MmCreateMemoryArea(NULL
,
264 MmGetKernelAddressSpace(),
267 MiNonPagedPoolLength
,
272 BoundaryAddressMultiple
);
274 BaseAddress
= MiKernelMapStart
;
275 Status
= MmCreateMemoryArea(NULL
,
276 MmGetKernelAddressSpace(),
281 &MiKernelMapDescriptor
,
284 BoundaryAddressMultiple
);
286 BaseAddress
= MmPagedPoolBase
;
287 Status
= MmCreateMemoryArea(NULL
,
288 MmGetKernelAddressSpace(),
289 MEMORY_AREA_PAGED_POOL
,
293 &MiPagedPoolDescriptor
,
296 BoundaryAddressMultiple
);
298 MmInitializePagedPool();
301 * Create the kernel mapping of the user/kernel shared memory.
303 BaseAddress
= (PVOID
)KI_USER_SHARED_DATA
;
305 MmCreateMemoryArea(NULL
,
306 MmGetKernelAddressSpace(),
311 &kernel_shared_data_desc
,
314 BoundaryAddressMultiple
);
316 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
,
317 &MmSharedDataPagePhysicalAddress
);
318 Status
= MmCreateVirtualMapping(NULL
,
319 (PVOID
)KI_USER_SHARED_DATA
,
321 MmSharedDataPagePhysicalAddress
,
323 if (!NT_SUCCESS(Status
))
325 DbgPrint("Unable to create virtual mapping\n");
328 RtlZeroMemory(BaseAddress
, Length
);
333 MmInitializeMemoryConsumer(MC_USER
, MmTrimUserMemory
);
338 MmInit1(ULONG FirstKrnlPhysAddr
,
339 ULONG LastKrnlPhysAddr
,
340 ULONG LastKernelAddress
,
341 PADDRESS_RANGE BIOSMemoryMap
,
342 ULONG AddressRangeCount
,
345 * FUNCTION: Initalize memory managment
351 extern unsigned int unmap_me
, unmap_me2
, unmap_me3
;
354 DPRINT("MmInit1(FirstKrnlPhysAddr, %x, LastKrnlPhysAddr %x, LastKernelAddress %x)\n",
360 if ((BIOSMemoryMap
!= NULL
) && (AddressRangeCount
> 0))
362 // If we have a bios memory map, recalulate the memory size
364 for (i
= 0; i
< AddressRangeCount
; i
++)
366 if (BIOSMemoryMap
[i
].Type
== 1
367 && (BIOSMemoryMap
[i
].BaseAddrLow
+ BIOSMemoryMap
[i
].LengthLow
+ PAGE_SIZE
-1) / PAGE_SIZE
> last
)
369 last
= (BIOSMemoryMap
[i
].BaseAddrLow
+ BIOSMemoryMap
[i
].LengthLow
+ PAGE_SIZE
-1) / PAGE_SIZE
;
372 if ((last
- 256) * 4 > KeLoaderBlock
.MemHigher
)
374 KeLoaderBlock
.MemHigher
= (last
- 256) * 4;
378 if (KeLoaderBlock
.MemHigher
>= (MaxMem
- 1) * 1024)
380 KeLoaderBlock
.MemHigher
= (MaxMem
- 1) * 1024;
384 * FIXME: Set this based on the system command line
386 MmSystemRangeStart
= (PVOID
)KERNEL_BASE
; // 0xC0000000
387 MmUserProbeAddress
= (PVOID
)0x7fff0000;
388 MmHighestUserAddress
= (PVOID
)0x7ffeffff;
390 MmInitGlobalKernelPageDirectory();
393 * Initialize memory managment statistics
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;
407 * Initialize the kernel address space
409 MmInitializeKernelAddressSpace();
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);
421 * Free all pages not used for kernel memory
422 * (we assume the kernel occupies a continuous range of physical
425 DPRINT("first krnl %x\nlast krnl %x\n",FirstKrnlPhysAddr
,
429 * Free physical memory not used by the kernel
431 MmStats
.NrTotalPages
= KeLoaderBlock
.MemHigher
/4;
432 if (!MmStats
.NrTotalPages
)
434 DbgPrint("Memory not detected, default to 8 MB\n");
435 MmStats
.NrTotalPages
= 2048;
439 /* add 1MB for standard memory (not extended) */
440 MmStats
.NrTotalPages
+= 256;
443 MmStats
.NrTotalPages
+= 16;
445 DbgPrint("Used memory %dKb\n", (MmStats
.NrTotalPages
* PAGE_SIZE
) / 1024);
447 LastKernelAddress
= (ULONG
)MmInitializePageList((PVOID
)FirstKrnlPhysAddr
,
448 (PVOID
)LastKrnlPhysAddr
,
449 MmStats
.NrTotalPages
,
450 PAGE_ROUND_UP(LastKernelAddress
),
453 kernel_len
= LastKrnlPhysAddr
- FirstKrnlPhysAddr
;
456 * Create a trap for null pointer references and protect text
460 #if defined(_MSC_VER)
461 DPRINT(".text start: %x, .data start: %x\n",
462 (int)FindSegmentStart(".text"),
463 (int)FindSegmentStart(".data"));
466 const char* pCode
= FindSegmentStart(".text");
467 const char* pData
= FindSegmentEnd(".text");
468 while (pCode
< pData
)
470 MmSetPageProtect(NULL
, (PVOID
)pCode
, PAGE_EXECUTE_READ
);
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
)
479 MmSetPageProtect(NULL
,
485 DPRINT("Invalidating between %x and %x\n",
486 LastKernelAddress
, 0xc0600000);
487 for (i
=(LastKernelAddress
); i
<0xc0600000; i
+=PAGE_SIZE
)
489 MmRawDeleteVirtualMapping((PVOID
)(i
));
492 DPRINT("Invalidating between %x and %x\n",
493 0xd0100000, 0xd0400000);
494 for (i
=0xd0100000; i
<0xd0400000; i
+=PAGE_SIZE
)
496 MmRawDeleteVirtualMapping((PVOID
)(i
));
499 DPRINT("Almost done MmInit()\n");
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
);
509 * Intialize memory areas
511 MmInitVirtualMemory(LastKernelAddress
, kernel_len
);
513 MmInitializeMdlImplementation();
519 MmInitializeRmapList();
520 MmInitializePageOp();
521 MmInitSectionImplementation();
532 /* In SMP mode we can unmap the low memory
533 if all processors are started. */
534 MmDeletePageTable(NULL
, 0);
536 MmInitZeroPageThread();
537 MmCreatePhysicalMemorySection();
538 MiInitBalancerThread();
541 * Initialise the modified page writer.
545 /* FIXME: Read parameters from memory */
549 MiFreeInitMemoryPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
550 PHYSICAL_ADDRESS PhysAddr
, SWAPENTRY SwapEntry
,
553 assert(SwapEntry
== 0);
554 if (PhysAddr
.QuadPart
!= 0)
556 MmReleasePageMemoryConsumer(MC_NPPOOL
, PhysAddr
);
561 MiFreeInitMemory(VOID
)
563 #if defined(_MSC_VER)
564 DPRINT1("Can not yet free .init memory for MSVC compiled kernel\n");
566 MmLockAddressSpace(MmGetKernelAddressSpace());
567 MmFreeMemoryArea(MmGetKernelAddressSpace(),
568 (PVOID
)&_init_start__
,
569 PAGE_ROUND_UP((ULONG
)&_init_end__
) - (ULONG
)_init_start__
,
570 MiFreeInitMemoryPage
,
572 MmUnlockAddressSpace(MmGetKernelAddressSpace());