Sync with trunk r43000
[reactos.git] / reactos / ntoskrnl / mm / ARM3 / i386 / init.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/i386/init.c
5 * PURPOSE: ARM Memory Manager Initialization for x86
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #line 15 "ARM³::INIT"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../../ARM3/miarm.h"
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 ULONG MmSizeOfNonPagedPoolInBytes;
27 ULONG MmMaximumNonPagedPoolInBytes;
28
29 //
30 // These numbers describe the discrete equation components of the nonpaged
31 // pool sizing algorithm.
32 //
33 // They are described on http://support.microsoft.com/default.aspx/kb/126402/ja
34 // along with the algorithm that uses them, which is implemented later below.
35 //
36 ULONG MmMinimumNonPagedPoolSize = 256 * 1024;
37 ULONG MmMinAdditionNonPagedPoolPerMb = 32 * 1024;
38 ULONG MmDefaultMaximumNonPagedPool = 1024 * 1024;
39 ULONG MmMaxAdditionNonPagedPoolPerMb = 400 * 1024;
40
41 //
42 // The memory layout (and especially variable names) of the NT kernel mode
43 // components can be a bit hard to twig, especially when it comes to the non
44 // paged area.
45 //
46 // There are really two components to the non-paged pool:
47 //
48 // - The initial nonpaged pool, sized dynamically up to a maximum.
49 // - The expansion nonpaged pool, sized dynamically up to a maximum.
50 //
51 // The initial nonpaged pool is physically continuous for performance, and
52 // immediately follows the PFN database, typically sharing the same PDE. It is
53 // a very small resource (32MB on a 1GB system), and capped at 128MB.
54 //
55 // Right now we call this the "ARM³ Nonpaged Pool" and it begins somewhere after
56 // the PFN database (which starts at 0xB0000000).
57 //
58 // The expansion nonpaged pool, on the other hand, can grow much bigger (400MB
59 // for a 1GB system). On ARM³ however, it is currently capped at 128MB.
60 //
61 // The address where the initial nonpaged pool starts is aptly named
62 // MmNonPagedPoolStart, and it describes a range of MmSizeOfNonPagedPoolInBytes
63 // bytes.
64 //
65 // Expansion nonpaged pool starts at an address described by the variable called
66 // MmNonPagedPoolExpansionStart, and it goes on for MmMaximumNonPagedPoolInBytes
67 // minus MmSizeOfNonPagedPoolInBytes bytes, always reaching MmNonPagedPoolEnd
68 // (because of the way it's calculated) at 0xFFBE0000.
69 //
70 // Initial nonpaged pool is allocated and mapped early-on during boot, but what
71 // about the expansion nonpaged pool? It is instead composed of special pages
72 // which belong to what are called System PTEs. These PTEs are the matter of a
73 // later discussion, but they are also considered part of the "nonpaged" OS, due
74 // to the fact that they are never paged out -- once an address is described by
75 // a System PTE, it is always valid, until the System PTE is torn down.
76 //
77 // System PTEs are actually composed of two "spaces", the system space proper,
78 // and the nonpaged pool expansion space. The latter, as we've already seen,
79 // begins at MmNonPagedPoolExpansionStart. Based on the number of System PTEs
80 // that the system will support, the remaining address space below this address
81 // is used to hold the system space PTEs. This address, in turn, is held in the
82 // variable named MmNonPagedSystemStart, which itself is never allowed to go
83 // below 0xEB000000 (thus creating an upper bound on the number of System PTEs).
84 //
85 // This means that 330MB are reserved for total nonpaged system VA, on top of
86 // whatever the initial nonpaged pool allocation is.
87 //
88 // The following URLs, valid as of April 23rd, 2008, support this evidence:
89 //
90 // http://www.cs.miami.edu/~burt/journal/NT/memory.html
91 // http://www.ditii.com/2007/09/28/windows-memory-management-x86-virtual-address-space/
92 //
93 PVOID MmNonPagedSystemStart;
94 PVOID MmNonPagedPoolStart;
95 PVOID MmNonPagedPoolExpansionStart;
96 PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END;
97
98 //
99 // This is where paged pool starts by default
100 //
101 PVOID MmPagedPoolStart = MI_PAGED_POOL_START;
102 PVOID MmPagedPoolEnd;
103
104 //
105 // And this is its default size
106 //
107 ULONG MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE;
108 PFN_NUMBER MmSizeOfPagedPoolInPages = MI_MIN_INIT_PAGED_POOLSIZE / PAGE_SIZE;
109
110 //
111 // Session space starts at 0xBFFFFFFF and grows downwards
112 // By default, it includes an 8MB image area where we map win32k and video card
113 // drivers, followed by a 4MB area containing the session's working set. This is
114 // then followed by a 20MB mapped view area and finally by the session's paged
115 // pool, by default 16MB.
116 //
117 // On a normal system, this results in session space occupying the region from
118 // 0xBD000000 to 0xC0000000
119 //
120 // See miarm.h for the defines that determine the sizing of this region. On an
121 // NT system, some of these can be configured through the registry, but we don't
122 // support that yet.
123 //
124 PVOID MiSessionSpaceEnd; // 0xC0000000
125 PVOID MiSessionImageEnd; // 0xC0000000
126 PVOID MiSessionImageStart; // 0xBF800000
127 PVOID MiSessionViewStart; // 0xBE000000
128 PVOID MiSessionPoolEnd; // 0xBE000000
129 PVOID MiSessionPoolStart; // 0xBD000000
130 PVOID MmSessionBase; // 0xBD000000
131 ULONG MmSessionSize;
132 ULONG MmSessionViewSize;
133 ULONG MmSessionPoolSize;
134 ULONG MmSessionImageSize;
135
136 //
137 // The system view space, on the other hand, is where sections that are memory
138 // mapped into "system space" end up.
139 //
140 // By default, it is a 16MB region.
141 //
142 PVOID MiSystemViewStart;
143 ULONG MmSystemViewSize;
144
145 //
146 // A copy of the system page directory (the page directory associated with the
147 // System process) is kept (double-mapped) by the manager in order to lazily
148 // map paged pool PDEs into external processes when they fault on a paged pool
149 // address.
150 //
151 PFN_NUMBER MmSystemPageDirectory;
152 PMMPTE MmSystemPagePtes;
153
154 //
155 // Windows NT seems to choose between 7000, 11000 and 50000
156 // On systems with more than 32MB, this number is then doubled, and further
157 // aligned up to a PDE boundary (4MB).
158 //
159 ULONG MmNumberOfSystemPtes;
160
161 //
162 // This is how many pages the PFN database will take up
163 // In Windows, this includes the Quark Color Table, but not in ARM³
164 //
165 ULONG MxPfnAllocation;
166
167 //
168 // Unlike the old ReactOS Memory Manager, ARM³ (and Windows) does not keep track
169 // of pages that are not actually valid physical memory, such as ACPI reserved
170 // regions, BIOS address ranges, or holes in physical memory address space which
171 // could indicate device-mapped I/O memory.
172 //
173 // In fact, the lack of a PFN entry for a page usually indicates that this is
174 // I/O space instead.
175 //
176 // A bitmap, called the PFN bitmap, keeps track of all page frames by assigning
177 // a bit to each. If the bit is set, then the page is valid physical RAM.
178 //
179 RTL_BITMAP MiPfnBitMap;
180
181 //
182 // This structure describes the different pieces of RAM-backed address space
183 //
184 PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
185
186 //
187 // Before we have a PFN database, memory comes straight from our physical memory
188 // blocks, which is nice because it's guaranteed contiguous and also because once
189 // we take a page from here, the system doesn't see it anymore.
190 // However, once the fun is over, those pages must be re-integrated back into
191 // PFN society life, and that requires us keeping a copy of the original layout
192 // so that we can parse it later.
193 //
194 PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor;
195 MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor;
196
197 //
198 // This is where we keep track of the most basic physical layout markers
199 //
200 ULONG MmNumberOfPhysicalPages, MmHighestPhysicalPage, MmLowestPhysicalPage = -1;
201
202 //
203 // The total number of pages mapped by the boot loader, which include the kernel
204 // HAL, boot drivers, registry, NLS files and other loader data structures is
205 // kept track of here. This depends on "LoaderPagesSpanned" being correct when
206 // coming from the loader.
207 //
208 // This number is later aligned up to a PDE boundary.
209 //
210 ULONG MmBootImageSize;
211
212 //
213 // These three variables keep track of the core separation of address space that
214 // exists between kernel mode and user mode.
215 //
216 ULONG MmUserProbeAddress;
217 PVOID MmHighestUserAddress;
218 PVOID MmSystemRangeStart;
219
220 /* PRIVATE FUNCTIONS **********************************************************/
221
222 //
223 // In Bavaria, this is probably a hate crime
224 //
225 VOID
226 FASTCALL
227 MiSyncARM3WithROS(IN PVOID AddressStart,
228 IN PVOID AddressEnd)
229 {
230 //
231 // Puerile piece of junk-grade carbonized horseshit puss sold to the lowest bidder
232 //
233 ULONG Pde = ADDR_TO_PDE_OFFSET(AddressStart);
234 while (Pde <= ADDR_TO_PDE_OFFSET(AddressEnd))
235 {
236 //
237 // This both odious and heinous
238 //
239 extern ULONG MmGlobalKernelPageDirectory[1024];
240 MmGlobalKernelPageDirectory[Pde] = ((PULONG)PDE_BASE)[Pde];
241 Pde++;
242 }
243 }
244
245 PFN_NUMBER
246 NTAPI
247 MxGetNextPage(IN PFN_NUMBER PageCount)
248 {
249 PFN_NUMBER Pfn;
250
251 //
252 // Make sure we have enough pages
253 //
254 if (PageCount > MxFreeDescriptor->PageCount)
255 {
256 //
257 // Crash the system
258 //
259 KeBugCheckEx(INSTALL_MORE_MEMORY,
260 MmNumberOfPhysicalPages,
261 MxFreeDescriptor->PageCount,
262 MxOldFreeDescriptor.PageCount,
263 PageCount);
264 }
265
266 //
267 // Use our lowest usable free pages
268 //
269 Pfn = MxFreeDescriptor->BasePage;
270 MxFreeDescriptor->BasePage += PageCount;
271 MxFreeDescriptor->PageCount -= PageCount;
272 return Pfn;
273 }
274
275 PPHYSICAL_MEMORY_DESCRIPTOR
276 NTAPI
277 MmInitializeMemoryLimits(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
278 IN PBOOLEAN IncludeType)
279 {
280 PLIST_ENTRY NextEntry;
281 ULONG Run = 0, InitialRuns = 0;
282 PFN_NUMBER NextPage = -1, PageCount = 0;
283 PPHYSICAL_MEMORY_DESCRIPTOR Buffer, NewBuffer;
284 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
285
286 //
287 // Scan the memory descriptors
288 //
289 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
290 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
291 {
292 //
293 // For each one, increase the memory allocation estimate
294 //
295 InitialRuns++;
296 NextEntry = NextEntry->Flink;
297 }
298
299 //
300 // Allocate the maximum we'll ever need
301 //
302 Buffer = ExAllocatePoolWithTag(NonPagedPool,
303 sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
304 sizeof(PHYSICAL_MEMORY_RUN) *
305 (InitialRuns - 1),
306 'lMmM');
307 if (!Buffer) return NULL;
308
309 //
310 // For now that's how many runs we have
311 //
312 Buffer->NumberOfRuns = InitialRuns;
313
314 //
315 // Now loop through the descriptors again
316 //
317 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
318 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
319 {
320 //
321 // Grab each one, and check if it's one we should include
322 //
323 MdBlock = CONTAINING_RECORD(NextEntry,
324 MEMORY_ALLOCATION_DESCRIPTOR,
325 ListEntry);
326 if ((MdBlock->MemoryType < LoaderMaximum) &&
327 (IncludeType[MdBlock->MemoryType]))
328 {
329 //
330 // Add this to our running total
331 //
332 PageCount += MdBlock->PageCount;
333
334 //
335 // Check if the next page is described by the next descriptor
336 //
337 if (MdBlock->BasePage == NextPage)
338 {
339 //
340 // Combine it into the same physical run
341 //
342 ASSERT(MdBlock->PageCount != 0);
343 Buffer->Run[Run - 1].PageCount += MdBlock->PageCount;
344 NextPage += MdBlock->PageCount;
345 }
346 else
347 {
348 //
349 // Otherwise just duplicate the descriptor's contents
350 //
351 Buffer->Run[Run].BasePage = MdBlock->BasePage;
352 Buffer->Run[Run].PageCount = MdBlock->PageCount;
353 NextPage = Buffer->Run[Run].BasePage + Buffer->Run[Run].PageCount;
354
355 //
356 // And in this case, increase the number of runs
357 //
358 Run++;
359 }
360 }
361
362 //
363 // Try the next descriptor
364 //
365 NextEntry = MdBlock->ListEntry.Flink;
366 }
367
368 //
369 // We should not have been able to go past our initial estimate
370 //
371 ASSERT(Run <= Buffer->NumberOfRuns);
372
373 //
374 // Our guess was probably exaggerated...
375 //
376 if (InitialRuns > Run)
377 {
378 //
379 // Allocate a more accurately sized buffer
380 //
381 NewBuffer = ExAllocatePoolWithTag(NonPagedPool,
382 sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
383 sizeof(PHYSICAL_MEMORY_RUN) *
384 (Run - 1),
385 'lMmM');
386 if (NewBuffer)
387 {
388 //
389 // Copy the old buffer into the new, then free it
390 //
391 RtlCopyMemory(NewBuffer->Run,
392 Buffer->Run,
393 sizeof(PHYSICAL_MEMORY_RUN) * Run);
394 ExFreePool(Buffer);
395
396 //
397 // Now use the new buffer
398 //
399 Buffer = NewBuffer;
400 }
401 }
402
403 //
404 // Write the final numbers, and return it
405 //
406 Buffer->NumberOfRuns = Run;
407 Buffer->NumberOfPages = PageCount;
408 return Buffer;
409 }
410
411 VOID
412 NTAPI
413 MiBuildPagedPool(VOID)
414 {
415 PMMPTE PointerPte, PointerPde;
416 MMPTE TempPte = HyperTemplatePte;
417 PFN_NUMBER PageFrameIndex;
418 KIRQL OldIrql;
419 ULONG Size, BitMapSize;
420
421 //
422 // Get the page frame number for the system page directory
423 //
424 PointerPte = MiAddressToPte(PDE_BASE);
425 MmSystemPageDirectory = PFN_FROM_PTE(PointerPte);
426
427 //
428 // Allocate a system PTE which will hold a copy of the page directory
429 //
430 PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
431 ASSERT(PointerPte);
432 MmSystemPagePtes = MiPteToAddress(PointerPte);
433
434 //
435 // Make this system PTE point to the system page directory.
436 // It is now essentially double-mapped. This will be used later for lazy
437 // evaluation of PDEs accross process switches, similarly to how the Global
438 // page directory array in the old ReactOS Mm is used (but in a less hacky
439 // way).
440 //
441 TempPte = HyperTemplatePte;
442 TempPte.u.Hard.PageFrameNumber = MmSystemPageDirectory;
443 ASSERT(PointerPte->u.Hard.Valid == 0);
444 ASSERT(TempPte.u.Hard.Valid == 1);
445 *PointerPte = TempPte;
446
447 //
448 // Let's get back to paged pool work: size it up.
449 // By default, it should be twice as big as nonpaged pool.
450 //
451 MmSizeOfPagedPoolInBytes = 2 * MmMaximumNonPagedPoolInBytes;
452 if (MmSizeOfPagedPoolInBytes > ((ULONG_PTR)MmNonPagedSystemStart -
453 (ULONG_PTR)MmPagedPoolStart))
454 {
455 //
456 // On the other hand, we have limited VA space, so make sure that the VA
457 // for paged pool doesn't overflow into nonpaged pool VA. Otherwise, set
458 // whatever maximum is possible.
459 //
460 MmSizeOfPagedPoolInBytes = (ULONG_PTR)MmNonPagedSystemStart -
461 (ULONG_PTR)MmPagedPoolStart;
462 }
463
464 //
465 // Get the size in pages and make sure paged pool is at least 32MB.
466 //
467 Size = MmSizeOfPagedPoolInBytes;
468 if (Size < MI_MIN_INIT_PAGED_POOLSIZE) Size = MI_MIN_INIT_PAGED_POOLSIZE;
469 Size = BYTES_TO_PAGES(Size);
470
471 //
472 // Now check how many PTEs will be required for these many pages.
473 //
474 Size = (Size + (1024 - 1)) / 1024;
475
476 //
477 // Recompute the page-aligned size of the paged pool, in bytes and pages.
478 //
479 MmSizeOfPagedPoolInBytes = Size * PAGE_SIZE * 1024;
480 MmSizeOfPagedPoolInPages = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT;
481
482 //
483 // Let's be really sure this doesn't overflow into nonpaged system VA
484 //
485 ASSERT((MmSizeOfPagedPoolInBytes + (ULONG_PTR)MmPagedPoolStart) <=
486 (ULONG_PTR)MmNonPagedSystemStart);
487
488 //
489 // This is where paged pool ends
490 //
491 MmPagedPoolEnd = (PVOID)(((ULONG_PTR)MmPagedPoolStart +
492 MmSizeOfPagedPoolInBytes) - 1);
493
494 //
495 // So now get the PDE for paged pool and zero it out
496 //
497 PointerPde = MiAddressToPde(MmPagedPoolStart);
498 RtlZeroMemory(PointerPde,
499 (1 + MiAddressToPde(MmPagedPoolEnd) - PointerPde) * sizeof(MMPTE));
500
501 //
502 // Next, get the first and last PTE
503 //
504 PointerPte = MiAddressToPte(MmPagedPoolStart);
505 MmPagedPoolInfo.FirstPteForPagedPool = PointerPte;
506 MmPagedPoolInfo.LastPteForPagedPool = MiAddressToPte(MmPagedPoolEnd);
507
508 //
509 // Lock the PFN database
510 //
511 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
512
513 //
514 // Allocate a page and map the first paged pool PDE
515 //
516 PageFrameIndex = MmAllocPage(MC_NPPOOL, 0);
517 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
518 ASSERT(PointerPde->u.Hard.Valid == 0);
519 ASSERT(TempPte.u.Hard.Valid == 1);
520 *PointerPde = TempPte;
521
522 //
523 // Release the PFN database lock
524 //
525 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
526
527 //
528 // We only have one PDE mapped for now... at fault time, additional PDEs
529 // will be allocated to handle paged pool growth. This is where they'll have
530 // to start.
531 //
532 MmPagedPoolInfo.NextPdeForPagedPoolExpansion = PointerPde + 1;
533
534 //
535 // We keep track of each page via a bit, so check how big the bitmap will
536 // have to be (make sure to align our page count such that it fits nicely
537 // into a 4-byte aligned bitmap.
538 //
539 // We'll also allocate the bitmap header itself part of the same buffer.
540 //
541 Size = Size * 1024;
542 ASSERT(Size == MmSizeOfPagedPoolInPages);
543 BitMapSize = sizeof(RTL_BITMAP) + (((Size + 31) / 32) * sizeof(ULONG));
544
545 //
546 // Allocate the allocation bitmap, which tells us which regions have not yet
547 // been mapped into memory
548 //
549 MmPagedPoolInfo.PagedPoolAllocationMap = ExAllocatePoolWithTag(NonPagedPool,
550 BitMapSize,
551 ' mM');
552 ASSERT(MmPagedPoolInfo.PagedPoolAllocationMap);
553
554 //
555 // Initialize it such that at first, only the first page's worth of PTEs is
556 // marked as allocated (incidentially, the first PDE we allocated earlier).
557 //
558 RtlInitializeBitMap(MmPagedPoolInfo.PagedPoolAllocationMap,
559 (PULONG)(MmPagedPoolInfo.PagedPoolAllocationMap + 1),
560 BitMapSize);
561 RtlSetAllBits(MmPagedPoolInfo.PagedPoolAllocationMap);
562 RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, 0, 1024);
563
564 //
565 // We have a second bitmap, which keeps track of where allocations end.
566 // Given the allocation bitmap and a base address, we can therefore figure
567 // out which page is the last page of that allocation, and thus how big the
568 // entire allocation is.
569 //
570 MmPagedPoolInfo.EndOfPagedPoolBitmap = ExAllocatePoolWithTag(NonPagedPool,
571 BitMapSize,
572 ' mM');
573 ASSERT(MmPagedPoolInfo.EndOfPagedPoolBitmap);
574 RtlInitializeBitMap(MmPagedPoolInfo.EndOfPagedPoolBitmap,
575 (PULONG)(MmPagedPoolInfo.EndOfPagedPoolBitmap + 1),
576 BitMapSize);
577
578 //
579 // Since no allocations have been made yet, there are no bits set as the end
580 //
581 RtlClearAllBits(MmPagedPoolInfo.EndOfPagedPoolBitmap);
582
583 //
584 // Initialize paged pool.
585 //
586 //InitializePool(PagedPool, 0);
587 }
588
589 NTSTATUS
590 NTAPI
591 MmArmInitSystem(IN ULONG Phase,
592 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
593 {
594 PLIST_ENTRY NextEntry;
595 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
596 ULONG FreePages = 0;
597 PMEMORY_AREA MArea;
598 PHYSICAL_ADDRESS BoundaryAddressMultiple;
599 PFN_NUMBER PageFrameIndex;
600 PMMPTE StartPde, EndPde, PointerPte, LastPte;
601 MMPTE TempPde = HyperTemplatePte, TempPte = HyperTemplatePte;
602 PVOID NonPagedPoolExpansionVa, BaseAddress;
603 NTSTATUS Status;
604 ULONG OldCount;
605 BOOLEAN IncludeType[LoaderMaximum];
606 ULONG i;
607 PVOID Bitmap;
608 PPHYSICAL_MEMORY_RUN Run;
609 PFN_NUMBER FreePage, FreePageCount, PagesLeft, BasePage, PageCount;
610 BoundaryAddressMultiple.QuadPart = 0;
611
612 if (Phase == 0)
613 {
614 //
615 // Define the basic user vs. kernel address space separation
616 //
617 MmSystemRangeStart = (PVOID)KSEG0_BASE;
618 MmUserProbeAddress = (ULONG_PTR)MmSystemRangeStart - 0x10000;
619 MmHighestUserAddress = (PVOID)(MmUserProbeAddress - 1);
620
621 //
622 // Get the size of the boot loader's image allocations and then round
623 // that region up to a PDE size, so that any PDEs we might create for
624 // whatever follows are separate from the PDEs that boot loader might've
625 // already created (and later, we can blow all that away if we want to).
626 //
627 MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned;
628 MmBootImageSize *= PAGE_SIZE;
629 MmBootImageSize = (MmBootImageSize + (4 * 1024 * 1024) - 1) & ~((4 * 1024 * 1024) - 1);
630 ASSERT((MmBootImageSize % (4 * 1024 * 1024)) == 0);
631
632 //
633 // Set the size of session view, pool, and image
634 //
635 MmSessionSize = MI_SESSION_SIZE;
636 MmSessionViewSize = MI_SESSION_VIEW_SIZE;
637 MmSessionPoolSize = MI_SESSION_POOL_SIZE;
638 MmSessionImageSize = MI_SESSION_IMAGE_SIZE;
639
640 //
641 // Set the size of system view
642 //
643 MmSystemViewSize = MI_SYSTEM_VIEW_SIZE;
644
645 //
646 // This is where it all ends
647 //
648 MiSessionImageEnd = (PVOID)PTE_BASE;
649
650 //
651 // This is where we will load Win32k.sys and the video driver
652 //
653 MiSessionImageStart = (PVOID)((ULONG_PTR)MiSessionImageEnd -
654 MmSessionImageSize);
655
656 //
657 // So the view starts right below the session working set (itself below
658 // the image area)
659 //
660 MiSessionViewStart = (PVOID)((ULONG_PTR)MiSessionImageEnd -
661 MmSessionImageSize -
662 MI_SESSION_WORKING_SET_SIZE -
663 MmSessionViewSize);
664
665 //
666 // Session pool follows
667 //
668 MiSessionPoolEnd = MiSessionViewStart;
669 MiSessionPoolStart = (PVOID)((ULONG_PTR)MiSessionPoolEnd -
670 MmSessionPoolSize);
671
672 //
673 // And it all begins here
674 //
675 MmSessionBase = MiSessionPoolStart;
676
677 //
678 // Sanity check that our math is correct
679 //
680 ASSERT((ULONG_PTR)MmSessionBase + MmSessionSize == PTE_BASE);
681
682 //
683 // Session space ends wherever image session space ends
684 //
685 MiSessionSpaceEnd = MiSessionImageEnd;
686
687 //
688 // System view space ends at session space, so now that we know where
689 // this is, we can compute the base address of system view space itself.
690 //
691 MiSystemViewStart = (PVOID)((ULONG_PTR)MmSessionBase -
692 MmSystemViewSize);
693
694 //
695 // Set CR3 for the system process
696 //
697 PointerPte = MiAddressToPde(PTE_BASE);
698 PageFrameIndex = PFN_FROM_PTE(PointerPte) << PAGE_SHIFT;
699 PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PageFrameIndex;
700
701 //
702 // Blow away user-mode
703 //
704 StartPde = MiAddressToPde(0);
705 EndPde = MiAddressToPde(KSEG0_BASE);
706 RtlZeroMemory(StartPde, (EndPde - StartPde) * sizeof(MMPTE));
707
708 //
709 // Loop the memory descriptors
710 //
711 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
712 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
713 {
714 //
715 // Get the memory block
716 //
717 MdBlock = CONTAINING_RECORD(NextEntry,
718 MEMORY_ALLOCATION_DESCRIPTOR,
719 ListEntry);
720
721 //
722 // Skip invisible memory
723 //
724 if ((MdBlock->MemoryType != LoaderFirmwarePermanent) &&
725 (MdBlock->MemoryType != LoaderSpecialMemory) &&
726 (MdBlock->MemoryType != LoaderHALCachedMemory) &&
727 (MdBlock->MemoryType != LoaderBBTMemory))
728 {
729 //
730 // Check if BURNMEM was used
731 //
732 if (MdBlock->MemoryType != LoaderBad)
733 {
734 //
735 // Count this in the total of pages
736 //
737 MmNumberOfPhysicalPages += MdBlock->PageCount;
738 }
739
740 //
741 // Check if this is the new lowest page
742 //
743 if (MdBlock->BasePage < MmLowestPhysicalPage)
744 {
745 //
746 // Update the lowest page
747 //
748 MmLowestPhysicalPage = MdBlock->BasePage;
749 }
750
751 //
752 // Check if this is the new highest page
753 //
754 PageFrameIndex = MdBlock->BasePage + MdBlock->PageCount;
755 if (PageFrameIndex > MmHighestPhysicalPage)
756 {
757 //
758 // Update the highest page
759 //
760 MmHighestPhysicalPage = PageFrameIndex - 1;
761 }
762
763 //
764 // Check if this is free memory
765 //
766 if ((MdBlock->MemoryType == LoaderFree) ||
767 (MdBlock->MemoryType == LoaderLoadedProgram) ||
768 (MdBlock->MemoryType == LoaderFirmwareTemporary) ||
769 (MdBlock->MemoryType == LoaderOsloaderStack))
770 {
771 //
772 // Check if this is the largest memory descriptor
773 //
774 if (MdBlock->PageCount > FreePages)
775 {
776 //
777 // For now, it is
778 //
779 FreePages = MdBlock->PageCount;
780 MxFreeDescriptor = MdBlock;
781 }
782 }
783 }
784
785 //
786 // Keep going
787 //
788 NextEntry = MdBlock->ListEntry.Flink;
789 }
790
791 //
792 // Save original values of the free descriptor, since it'll be
793 // altered by early allocations
794 //
795 MxOldFreeDescriptor = *MxFreeDescriptor;
796
797 //
798 // Check if this is a machine with less than 19MB of RAM
799 //
800 if (MmNumberOfPhysicalPages < MI_MIN_PAGES_FOR_SYSPTE_TUNING)
801 {
802 //
803 // Use the very minimum of system PTEs
804 //
805 MmNumberOfSystemPtes = 7000;
806 }
807 else
808 {
809 //
810 // Use the default, but check if we have more than 32MB of RAM
811 //
812 MmNumberOfSystemPtes = 11000;
813 if (MmNumberOfPhysicalPages > MI_MIN_PAGES_FOR_SYSPTE_BOOST)
814 {
815 //
816 // Double the amount of system PTEs
817 //
818 MmNumberOfSystemPtes <<= 1;
819 }
820 }
821
822 DPRINT("System PTE count has been tuned to %d (%d bytes)\n",
823 MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE);
824
825 //
826 // Check if this is a machine with less than 256MB of RAM, and no overide
827 //
828 if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) &&
829 !(MmSizeOfNonPagedPoolInBytes))
830 {
831 //
832 // Force the non paged pool to be 2MB so we can reduce RAM usage
833 //
834 MmSizeOfNonPagedPoolInBytes = 2 * 1024 * 1024;
835 }
836
837 //
838 // Check if the user gave a ridicuously large nonpaged pool RAM size
839 //
840 if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) >
841 (MmNumberOfPhysicalPages * 7 / 8))
842 {
843 //
844 // More than 7/8ths of RAM was dedicated to nonpaged pool, ignore!
845 //
846 MmSizeOfNonPagedPoolInBytes = 0;
847 }
848
849 //
850 // Check if no registry setting was set, or if the setting was too low
851 //
852 if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize)
853 {
854 //
855 // Start with the minimum (256 KB) and add 32 KB for each MB above 4
856 //
857 MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize;
858 MmSizeOfNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
859 256 * MmMinAdditionNonPagedPoolPerMb;
860 }
861
862 //
863 // Check if the registy setting or our dynamic calculation was too high
864 //
865 if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE)
866 {
867 //
868 // Set it to the maximum
869 //
870 MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE;
871 }
872
873 //
874 // Check if a percentage cap was set through the registry
875 //
876 if (MmMaximumNonPagedPoolPercent)
877 {
878 //
879 // Don't feel like supporting this right now
880 //
881 UNIMPLEMENTED;
882 }
883
884 //
885 // Page-align the nonpaged pool size
886 //
887 MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1);
888
889 //
890 // Now, check if there was a registry size for the maximum size
891 //
892 if (!MmMaximumNonPagedPoolInBytes)
893 {
894 //
895 // Start with the default (1MB) and add 400 KB for each MB above 4
896 //
897 MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool;
898 MmMaximumNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
899 256 * MmMaxAdditionNonPagedPoolPerMb;
900 }
901
902 //
903 // Don't let the maximum go too high
904 //
905 if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE)
906 {
907 //
908 // Set it to the upper limit
909 //
910 MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE;
911 }
912
913 //
914 // Calculate the number of bytes, and then convert to pages
915 //
916 MxPfnAllocation = (MmHighestPhysicalPage + 1) * sizeof(MMPFN);
917 MxPfnAllocation >>= PAGE_SHIFT;
918
919 //
920 // We have to add one to the count here, because in the process of
921 // shifting down to the page size, we actually ended up getting the
922 // lower aligned size (so say, 0x5FFFF bytes is now 0x5F pages).
923 // Later on, we'll shift this number back into bytes, which would cause
924 // us to end up with only 0x5F000 bytes -- when we actually want to have
925 // 0x60000 bytes.
926 //
927 MxPfnAllocation++;
928
929 //
930 // Now calculate the nonpaged pool expansion VA region
931 //
932 MmNonPagedPoolStart = (PVOID)((ULONG_PTR)MmNonPagedPoolEnd -
933 MmMaximumNonPagedPoolInBytes +
934 MmSizeOfNonPagedPoolInBytes);
935 MmNonPagedPoolStart = (PVOID)PAGE_ALIGN(MmNonPagedPoolStart);
936 NonPagedPoolExpansionVa = MmNonPagedPoolStart;
937 DPRINT("NP Pool has been tuned to: %d bytes and %d bytes\n",
938 MmSizeOfNonPagedPoolInBytes, MmMaximumNonPagedPoolInBytes);
939
940 //
941 // Now calculate the nonpaged system VA region, which includes the
942 // nonpaged pool expansion (above) and the system PTEs. Note that it is
943 // then aligned to a PDE boundary (4MB).
944 //
945 MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedPoolStart -
946 (MmNumberOfSystemPtes + 1) * PAGE_SIZE);
947 MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedSystemStart &
948 ~((4 * 1024 * 1024) - 1));
949
950 //
951 // Don't let it go below the minimum
952 //
953 if (MmNonPagedSystemStart < (PVOID)0xEB000000)
954 {
955 //
956 // This is a hard-coded limit in the Windows NT address space
957 //
958 MmNonPagedSystemStart = (PVOID)0xEB000000;
959
960 //
961 // Reduce the amount of system PTEs to reach this point
962 //
963 MmNumberOfSystemPtes = ((ULONG_PTR)MmNonPagedPoolStart -
964 (ULONG_PTR)MmNonPagedSystemStart) >>
965 PAGE_SHIFT;
966 MmNumberOfSystemPtes--;
967 ASSERT(MmNumberOfSystemPtes > 1000);
968 }
969
970 //
971 // Normally, the PFN database should start after the loader images.
972 // This is already the case in ReactOS, but for now we want to co-exist
973 // with the old memory manager, so we'll create a "Shadow PFN Database"
974 // instead, and arbitrarly start it at 0xB0000000.
975 //
976 MmPfnDatabase = (PVOID)0xB0000000;
977 ASSERT(((ULONG_PTR)MmPfnDatabase & ((4 * 1024 * 1024) - 1)) == 0);
978
979 //
980 // Non paged pool comes after the PFN database
981 //
982 MmNonPagedPoolStart = (PVOID)((ULONG_PTR)MmPfnDatabase +
983 (MxPfnAllocation << PAGE_SHIFT));
984
985 //
986 // Now we actually need to get these many physical pages. Nonpaged pool
987 // is actually also physically contiguous (but not the expansion)
988 //
989 PageFrameIndex = MxGetNextPage(MxPfnAllocation +
990 (MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT));
991 ASSERT(PageFrameIndex != 0);
992 DPRINT("PFN DB PA PFN begins at: %lx\n", PageFrameIndex);
993 DPRINT("NP PA PFN begins at: %lx\n", PageFrameIndex + MxPfnAllocation);
994
995 //
996 // Now we need some pages to create the page tables for the NP system VA
997 // which includes system PTEs and expansion NP
998 //
999 StartPde = MiAddressToPde(MmNonPagedSystemStart);
1000 EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolEnd - 1));
1001 while (StartPde <= EndPde)
1002 {
1003 //
1004 // Sanity check
1005 //
1006 ASSERT(StartPde->u.Hard.Valid == 0);
1007
1008 //
1009 // Get a page
1010 //
1011 TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
1012 ASSERT(TempPde.u.Hard.Valid == 1);
1013 *StartPde = TempPde;
1014
1015 //
1016 // Zero out the page table
1017 //
1018 PointerPte = MiPteToAddress(StartPde);
1019 RtlZeroMemory(PointerPte, PAGE_SIZE);
1020
1021 //
1022 // Next
1023 //
1024 StartPde++;
1025 }
1026
1027 //
1028 // Now we need pages for the page tables which will map initial NP
1029 //
1030 StartPde = MiAddressToPde(MmPfnDatabase);
1031 EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolStart +
1032 MmSizeOfNonPagedPoolInBytes - 1));
1033 while (StartPde <= EndPde)
1034 {
1035 //
1036 // Sanity check
1037 //
1038 ASSERT(StartPde->u.Hard.Valid == 0);
1039
1040 //
1041 // Get a page
1042 //
1043 TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
1044 ASSERT(TempPde.u.Hard.Valid == 1);
1045 *StartPde = TempPde;
1046
1047 //
1048 // Zero out the page table
1049 //
1050 PointerPte = MiPteToAddress(StartPde);
1051 RtlZeroMemory(PointerPte, PAGE_SIZE);
1052
1053 //
1054 // Next
1055 //
1056 StartPde++;
1057 }
1058
1059 //
1060 // Now remember where the expansion starts
1061 //
1062 MmNonPagedPoolExpansionStart = NonPagedPoolExpansionVa;
1063
1064 //
1065 // Last step is to actually map the nonpaged pool
1066 //
1067 PointerPte = MiAddressToPte(MmNonPagedPoolStart);
1068 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)MmNonPagedPoolStart +
1069 MmSizeOfNonPagedPoolInBytes - 1));
1070 while (PointerPte <= LastPte)
1071 {
1072 //
1073 // Use one of our contigous pages
1074 //
1075 TempPte.u.Hard.PageFrameNumber = PageFrameIndex++;
1076 ASSERT(PointerPte->u.Hard.Valid == 0);
1077 ASSERT(TempPte.u.Hard.Valid == 1);
1078 *PointerPte++ = TempPte;
1079 }
1080
1081 //
1082 // ReactOS requires a memory area to keep the initial NP area off-bounds
1083 //
1084 BaseAddress = MmNonPagedPoolStart;
1085 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
1086 MEMORY_AREA_SYSTEM | MEMORY_AREA_STATIC,
1087 &BaseAddress,
1088 MmSizeOfNonPagedPoolInBytes,
1089 PAGE_READWRITE,
1090 &MArea,
1091 TRUE,
1092 0,
1093 BoundaryAddressMultiple);
1094 ASSERT(Status == STATUS_SUCCESS);
1095
1096 //
1097 // And we need one more for the system NP
1098 //
1099 BaseAddress = MmNonPagedSystemStart;
1100 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
1101 MEMORY_AREA_SYSTEM | MEMORY_AREA_STATIC,
1102 &BaseAddress,
1103 (ULONG_PTR)MmNonPagedPoolEnd -
1104 (ULONG_PTR)MmNonPagedSystemStart,
1105 PAGE_READWRITE,
1106 &MArea,
1107 TRUE,
1108 0,
1109 BoundaryAddressMultiple);
1110 ASSERT(Status == STATUS_SUCCESS);
1111
1112 //
1113 // Sanity check: make sure we have properly defined the system PTE space
1114 //
1115 ASSERT(MiAddressToPte(MmNonPagedSystemStart) <
1116 MiAddressToPte(MmNonPagedPoolExpansionStart));
1117
1118 //
1119 // Now go ahead and initialize the ARM³ nonpaged pool
1120 //
1121 MiInitializeArmPool();
1122
1123 //
1124 // Get current page data, since we won't be using MxGetNextPage as it
1125 // would corrupt our state
1126 //
1127 FreePage = MxFreeDescriptor->BasePage;
1128 FreePageCount = MxFreeDescriptor->PageCount;
1129 PagesLeft = 0;
1130
1131 //
1132 // Loop the memory descriptors
1133 //
1134 NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink;
1135 while (NextEntry != &KeLoaderBlock->MemoryDescriptorListHead)
1136 {
1137 //
1138 // Get the descriptor
1139 //
1140 MdBlock = CONTAINING_RECORD(NextEntry,
1141 MEMORY_ALLOCATION_DESCRIPTOR,
1142 ListEntry);
1143 if ((MdBlock->MemoryType == LoaderFirmwarePermanent) ||
1144 (MdBlock->MemoryType == LoaderBBTMemory) ||
1145 (MdBlock->MemoryType == LoaderSpecialMemory))
1146 {
1147 //
1148 // These pages are not part of the PFN database
1149 //
1150 NextEntry = MdBlock->ListEntry.Flink;
1151 continue;
1152 }
1153
1154 //
1155 // Next, check if this is our special free descriptor we've found
1156 //
1157 if (MdBlock == MxFreeDescriptor)
1158 {
1159 //
1160 // Use the real numbers instead
1161 //
1162 BasePage = MxOldFreeDescriptor.BasePage;
1163 PageCount = MxOldFreeDescriptor.PageCount;
1164 }
1165 else
1166 {
1167 //
1168 // Use the descriptor's numbers
1169 //
1170 BasePage = MdBlock->BasePage;
1171 PageCount = MdBlock->PageCount;
1172 }
1173
1174 //
1175 // Get the PTEs for this range
1176 //
1177 PointerPte = MiAddressToPte(&MmPfnDatabase[BasePage]);
1178 LastPte = MiAddressToPte(((ULONG_PTR)&MmPfnDatabase[BasePage + PageCount]) - 1);
1179 DPRINT("MD Type: %lx Base: %lx Count: %lx\n", MdBlock->MemoryType, BasePage, PageCount);
1180
1181 //
1182 // Loop them
1183 //
1184 while (PointerPte <= LastPte)
1185 {
1186 //
1187 // We'll only touch PTEs that aren't already valid
1188 //
1189 if (PointerPte->u.Hard.Valid == 0)
1190 {
1191 //
1192 // Use the next free page
1193 //
1194 TempPte.u.Hard.PageFrameNumber = FreePage;
1195 ASSERT(FreePageCount != 0);
1196
1197 //
1198 // Consume free pages
1199 //
1200 FreePage++;
1201 FreePageCount--;
1202 if (!FreePageCount)
1203 {
1204 //
1205 // Out of memory
1206 //
1207 KeBugCheckEx(INSTALL_MORE_MEMORY,
1208 MmNumberOfPhysicalPages,
1209 FreePageCount,
1210 MxOldFreeDescriptor.PageCount,
1211 1);
1212 }
1213
1214 //
1215 // Write out this PTE
1216 //
1217 PagesLeft++;
1218 ASSERT(PointerPte->u.Hard.Valid == 0);
1219 ASSERT(TempPte.u.Hard.Valid == 1);
1220 *PointerPte = TempPte;
1221
1222 //
1223 // Zero this page
1224 //
1225 RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE);
1226 }
1227
1228 //
1229 // Next!
1230 //
1231 PointerPte++;
1232 }
1233
1234 //
1235 // Do the next address range
1236 //
1237 NextEntry = MdBlock->ListEntry.Flink;
1238 }
1239
1240 //
1241 // Now update the free descriptors to consume the pages we used up during
1242 // the PFN allocation loop
1243 //
1244 MxFreeDescriptor->BasePage = FreePage;
1245 MxFreeDescriptor->PageCount = FreePageCount;
1246 }
1247 else if (Phase == 1) // IN BETWEEN, THE PFN DATABASE IS NOW CREATED
1248 {
1249 //
1250 // Reset the descriptor back so we can create the correct memory blocks
1251 //
1252 *MxFreeDescriptor = MxOldFreeDescriptor;
1253
1254 //
1255 // Initialize the nonpaged pool
1256 //
1257 InitializePool(NonPagedPool, 0);
1258
1259 //
1260 // We PDE-aligned the nonpaged system start VA, so haul some extra PTEs!
1261 //
1262 PointerPte = MiAddressToPte(MmNonPagedSystemStart);
1263 OldCount = MmNumberOfSystemPtes;
1264 MmNumberOfSystemPtes = MiAddressToPte(MmNonPagedPoolExpansionStart) -
1265 PointerPte;
1266 MmNumberOfSystemPtes--;
1267 DPRINT("Final System PTE count: %d (%d bytes)\n",
1268 MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE);
1269
1270 //
1271 // Create the system PTE space
1272 //
1273 MiInitializeSystemPtes(PointerPte, MmNumberOfSystemPtes, SystemPteSpace);
1274
1275 //
1276 // Get the PDE For hyperspace
1277 //
1278 StartPde = MiAddressToPde(HYPER_SPACE);
1279
1280 //
1281 // Allocate a page for it and create it
1282 //
1283 PageFrameIndex = MmAllocPage(MC_SYSTEM, 0);
1284 TempPde.u.Hard.PageFrameNumber = PageFrameIndex;
1285 TempPde.u.Hard.Global = FALSE; // Hyperspace is local!
1286 ASSERT(StartPde->u.Hard.Valid == 0);
1287 ASSERT(TempPde.u.Hard.Valid == 1);
1288 *StartPde = TempPde;
1289
1290 //
1291 // Zero out the page table now
1292 //
1293 PointerPte = MiAddressToPte(HYPER_SPACE);
1294 RtlZeroMemory(PointerPte, PAGE_SIZE);
1295
1296 //
1297 // Setup the mapping PTEs
1298 //
1299 MmFirstReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_START);
1300 MmLastReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_END);
1301 MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
1302
1303 //
1304 // Reserve system PTEs for zeroing PTEs and clear them
1305 //
1306 MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES,
1307 SystemPteSpace);
1308 RtlZeroMemory(MiFirstReservedZeroingPte, MI_ZERO_PTES * sizeof(MMPTE));
1309
1310 //
1311 // Set the counter to maximum to boot with
1312 //
1313 MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
1314
1315 //
1316 // Sync us up with ReactOS Mm
1317 //
1318 MiSyncARM3WithROS(MmNonPagedSystemStart, (PVOID)((ULONG_PTR)MmNonPagedPoolEnd - 1));
1319 MiSyncARM3WithROS(MmPfnDatabase, (PVOID)((ULONG_PTR)MmNonPagedPoolStart + MmSizeOfNonPagedPoolInBytes - 1));
1320 MiSyncARM3WithROS((PVOID)HYPER_SPACE, (PVOID)(HYPER_SPACE + PAGE_SIZE - 1));
1321 }
1322 else // NOW WE HAVE NONPAGED POOL
1323 {
1324 //
1325 // Instantiate memory that we don't consider RAM/usable
1326 // We use the same exclusions that Windows does, in order to try to be
1327 // compatible with WinLDR-style booting
1328 //
1329 for (i = 0; i < LoaderMaximum; i++) IncludeType[i] = TRUE;
1330 IncludeType[LoaderBad] = FALSE;
1331 IncludeType[LoaderFirmwarePermanent] = FALSE;
1332 IncludeType[LoaderSpecialMemory] = FALSE;
1333 IncludeType[LoaderBBTMemory] = FALSE;
1334
1335 //
1336 // Build the physical memory block
1337 //
1338 MmPhysicalMemoryBlock = MmInitializeMemoryLimits(LoaderBlock,
1339 IncludeType);
1340
1341 //
1342 // Allocate enough buffer for the PFN bitmap
1343 // Align it up to a 32-bit boundary
1344 //
1345 Bitmap = ExAllocatePoolWithTag(NonPagedPool,
1346 (((MmHighestPhysicalPage + 1) + 31) / 32) * 4,
1347 ' mM');
1348 if (!Bitmap)
1349 {
1350 //
1351 // This is critical
1352 //
1353 KeBugCheckEx(INSTALL_MORE_MEMORY,
1354 MmNumberOfPhysicalPages,
1355 MmLowestPhysicalPage,
1356 MmHighestPhysicalPage,
1357 0x101);
1358 }
1359
1360 //
1361 // Initialize it and clear all the bits to begin with
1362 //
1363 RtlInitializeBitMap(&MiPfnBitMap,
1364 Bitmap,
1365 MmHighestPhysicalPage + 1);
1366 RtlClearAllBits(&MiPfnBitMap);
1367
1368 //
1369 // Loop physical memory runs
1370 //
1371 for (i = 0; i < MmPhysicalMemoryBlock->NumberOfRuns; i++)
1372 {
1373 //
1374 // Get the run
1375 //
1376 Run = &MmPhysicalMemoryBlock->Run[i];
1377 DPRINT("PHYSICAL RAM [0x%08p to 0x%08p]\n",
1378 Run->BasePage << PAGE_SHIFT,
1379 (Run->BasePage + Run->PageCount) << PAGE_SHIFT);
1380
1381 //
1382 // Make sure it has pages inside it
1383 //
1384 if (Run->PageCount)
1385 {
1386 //
1387 // Set the bits in the PFN bitmap
1388 //
1389 RtlSetBits(&MiPfnBitMap, Run->BasePage, Run->PageCount);
1390 }
1391 }
1392
1393 //
1394 // Size up paged pool and build the shadow system page directory
1395 //
1396 MiBuildPagedPool();
1397
1398 //
1399 // Print the memory layout
1400 //
1401 DPRINT1(" 0x%p - 0x%p\t%s\n",
1402 MmSystemRangeStart,
1403 (ULONG_PTR)MmSystemRangeStart + MmBootImageSize,
1404 "Boot Loaded Image");
1405 DPRINT1(" 0x%p - 0x%p\t%s\n",
1406 MmPagedPoolBase,
1407 (ULONG_PTR)MmPagedPoolBase + MmPagedPoolSize,
1408 "Paged Pool");
1409 DPRINT1(" 0x%p - 0x%p\t%s\n",
1410 MmPfnDatabase,
1411 (ULONG_PTR)MmPfnDatabase + (MxPfnAllocation << PAGE_SHIFT),
1412 "PFN Database");
1413 DPRINT1(" 0x%p - 0x%p\t%s\n",
1414 MmNonPagedPoolStart,
1415 (ULONG_PTR)MmNonPagedPoolStart + MmSizeOfNonPagedPoolInBytes,
1416 "ARM³ Non Paged Pool");
1417 DPRINT1(" 0x%p - 0x%p\t%s\n",
1418 MiSystemViewStart,
1419 (ULONG_PTR)MiSystemViewStart + MmSystemViewSize,
1420 "System View Space");
1421 DPRINT1(" 0x%p - 0x%p\t%s\n",
1422 MmSessionBase,
1423 MiSessionSpaceEnd,
1424 "Session Space");
1425 DPRINT1(" 0x%p - 0x%p\t%s\n",
1426 PTE_BASE, PDE_BASE,
1427 "Page Tables");
1428 DPRINT1(" 0x%p - 0x%p\t%s\n",
1429 PDE_BASE, HYPER_SPACE,
1430 "Page Directories");
1431 DPRINT1(" 0x%p - 0x%p\t%s\n",
1432 HYPER_SPACE, HYPER_SPACE + (4 * 1024 * 1024),
1433 "Hyperspace");
1434 DPRINT1(" 0x%p - 0x%p\t%s\n",
1435 MmPagedPoolStart,
1436 (ULONG_PTR)MmPagedPoolStart + MmSizeOfPagedPoolInBytes,
1437 "ARM³ Paged Pool");
1438 DPRINT1(" 0x%p - 0x%p\t%s\n",
1439 MmNonPagedSystemStart, MmNonPagedPoolExpansionStart,
1440 "System PTE Space");
1441 DPRINT1(" 0x%p - 0x%p\t%s\n",
1442 MmNonPagedPoolExpansionStart, MmNonPagedPoolEnd,
1443 "Non Paged Pool Expansion PTE Space");
1444 }
1445
1446 //
1447 // Always return success for now
1448 //
1449 return STATUS_SUCCESS;
1450 }
1451
1452 /* EOF */