76d4a4bee8c3f416dfb9cc825863a9b86aa0d840
[reactos.git] / ntoskrnl / mm / ARM3 / mminit.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/mminit.c
5 * PURPOSE: ARM Memory Manager Initialization
6 * PROGRAMMERS: ReactOS Portable Systems Group
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 "miarm.h"
17 #undef MmSystemRangeStart
18
19 /* GLOBALS ********************************************************************/
20
21 //
22 // These are all registry-configurable, but by default, the memory manager will
23 // figure out the most appropriate values.
24 //
25 ULONG MmMaximumNonPagedPoolPercent;
26 SIZE_T MmSizeOfNonPagedPoolInBytes;
27 SIZE_T MmMaximumNonPagedPoolInBytes;
28
29 /* Some of the same values, in pages */
30 PFN_NUMBER MmMaximumNonPagedPoolInPages;
31
32 //
33 // These numbers describe the discrete equation components of the nonpaged
34 // pool sizing algorithm.
35 //
36 // They are described on http://support.microsoft.com/default.aspx/kb/126402/ja
37 // along with the algorithm that uses them, which is implemented later below.
38 //
39 SIZE_T MmMinimumNonPagedPoolSize = 256 * 1024;
40 ULONG MmMinAdditionNonPagedPoolPerMb = 32 * 1024;
41 SIZE_T MmDefaultMaximumNonPagedPool = 1024 * 1024;
42 ULONG MmMaxAdditionNonPagedPoolPerMb = 400 * 1024;
43
44 //
45 // The memory layout (and especially variable names) of the NT kernel mode
46 // components can be a bit hard to twig, especially when it comes to the non
47 // paged area.
48 //
49 // There are really two components to the non-paged pool:
50 //
51 // - The initial nonpaged pool, sized dynamically up to a maximum.
52 // - The expansion nonpaged pool, sized dynamically up to a maximum.
53 //
54 // The initial nonpaged pool is physically continuous for performance, and
55 // immediately follows the PFN database, typically sharing the same PDE. It is
56 // a very small resource (32MB on a 1GB system), and capped at 128MB.
57 //
58 // Right now we call this the "ARM³ Nonpaged Pool" and it begins somewhere after
59 // the PFN database (which starts at 0xB0000000).
60 //
61 // The expansion nonpaged pool, on the other hand, can grow much bigger (400MB
62 // for a 1GB system). On ARM³ however, it is currently capped at 128MB.
63 //
64 // The address where the initial nonpaged pool starts is aptly named
65 // MmNonPagedPoolStart, and it describes a range of MmSizeOfNonPagedPoolInBytes
66 // bytes.
67 //
68 // Expansion nonpaged pool starts at an address described by the variable called
69 // MmNonPagedPoolExpansionStart, and it goes on for MmMaximumNonPagedPoolInBytes
70 // minus MmSizeOfNonPagedPoolInBytes bytes, always reaching MmNonPagedPoolEnd
71 // (because of the way it's calculated) at 0xFFBE0000.
72 //
73 // Initial nonpaged pool is allocated and mapped early-on during boot, but what
74 // about the expansion nonpaged pool? It is instead composed of special pages
75 // which belong to what are called System PTEs. These PTEs are the matter of a
76 // later discussion, but they are also considered part of the "nonpaged" OS, due
77 // to the fact that they are never paged out -- once an address is described by
78 // a System PTE, it is always valid, until the System PTE is torn down.
79 //
80 // System PTEs are actually composed of two "spaces", the system space proper,
81 // and the nonpaged pool expansion space. The latter, as we've already seen,
82 // begins at MmNonPagedPoolExpansionStart. Based on the number of System PTEs
83 // that the system will support, the remaining address space below this address
84 // is used to hold the system space PTEs. This address, in turn, is held in the
85 // variable named MmNonPagedSystemStart, which itself is never allowed to go
86 // below 0xEB000000 (thus creating an upper bound on the number of System PTEs).
87 //
88 // This means that 330MB are reserved for total nonpaged system VA, on top of
89 // whatever the initial nonpaged pool allocation is.
90 //
91 // The following URLs, valid as of April 23rd, 2008, support this evidence:
92 //
93 // http://www.cs.miami.edu/~burt/journal/NT/memory.html
94 // http://www.ditii.com/2007/09/28/windows-memory-management-x86-virtual-address-space/
95 //
96 PVOID MmNonPagedSystemStart;
97 PVOID MmNonPagedPoolStart;
98 PVOID MmNonPagedPoolExpansionStart;
99 PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END;
100
101 //
102 // This is where paged pool starts by default
103 //
104 PVOID MmPagedPoolStart = MI_PAGED_POOL_START;
105 PVOID MmPagedPoolEnd;
106
107 //
108 // And this is its default size
109 //
110 SIZE_T MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE;
111 PFN_NUMBER MmSizeOfPagedPoolInPages = MI_MIN_INIT_PAGED_POOLSIZE / PAGE_SIZE;
112
113 //
114 // Session space starts at 0xBFFFFFFF and grows downwards
115 // By default, it includes an 8MB image area where we map win32k and video card
116 // drivers, followed by a 4MB area containing the session's working set. This is
117 // then followed by a 20MB mapped view area and finally by the session's paged
118 // pool, by default 16MB.
119 //
120 // On a normal system, this results in session space occupying the region from
121 // 0xBD000000 to 0xC0000000
122 //
123 // See miarm.h for the defines that determine the sizing of this region. On an
124 // NT system, some of these can be configured through the registry, but we don't
125 // support that yet.
126 //
127 PVOID MiSessionSpaceEnd; // 0xC0000000
128 PVOID MiSessionImageEnd; // 0xC0000000
129 PVOID MiSessionImageStart; // 0xBF800000
130 PVOID MiSessionSpaceWs;
131 PVOID MiSessionViewStart; // 0xBE000000
132 PVOID MiSessionPoolEnd; // 0xBE000000
133 PVOID MiSessionPoolStart; // 0xBD000000
134 PVOID MmSessionBase; // 0xBD000000
135 SIZE_T MmSessionSize;
136 SIZE_T MmSessionViewSize;
137 SIZE_T MmSessionPoolSize;
138 SIZE_T MmSessionImageSize;
139
140 /*
141 * These are the PTE addresses of the boundaries carved out above
142 */
143 PMMPTE MiSessionImagePteStart;
144 PMMPTE MiSessionImagePteEnd;
145 PMMPTE MiSessionBasePte;
146 PMMPTE MiSessionLastPte;
147
148 //
149 // The system view space, on the other hand, is where sections that are memory
150 // mapped into "system space" end up.
151 //
152 // By default, it is a 16MB region, but we hack it to be 32MB for ReactOS
153 //
154 PVOID MiSystemViewStart;
155 SIZE_T MmSystemViewSize;
156
157 #if (_MI_PAGING_LEVELS == 2)
158 //
159 // A copy of the system page directory (the page directory associated with the
160 // System process) is kept (double-mapped) by the manager in order to lazily
161 // map paged pool PDEs into external processes when they fault on a paged pool
162 // address.
163 //
164 PFN_NUMBER MmSystemPageDirectory[PD_COUNT];
165 PMMPDE MmSystemPagePtes;
166 #endif
167
168 //
169 // The system cache starts right after hyperspace. The first few pages are for
170 // keeping track of the system working set list.
171 //
172 // This should be 0xC0C00000 -- the cache itself starts at 0xC1000000
173 //
174 PMMWSL MmSystemCacheWorkingSetList = (PVOID)MI_SYSTEM_CACHE_WS_START;
175
176 //
177 // Windows NT seems to choose between 7000, 11000 and 50000
178 // On systems with more than 32MB, this number is then doubled, and further
179 // aligned up to a PDE boundary (4MB).
180 //
181 PFN_COUNT MmNumberOfSystemPtes;
182
183 //
184 // This is how many pages the PFN database will take up
185 // In Windows, this includes the Quark Color Table, but not in ARM³
186 //
187 PFN_NUMBER MxPfnAllocation;
188
189 //
190 // Unlike the old ReactOS Memory Manager, ARM³ (and Windows) does not keep track
191 // of pages that are not actually valid physical memory, such as ACPI reserved
192 // regions, BIOS address ranges, or holes in physical memory address space which
193 // could indicate device-mapped I/O memory.
194 //
195 // In fact, the lack of a PFN entry for a page usually indicates that this is
196 // I/O space instead.
197 //
198 // A bitmap, called the PFN bitmap, keeps track of all page frames by assigning
199 // a bit to each. If the bit is set, then the page is valid physical RAM.
200 //
201 RTL_BITMAP MiPfnBitMap;
202
203 //
204 // This structure describes the different pieces of RAM-backed address space
205 //
206 PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
207
208 //
209 // This is where we keep track of the most basic physical layout markers
210 //
211 PFN_NUMBER MmHighestPhysicalPage, MmLowestPhysicalPage = -1;
212 PFN_COUNT MmNumberOfPhysicalPages;
213
214 //
215 // The total number of pages mapped by the boot loader, which include the kernel
216 // HAL, boot drivers, registry, NLS files and other loader data structures is
217 // kept track of here. This depends on "LoaderPagesSpanned" being correct when
218 // coming from the loader.
219 //
220 // This number is later aligned up to a PDE boundary.
221 //
222 SIZE_T MmBootImageSize;
223
224 //
225 // These three variables keep track of the core separation of address space that
226 // exists between kernel mode and user mode.
227 //
228 ULONG_PTR MmUserProbeAddress;
229 PVOID MmHighestUserAddress;
230 PVOID MmSystemRangeStart;
231
232 /* And these store the respective highest PTE/PDE address */
233 PMMPTE MiHighestUserPte;
234 PMMPDE MiHighestUserPde;
235 #if (_MI_PAGING_LEVELS >= 3)
236 PMMPTE MiHighestUserPpe;
237 #if (_MI_PAGING_LEVELS >= 4)
238 PMMPTE MiHighestUserPxe;
239 #endif
240 #endif
241
242 /* These variables define the system cache address space */
243 PVOID MmSystemCacheStart;
244 PVOID MmSystemCacheEnd;
245 MMSUPPORT MmSystemCacheWs;
246
247 //
248 // This is where hyperspace ends (followed by the system cache working set)
249 //
250 PVOID MmHyperSpaceEnd;
251
252 //
253 // Page coloring algorithm data
254 //
255 ULONG MmSecondaryColors;
256 ULONG MmSecondaryColorMask;
257
258 //
259 // Actual (registry-configurable) size of a GUI thread's stack
260 //
261 ULONG MmLargeStackSize = KERNEL_LARGE_STACK_SIZE;
262
263 //
264 // Before we have a PFN database, memory comes straight from our physical memory
265 // blocks, which is nice because it's guaranteed contiguous and also because once
266 // we take a page from here, the system doesn't see it anymore.
267 // However, once the fun is over, those pages must be re-integrated back into
268 // PFN society life, and that requires us keeping a copy of the original layout
269 // so that we can parse it later.
270 //
271 PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor;
272 MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor;
273
274 /*
275 * For each page's worth bytes of L2 cache in a given set/way line, the zero and
276 * free lists are organized in what is called a "color".
277 *
278 * This array points to the two lists, so it can be thought of as a multi-dimensional
279 * array of MmFreePagesByColor[2][MmSecondaryColors]. Since the number is dynamic,
280 * we describe the array in pointer form instead.
281 *
282 * On a final note, the color tables themselves are right after the PFN database.
283 */
284 C_ASSERT(FreePageList == 1);
285 PMMCOLOR_TABLES MmFreePagesByColor[FreePageList + 1];
286
287 /* An event used in Phase 0 before the rest of the system is ready to go */
288 KEVENT MiTempEvent;
289
290 /* All the events used for memory threshold notifications */
291 PKEVENT MiLowMemoryEvent;
292 PKEVENT MiHighMemoryEvent;
293 PKEVENT MiLowPagedPoolEvent;
294 PKEVENT MiHighPagedPoolEvent;
295 PKEVENT MiLowNonPagedPoolEvent;
296 PKEVENT MiHighNonPagedPoolEvent;
297
298 /* The actual thresholds themselves, in page numbers */
299 PFN_NUMBER MmLowMemoryThreshold;
300 PFN_NUMBER MmHighMemoryThreshold;
301 PFN_NUMBER MiLowPagedPoolThreshold;
302 PFN_NUMBER MiHighPagedPoolThreshold;
303 PFN_NUMBER MiLowNonPagedPoolThreshold;
304 PFN_NUMBER MiHighNonPagedPoolThreshold;
305
306 /*
307 * This number determines how many free pages must exist, at minimum, until we
308 * start trimming working sets and flushing modified pages to obtain more free
309 * pages.
310 *
311 * This number changes if the system detects that this is a server product
312 */
313 PFN_NUMBER MmMinimumFreePages = 26;
314
315 /*
316 * This number indicates how many pages we consider to be a low limit of having
317 * "plenty" of free memory.
318 *
319 * It is doubled on systems that have more than 63MB of memory
320 */
321 PFN_NUMBER MmPlentyFreePages = 400;
322
323 /* These values store the type of system this is (small, med, large) and if server */
324 ULONG MmProductType;
325 MM_SYSTEMSIZE MmSystemSize;
326
327 /*
328 * These values store the cache working set minimums and maximums, in pages
329 *
330 * The minimum value is boosted on systems with more than 24MB of RAM, and cut
331 * down to only 32 pages on embedded (<24MB RAM) systems.
332 *
333 * An extra boost of 2MB is given on systems with more than 33MB of RAM.
334 */
335 PFN_NUMBER MmSystemCacheWsMinimum = 288;
336 PFN_NUMBER MmSystemCacheWsMaximum = 350;
337
338 /* FIXME: Move to cache/working set code later */
339 BOOLEAN MmLargeSystemCache;
340
341 /*
342 * This value determines in how many fragments/chunks the subsection prototype
343 * PTEs should be allocated when mapping a section object. It is configurable in
344 * the registry through the MapAllocationFragment parameter.
345 *
346 * The default is 64KB on systems with more than 1GB of RAM, 32KB on systems with
347 * more than 256MB of RAM, and 16KB on systems with less than 256MB of RAM.
348 *
349 * The maximum it can be set to is 2MB, and the minimum is 4KB.
350 */
351 SIZE_T MmAllocationFragment;
352
353 /*
354 * These two values track how much virtual memory can be committed, and when
355 * expansion should happen.
356 */
357 // FIXME: They should be moved elsewhere since it's not an "init" setting?
358 SIZE_T MmTotalCommitLimit;
359 SIZE_T MmTotalCommitLimitMaximum;
360
361 /*
362 * These values tune certain user parameters. They have default values set here,
363 * as well as in the code, and can be overwritten by registry settings.
364 */
365 SIZE_T MmHeapSegmentReserve = 1 * _1MB;
366 SIZE_T MmHeapSegmentCommit = 2 * PAGE_SIZE;
367 SIZE_T MmHeapDeCommitTotalFreeThreshold = 64 * _1KB;
368 SIZE_T MmHeapDeCommitFreeBlockThreshold = PAGE_SIZE;
369 SIZE_T MmMinimumStackCommitInBytes = 0;
370
371 /* Internal setting used for debugging memory descriptors */
372 BOOLEAN MiDbgEnableMdDump =
373 #ifdef _ARM_
374 TRUE;
375 #else
376 FALSE;
377 #endif
378
379 /* Number of memory descriptors in the loader block */
380 ULONG MiNumberDescriptors = 0;
381
382 /* Number of free pages in the loader block */
383 PFN_NUMBER MiNumberOfFreePages = 0;
384
385 /* Timeout value for critical sections (2.5 minutes) */
386 ULONG MmCritsectTimeoutSeconds = 150; // NT value: 720 * 60 * 60; (30 days)
387 LARGE_INTEGER MmCriticalSectionTimeout;
388
389 /* PRIVATE FUNCTIONS **********************************************************/
390
391 VOID
392 NTAPI
393 MiScanMemoryDescriptors(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
394 {
395 PLIST_ENTRY ListEntry;
396 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
397 PFN_NUMBER PageFrameIndex, FreePages = 0;
398
399 /* Loop the memory descriptors */
400 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
401 ListEntry != &LoaderBlock->MemoryDescriptorListHead;
402 ListEntry = ListEntry->Flink)
403 {
404 /* Get the descriptor */
405 Descriptor = CONTAINING_RECORD(ListEntry,
406 MEMORY_ALLOCATION_DESCRIPTOR,
407 ListEntry);
408 DPRINT("MD Type: %lx Base: %lx Count: %lx\n",
409 Descriptor->MemoryType, Descriptor->BasePage, Descriptor->PageCount);
410
411 /* Count this descriptor */
412 MiNumberDescriptors++;
413
414 /* Check if this is invisible memory */
415 if ((Descriptor->MemoryType == LoaderFirmwarePermanent) ||
416 (Descriptor->MemoryType == LoaderSpecialMemory) ||
417 (Descriptor->MemoryType == LoaderHALCachedMemory) ||
418 (Descriptor->MemoryType == LoaderBBTMemory))
419 {
420 /* Skip this descriptor */
421 continue;
422 }
423
424 /* Check if this is bad memory */
425 if (Descriptor->MemoryType != LoaderBad)
426 {
427 /* Count this in the total of pages */
428 MmNumberOfPhysicalPages += (PFN_COUNT)Descriptor->PageCount;
429 }
430
431 /* Check if this is the new lowest page */
432 if (Descriptor->BasePage < MmLowestPhysicalPage)
433 {
434 /* Update the lowest page */
435 MmLowestPhysicalPage = Descriptor->BasePage;
436 }
437
438 /* Check if this is the new highest page */
439 PageFrameIndex = Descriptor->BasePage + Descriptor->PageCount;
440 if (PageFrameIndex > MmHighestPhysicalPage)
441 {
442 /* Update the highest page */
443 MmHighestPhysicalPage = PageFrameIndex - 1;
444 }
445
446 /* Check if this is free memory */
447 if ((Descriptor->MemoryType == LoaderFree) ||
448 (Descriptor->MemoryType == LoaderLoadedProgram) ||
449 (Descriptor->MemoryType == LoaderFirmwareTemporary) ||
450 (Descriptor->MemoryType == LoaderOsloaderStack))
451 {
452 /* Count it too free pages */
453 MiNumberOfFreePages += Descriptor->PageCount;
454
455 /* Check if this is the largest memory descriptor */
456 if (Descriptor->PageCount > FreePages)
457 {
458 /* Remember it */
459 MxFreeDescriptor = Descriptor;
460 FreePages = Descriptor->PageCount;
461 }
462 }
463 }
464
465 /* Save original values of the free descriptor, since it'll be
466 * altered by early allocations */
467 MxOldFreeDescriptor = *MxFreeDescriptor;
468 }
469
470 PFN_NUMBER
471 NTAPI
472 INIT_FUNCTION
473 MxGetNextPage(IN PFN_NUMBER PageCount)
474 {
475 PFN_NUMBER Pfn;
476
477 /* Make sure we have enough pages */
478 if (PageCount > MxFreeDescriptor->PageCount)
479 {
480 /* Crash the system */
481 KeBugCheckEx(INSTALL_MORE_MEMORY,
482 MmNumberOfPhysicalPages,
483 MxFreeDescriptor->PageCount,
484 MxOldFreeDescriptor.PageCount,
485 PageCount);
486 }
487
488 /* Use our lowest usable free pages */
489 Pfn = MxFreeDescriptor->BasePage;
490 MxFreeDescriptor->BasePage += PageCount;
491 MxFreeDescriptor->PageCount -= PageCount;
492 return Pfn;
493 }
494
495 VOID
496 NTAPI
497 INIT_FUNCTION
498 MiComputeColorInformation(VOID)
499 {
500 ULONG L2Associativity;
501
502 /* Check if no setting was provided already */
503 if (!MmSecondaryColors)
504 {
505 /* Get L2 cache information */
506 L2Associativity = KeGetPcr()->SecondLevelCacheAssociativity;
507
508 /* The number of colors is the number of cache bytes by set/way */
509 MmSecondaryColors = KeGetPcr()->SecondLevelCacheSize;
510 if (L2Associativity) MmSecondaryColors /= L2Associativity;
511 }
512
513 /* Now convert cache bytes into pages */
514 MmSecondaryColors >>= PAGE_SHIFT;
515 if (!MmSecondaryColors)
516 {
517 /* If there was no cache data from the KPCR, use the default colors */
518 MmSecondaryColors = MI_SECONDARY_COLORS;
519 }
520 else
521 {
522 /* Otherwise, make sure there aren't too many colors */
523 if (MmSecondaryColors > MI_MAX_SECONDARY_COLORS)
524 {
525 /* Set the maximum */
526 MmSecondaryColors = MI_MAX_SECONDARY_COLORS;
527 }
528
529 /* Make sure there aren't too little colors */
530 if (MmSecondaryColors < MI_MIN_SECONDARY_COLORS)
531 {
532 /* Set the default */
533 MmSecondaryColors = MI_SECONDARY_COLORS;
534 }
535
536 /* Finally make sure the colors are a power of two */
537 if (MmSecondaryColors & (MmSecondaryColors - 1))
538 {
539 /* Set the default */
540 MmSecondaryColors = MI_SECONDARY_COLORS;
541 }
542 }
543
544 /* Compute the mask and store it */
545 MmSecondaryColorMask = MmSecondaryColors - 1;
546 KeGetCurrentPrcb()->SecondaryColorMask = MmSecondaryColorMask;
547 }
548
549 VOID
550 NTAPI
551 INIT_FUNCTION
552 MiInitializeColorTables(VOID)
553 {
554 ULONG i;
555 PMMPTE PointerPte, LastPte;
556 MMPTE TempPte = ValidKernelPte;
557
558 /* The color table starts after the ARM3 PFN database */
559 MmFreePagesByColor[0] = (PMMCOLOR_TABLES)&MmPfnDatabase[MmHighestPhysicalPage + 1];
560
561 /* Loop the PTEs. We have two color tables for each secondary color */
562 PointerPte = MiAddressToPte(&MmFreePagesByColor[0][0]);
563 LastPte = MiAddressToPte((ULONG_PTR)MmFreePagesByColor[0] +
564 (2 * MmSecondaryColors * sizeof(MMCOLOR_TABLES))
565 - 1);
566 while (PointerPte <= LastPte)
567 {
568 /* Check for valid PTE */
569 if (PointerPte->u.Hard.Valid == 0)
570 {
571 /* Get a page and map it */
572 TempPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
573 MI_WRITE_VALID_PTE(PointerPte, TempPte);
574
575 /* Zero out the page */
576 RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE);
577 }
578
579 /* Next */
580 PointerPte++;
581 }
582
583 /* Now set the address of the next list, right after this one */
584 MmFreePagesByColor[1] = &MmFreePagesByColor[0][MmSecondaryColors];
585
586 /* Now loop the lists to set them up */
587 for (i = 0; i < MmSecondaryColors; i++)
588 {
589 /* Set both free and zero lists for each color */
590 MmFreePagesByColor[ZeroedPageList][i].Flink = LIST_HEAD;
591 MmFreePagesByColor[ZeroedPageList][i].Blink = (PVOID)LIST_HEAD;
592 MmFreePagesByColor[ZeroedPageList][i].Count = 0;
593 MmFreePagesByColor[FreePageList][i].Flink = LIST_HEAD;
594 MmFreePagesByColor[FreePageList][i].Blink = (PVOID)LIST_HEAD;
595 MmFreePagesByColor[FreePageList][i].Count = 0;
596 }
597 }
598
599 #ifndef _M_AMD64
600 BOOLEAN
601 NTAPI
602 INIT_FUNCTION
603 MiIsRegularMemory(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
604 IN PFN_NUMBER Pfn)
605 {
606 PLIST_ENTRY NextEntry;
607 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
608
609 /* Loop the memory descriptors */
610 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
611 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
612 {
613 /* Get the memory descriptor */
614 MdBlock = CONTAINING_RECORD(NextEntry,
615 MEMORY_ALLOCATION_DESCRIPTOR,
616 ListEntry);
617
618 /* Check if this PFN could be part of the block */
619 if (Pfn >= (MdBlock->BasePage))
620 {
621 /* Check if it really is part of the block */
622 if (Pfn < (MdBlock->BasePage + MdBlock->PageCount))
623 {
624 /* Check if the block is actually memory we don't map */
625 if ((MdBlock->MemoryType == LoaderFirmwarePermanent) ||
626 (MdBlock->MemoryType == LoaderBBTMemory) ||
627 (MdBlock->MemoryType == LoaderSpecialMemory))
628 {
629 /* We don't need PFN database entries for this memory */
630 break;
631 }
632
633 /* This is memory we want to map */
634 return TRUE;
635 }
636 }
637 else
638 {
639 /* Blocks are ordered, so if it's not here, it doesn't exist */
640 break;
641 }
642
643 /* Get to the next descriptor */
644 NextEntry = MdBlock->ListEntry.Flink;
645 }
646
647 /* Check if this PFN is actually from our free memory descriptor */
648 if ((Pfn >= MxOldFreeDescriptor.BasePage) &&
649 (Pfn < MxOldFreeDescriptor.BasePage + MxOldFreeDescriptor.PageCount))
650 {
651 /* We use these pages for initial mappings, so we do want to count them */
652 return TRUE;
653 }
654
655 /* Otherwise this isn't memory that we describe or care about */
656 return FALSE;
657 }
658
659 VOID
660 NTAPI
661 INIT_FUNCTION
662 MiMapPfnDatabase(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
663 {
664 PFN_NUMBER FreePage, FreePageCount, PagesLeft, BasePage, PageCount;
665 PLIST_ENTRY NextEntry;
666 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
667 PMMPTE PointerPte, LastPte;
668 MMPTE TempPte = ValidKernelPte;
669
670 /* Get current page data, since we won't be using MxGetNextPage as it would corrupt our state */
671 FreePage = MxFreeDescriptor->BasePage;
672 FreePageCount = MxFreeDescriptor->PageCount;
673 PagesLeft = 0;
674
675 /* Loop the memory descriptors */
676 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
677 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
678 {
679 /* Get the descriptor */
680 MdBlock = CONTAINING_RECORD(NextEntry,
681 MEMORY_ALLOCATION_DESCRIPTOR,
682 ListEntry);
683 if ((MdBlock->MemoryType == LoaderFirmwarePermanent) ||
684 (MdBlock->MemoryType == LoaderBBTMemory) ||
685 (MdBlock->MemoryType == LoaderSpecialMemory))
686 {
687 /* These pages are not part of the PFN database */
688 NextEntry = MdBlock->ListEntry.Flink;
689 continue;
690 }
691
692 /* Next, check if this is our special free descriptor we've found */
693 if (MdBlock == MxFreeDescriptor)
694 {
695 /* Use the real numbers instead */
696 BasePage = MxOldFreeDescriptor.BasePage;
697 PageCount = MxOldFreeDescriptor.PageCount;
698 }
699 else
700 {
701 /* Use the descriptor's numbers */
702 BasePage = MdBlock->BasePage;
703 PageCount = MdBlock->PageCount;
704 }
705
706 /* Get the PTEs for this range */
707 PointerPte = MiAddressToPte(&MmPfnDatabase[BasePage]);
708 LastPte = MiAddressToPte(((ULONG_PTR)&MmPfnDatabase[BasePage + PageCount]) - 1);
709 DPRINT("MD Type: %lx Base: %lx Count: %lx\n", MdBlock->MemoryType, BasePage, PageCount);
710
711 /* Loop them */
712 while (PointerPte <= LastPte)
713 {
714 /* We'll only touch PTEs that aren't already valid */
715 if (PointerPte->u.Hard.Valid == 0)
716 {
717 /* Use the next free page */
718 TempPte.u.Hard.PageFrameNumber = FreePage;
719 ASSERT(FreePageCount != 0);
720
721 /* Consume free pages */
722 FreePage++;
723 FreePageCount--;
724 if (!FreePageCount)
725 {
726 /* Out of memory */
727 KeBugCheckEx(INSTALL_MORE_MEMORY,
728 MmNumberOfPhysicalPages,
729 FreePageCount,
730 MxOldFreeDescriptor.PageCount,
731 1);
732 }
733
734 /* Write out this PTE */
735 PagesLeft++;
736 MI_WRITE_VALID_PTE(PointerPte, TempPte);
737
738 /* Zero this page */
739 RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE);
740 }
741
742 /* Next! */
743 PointerPte++;
744 }
745
746 /* Do the next address range */
747 NextEntry = MdBlock->ListEntry.Flink;
748 }
749
750 /* Now update the free descriptors to consume the pages we used up during the PFN allocation loop */
751 MxFreeDescriptor->BasePage = FreePage;
752 MxFreeDescriptor->PageCount = FreePageCount;
753 }
754
755 VOID
756 NTAPI
757 INIT_FUNCTION
758 MiBuildPfnDatabaseFromPages(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
759 {
760 PMMPDE PointerPde;
761 PMMPTE PointerPte;
762 ULONG i, Count, j;
763 PFN_NUMBER PageFrameIndex, StartupPdIndex, PtePageIndex;
764 PMMPFN Pfn1, Pfn2;
765 ULONG_PTR BaseAddress = 0;
766
767 /* PFN of the startup page directory */
768 StartupPdIndex = PFN_FROM_PTE(MiAddressToPde(PDE_BASE));
769
770 /* Start with the first PDE and scan them all */
771 PointerPde = MiAddressToPde(NULL);
772 Count = PD_COUNT * PDE_COUNT;
773 for (i = 0; i < Count; i++)
774 {
775 /* Check for valid PDE */
776 if (PointerPde->u.Hard.Valid == 1)
777 {
778 /* Get the PFN from it */
779 PageFrameIndex = PFN_FROM_PTE(PointerPde);
780
781 /* Do we want a PFN entry for this page? */
782 if (MiIsRegularMemory(LoaderBlock, PageFrameIndex))
783 {
784 /* Yes we do, set it up */
785 Pfn1 = MiGetPfnEntry(PageFrameIndex);
786 Pfn1->u4.PteFrame = StartupPdIndex;
787 Pfn1->PteAddress = (PMMPTE)PointerPde;
788 Pfn1->u2.ShareCount++;
789 Pfn1->u3.e2.ReferenceCount = 1;
790 Pfn1->u3.e1.PageLocation = ActiveAndValid;
791 Pfn1->u3.e1.CacheAttribute = MiNonCached;
792 #if MI_TRACE_PFNS
793 Pfn1->PfnUsage = MI_USAGE_INIT_MEMORY;
794 memcpy(Pfn1->ProcessName, "Initial PDE", 16);
795 #endif
796 }
797 else
798 {
799 /* No PFN entry */
800 Pfn1 = NULL;
801 }
802
803 /* Now get the PTE and scan the pages */
804 PointerPte = MiAddressToPte(BaseAddress);
805 for (j = 0; j < PTE_COUNT; j++)
806 {
807 /* Check for a valid PTE */
808 if (PointerPte->u.Hard.Valid == 1)
809 {
810 /* Increase the shared count of the PFN entry for the PDE */
811 ASSERT(Pfn1 != NULL);
812 Pfn1->u2.ShareCount++;
813
814 /* Now check if the PTE is valid memory too */
815 PtePageIndex = PFN_FROM_PTE(PointerPte);
816 if (MiIsRegularMemory(LoaderBlock, PtePageIndex))
817 {
818 /*
819 * Only add pages above the end of system code or pages
820 * that are part of nonpaged pool
821 */
822 if ((BaseAddress >= 0xA0000000) ||
823 ((BaseAddress >= (ULONG_PTR)MmNonPagedPoolStart) &&
824 (BaseAddress < (ULONG_PTR)MmNonPagedPoolStart +
825 MmSizeOfNonPagedPoolInBytes)))
826 {
827 /* Get the PFN entry and make sure it too is valid */
828 Pfn2 = MiGetPfnEntry(PtePageIndex);
829 if ((MmIsAddressValid(Pfn2)) &&
830 (MmIsAddressValid(Pfn2 + 1)))
831 {
832 /* Setup the PFN entry */
833 Pfn2->u4.PteFrame = PageFrameIndex;
834 Pfn2->PteAddress = PointerPte;
835 Pfn2->u2.ShareCount++;
836 Pfn2->u3.e2.ReferenceCount = 1;
837 Pfn2->u3.e1.PageLocation = ActiveAndValid;
838 Pfn2->u3.e1.CacheAttribute = MiNonCached;
839 #if MI_TRACE_PFNS
840 Pfn2->PfnUsage = MI_USAGE_INIT_MEMORY;
841 memcpy(Pfn1->ProcessName, "Initial PTE", 16);
842 #endif
843 }
844 }
845 }
846 }
847
848 /* Next PTE */
849 PointerPte++;
850 BaseAddress += PAGE_SIZE;
851 }
852 }
853 else
854 {
855 /* Next PDE mapped address */
856 BaseAddress += PDE_MAPPED_VA;
857 }
858
859 /* Next PTE */
860 PointerPde++;
861 }
862 }
863
864 VOID
865 NTAPI
866 INIT_FUNCTION
867 MiBuildPfnDatabaseZeroPage(VOID)
868 {
869 PMMPFN Pfn1;
870 PMMPDE PointerPde;
871
872 /* Grab the lowest page and check if it has no real references */
873 Pfn1 = MiGetPfnEntry(MmLowestPhysicalPage);
874 if (!(MmLowestPhysicalPage) && !(Pfn1->u3.e2.ReferenceCount))
875 {
876 /* Make it a bogus page to catch errors */
877 PointerPde = MiAddressToPde(0xFFFFFFFF);
878 Pfn1->u4.PteFrame = PFN_FROM_PTE(PointerPde);
879 Pfn1->PteAddress = (PMMPTE)PointerPde;
880 Pfn1->u2.ShareCount++;
881 Pfn1->u3.e2.ReferenceCount = 0xFFF0;
882 Pfn1->u3.e1.PageLocation = ActiveAndValid;
883 Pfn1->u3.e1.CacheAttribute = MiNonCached;
884 }
885 }
886
887 VOID
888 NTAPI
889 INIT_FUNCTION
890 MiBuildPfnDatabaseFromLoaderBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
891 {
892 PLIST_ENTRY NextEntry;
893 PFN_NUMBER PageCount = 0;
894 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
895 PFN_NUMBER PageFrameIndex;
896 PMMPFN Pfn1;
897 PMMPTE PointerPte;
898 PMMPDE PointerPde;
899 KIRQL OldIrql;
900
901 /* Now loop through the descriptors */
902 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
903 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
904 {
905 /* Get the current descriptor */
906 MdBlock = CONTAINING_RECORD(NextEntry,
907 MEMORY_ALLOCATION_DESCRIPTOR,
908 ListEntry);
909
910 /* Read its data */
911 PageCount = MdBlock->PageCount;
912 PageFrameIndex = MdBlock->BasePage;
913
914 /* Don't allow memory above what the PFN database is mapping */
915 if (PageFrameIndex > MmHighestPhysicalPage)
916 {
917 /* Since they are ordered, everything past here will be larger */
918 break;
919 }
920
921 /* On the other hand, the end page might be higher up... */
922 if ((PageFrameIndex + PageCount) > (MmHighestPhysicalPage + 1))
923 {
924 /* In which case we'll trim the descriptor to go as high as we can */
925 PageCount = MmHighestPhysicalPage + 1 - PageFrameIndex;
926 MdBlock->PageCount = PageCount;
927
928 /* But if there's nothing left to trim, we got too high, so quit */
929 if (!PageCount) break;
930 }
931
932 /* Now check the descriptor type */
933 switch (MdBlock->MemoryType)
934 {
935 /* Check for bad RAM */
936 case LoaderBad:
937
938 DPRINT1("You either have specified /BURNMEMORY or damaged RAM modules.\n");
939 break;
940
941 /* Check for free RAM */
942 case LoaderFree:
943 case LoaderLoadedProgram:
944 case LoaderFirmwareTemporary:
945 case LoaderOsloaderStack:
946
947 /* Get the last page of this descriptor. Note we loop backwards */
948 PageFrameIndex += PageCount - 1;
949 Pfn1 = MiGetPfnEntry(PageFrameIndex);
950
951 /* Lock the PFN Database */
952 OldIrql = MiAcquirePfnLock();
953 while (PageCount--)
954 {
955 /* If the page really has no references, mark it as free */
956 if (!Pfn1->u3.e2.ReferenceCount)
957 {
958 /* Add it to the free list */
959 Pfn1->u3.e1.CacheAttribute = MiNonCached;
960 MiInsertPageInFreeList(PageFrameIndex);
961 }
962
963 /* Go to the next page */
964 Pfn1--;
965 PageFrameIndex--;
966 }
967
968 /* Release PFN database */
969 MiReleasePfnLock(OldIrql);
970
971 /* Done with this block */
972 break;
973
974 /* Check for pages that are invisible to us */
975 case LoaderFirmwarePermanent:
976 case LoaderSpecialMemory:
977 case LoaderBBTMemory:
978
979 /* And skip them */
980 break;
981
982 default:
983
984 /* Map these pages with the KSEG0 mapping that adds 0x80000000 */
985 PointerPte = MiAddressToPte(KSEG0_BASE + (PageFrameIndex << PAGE_SHIFT));
986 Pfn1 = MiGetPfnEntry(PageFrameIndex);
987 while (PageCount--)
988 {
989 /* Check if the page is really unused */
990 PointerPde = MiAddressToPde(KSEG0_BASE + (PageFrameIndex << PAGE_SHIFT));
991 if (!Pfn1->u3.e2.ReferenceCount)
992 {
993 /* Mark it as being in-use */
994 Pfn1->u4.PteFrame = PFN_FROM_PTE(PointerPde);
995 Pfn1->PteAddress = PointerPte;
996 Pfn1->u2.ShareCount++;
997 Pfn1->u3.e2.ReferenceCount = 1;
998 Pfn1->u3.e1.PageLocation = ActiveAndValid;
999 Pfn1->u3.e1.CacheAttribute = MiNonCached;
1000 #if MI_TRACE_PFNS
1001 Pfn1->PfnUsage = MI_USAGE_BOOT_DRIVER;
1002 #endif
1003
1004 /* Check for RAM disk page */
1005 if (MdBlock->MemoryType == LoaderXIPRom)
1006 {
1007 /* Make it a pseudo-I/O ROM mapping */
1008 Pfn1->u1.Flink = 0;
1009 Pfn1->u2.ShareCount = 0;
1010 Pfn1->u3.e2.ReferenceCount = 0;
1011 Pfn1->u3.e1.PageLocation = 0;
1012 Pfn1->u3.e1.Rom = 1;
1013 Pfn1->u4.InPageError = 0;
1014 Pfn1->u3.e1.PrototypePte = 1;
1015 }
1016 }
1017
1018 /* Advance page structures */
1019 Pfn1++;
1020 PageFrameIndex++;
1021 PointerPte++;
1022 }
1023 break;
1024 }
1025
1026 /* Next descriptor entry */
1027 NextEntry = MdBlock->ListEntry.Flink;
1028 }
1029 }
1030
1031 VOID
1032 NTAPI
1033 INIT_FUNCTION
1034 MiBuildPfnDatabaseSelf(VOID)
1035 {
1036 PMMPTE PointerPte, LastPte;
1037 PMMPFN Pfn1;
1038
1039 /* Loop the PFN database page */
1040 PointerPte = MiAddressToPte(MiGetPfnEntry(MmLowestPhysicalPage));
1041 LastPte = MiAddressToPte(MiGetPfnEntry(MmHighestPhysicalPage));
1042 while (PointerPte <= LastPte)
1043 {
1044 /* Make sure the page is valid */
1045 if (PointerPte->u.Hard.Valid == 1)
1046 {
1047 /* Get the PFN entry and just mark it referenced */
1048 Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber);
1049 Pfn1->u2.ShareCount = 1;
1050 Pfn1->u3.e2.ReferenceCount = 1;
1051 #if MI_TRACE_PFNS
1052 Pfn1->PfnUsage = MI_USAGE_PFN_DATABASE;
1053 #endif
1054 }
1055
1056 /* Next */
1057 PointerPte++;
1058 }
1059 }
1060
1061 VOID
1062 NTAPI
1063 INIT_FUNCTION
1064 MiInitializePfnDatabase(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
1065 {
1066 /* Scan memory and start setting up PFN entries */
1067 MiBuildPfnDatabaseFromPages(LoaderBlock);
1068
1069 /* Add the zero page */
1070 MiBuildPfnDatabaseZeroPage();
1071
1072 /* Scan the loader block and build the rest of the PFN database */
1073 MiBuildPfnDatabaseFromLoaderBlock(LoaderBlock);
1074
1075 /* Finally add the pages for the PFN database itself */
1076 MiBuildPfnDatabaseSelf();
1077 }
1078 #endif /* !_M_AMD64 */
1079
1080 VOID
1081 NTAPI
1082 INIT_FUNCTION
1083 MmFreeLoaderBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
1084 {
1085 PLIST_ENTRY NextMd;
1086 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
1087 ULONG_PTR i;
1088 PFN_NUMBER BasePage, LoaderPages;
1089 PMMPFN Pfn1;
1090 KIRQL OldIrql;
1091 PPHYSICAL_MEMORY_RUN Buffer, Entry;
1092
1093 /* Loop the descriptors in order to count them */
1094 i = 0;
1095 NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
1096 while (NextMd != &LoaderBlock->MemoryDescriptorListHead)
1097 {
1098 MdBlock = CONTAINING_RECORD(NextMd,
1099 MEMORY_ALLOCATION_DESCRIPTOR,
1100 ListEntry);
1101 i++;
1102 NextMd = MdBlock->ListEntry.Flink;
1103 }
1104
1105 /* Allocate a structure to hold the physical runs */
1106 Buffer = ExAllocatePoolWithTag(NonPagedPool,
1107 i * sizeof(PHYSICAL_MEMORY_RUN),
1108 'lMmM');
1109 ASSERT(Buffer != NULL);
1110 Entry = Buffer;
1111
1112 /* Loop the descriptors again */
1113 NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
1114 while (NextMd != &LoaderBlock->MemoryDescriptorListHead)
1115 {
1116 /* Check what kind this was */
1117 MdBlock = CONTAINING_RECORD(NextMd,
1118 MEMORY_ALLOCATION_DESCRIPTOR,
1119 ListEntry);
1120 switch (MdBlock->MemoryType)
1121 {
1122 /* Registry, NLS, and heap data */
1123 case LoaderRegistryData:
1124 case LoaderOsloaderHeap:
1125 case LoaderNlsData:
1126 /* Are all a candidate for deletion */
1127 Entry->BasePage = MdBlock->BasePage;
1128 Entry->PageCount = MdBlock->PageCount;
1129 Entry++;
1130
1131 /* We keep the rest */
1132 default:
1133 break;
1134 }
1135
1136 /* Move to the next descriptor */
1137 NextMd = MdBlock->ListEntry.Flink;
1138 }
1139
1140 /* Acquire the PFN lock */
1141 OldIrql = MiAcquirePfnLock();
1142
1143 /* Loop the runs */
1144 LoaderPages = 0;
1145 while (--Entry >= Buffer)
1146 {
1147 /* See how many pages are in this run */
1148 i = Entry->PageCount;
1149 BasePage = Entry->BasePage;
1150
1151 /* Loop each page */
1152 Pfn1 = MiGetPfnEntry(BasePage);
1153 while (i--)
1154 {
1155 /* Check if it has references or is in any kind of list */
1156 if (!(Pfn1->u3.e2.ReferenceCount) && (!Pfn1->u1.Flink))
1157 {
1158 /* Set the new PTE address and put this page into the free list */
1159 Pfn1->PteAddress = (PMMPTE)(BasePage << PAGE_SHIFT);
1160 MiInsertPageInFreeList(BasePage);
1161 LoaderPages++;
1162 }
1163 else if (BasePage)
1164 {
1165 /* It has a reference, so simply drop it */
1166 ASSERT(MI_IS_PHYSICAL_ADDRESS(MiPteToAddress(Pfn1->PteAddress)) == FALSE);
1167
1168 /* Drop a dereference on this page, which should delete it */
1169 Pfn1->PteAddress->u.Long = 0;
1170 MI_SET_PFN_DELETED(Pfn1);
1171 MiDecrementShareCount(Pfn1, BasePage);
1172 LoaderPages++;
1173 }
1174
1175 /* Move to the next page */
1176 Pfn1++;
1177 BasePage++;
1178 }
1179 }
1180
1181 /* Release the PFN lock and flush the TLB */
1182 DPRINT("Loader pages freed: %lx\n", LoaderPages);
1183 MiReleasePfnLock(OldIrql);
1184 KeFlushCurrentTb();
1185
1186 /* Free our run structure */
1187 ExFreePoolWithTag(Buffer, 'lMmM');
1188 }
1189
1190 VOID
1191 NTAPI
1192 INIT_FUNCTION
1193 MiAdjustWorkingSetManagerParameters(IN BOOLEAN Client)
1194 {
1195 /* This function needs to do more work, for now, we tune page minimums */
1196
1197 /* Check for a system with around 64MB RAM or more */
1198 if (MmNumberOfPhysicalPages >= (63 * _1MB) / PAGE_SIZE)
1199 {
1200 /* Double the minimum amount of pages we consider for a "plenty free" scenario */
1201 MmPlentyFreePages *= 2;
1202 }
1203 }
1204
1205 VOID
1206 NTAPI
1207 INIT_FUNCTION
1208 MiNotifyMemoryEvents(VOID)
1209 {
1210 /* Are we in a low-memory situation? */
1211 if (MmAvailablePages < MmLowMemoryThreshold)
1212 {
1213 /* Clear high, set low */
1214 if (KeReadStateEvent(MiHighMemoryEvent)) KeClearEvent(MiHighMemoryEvent);
1215 if (!KeReadStateEvent(MiLowMemoryEvent)) KeSetEvent(MiLowMemoryEvent, 0, FALSE);
1216 }
1217 else if (MmAvailablePages < MmHighMemoryThreshold)
1218 {
1219 /* We are in between, clear both */
1220 if (KeReadStateEvent(MiHighMemoryEvent)) KeClearEvent(MiHighMemoryEvent);
1221 if (KeReadStateEvent(MiLowMemoryEvent)) KeClearEvent(MiLowMemoryEvent);
1222 }
1223 else
1224 {
1225 /* Clear low, set high */
1226 if (KeReadStateEvent(MiLowMemoryEvent)) KeClearEvent(MiLowMemoryEvent);
1227 if (!KeReadStateEvent(MiHighMemoryEvent)) KeSetEvent(MiHighMemoryEvent, 0, FALSE);
1228 }
1229 }
1230
1231 NTSTATUS
1232 NTAPI
1233 INIT_FUNCTION
1234 MiCreateMemoryEvent(IN PUNICODE_STRING Name,
1235 OUT PKEVENT *Event)
1236 {
1237 PACL Dacl;
1238 HANDLE EventHandle;
1239 ULONG DaclLength;
1240 NTSTATUS Status;
1241 OBJECT_ATTRIBUTES ObjectAttributes;
1242 SECURITY_DESCRIPTOR SecurityDescriptor;
1243
1244 /* Create the SD */
1245 Status = RtlCreateSecurityDescriptor(&SecurityDescriptor,
1246 SECURITY_DESCRIPTOR_REVISION);
1247 if (!NT_SUCCESS(Status)) return Status;
1248
1249 /* One ACL with 3 ACEs, containing each one SID */
1250 DaclLength = sizeof(ACL) +
1251 3 * sizeof(ACCESS_ALLOWED_ACE) +
1252 RtlLengthSid(SeLocalSystemSid) +
1253 RtlLengthSid(SeAliasAdminsSid) +
1254 RtlLengthSid(SeWorldSid);
1255
1256 /* Allocate space for the DACL */
1257 Dacl = ExAllocatePoolWithTag(PagedPool, DaclLength, 'lcaD');
1258 if (!Dacl) return STATUS_INSUFFICIENT_RESOURCES;
1259
1260 /* Setup the ACL inside it */
1261 Status = RtlCreateAcl(Dacl, DaclLength, ACL_REVISION);
1262 if (!NT_SUCCESS(Status)) goto CleanUp;
1263
1264 /* Add query rights for everyone */
1265 Status = RtlAddAccessAllowedAce(Dacl,
1266 ACL_REVISION,
1267 SYNCHRONIZE | EVENT_QUERY_STATE | READ_CONTROL,
1268 SeWorldSid);
1269 if (!NT_SUCCESS(Status)) goto CleanUp;
1270
1271 /* Full rights for the admin */
1272 Status = RtlAddAccessAllowedAce(Dacl,
1273 ACL_REVISION,
1274 EVENT_ALL_ACCESS,
1275 SeAliasAdminsSid);
1276 if (!NT_SUCCESS(Status)) goto CleanUp;
1277
1278 /* As well as full rights for the system */
1279 Status = RtlAddAccessAllowedAce(Dacl,
1280 ACL_REVISION,
1281 EVENT_ALL_ACCESS,
1282 SeLocalSystemSid);
1283 if (!NT_SUCCESS(Status)) goto CleanUp;
1284
1285 /* Set this DACL inside the SD */
1286 Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor,
1287 TRUE,
1288 Dacl,
1289 FALSE);
1290 if (!NT_SUCCESS(Status)) goto CleanUp;
1291
1292 /* Setup the event attributes, making sure it's a permanent one */
1293 InitializeObjectAttributes(&ObjectAttributes,
1294 Name,
1295 OBJ_KERNEL_HANDLE | OBJ_PERMANENT,
1296 NULL,
1297 &SecurityDescriptor);
1298
1299 /* Create the event */
1300 Status = ZwCreateEvent(&EventHandle,
1301 EVENT_ALL_ACCESS,
1302 &ObjectAttributes,
1303 NotificationEvent,
1304 FALSE);
1305 CleanUp:
1306 /* Free the DACL */
1307 ExFreePoolWithTag(Dacl, 'lcaD');
1308
1309 /* Check if this is the success path */
1310 if (NT_SUCCESS(Status))
1311 {
1312 /* Add a reference to the object, then close the handle we had */
1313 Status = ObReferenceObjectByHandle(EventHandle,
1314 EVENT_MODIFY_STATE,
1315 ExEventObjectType,
1316 KernelMode,
1317 (PVOID*)Event,
1318 NULL);
1319 ZwClose (EventHandle);
1320 }
1321
1322 /* Return status */
1323 return Status;
1324 }
1325
1326 BOOLEAN
1327 NTAPI
1328 INIT_FUNCTION
1329 MiInitializeMemoryEvents(VOID)
1330 {
1331 UNICODE_STRING LowString = RTL_CONSTANT_STRING(L"\\KernelObjects\\LowMemoryCondition");
1332 UNICODE_STRING HighString = RTL_CONSTANT_STRING(L"\\KernelObjects\\HighMemoryCondition");
1333 UNICODE_STRING LowPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\LowPagedPoolCondition");
1334 UNICODE_STRING HighPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\HighPagedPoolCondition");
1335 UNICODE_STRING LowNonPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\LowNonPagedPoolCondition");
1336 UNICODE_STRING HighNonPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\HighNonPagedPoolCondition");
1337 NTSTATUS Status;
1338
1339 /* Check if we have a registry setting */
1340 if (MmLowMemoryThreshold)
1341 {
1342 /* Convert it to pages */
1343 MmLowMemoryThreshold *= (_1MB / PAGE_SIZE);
1344 }
1345 else
1346 {
1347 /* The low memory threshold is hit when we don't consider that we have "plenty" of free pages anymore */
1348 MmLowMemoryThreshold = MmPlentyFreePages;
1349
1350 /* More than one GB of memory? */
1351 if (MmNumberOfPhysicalPages > 0x40000)
1352 {
1353 /* Start at 32MB, and add another 16MB for each GB */
1354 MmLowMemoryThreshold = (32 * _1MB) / PAGE_SIZE;
1355 MmLowMemoryThreshold += ((MmNumberOfPhysicalPages - 0x40000) >> 7);
1356 }
1357 else if (MmNumberOfPhysicalPages > 0x8000)
1358 {
1359 /* For systems with > 128MB RAM, add another 4MB for each 128MB */
1360 MmLowMemoryThreshold += ((MmNumberOfPhysicalPages - 0x8000) >> 5);
1361 }
1362
1363 /* Don't let the minimum threshold go past 64MB */
1364 MmLowMemoryThreshold = min(MmLowMemoryThreshold, (64 * _1MB) / PAGE_SIZE);
1365 }
1366
1367 /* Check if we have a registry setting */
1368 if (MmHighMemoryThreshold)
1369 {
1370 /* Convert it into pages */
1371 MmHighMemoryThreshold *= (_1MB / PAGE_SIZE);
1372 }
1373 else
1374 {
1375 /* Otherwise, the default is three times the low memory threshold */
1376 MmHighMemoryThreshold = 3 * MmLowMemoryThreshold;
1377 ASSERT(MmHighMemoryThreshold > MmLowMemoryThreshold);
1378 }
1379
1380 /* Make sure high threshold is actually higher than the low */
1381 MmHighMemoryThreshold = max(MmHighMemoryThreshold, MmLowMemoryThreshold);
1382
1383 /* Create the memory events for all the thresholds */
1384 Status = MiCreateMemoryEvent(&LowString, &MiLowMemoryEvent);
1385 if (!NT_SUCCESS(Status)) return FALSE;
1386 Status = MiCreateMemoryEvent(&HighString, &MiHighMemoryEvent);
1387 if (!NT_SUCCESS(Status)) return FALSE;
1388 Status = MiCreateMemoryEvent(&LowPagedPoolString, &MiLowPagedPoolEvent);
1389 if (!NT_SUCCESS(Status)) return FALSE;
1390 Status = MiCreateMemoryEvent(&HighPagedPoolString, &MiHighPagedPoolEvent);
1391 if (!NT_SUCCESS(Status)) return FALSE;
1392 Status = MiCreateMemoryEvent(&LowNonPagedPoolString, &MiLowNonPagedPoolEvent);
1393 if (!NT_SUCCESS(Status)) return FALSE;
1394 Status = MiCreateMemoryEvent(&HighNonPagedPoolString, &MiHighNonPagedPoolEvent);
1395 if (!NT_SUCCESS(Status)) return FALSE;
1396
1397 /* Now setup the pool events */
1398 MiInitializePoolEvents();
1399
1400 /* Set the initial event state */
1401 MiNotifyMemoryEvents();
1402 return TRUE;
1403 }
1404
1405 VOID
1406 NTAPI
1407 INIT_FUNCTION
1408 MiAddHalIoMappings(VOID)
1409 {
1410 PVOID BaseAddress;
1411 PMMPDE PointerPde, LastPde;
1412 PMMPTE PointerPte;
1413 ULONG j;
1414 PFN_NUMBER PageFrameIndex;
1415
1416 /* HAL Heap address -- should be on a PDE boundary */
1417 BaseAddress = (PVOID)MM_HAL_VA_START;
1418 ASSERT(MiAddressToPteOffset(BaseAddress) == 0);
1419
1420 /* Check how many PDEs the heap has */
1421 PointerPde = MiAddressToPde(BaseAddress);
1422 LastPde = MiAddressToPde((PVOID)MM_HAL_VA_END);
1423
1424 while (PointerPde <= LastPde)
1425 {
1426 /* Does the HAL own this mapping? */
1427 if ((PointerPde->u.Hard.Valid == 1) &&
1428 (MI_IS_PAGE_LARGE(PointerPde) == FALSE))
1429 {
1430 /* Get the PTE for it and scan each page */
1431 PointerPte = MiAddressToPte(BaseAddress);
1432 for (j = 0 ; j < PTE_COUNT; j++)
1433 {
1434 /* Does the HAL own this page? */
1435 if (PointerPte->u.Hard.Valid == 1)
1436 {
1437 /* Is the HAL using it for device or I/O mapped memory? */
1438 PageFrameIndex = PFN_FROM_PTE(PointerPte);
1439 if (!MiGetPfnEntry(PageFrameIndex))
1440 {
1441 /* FIXME: For PAT, we need to track I/O cache attributes for coherency */
1442 DPRINT1("HAL I/O Mapping at %p is unsafe\n", BaseAddress);
1443 }
1444 }
1445
1446 /* Move to the next page */
1447 BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + PAGE_SIZE);
1448 PointerPte++;
1449 }
1450 }
1451 else
1452 {
1453 /* Move to the next address */
1454 BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + PDE_MAPPED_VA);
1455 }
1456
1457 /* Move to the next PDE */
1458 PointerPde++;
1459 }
1460 }
1461
1462 VOID
1463 NTAPI
1464 MmDumpArmPfnDatabase(IN BOOLEAN StatusOnly)
1465 {
1466 ULONG i;
1467 PMMPFN Pfn1;
1468 PCHAR Consumer = "Unknown";
1469 KIRQL OldIrql;
1470 ULONG ActivePages = 0, FreePages = 0, OtherPages = 0;
1471 #if MI_TRACE_PFNS
1472 ULONG UsageBucket[MI_USAGE_FREE_PAGE + 1] = {0};
1473 PCHAR MI_USAGE_TEXT[MI_USAGE_FREE_PAGE + 1] =
1474 {
1475 "Not set",
1476 "Paged Pool",
1477 "Nonpaged Pool",
1478 "Nonpaged Pool Ex",
1479 "Kernel Stack",
1480 "Kernel Stack Ex",
1481 "System PTE",
1482 "VAD",
1483 "PEB/TEB",
1484 "Section",
1485 "Page Table",
1486 "Page Directory",
1487 "Old Page Table",
1488 "Driver Page",
1489 "Contiguous Alloc",
1490 "MDL",
1491 "Demand Zero",
1492 "Zero Loop",
1493 "Cache",
1494 "PFN Database",
1495 "Boot Driver",
1496 "Initial Memory",
1497 "Free Page"
1498 };
1499 #endif
1500 //
1501 // Loop the PFN database
1502 //
1503 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1504 for (i = 0; i <= MmHighestPhysicalPage; i++)
1505 {
1506 Pfn1 = MiGetPfnEntry(i);
1507 if (!Pfn1) continue;
1508 #if MI_TRACE_PFNS
1509 ASSERT(Pfn1->PfnUsage <= MI_USAGE_FREE_PAGE);
1510 #endif
1511 //
1512 // Get the page location
1513 //
1514 switch (Pfn1->u3.e1.PageLocation)
1515 {
1516 case ActiveAndValid:
1517
1518 Consumer = "Active and Valid";
1519 ActivePages++;
1520 break;
1521
1522 case ZeroedPageList:
1523
1524 Consumer = "Zero Page List";
1525 FreePages++;
1526 break;//continue;
1527
1528 case FreePageList:
1529
1530 Consumer = "Free Page List";
1531 FreePages++;
1532 break;//continue;
1533
1534 default:
1535
1536 Consumer = "Other (ASSERT!)";
1537 OtherPages++;
1538 break;
1539 }
1540
1541 #if MI_TRACE_PFNS
1542 /* Add into bucket */
1543 UsageBucket[Pfn1->PfnUsage]++;
1544 #endif
1545
1546 //
1547 // Pretty-print the page
1548 //
1549 if (!StatusOnly)
1550 DbgPrint("0x%08p:\t%20s\t(%04d.%04d)\t[%16s - %16s])\n",
1551 i << PAGE_SHIFT,
1552 Consumer,
1553 Pfn1->u3.e2.ReferenceCount,
1554 Pfn1->u2.ShareCount == LIST_HEAD ? 0xFFFF : Pfn1->u2.ShareCount,
1555 #if MI_TRACE_PFNS
1556 MI_USAGE_TEXT[Pfn1->PfnUsage],
1557 Pfn1->ProcessName);
1558 #else
1559 "Page tracking",
1560 "is disabled");
1561 #endif
1562 }
1563
1564 DbgPrint("Active: %5d pages\t[%6d KB]\n", ActivePages, (ActivePages << PAGE_SHIFT) / 1024);
1565 DbgPrint("Free: %5d pages\t[%6d KB]\n", FreePages, (FreePages << PAGE_SHIFT) / 1024);
1566 DbgPrint("Other: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1567 DbgPrint("-----------------------------------------\n");
1568 #if MI_TRACE_PFNS
1569 OtherPages = UsageBucket[MI_USAGE_BOOT_DRIVER];
1570 DbgPrint("Boot Images: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1571 OtherPages = UsageBucket[MI_USAGE_DRIVER_PAGE];
1572 DbgPrint("System Drivers: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1573 OtherPages = UsageBucket[MI_USAGE_PFN_DATABASE];
1574 DbgPrint("PFN Database: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1575 OtherPages = UsageBucket[MI_USAGE_PAGE_TABLE] + UsageBucket[MI_USAGE_PAGE_DIRECTORY] + UsageBucket[MI_USAGE_LEGACY_PAGE_DIRECTORY];
1576 DbgPrint("Page Tables: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1577 OtherPages = UsageBucket[MI_USAGE_SYSTEM_PTE];
1578 DbgPrint("System PTEs: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1579 OtherPages = UsageBucket[MI_USAGE_VAD];
1580 DbgPrint("VADs: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1581 OtherPages = UsageBucket[MI_USAGE_CONTINOUS_ALLOCATION];
1582 DbgPrint("Continuous Allocs: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1583 OtherPages = UsageBucket[MI_USAGE_MDL];
1584 DbgPrint("MDLs: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1585 OtherPages = UsageBucket[MI_USAGE_NONPAGED_POOL] + UsageBucket[MI_USAGE_NONPAGED_POOL_EXPANSION];
1586 DbgPrint("NonPaged Pool: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1587 OtherPages = UsageBucket[MI_USAGE_PAGED_POOL];
1588 DbgPrint("Paged Pool: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1589 OtherPages = UsageBucket[MI_USAGE_DEMAND_ZERO];
1590 DbgPrint("Demand Zero: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1591 OtherPages = UsageBucket[MI_USAGE_ZERO_LOOP];
1592 DbgPrint("Zero Loop: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1593 OtherPages = UsageBucket[MI_USAGE_PEB_TEB];
1594 DbgPrint("PEB/TEB: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1595 OtherPages = UsageBucket[MI_USAGE_KERNEL_STACK] + UsageBucket[MI_USAGE_KERNEL_STACK_EXPANSION];
1596 DbgPrint("Kernel Stack: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1597 OtherPages = UsageBucket[MI_USAGE_INIT_MEMORY];
1598 DbgPrint("Init Memory: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1599 OtherPages = UsageBucket[MI_USAGE_SECTION];
1600 DbgPrint("Sections: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1601 OtherPages = UsageBucket[MI_USAGE_CACHE];
1602 DbgPrint("Cache: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1603 OtherPages = UsageBucket[MI_USAGE_FREE_PAGE];
1604 DbgPrint("Free: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024);
1605 #endif
1606 KeLowerIrql(OldIrql);
1607 }
1608
1609 PPHYSICAL_MEMORY_DESCRIPTOR
1610 NTAPI
1611 INIT_FUNCTION
1612 MmInitializeMemoryLimits(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
1613 IN PBOOLEAN IncludeType)
1614 {
1615 PLIST_ENTRY NextEntry;
1616 ULONG Run = 0, InitialRuns;
1617 PFN_NUMBER NextPage = -1, PageCount = 0;
1618 PPHYSICAL_MEMORY_DESCRIPTOR Buffer, NewBuffer;
1619 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
1620
1621 //
1622 // Start with the maximum we might need
1623 //
1624 InitialRuns = MiNumberDescriptors;
1625
1626 //
1627 // Allocate the maximum we'll ever need
1628 //
1629 Buffer = ExAllocatePoolWithTag(NonPagedPool,
1630 sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
1631 sizeof(PHYSICAL_MEMORY_RUN) *
1632 (InitialRuns - 1),
1633 'lMmM');
1634 if (!Buffer) return NULL;
1635
1636 //
1637 // For now that's how many runs we have
1638 //
1639 Buffer->NumberOfRuns = InitialRuns;
1640
1641 //
1642 // Now loop through the descriptors again
1643 //
1644 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
1645 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
1646 {
1647 //
1648 // Grab each one, and check if it's one we should include
1649 //
1650 MdBlock = CONTAINING_RECORD(NextEntry,
1651 MEMORY_ALLOCATION_DESCRIPTOR,
1652 ListEntry);
1653 if ((MdBlock->MemoryType < LoaderMaximum) &&
1654 (IncludeType[MdBlock->MemoryType]))
1655 {
1656 //
1657 // Add this to our running total
1658 //
1659 PageCount += MdBlock->PageCount;
1660
1661 //
1662 // Check if the next page is described by the next descriptor
1663 //
1664 if (MdBlock->BasePage == NextPage)
1665 {
1666 //
1667 // Combine it into the same physical run
1668 //
1669 ASSERT(MdBlock->PageCount != 0);
1670 Buffer->Run[Run - 1].PageCount += MdBlock->PageCount;
1671 NextPage += MdBlock->PageCount;
1672 }
1673 else
1674 {
1675 //
1676 // Otherwise just duplicate the descriptor's contents
1677 //
1678 Buffer->Run[Run].BasePage = MdBlock->BasePage;
1679 Buffer->Run[Run].PageCount = MdBlock->PageCount;
1680 NextPage = Buffer->Run[Run].BasePage + Buffer->Run[Run].PageCount;
1681
1682 //
1683 // And in this case, increase the number of runs
1684 //
1685 Run++;
1686 }
1687 }
1688
1689 //
1690 // Try the next descriptor
1691 //
1692 NextEntry = MdBlock->ListEntry.Flink;
1693 }
1694
1695 //
1696 // We should not have been able to go past our initial estimate
1697 //
1698 ASSERT(Run <= Buffer->NumberOfRuns);
1699
1700 //
1701 // Our guess was probably exaggerated...
1702 //
1703 if (InitialRuns > Run)
1704 {
1705 //
1706 // Allocate a more accurately sized buffer
1707 //
1708 NewBuffer = ExAllocatePoolWithTag(NonPagedPool,
1709 sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
1710 sizeof(PHYSICAL_MEMORY_RUN) *
1711 (Run - 1),
1712 'lMmM');
1713 if (NewBuffer)
1714 {
1715 //
1716 // Copy the old buffer into the new, then free it
1717 //
1718 RtlCopyMemory(NewBuffer->Run,
1719 Buffer->Run,
1720 sizeof(PHYSICAL_MEMORY_RUN) * Run);
1721 ExFreePoolWithTag(Buffer, 'lMmM');
1722
1723 //
1724 // Now use the new buffer
1725 //
1726 Buffer = NewBuffer;
1727 }
1728 }
1729
1730 //
1731 // Write the final numbers, and return it
1732 //
1733 Buffer->NumberOfRuns = Run;
1734 Buffer->NumberOfPages = PageCount;
1735 return Buffer;
1736 }
1737
1738 VOID
1739 NTAPI
1740 INIT_FUNCTION
1741 MiBuildPagedPool(VOID)
1742 {
1743 PMMPTE PointerPte;
1744 PMMPDE PointerPde;
1745 MMPDE TempPde = ValidKernelPde;
1746 PFN_NUMBER PageFrameIndex;
1747 KIRQL OldIrql;
1748 SIZE_T Size;
1749 ULONG BitMapSize;
1750 #if (_MI_PAGING_LEVELS >= 3)
1751 MMPPE TempPpe = ValidKernelPpe;
1752 PMMPPE PointerPpe;
1753 #elif (_MI_PAGING_LEVELS == 2)
1754 MMPTE TempPte = ValidKernelPte;
1755
1756 //
1757 // Get the page frame number for the system page directory
1758 //
1759 PointerPte = MiAddressToPte(PDE_BASE);
1760 ASSERT(PD_COUNT == 1);
1761 MmSystemPageDirectory[0] = PFN_FROM_PTE(PointerPte);
1762
1763 //
1764 // Allocate a system PTE which will hold a copy of the page directory
1765 //
1766 PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
1767 ASSERT(PointerPte);
1768 MmSystemPagePtes = MiPteToAddress(PointerPte);
1769
1770 //
1771 // Make this system PTE point to the system page directory.
1772 // It is now essentially double-mapped. This will be used later for lazy
1773 // evaluation of PDEs accross process switches, similarly to how the Global
1774 // page directory array in the old ReactOS Mm is used (but in a less hacky
1775 // way).
1776 //
1777 TempPte = ValidKernelPte;
1778 ASSERT(PD_COUNT == 1);
1779 TempPte.u.Hard.PageFrameNumber = MmSystemPageDirectory[0];
1780 MI_WRITE_VALID_PTE(PointerPte, TempPte);
1781 #endif
1782
1783 #ifdef _M_IX86
1784 //
1785 // Let's get back to paged pool work: size it up.
1786 // By default, it should be twice as big as nonpaged pool.
1787 //
1788 MmSizeOfPagedPoolInBytes = 2 * MmMaximumNonPagedPoolInBytes;
1789 if (MmSizeOfPagedPoolInBytes > ((ULONG_PTR)MmNonPagedSystemStart -
1790 (ULONG_PTR)MmPagedPoolStart))
1791 {
1792 //
1793 // On the other hand, we have limited VA space, so make sure that the VA
1794 // for paged pool doesn't overflow into nonpaged pool VA. Otherwise, set
1795 // whatever maximum is possible.
1796 //
1797 MmSizeOfPagedPoolInBytes = (ULONG_PTR)MmNonPagedSystemStart -
1798 (ULONG_PTR)MmPagedPoolStart;
1799 }
1800 #endif // _M_IX86
1801
1802 //
1803 // Get the size in pages and make sure paged pool is at least 32MB.
1804 //
1805 Size = MmSizeOfPagedPoolInBytes;
1806 if (Size < MI_MIN_INIT_PAGED_POOLSIZE) Size = MI_MIN_INIT_PAGED_POOLSIZE;
1807 Size = BYTES_TO_PAGES(Size);
1808
1809 //
1810 // Now check how many PTEs will be required for these many pages.
1811 //
1812 Size = (Size + (1024 - 1)) / 1024;
1813
1814 //
1815 // Recompute the page-aligned size of the paged pool, in bytes and pages.
1816 //
1817 MmSizeOfPagedPoolInBytes = Size * PAGE_SIZE * 1024;
1818 MmSizeOfPagedPoolInPages = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT;
1819
1820 #ifdef _M_IX86
1821 //
1822 // Let's be really sure this doesn't overflow into nonpaged system VA
1823 //
1824 ASSERT((MmSizeOfPagedPoolInBytes + (ULONG_PTR)MmPagedPoolStart) <=
1825 (ULONG_PTR)MmNonPagedSystemStart);
1826 #endif // _M_IX86
1827
1828 //
1829 // This is where paged pool ends
1830 //
1831 MmPagedPoolEnd = (PVOID)(((ULONG_PTR)MmPagedPoolStart +
1832 MmSizeOfPagedPoolInBytes) - 1);
1833
1834 //
1835 // Lock the PFN database
1836 //
1837 OldIrql = MiAcquirePfnLock();
1838
1839 #if (_MI_PAGING_LEVELS >= 3)
1840 /* On these systems, there's no double-mapping, so instead, the PPEs
1841 * are setup to span the entire paged pool area, so there's no need for the
1842 * system PD */
1843 for (PointerPpe = MiAddressToPpe(MmPagedPoolStart);
1844 PointerPpe <= MiAddressToPpe(MmPagedPoolEnd);
1845 PointerPpe++)
1846 {
1847 /* Check if the PPE is already valid */
1848 if (!PointerPpe->u.Hard.Valid)
1849 {
1850 /* It is not, so map a fresh zeroed page */
1851 TempPpe.u.Hard.PageFrameNumber = MiRemoveZeroPage(0);
1852 MI_WRITE_VALID_PPE(PointerPpe, TempPpe);
1853 }
1854 }
1855 #endif
1856
1857 //
1858 // So now get the PDE for paged pool and zero it out
1859 //
1860 PointerPde = MiAddressToPde(MmPagedPoolStart);
1861 RtlZeroMemory(PointerPde,
1862 (1 + MiAddressToPde(MmPagedPoolEnd) - PointerPde) * sizeof(MMPDE));
1863
1864 //
1865 // Next, get the first and last PTE
1866 //
1867 PointerPte = MiAddressToPte(MmPagedPoolStart);
1868 MmPagedPoolInfo.FirstPteForPagedPool = PointerPte;
1869 MmPagedPoolInfo.LastPteForPagedPool = MiAddressToPte(MmPagedPoolEnd);
1870
1871 /* Allocate a page and map the first paged pool PDE */
1872 MI_SET_USAGE(MI_USAGE_PAGED_POOL);
1873 MI_SET_PROCESS2("Kernel");
1874 PageFrameIndex = MiRemoveZeroPage(0);
1875 TempPde.u.Hard.PageFrameNumber = PageFrameIndex;
1876 MI_WRITE_VALID_PDE(PointerPde, TempPde);
1877 #if (_MI_PAGING_LEVELS >= 3)
1878 /* Use the PPE of MmPagedPoolStart that was setup above */
1879 // Bla = PFN_FROM_PTE(PpeAddress(MmPagedPool...));
1880
1881 /* Initialize the PFN entry for it */
1882 MiInitializePfnForOtherProcess(PageFrameIndex,
1883 (PMMPTE)PointerPde,
1884 PFN_FROM_PTE(MiAddressToPpe(MmPagedPoolStart)));
1885 #else
1886 /* Do it this way */
1887 // Bla = MmSystemPageDirectory[(PointerPde - (PMMPTE)PDE_BASE) / PDE_COUNT]
1888
1889 /* Initialize the PFN entry for it */
1890 MiInitializePfnForOtherProcess(PageFrameIndex,
1891 (PMMPTE)PointerPde,
1892 MmSystemPageDirectory[(PointerPde - (PMMPDE)PDE_BASE) / PDE_COUNT]);
1893 #endif
1894
1895 //
1896 // Release the PFN database lock
1897 //
1898 MiReleasePfnLock(OldIrql);
1899
1900 //
1901 // We only have one PDE mapped for now... at fault time, additional PDEs
1902 // will be allocated to handle paged pool growth. This is where they'll have
1903 // to start.
1904 //
1905 MmPagedPoolInfo.NextPdeForPagedPoolExpansion = PointerPde + 1;
1906
1907 //
1908 // We keep track of each page via a bit, so check how big the bitmap will
1909 // have to be (make sure to align our page count such that it fits nicely
1910 // into a 4-byte aligned bitmap.
1911 //
1912 // We'll also allocate the bitmap header itself part of the same buffer.
1913 //
1914 Size = Size * 1024;
1915 ASSERT(Size == MmSizeOfPagedPoolInPages);
1916 BitMapSize = (ULONG)Size;
1917 Size = sizeof(RTL_BITMAP) + (((Size + 31) / 32) * sizeof(ULONG));
1918
1919 //
1920 // Allocate the allocation bitmap, which tells us which regions have not yet
1921 // been mapped into memory
1922 //
1923 MmPagedPoolInfo.PagedPoolAllocationMap = ExAllocatePoolWithTag(NonPagedPool,
1924 Size,
1925 TAG_MM);
1926 ASSERT(MmPagedPoolInfo.PagedPoolAllocationMap);
1927
1928 //
1929 // Initialize it such that at first, only the first page's worth of PTEs is
1930 // marked as allocated (incidentially, the first PDE we allocated earlier).
1931 //
1932 RtlInitializeBitMap(MmPagedPoolInfo.PagedPoolAllocationMap,
1933 (PULONG)(MmPagedPoolInfo.PagedPoolAllocationMap + 1),
1934 BitMapSize);
1935 RtlSetAllBits(MmPagedPoolInfo.PagedPoolAllocationMap);
1936 RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, 0, 1024);
1937
1938 //
1939 // We have a second bitmap, which keeps track of where allocations end.
1940 // Given the allocation bitmap and a base address, we can therefore figure
1941 // out which page is the last page of that allocation, and thus how big the
1942 // entire allocation is.
1943 //
1944 MmPagedPoolInfo.EndOfPagedPoolBitmap = ExAllocatePoolWithTag(NonPagedPool,
1945 Size,
1946 TAG_MM);
1947 ASSERT(MmPagedPoolInfo.EndOfPagedPoolBitmap);
1948 RtlInitializeBitMap(MmPagedPoolInfo.EndOfPagedPoolBitmap,
1949 (PULONG)(MmPagedPoolInfo.EndOfPagedPoolBitmap + 1),
1950 BitMapSize);
1951
1952 //
1953 // Since no allocations have been made yet, there are no bits set as the end
1954 //
1955 RtlClearAllBits(MmPagedPoolInfo.EndOfPagedPoolBitmap);
1956
1957 //
1958 // Initialize paged pool.
1959 //
1960 InitializePool(PagedPool, 0);
1961
1962 /* Initialize special pool */
1963 MiInitializeSpecialPool();
1964
1965 /* Default low threshold of 30MB or one fifth of paged pool */
1966 MiLowPagedPoolThreshold = (30 * _1MB) >> PAGE_SHIFT;
1967 MiLowPagedPoolThreshold = min(MiLowPagedPoolThreshold, Size / 5);
1968
1969 /* Default high threshold of 60MB or 25% */
1970 MiHighPagedPoolThreshold = (60 * _1MB) >> PAGE_SHIFT;
1971 MiHighPagedPoolThreshold = min(MiHighPagedPoolThreshold, (Size * 2) / 5);
1972 ASSERT(MiLowPagedPoolThreshold < MiHighPagedPoolThreshold);
1973
1974 /* Setup the global session space */
1975 MiInitializeSystemSpaceMap(NULL);
1976 }
1977
1978 VOID
1979 NTAPI
1980 INIT_FUNCTION
1981 MiDbgDumpMemoryDescriptors(VOID)
1982 {
1983 PLIST_ENTRY NextEntry;
1984 PMEMORY_ALLOCATION_DESCRIPTOR Md;
1985 PFN_NUMBER TotalPages = 0;
1986 PCHAR
1987 MemType[] =
1988 {
1989 "ExceptionBlock ",
1990 "SystemBlock ",
1991 "Free ",
1992 "Bad ",
1993 "LoadedProgram ",
1994 "FirmwareTemporary ",
1995 "FirmwarePermanent ",
1996 "OsloaderHeap ",
1997 "OsloaderStack ",
1998 "SystemCode ",
1999 "HalCode ",
2000 "BootDriver ",
2001 "ConsoleInDriver ",
2002 "ConsoleOutDriver ",
2003 "StartupDpcStack ",
2004 "StartupKernelStack",
2005 "StartupPanicStack ",
2006 "StartupPcrPage ",
2007 "StartupPdrPage ",
2008 "RegistryData ",
2009 "MemoryData ",
2010 "NlsData ",
2011 "SpecialMemory ",
2012 "BBTMemory ",
2013 "LoaderReserve ",
2014 "LoaderXIPRom "
2015 };
2016
2017 DPRINT1("Base\t\tLength\t\tType\n");
2018 for (NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink;
2019 NextEntry != &KeLoaderBlock->MemoryDescriptorListHead;
2020 NextEntry = NextEntry->Flink)
2021 {
2022 Md = CONTAINING_RECORD(NextEntry, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry);
2023 DPRINT1("%08lX\t%08lX\t%s\n", Md->BasePage, Md->PageCount, MemType[Md->MemoryType]);
2024 TotalPages += Md->PageCount;
2025 }
2026
2027 DPRINT1("Total: %08lX (%lu MB)\n", (ULONG)TotalPages, (ULONG)(TotalPages * PAGE_SIZE) / 1024 / 1024);
2028 }
2029
2030 BOOLEAN
2031 NTAPI
2032 INIT_FUNCTION
2033 MmArmInitSystem(IN ULONG Phase,
2034 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
2035 {
2036 ULONG i;
2037 BOOLEAN IncludeType[LoaderMaximum];
2038 PVOID Bitmap;
2039 PPHYSICAL_MEMORY_RUN Run;
2040 PFN_NUMBER PageCount;
2041 #if DBG
2042 ULONG j;
2043 PMMPTE PointerPte, TestPte;
2044 MMPTE TempPte;
2045 #endif
2046
2047 /* Dump memory descriptors */
2048 if (MiDbgEnableMdDump) MiDbgDumpMemoryDescriptors();
2049
2050 //
2051 // Instantiate memory that we don't consider RAM/usable
2052 // We use the same exclusions that Windows does, in order to try to be
2053 // compatible with WinLDR-style booting
2054 //
2055 for (i = 0; i < LoaderMaximum; i++) IncludeType[i] = TRUE;
2056 IncludeType[LoaderBad] = FALSE;
2057 IncludeType[LoaderFirmwarePermanent] = FALSE;
2058 IncludeType[LoaderSpecialMemory] = FALSE;
2059 IncludeType[LoaderBBTMemory] = FALSE;
2060 if (Phase == 0)
2061 {
2062 /* Count physical pages on the system */
2063 MiScanMemoryDescriptors(LoaderBlock);
2064
2065 /* Initialize the phase 0 temporary event */
2066 KeInitializeEvent(&MiTempEvent, NotificationEvent, FALSE);
2067
2068 /* Set all the events to use the temporary event for now */
2069 MiLowMemoryEvent = &MiTempEvent;
2070 MiHighMemoryEvent = &MiTempEvent;
2071 MiLowPagedPoolEvent = &MiTempEvent;
2072 MiHighPagedPoolEvent = &MiTempEvent;
2073 MiLowNonPagedPoolEvent = &MiTempEvent;
2074 MiHighNonPagedPoolEvent = &MiTempEvent;
2075
2076 //
2077 // Define the basic user vs. kernel address space separation
2078 //
2079 MmSystemRangeStart = (PVOID)MI_DEFAULT_SYSTEM_RANGE_START;
2080 MmUserProbeAddress = (ULONG_PTR)MI_USER_PROBE_ADDRESS;
2081 MmHighestUserAddress = (PVOID)MI_HIGHEST_USER_ADDRESS;
2082
2083 /* Highest PTE and PDE based on the addresses above */
2084 MiHighestUserPte = MiAddressToPte(MmHighestUserAddress);
2085 MiHighestUserPde = MiAddressToPde(MmHighestUserAddress);
2086 #if (_MI_PAGING_LEVELS >= 3)
2087 MiHighestUserPpe = MiAddressToPpe(MmHighestUserAddress);
2088 #if (_MI_PAGING_LEVELS >= 4)
2089 MiHighestUserPxe = MiAddressToPxe(MmHighestUserAddress);
2090 #endif
2091 #endif
2092 //
2093 // Get the size of the boot loader's image allocations and then round
2094 // that region up to a PDE size, so that any PDEs we might create for
2095 // whatever follows are separate from the PDEs that boot loader might've
2096 // already created (and later, we can blow all that away if we want to).
2097 //
2098 MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned;
2099 MmBootImageSize *= PAGE_SIZE;
2100 MmBootImageSize = (MmBootImageSize + PDE_MAPPED_VA - 1) & ~(PDE_MAPPED_VA - 1);
2101 ASSERT((MmBootImageSize % PDE_MAPPED_VA) == 0);
2102
2103 /* Initialize session space address layout */
2104 MiInitializeSessionSpaceLayout();
2105
2106 /* Set the based section highest address */
2107 MmHighSectionBase = (PVOID)((ULONG_PTR)MmHighestUserAddress - 0x800000);
2108
2109 #if DBG
2110 /* The subection PTE format depends on things being 8-byte aligned */
2111 ASSERT((sizeof(CONTROL_AREA) % 8) == 0);
2112 ASSERT((sizeof(SUBSECTION) % 8) == 0);
2113
2114 /* Prototype PTEs are assumed to be in paged pool, so check if the math works */
2115 PointerPte = (PMMPTE)MmPagedPoolStart;
2116 MI_MAKE_PROTOTYPE_PTE(&TempPte, PointerPte);
2117 TestPte = MiProtoPteToPte(&TempPte);
2118 ASSERT(PointerPte == TestPte);
2119
2120 /* Try the last nonpaged pool address */
2121 PointerPte = (PMMPTE)MI_NONPAGED_POOL_END;
2122 MI_MAKE_PROTOTYPE_PTE(&TempPte, PointerPte);
2123 TestPte = MiProtoPteToPte(&TempPte);
2124 ASSERT(PointerPte == TestPte);
2125
2126 /* Try a bunch of random addresses near the end of the address space */
2127 PointerPte = (PMMPTE)((ULONG_PTR)MI_HIGHEST_SYSTEM_ADDRESS - 0x37FFF);
2128 for (j = 0; j < 20; j += 1)
2129 {
2130 MI_MAKE_PROTOTYPE_PTE(&TempPte, PointerPte);
2131 TestPte = MiProtoPteToPte(&TempPte);
2132 ASSERT(PointerPte == TestPte);
2133 PointerPte++;
2134 }
2135
2136 /* Subsection PTEs are always in nonpaged pool, pick a random address to try */
2137 PointerPte = (PMMPTE)((ULONG_PTR)MmNonPagedPoolStart + (MmSizeOfNonPagedPoolInBytes / 2));
2138 MI_MAKE_SUBSECTION_PTE(&TempPte, PointerPte);
2139 TestPte = MiSubsectionPteToSubsection(&TempPte);
2140 ASSERT(PointerPte == TestPte);
2141 #endif
2142
2143 /* Loop all 8 standby lists */
2144 for (i = 0; i < 8; i++)
2145 {
2146 /* Initialize them */
2147 MmStandbyPageListByPriority[i].Total = 0;
2148 MmStandbyPageListByPriority[i].ListName = StandbyPageList;
2149 MmStandbyPageListByPriority[i].Flink = MM_EMPTY_LIST;
2150 MmStandbyPageListByPriority[i].Blink = MM_EMPTY_LIST;
2151 }
2152
2153 /* Initialize the user mode image list */
2154 InitializeListHead(&MmLoadedUserImageList);
2155
2156 /* Initialize critical section timeout value (relative time is negative) */
2157 MmCriticalSectionTimeout.QuadPart = MmCritsectTimeoutSeconds * (-10000000LL);
2158
2159 /* Initialize the paged pool mutex and the section commit mutex */
2160 KeInitializeGuardedMutex(&MmPagedPoolMutex);
2161 KeInitializeGuardedMutex(&MmSectionCommitMutex);
2162 KeInitializeGuardedMutex(&MmSectionBasedMutex);
2163
2164 /* Initialize the Loader Lock */
2165 KeInitializeMutant(&MmSystemLoadLock, FALSE);
2166
2167 /* Set the zero page event */
2168 KeInitializeEvent(&MmZeroingPageEvent, SynchronizationEvent, FALSE);
2169 MmZeroingPageThreadActive = FALSE;
2170
2171 /* Initialize the dead stack S-LIST */
2172 InitializeSListHead(&MmDeadStackSListHead);
2173
2174 //
2175 // Check if this is a machine with less than 19MB of RAM
2176 //
2177 PageCount = MmNumberOfPhysicalPages;
2178 if (PageCount < MI_MIN_PAGES_FOR_SYSPTE_TUNING)
2179 {
2180 //
2181 // Use the very minimum of system PTEs
2182 //
2183 MmNumberOfSystemPtes = 7000;
2184 }
2185 else
2186 {
2187 //
2188 // Use the default
2189 //
2190 MmNumberOfSystemPtes = 11000;
2191 if (PageCount > MI_MIN_PAGES_FOR_SYSPTE_BOOST)
2192 {
2193 //
2194 // Double the amount of system PTEs
2195 //
2196 MmNumberOfSystemPtes <<= 1;
2197 }
2198 if (PageCount > MI_MIN_PAGES_FOR_SYSPTE_BOOST_BOOST)
2199 {
2200 //
2201 // Double the amount of system PTEs
2202 //
2203 MmNumberOfSystemPtes <<= 1;
2204 }
2205 if (MmSpecialPoolTag != 0 && MmSpecialPoolTag != -1)
2206 {
2207 //
2208 // Add some extra PTEs for special pool
2209 //
2210 MmNumberOfSystemPtes += 0x6000;
2211 }
2212 }
2213
2214 DPRINT("System PTE count has been tuned to %lu (%lu bytes)\n",
2215 MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE);
2216
2217 /* Check if no values are set for the heap limits */
2218 if (MmHeapSegmentReserve == 0)
2219 {
2220 MmHeapSegmentReserve = 2 * _1MB;
2221 }
2222
2223 if (MmHeapSegmentCommit == 0)
2224 {
2225 MmHeapSegmentCommit = 2 * PAGE_SIZE;
2226 }
2227
2228 if (MmHeapDeCommitTotalFreeThreshold == 0)
2229 {
2230 MmHeapDeCommitTotalFreeThreshold = 64 * _1KB;
2231 }
2232
2233 if (MmHeapDeCommitFreeBlockThreshold == 0)
2234 {
2235 MmHeapDeCommitFreeBlockThreshold = PAGE_SIZE;
2236 }
2237
2238 /* Initialize the working set lock */
2239 ExInitializePushLock(&MmSystemCacheWs.WorkingSetMutex);
2240
2241 /* Set commit limit */
2242 MmTotalCommitLimit = 2 * _1GB;
2243 MmTotalCommitLimitMaximum = MmTotalCommitLimit;
2244
2245 /* Has the allocation fragment been setup? */
2246 if (!MmAllocationFragment)
2247 {
2248 /* Use the default value */
2249 MmAllocationFragment = MI_ALLOCATION_FRAGMENT;
2250 if (PageCount < ((256 * _1MB) / PAGE_SIZE))
2251 {
2252 /* On memory systems with less than 256MB, divide by 4 */
2253 MmAllocationFragment = MI_ALLOCATION_FRAGMENT / 4;
2254 }
2255 else if (PageCount < (_1GB / PAGE_SIZE))
2256 {
2257 /* On systems with less than 1GB, divide by 2 */
2258 MmAllocationFragment = MI_ALLOCATION_FRAGMENT / 2;
2259 }
2260 }
2261 else
2262 {
2263 /* Convert from 1KB fragments to pages */
2264 MmAllocationFragment *= _1KB;
2265 MmAllocationFragment = ROUND_TO_PAGES(MmAllocationFragment);
2266
2267 /* Don't let it past the maximum */
2268 MmAllocationFragment = min(MmAllocationFragment,
2269 MI_MAX_ALLOCATION_FRAGMENT);
2270
2271 /* Don't let it too small either */
2272 MmAllocationFragment = max(MmAllocationFragment,
2273 MI_MIN_ALLOCATION_FRAGMENT);
2274 }
2275
2276 /* Check for kernel stack size that's too big */
2277 if (MmLargeStackSize > (KERNEL_LARGE_STACK_SIZE / _1KB))
2278 {
2279 /* Sanitize to default value */
2280 MmLargeStackSize = KERNEL_LARGE_STACK_SIZE;
2281 }
2282 else
2283 {
2284 /* Take the registry setting, and convert it into bytes */
2285 MmLargeStackSize *= _1KB;
2286
2287 /* Now align it to a page boundary */
2288 MmLargeStackSize = PAGE_ROUND_UP(MmLargeStackSize);
2289
2290 /* Sanity checks */
2291 ASSERT(MmLargeStackSize <= KERNEL_LARGE_STACK_SIZE);
2292 ASSERT((MmLargeStackSize & (PAGE_SIZE - 1)) == 0);
2293
2294 /* Make sure it's not too low */
2295 if (MmLargeStackSize < KERNEL_STACK_SIZE) MmLargeStackSize = KERNEL_STACK_SIZE;
2296 }
2297
2298 /* Compute color information (L2 cache-separated paging lists) */
2299 MiComputeColorInformation();
2300
2301 // Calculate the number of bytes for the PFN database
2302 // then add the color tables and convert to pages
2303 MxPfnAllocation = (MmHighestPhysicalPage + 1) * sizeof(MMPFN);
2304 MxPfnAllocation += (MmSecondaryColors * sizeof(MMCOLOR_TABLES) * 2);
2305 MxPfnAllocation >>= PAGE_SHIFT;
2306
2307 // We have to add one to the count here, because in the process of
2308 // shifting down to the page size, we actually ended up getting the
2309 // lower aligned size (so say, 0x5FFFF bytes is now 0x5F pages).
2310 // Later on, we'll shift this number back into bytes, which would cause
2311 // us to end up with only 0x5F000 bytes -- when we actually want to have
2312 // 0x60000 bytes.
2313 MxPfnAllocation++;
2314
2315 /* Initialize the platform-specific parts */
2316 MiInitMachineDependent(LoaderBlock);
2317
2318 //
2319 // Build the physical memory block
2320 //
2321 MmPhysicalMemoryBlock = MmInitializeMemoryLimits(LoaderBlock,
2322 IncludeType);
2323
2324 //
2325 // Allocate enough buffer for the PFN bitmap
2326 // Align it up to a 32-bit boundary
2327 //
2328 Bitmap = ExAllocatePoolWithTag(NonPagedPool,
2329 (((MmHighestPhysicalPage + 1) + 31) / 32) * 4,
2330 TAG_MM);
2331 if (!Bitmap)
2332 {
2333 //
2334 // This is critical
2335 //
2336 KeBugCheckEx(INSTALL_MORE_MEMORY,
2337 MmNumberOfPhysicalPages,
2338 MmLowestPhysicalPage,
2339 MmHighestPhysicalPage,
2340 0x101);
2341 }
2342
2343 //
2344 // Initialize it and clear all the bits to begin with
2345 //
2346 RtlInitializeBitMap(&MiPfnBitMap,
2347 Bitmap,
2348 (ULONG)MmHighestPhysicalPage + 1);
2349 RtlClearAllBits(&MiPfnBitMap);
2350
2351 //
2352 // Loop physical memory runs
2353 //
2354 for (i = 0; i < MmPhysicalMemoryBlock->NumberOfRuns; i++)
2355 {
2356 //
2357 // Get the run
2358 //
2359 Run = &MmPhysicalMemoryBlock->Run[i];
2360 DPRINT("PHYSICAL RAM [0x%08p to 0x%08p]\n",
2361 Run->BasePage << PAGE_SHIFT,
2362 (Run->BasePage + Run->PageCount) << PAGE_SHIFT);
2363
2364 //
2365 // Make sure it has pages inside it
2366 //
2367 if (Run->PageCount)
2368 {
2369 //
2370 // Set the bits in the PFN bitmap
2371 //
2372 RtlSetBits(&MiPfnBitMap, (ULONG)Run->BasePage, (ULONG)Run->PageCount);
2373 }
2374 }
2375
2376 /* Look for large page cache entries that need caching */
2377 MiSyncCachedRanges();
2378
2379 /* Loop for HAL Heap I/O device mappings that need coherency tracking */
2380 MiAddHalIoMappings();
2381
2382 /* Set the initial resident page count */
2383 MmResidentAvailablePages = MmAvailablePages - 32;
2384
2385 /* Initialize large page structures on PAE/x64, and MmProcessList on x86 */
2386 MiInitializeLargePageSupport();
2387
2388 /* Check if the registry says any drivers should be loaded with large pages */
2389 MiInitializeDriverLargePageList();
2390
2391 /* Relocate the boot drivers into system PTE space and fixup their PFNs */
2392 MiReloadBootLoadedDrivers(LoaderBlock);
2393
2394 /* FIXME: Call out into Driver Verifier for initialization */
2395
2396 /* Check how many pages the system has */
2397 if (MmNumberOfPhysicalPages <= ((13 * _1MB) / PAGE_SIZE))
2398 {
2399 /* Set small system */
2400 MmSystemSize = MmSmallSystem;
2401 MmMaximumDeadKernelStacks = 0;
2402 }
2403 else if (MmNumberOfPhysicalPages <= ((19 * _1MB) / PAGE_SIZE))
2404 {
2405 /* Set small system and add 100 pages for the cache */
2406 MmSystemSize = MmSmallSystem;
2407 MmSystemCacheWsMinimum += 100;
2408 MmMaximumDeadKernelStacks = 2;
2409 }
2410 else
2411 {
2412 /* Set medium system and add 400 pages for the cache */
2413 MmSystemSize = MmMediumSystem;
2414 MmSystemCacheWsMinimum += 400;
2415 MmMaximumDeadKernelStacks = 5;
2416 }
2417
2418 /* Check for less than 24MB */
2419 if (MmNumberOfPhysicalPages < ((24 * _1MB) / PAGE_SIZE))
2420 {
2421 /* No more than 32 pages */
2422 MmSystemCacheWsMinimum = 32;
2423 }
2424
2425 /* Check for more than 32MB */
2426 if (MmNumberOfPhysicalPages >= ((32 * _1MB) / PAGE_SIZE))
2427 {
2428 /* Check for product type being "Wi" for WinNT */
2429 if (MmProductType == '\0i\0W')
2430 {
2431 /* Then this is a large system */
2432 MmSystemSize = MmLargeSystem;
2433 }
2434 else
2435 {
2436 /* For servers, we need 64MB to consider this as being large */
2437 if (MmNumberOfPhysicalPages >= ((64 * _1MB) / PAGE_SIZE))
2438 {
2439 /* Set it as large */
2440 MmSystemSize = MmLargeSystem;
2441 }
2442 }
2443 }
2444
2445 /* Check for more than 33 MB */
2446 if (MmNumberOfPhysicalPages > ((33 * _1MB) / PAGE_SIZE))
2447 {
2448 /* Add another 500 pages to the cache */
2449 MmSystemCacheWsMinimum += 500;
2450 }
2451
2452 /* Now setup the shared user data fields */
2453 ASSERT(SharedUserData->NumberOfPhysicalPages == 0);
2454 SharedUserData->NumberOfPhysicalPages = MmNumberOfPhysicalPages;
2455 SharedUserData->LargePageMinimum = 0;
2456
2457 /* Check for workstation (Wi for WinNT) */
2458 if (MmProductType == '\0i\0W')
2459 {
2460 /* Set Windows NT Workstation product type */
2461 SharedUserData->NtProductType = NtProductWinNt;
2462 MmProductType = 0;
2463 }
2464 else
2465 {
2466 /* Check for LanMan server (La for LanmanNT) */
2467 if (MmProductType == '\0a\0L')
2468 {
2469 /* This is a domain controller */
2470 SharedUserData->NtProductType = NtProductLanManNt;
2471 }
2472 else
2473 {
2474 /* Otherwise it must be a normal server (Se for ServerNT) */
2475 SharedUserData->NtProductType = NtProductServer;
2476 }
2477
2478 /* Set the product type, and make the system more aggressive with low memory */
2479 MmProductType = 1;
2480 MmMinimumFreePages = 81;
2481 }
2482
2483 /* Update working set tuning parameters */
2484 MiAdjustWorkingSetManagerParameters(!MmProductType);
2485
2486 /* Finetune the page count by removing working set and NP expansion */
2487 MmResidentAvailablePages -= MiExpansionPoolPagesInitialCharge;
2488 MmResidentAvailablePages -= MmSystemCacheWsMinimum;
2489 MmResidentAvailableAtInit = MmResidentAvailablePages;
2490 if (MmResidentAvailablePages <= 0)
2491 {
2492 /* This should not happen */
2493 DPRINT1("System cache working set too big\n");
2494 return FALSE;
2495 }
2496
2497 /* Initialize the system cache */
2498 //MiInitializeSystemCache(MmSystemCacheWsMinimum, MmAvailablePages);
2499
2500 /* Update the commit limit */
2501 MmTotalCommitLimit = MmAvailablePages;
2502 if (MmTotalCommitLimit > 1024) MmTotalCommitLimit -= 1024;
2503 MmTotalCommitLimitMaximum = MmTotalCommitLimit;
2504
2505 /* Size up paged pool and build the shadow system page directory */
2506 MiBuildPagedPool();
2507
2508 /* Debugger physical memory support is now ready to be used */
2509 MmDebugPte = MiAddressToPte(MiDebugMapping);
2510
2511 /* Initialize the loaded module list */
2512 MiInitializeLoadedModuleList(LoaderBlock);
2513 }
2514
2515 //
2516 // Always return success for now
2517 //
2518 return TRUE;
2519 }
2520
2521 /* EOF */