eab7192edfc3a2ecf30515c04cc3a37c804d6d85
[reactos.git] / reactos / ntoskrnl / mm / amd64 / init.c
1 /*
2 * COPYRIGHT: GPL, See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/amd64/init.c
5 * PURPOSE: Memory Manager Initialization for amd64
6 *
7 * PROGRAMMERS: Timo kreuzer (timo.kreuzer@reactos.org)
8 * ReactOS Portable Systems Group
9 */
10
11 /* INCLUDES ***************************************************************/
12
13 #include <ntoskrnl.h>
14 //#define NDEBUG
15 #include <debug.h>
16
17 #include "../ARM3/miarm.h"
18
19 #ifdef _WINKD_
20 extern PMMPTE MmDebugPte;
21 #endif
22
23 VOID
24 NTAPI
25 HalInitializeBios(ULONG Unknown, PLOADER_PARAMETER_BLOCK LoaderBlock);
26
27 /* GLOBALS *****************************************************************/
28
29 /* Template PTE and PDE for a kernel page */
30 MMPTE ValidKernelPde = {.u.Hard.Valid = 1, .u.Hard.Write = 1, .u.Hard.Dirty = 1, .u.Hard.Accessed = 1};
31 MMPTE ValidKernelPte = {.u.Hard.Valid = 1, .u.Hard.Write = 1, .u.Hard.Dirty = 1, .u.Hard.Accessed = 1};
32 MMPDE DemandZeroPde = {.u.Long = (MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS)};
33 MMPTE PrototypePte = {.u.Long = (MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS) | PTE_PROTOTYPE | 0xFFFFF000};
34
35 /* Sizes */
36 ///SIZE_T MmSessionSize = MI_SESSION_SIZE;
37 SIZE_T MmSessionViewSize = MI_SESSION_VIEW_SIZE;
38 SIZE_T MmSessionPoolSize = MI_SESSION_POOL_SIZE;
39 SIZE_T MmSessionImageSize = MI_SESSION_IMAGE_SIZE;
40 SIZE_T MmSystemViewSize = MI_SYSTEM_VIEW_SIZE;
41 SIZE_T MiNonPagedSystemSize;
42
43 /* Address ranges */
44 ULONG64 MmUserProbeAddress = 0x7FFFFFF0000ULL;
45 PVOID MmHighestUserAddress = (PVOID)0x7FFFFFEFFFFULL;
46 PVOID MmSystemRangeStart = (PVOID)0xFFFF080000000000ULL;
47 PVOID MmSessionBase; // FFFFF90000000000 = MiSessionPoolStart
48 PVOID MiSessionPoolStart; // FFFFF90000000000 = MiSessionPoolEnd - MmSessionPoolSize
49 PVOID MiSessionPoolEnd; // = MiSessionViewStart
50 PVOID MiSessionViewStart; // = MiSessionViewEnd - MmSessionViewSize
51 PVOID MiSessionViewEnd; // FFFFF97FFF000000
52 PVOID MiSessionImageStart; // ?FFFFF97FFF000000 = MiSessionImageEnd - MmSessionImageSize
53 PVOID MiSessionImageEnd; // FFFFF98000000000 = MiSessionSpaceEnd
54 PVOID MiSessionSpaceEnd = MI_SESSION_SPACE_END; // FFFFF98000000000
55 PVOID MmSystemCacheStart; // FFFFF98000000000
56 PVOID MmSystemCacheEnd; // FFFFFA8000000000
57 /// PVOID MmPagedPoolStart = MI_PAGED_POOL_START; // FFFFFA8000000000
58 PVOID MmPagedPoolEnd; // FFFFFAA000000000
59 PVOID MiSystemViewStart;
60 PVOID MmNonPagedSystemStart; // FFFFFAA000000000
61 PVOID MmNonPagedPoolStart;
62 PVOID MmNonPagedPoolExpansionStart;
63 ///PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END; // 0xFFFFFAE000000000
64 PVOID MmHyperSpaceEnd = (PVOID)HYPER_SPACE_END;
65
66 MMSUPPORT MmSystemCacheWs;
67
68 ULONG64 MxPfnSizeInBytes;
69
70 PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor;
71 MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor;
72 ULONG MiNumberDescriptors = 0;
73 PFN_NUMBER MiSystemPages = 0;
74 BOOLEAN MiIncludeType[LoaderMaximum];
75
76 PFN_NUMBER MxFreePageBase;
77 ULONG64 MxFreePageCount = 0;
78
79 extern PFN_NUMBER MmSystemPageDirectory[PD_COUNT];
80
81 BOOLEAN MiPfnsInitialized = FALSE;
82
83 /* FUNCTIONS *****************************************************************/
84
85 ULONG
86 NoDbgPrint(const char *Format, ...)
87 {
88 return 0;
89 }
90
91 VOID
92 NTAPI
93 MiEvaluateMemoryDescriptors(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
94 {
95 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
96 PLIST_ENTRY ListEntry;
97 PFN_NUMBER LastPage;
98 ULONG i;
99
100 /* Get the size of the boot loader's image allocations */
101 MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned * PAGE_SIZE;
102 MmBootImageSize = ROUND_UP(MmBootImageSize, 4 * 1024 * 1024);
103
104 /* Instantiate memory that we don't consider RAM/usable */
105 for (i = 0; i < LoaderMaximum; i++) MiIncludeType[i] = TRUE;
106 MiIncludeType[LoaderBad] = FALSE;
107 MiIncludeType[LoaderFirmwarePermanent] = FALSE;
108 MiIncludeType[LoaderSpecialMemory] = FALSE;
109 MiIncludeType[LoaderBBTMemory] = FALSE;
110
111 /* Loop the memory descriptors */
112 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
113 ListEntry != &LoaderBlock->MemoryDescriptorListHead;
114 ListEntry = ListEntry->Flink)
115 {
116 /* Get the memory descriptor */
117 Descriptor = CONTAINING_RECORD(ListEntry,
118 MEMORY_ALLOCATION_DESCRIPTOR,
119 ListEntry);
120
121 /* Count it */
122 MiNumberDescriptors++;
123
124 /* Skip pages that are not part of the PFN database */
125 if (!MiIncludeType[Descriptor->MemoryType])
126 {
127 continue;
128 }
129
130 /* Add this to the total of pages */
131 MmNumberOfPhysicalPages += Descriptor->PageCount;
132
133 /* Check if this is the new lowest page */
134 if (Descriptor->BasePage < MmLowestPhysicalPage)
135 {
136 /* Update the lowest page */
137 MmLowestPhysicalPage = Descriptor->BasePage;
138 }
139
140 /* Check if this is the new highest page */
141 LastPage = Descriptor->BasePage + Descriptor->PageCount - 1;
142 if (LastPage > MmHighestPhysicalPage)
143 {
144 /* Update the highest page */
145 MmHighestPhysicalPage = LastPage;
146 }
147
148 /* Check if this is currently free memory */
149 if ((Descriptor->MemoryType == LoaderFree) ||
150 (Descriptor->MemoryType == LoaderLoadedProgram) ||
151 (Descriptor->MemoryType == LoaderFirmwareTemporary) ||
152 (Descriptor->MemoryType == LoaderOsloaderStack))
153 {
154 /* Check if this is the largest memory descriptor */
155 if (Descriptor->PageCount > MxFreePageCount)
156 {
157 /* For now, it is */
158 MxFreeDescriptor = Descriptor;
159 MxFreePageBase = Descriptor->BasePage;
160 MxFreePageCount = Descriptor->PageCount;
161 }
162 }
163 else
164 {
165 /* Add it to the amount of system used pages */
166 MiSystemPages += Descriptor->PageCount;
167 }
168 }
169 }
170
171 PFN_NUMBER
172 NTAPI
173 MiEarlyAllocPage()
174 {
175 PFN_NUMBER Pfn;
176
177 if (MiPfnsInitialized)
178 {
179 return MmAllocPage(MC_SYSTEM);
180 }
181
182 /* Make sure we have enough pages */
183 if (!MxFreePageCount)
184 {
185 /* Crash the system */
186 KeBugCheckEx(INSTALL_MORE_MEMORY,
187 MmNumberOfPhysicalPages,
188 MxFreeDescriptor->PageCount,
189 MxOldFreeDescriptor.PageCount,
190 1);
191 }
192
193 /* Use our lowest usable free pages */
194 Pfn = MxFreePageBase;
195 MxFreePageBase++;
196 MxFreePageCount--;
197 return Pfn;
198 }
199
200 PMMPTE
201 NTAPI
202 MxGetPte(PVOID Address)
203 {
204 PMMPTE Pte;
205 MMPTE TmplPte;
206
207 /* Setup template pte */
208 TmplPte.u.Long = 0;
209 TmplPte.u.Flush.Valid = 1;
210 TmplPte.u.Flush.Write = 1;
211
212 /* Get a pointer to the PXE */
213 Pte = MiAddressToPxe(Address);
214 if (!Pte->u.Hard.Valid)
215 {
216 /* It's not valid, map it! */
217 TmplPte.u.Hard.PageFrameNumber = MiEarlyAllocPage();
218 *Pte = TmplPte;
219
220 /* Zero the page */
221 RtlZeroMemory(MiPteToAddress(Pte), PAGE_SIZE);
222 }
223
224 /* Get a pointer to the PPE */
225 Pte = MiAddressToPpe(Address);
226 if (!Pte->u.Hard.Valid)
227 {
228 /* It's not valid, map it! */
229 TmplPte.u.Hard.PageFrameNumber = MiEarlyAllocPage();
230 *Pte = TmplPte;
231
232 /* Zero the page */
233 RtlZeroMemory(MiPteToAddress(Pte), PAGE_SIZE);
234 }
235
236 /* Get a pointer to the PDE */
237 Pte = MiAddressToPde(Address);
238 if (!Pte->u.Hard.Valid)
239 {
240 /* It's not valid, map it! */
241 TmplPte.u.Hard.PageFrameNumber = MiEarlyAllocPage();
242 *Pte = TmplPte;
243
244 /* Zero the page */
245 RtlZeroMemory(MiPteToAddress(Pte), PAGE_SIZE);
246 }
247
248 /* Get a pointer to the PTE */
249 Pte = MiAddressToPte(Address);
250 return Pte;
251 }
252
253 VOID
254 NTAPI
255 MxMapPage(PVOID Address)
256 {
257 MMPTE TmplPte, *Pte;
258
259 /* Setup template pte */
260 TmplPte.u.Long = 0;
261 TmplPte.u.Flush.Valid = 1;
262 TmplPte.u.Flush.Write = 1;
263 TmplPte.u.Hard.PageFrameNumber = MiEarlyAllocPage();
264
265 /* Get the PTE for that page */
266 Pte = MxGetPte(Address);
267 ASSERT(Pte->u.Hard.Valid == 0);
268
269 /* Map a physical page */
270 *Pte = TmplPte;
271 }
272
273 VOID
274 MxMapPageRange(PVOID Address, ULONG64 PageCount)
275 {
276 while (PageCount--)
277 {
278 /* Map the page */
279 MxMapPage(Address);
280
281 /* Goto next page */
282 Address = (PVOID)((ULONG64)Address + PAGE_SIZE);
283 }
284 }
285
286 VOID
287 NTAPI
288 MiPreparePfnDatabse(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
289 {
290 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
291 PLIST_ENTRY ListEntry;
292 PUCHAR Page, FirstPage;
293 SIZE_T Size;
294
295 /* Calculate the size of the PFN database and convert to pages */
296 MxPfnSizeInBytes = ROUND_TO_PAGES((MmHighestPhysicalPage + 1) * sizeof(MMPFN));
297 MxPfnAllocation = MxPfnSizeInBytes >> PAGE_SHIFT;
298
299 /* Simply start at hardcoded address */
300 MmPfnDatabase = MI_PFN_DATABASE;
301
302 /* Loop the memory descriptors */
303 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
304 ListEntry != &LoaderBlock->MemoryDescriptorListHead;
305 ListEntry = ListEntry->Flink)
306 {
307 /* Get the memory descriptor */
308 Descriptor = CONTAINING_RECORD(ListEntry,
309 MEMORY_ALLOCATION_DESCRIPTOR,
310 ListEntry);
311
312 /* Skip pages that are not part of the PFN database */
313 if (MiIncludeType[Descriptor->MemoryType])
314 {
315 /* Get the base and size of this pfn database entry */
316 FirstPage = PAGE_ALIGN(&MmPfnDatabase[Descriptor->BasePage]);
317 Size = ROUND_TO_PAGES(Descriptor->PageCount * sizeof(MMPFN));
318
319 /* Loop the pages of this Pfn database entry */
320 for (Page = FirstPage; Page < FirstPage + Size; Page += PAGE_SIZE)
321 {
322 /* Is the page already mapped? */
323 if (!MmIsAddressValid(Page))
324 {
325 /* It's not, map it now */
326 MxMapPage(Page);
327 RtlZeroMemory(Page, PAGE_SIZE);
328 }
329 }
330
331 /* Zero out the pages */
332 RtlZeroMemory(FirstPage, Size);
333 }
334 }
335 }
336
337
338 VOID
339 NTAPI
340 MiInitializeSessionSpace(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
341 {
342 /* Set up session space */
343 MiSessionSpaceEnd = (PVOID)MI_SESSION_SPACE_END;
344
345 /* This is where we will load Win32k.sys and the video driver */
346 MiSessionImageEnd = MiSessionSpaceEnd;
347 MiSessionImageStart = (PCHAR)MiSessionImageEnd - MmSessionImageSize;
348
349 /* The view starts right below the session working set (itself below
350 * the image area) */
351 MiSessionViewEnd = MI_SESSION_VIEW_END;
352 MiSessionViewStart = (PCHAR)MiSessionViewEnd - MmSessionViewSize;
353 ASSERT(IS_PAGE_ALIGNED(MiSessionViewStart));
354
355 /* Session pool follows */
356 MiSessionPoolEnd = MiSessionViewStart;
357 MiSessionPoolStart = (PCHAR)MiSessionPoolEnd - MmSessionPoolSize;
358 ASSERT(IS_PAGE_ALIGNED(MiSessionPoolStart));
359
360 /* And it all begins here */
361 MmSessionBase = MiSessionPoolStart;
362
363 /* System view space ends at session space, so now that we know where
364 * this is, we can compute the base address of system view space itself. */
365 MiSystemViewStart = (PCHAR)MmSessionBase - MmSystemViewSize;
366 ASSERT(IS_PAGE_ALIGNED(MiSystemViewStart));
367
368 /* Sanity checks */
369 ASSERT(MiSessionViewEnd <= MiSessionImageStart);
370 ASSERT(MmSessionBase <= MiSessionPoolStart);
371 }
372
373 VOID
374 MiInitializePageTable()
375 {
376 ULONG64 PageFrameOffset;
377 MMPTE TmplPte, *Pte;
378
379 /* HACK: don't use freeldr debug print anymore */
380 //FrLdrDbgPrint = NoDbgPrint;
381
382 /* Get current directory base */
383 MmSystemPageDirectory[0] = ((PMMPTE)PXE_SELFMAP)->u.Hard.PageFrameNumber;
384 PageFrameOffset = MmSystemPageDirectory[0] << PAGE_SHIFT;
385 ASSERT(PageFrameOffset == __readcr3());
386
387 /* Set directory base for the system process */
388 PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PageFrameOffset;
389
390 /* Enable global pages */
391 __writecr4(__readcr4() | CR4_PGE);
392 ASSERT(__readcr4() & CR4_PGE);
393
394 /* Enable no execute */
395 __writemsr(X86_MSR_EFER, __readmsr(X86_MSR_EFER) | EFER_NXE);
396
397 /* Loop the user mode PXEs */
398 for (Pte = MiAddressToPxe(0);
399 Pte <= MiAddressToPxe(MmHighestUserAddress);
400 Pte++)
401 {
402 /* Zero the PXE, clear all mappings */
403 Pte->u.Long = 0;
404 }
405
406 /* Flush the TLB */
407 KeFlushCurrentTb();
408
409 /* Set up a template PTE */
410 TmplPte.u.Long = 0;
411 TmplPte.u.Flush.Valid = 1;
412 TmplPte.u.Flush.Write = 1;
413 HyperTemplatePte = TmplPte;
414
415 /* Create PDPTs (72 KB) for shared system address space,
416 * skip page tables and hyperspace */
417
418 /* Loop the PXEs */
419 for (Pte = MiAddressToPxe((PVOID)(HYPER_SPACE_END + 1));
420 Pte <= MiAddressToPxe(MI_HIGHEST_SYSTEM_ADDRESS);
421 Pte++)
422 {
423 /* Is the PXE already valid? */
424 if (!Pte->u.Hard.Valid)
425 {
426 /* It's not Initialize it */
427 TmplPte.u.Flush.PageFrameNumber = MiEarlyAllocPage(0);
428 *Pte = TmplPte;
429
430 /* Zero the page. The PXE is the PTE for the PDPT. */
431 RtlZeroMemory(MiPteToAddress(Pte), PAGE_SIZE);
432 }
433 }
434
435 /* Setup the mapping PTEs */
436 MmFirstReservedMappingPte = MxGetPte((PVOID)MI_MAPPING_RANGE_START);
437 MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
438 MmLastReservedMappingPte = MiAddressToPte((PVOID)MI_MAPPING_RANGE_END);
439
440 #ifdef _WINKD_
441 /* Setup debug mapping PTE */
442 MmDebugPte = MxGetPte(MI_DEBUG_MAPPING);
443 #endif
444 }
445
446 VOID
447 NTAPI
448 MiBuildNonPagedPool(VOID)
449 {
450 PMMPTE Pte;
451 PFN_COUNT PageCount;
452
453 /* Check if this is a machine with less than 256MB of RAM, and no overide */
454 if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) &&
455 !(MmSizeOfNonPagedPoolInBytes))
456 {
457 /* Force the non paged pool to be 2MB so we can reduce RAM usage */
458 MmSizeOfNonPagedPoolInBytes = 2 * 1024 * 1024;
459 }
460
461 /* Check if the user gave a ridicuously large nonpaged pool RAM size */
462 if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) >
463 (MmNumberOfPhysicalPages * 7 / 8))
464 {
465 /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */
466 MmSizeOfNonPagedPoolInBytes = 0;
467 }
468
469 /* Check if no registry setting was set, or if the setting was too low */
470 if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize)
471 {
472 /* Start with the minimum (256 KB) and add 32 KB for each MB above 4 */
473 MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize;
474 MmSizeOfNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
475 256 * MmMinAdditionNonPagedPoolPerMb;
476 }
477
478 /* Check if the registy setting or our dynamic calculation was too high */
479 if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE)
480 {
481 /* Set it to the maximum */
482 MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE;
483 }
484
485 /* Check if a percentage cap was set through the registry */
486 if (MmMaximumNonPagedPoolPercent)
487 {
488 /* Don't feel like supporting this right now */
489 UNIMPLEMENTED;
490 }
491
492 /* Page-align the nonpaged pool size */
493 MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1);
494
495 /* Now, check if there was a registry size for the maximum size */
496 if (!MmMaximumNonPagedPoolInBytes)
497 {
498 /* Start with the default (1MB) and add 400 KB for each MB above 4 */
499 MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool;
500 MmMaximumNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
501 256 * MmMaxAdditionNonPagedPoolPerMb;
502 }
503
504 /* Don't let the maximum go too high */
505 if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE)
506 {
507 /* Set it to the upper limit */
508 MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE;
509 }
510
511 /* Put non paged pool to the end of the region */
512 MmNonPagedPoolStart = (PCHAR)MmNonPagedPoolEnd - MmMaximumNonPagedPoolInBytes;
513
514 /* Make sure it doesn't collide with the PFN database */
515 if ((PCHAR)MmNonPagedPoolStart < (PCHAR)MmPfnDatabase + MxPfnSizeInBytes)
516 {
517 /* Put non paged pool after the PFN database */
518 MmNonPagedPoolStart = (PCHAR)MmPfnDatabase + MxPfnSizeInBytes;
519 MmMaximumNonPagedPoolInBytes = (ULONG64)MmNonPagedPoolEnd -
520 (ULONG64)MmNonPagedPoolStart;
521 }
522
523 ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolStart));
524
525 /* Calculate the nonpaged pool expansion start region */
526 MmNonPagedPoolExpansionStart = (PCHAR)MmNonPagedPoolStart +
527 MmSizeOfNonPagedPoolInBytes;
528 ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolExpansionStart));
529
530 /* Map the nonpaged pool */
531 PageCount = (MmSizeOfNonPagedPoolInBytes + PAGE_SIZE - 1) / PAGE_SIZE;
532 MxMapPageRange(MmNonPagedPoolStart, PageCount);
533
534 /* Loop the non paged pool extension PTEs */
535 for (Pte = MiAddressToPte(MmNonPagedPoolExpansionStart);
536 Pte <= MiAddressToPte(MmNonPagedPoolEnd);
537 Pte++)
538 {
539 /* Create PXE, PPE, PDE and zero the PTE */
540 MxGetPte(MiPteToAddress(Pte))->u.Long = 0;
541 }
542
543 /* Initialize the ARM3 nonpaged pool */
544 MiInitializeNonPagedPool();
545
546 /* Initialize the nonpaged pool */
547 InitializePool(NonPagedPool, 0);
548 }
549
550 VOID
551 NTAPI
552 MiBuildSystemPteSpace()
553 {
554 PMMPTE Pte, StartPte, EndPte;
555
556 /* Use the default numer of system PTEs */
557 MmNumberOfSystemPtes = MI_NUMBER_SYSTEM_PTES;
558
559 /* System PTE pool is below the PFN database */
560 MiNonPagedSystemSize = (MmNumberOfSystemPtes + 1) * PAGE_SIZE;
561 MmNonPagedSystemStart = (PCHAR)MmPfnDatabase - MiNonPagedSystemSize;
562 MmNonPagedSystemStart = MM_ROUND_DOWN(MmNonPagedSystemStart, 512 * PAGE_SIZE);
563
564 /* Don't let it go below the minimum */
565 if (MmNonPagedSystemStart < (PVOID)MI_NON_PAGED_SYSTEM_START_MIN)
566 {
567 /* This is a hard-coded limit in the Windows NT address space */
568 MmNonPagedSystemStart = (PVOID)MI_NON_PAGED_SYSTEM_START_MIN;
569
570 /* Reduce the amount of system PTEs to reach this point */
571 MmNumberOfSystemPtes = ((ULONG64)MmPfnDatabase -
572 (ULONG64)MmNonPagedSystemStart) >>
573 PAGE_SHIFT;
574 MmNumberOfSystemPtes--;
575 ASSERT(MmNumberOfSystemPtes > 1000);
576 }
577
578 /* Set the range of system PTEs */
579 StartPte = MiAddressToPte(MI_SYSTEM_PTE_START);
580 EndPte = StartPte + MmNumberOfSystemPtes - 1;
581
582 /* Loop the system PTEs */
583 for (Pte = StartPte; Pte <= EndPte; Pte++)
584 {
585 /* Create PXE, PPE, PDE and zero the PTE */
586 MxGetPte(MiPteToAddress(Pte))->u.Long = 0;
587 }
588
589 /* Create the system PTE space */
590 Pte = MiAddressToPte(MI_SYSTEM_PTE_START);
591 MiInitializeSystemPtes(Pte, MmNumberOfSystemPtes, SystemPteSpace);
592
593 /* Reserve system PTEs for zeroing PTEs and clear them */
594 MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES, SystemPteSpace);
595 RtlZeroMemory(MiFirstReservedZeroingPte, MI_ZERO_PTES * sizeof(MMPTE));
596
597 /* Set the counter to maximum */
598 MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
599 }
600
601 VOID
602 NTAPI
603 MiBuildPhysicalMemoryBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
604 {
605 PPHYSICAL_MEMORY_DESCRIPTOR Buffer;
606 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
607 PLIST_ENTRY ListEntry;
608 PFN_NUMBER NextPage = -1;
609 PULONG Bitmap;
610 ULONG Runs = 0;
611 ULONG Size;
612
613 /* Calculate size for the PFN bitmap */
614 Size = ROUND_UP(MmHighestPhysicalPage + 1, sizeof(ULONG));
615
616 /* Allocate the PFN bitmap */
617 Bitmap = ExAllocatePoolWithTag(NonPagedPool, Size, ' mM');
618
619 /* Allocate enough memory for the physical memory block */
620 Buffer = ExAllocatePoolWithTag(NonPagedPool,
621 sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
622 sizeof(PHYSICAL_MEMORY_RUN) *
623 (MiNumberDescriptors - 1),
624 'lMmM');
625 if (!Bitmap || !Buffer)
626 {
627 /* This is critical */
628 KeBugCheckEx(INSTALL_MORE_MEMORY,
629 MmNumberOfPhysicalPages,
630 MmLowestPhysicalPage,
631 MmHighestPhysicalPage,
632 0x101);
633 }
634
635 /* Initialize the bitmap and clear all bits */
636 RtlInitializeBitMap(&MiPfnBitMap, Bitmap, MmHighestPhysicalPage + 1);
637 RtlClearAllBits(&MiPfnBitMap);
638
639 /* Loop the memory descriptors */
640 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
641 ListEntry != &LoaderBlock->MemoryDescriptorListHead;
642 ListEntry = ListEntry->Flink)
643 {
644 /* Get the memory descriptor */
645 Descriptor = CONTAINING_RECORD(ListEntry,
646 MEMORY_ALLOCATION_DESCRIPTOR,
647 ListEntry);
648
649 /* Skip pages that are not part of the PFN database */
650 if (!MiIncludeType[Descriptor->MemoryType])
651 {
652 continue;
653 }
654
655 /* Does the memory block begin where the last ended? */
656 if (Descriptor->BasePage == NextPage)
657 {
658 /* Add it to the current run */
659 Buffer->Run[Runs - 1].PageCount += Descriptor->PageCount;
660 }
661 else
662 {
663 /* Create a new run */
664 Runs++;
665 Buffer->Run[Runs - 1].BasePage = Descriptor->BasePage;
666 Buffer->Run[Runs - 1].PageCount = Descriptor->PageCount;
667 }
668
669 /* Set the bits in the PFN bitmap */
670 RtlSetBits(&MiPfnBitMap, Descriptor->BasePage, Descriptor->PageCount);
671
672 /* Set the next page */
673 NextPage = Descriptor->BasePage + Descriptor->PageCount;
674 }
675
676 // FIXME: allocate a buffer of better size
677
678 Buffer->NumberOfRuns = Runs;
679 Buffer->NumberOfPages = MmNumberOfPhysicalPages;
680 MmPhysicalMemoryBlock = Buffer;
681 }
682
683 VOID
684 NTAPI
685 MiBuildPagedPool_x(VOID)
686 {
687 PMMPTE Pte;
688 MMPTE TmplPte;
689 ULONG Size, BitMapSize;
690
691 /* Default size for paged pool is 4 times non paged pool */
692 MmSizeOfPagedPoolInBytes = 4 * MmMaximumNonPagedPoolInBytes;
693
694 /* Make sure it doesn't overflow */
695 if (MmSizeOfPagedPoolInBytes > ((ULONG64)MmNonPagedSystemStart -
696 (ULONG64)MmPagedPoolStart))
697 {
698 MmSizeOfPagedPoolInBytes = (ULONG64)MmNonPagedSystemStart -
699 (ULONG64)MmPagedPoolStart;
700 }
701
702 /* Make sure paged pool is big enough */
703 if (MmSizeOfPagedPoolInBytes < MI_MIN_INIT_PAGED_POOLSIZE)
704 {
705 MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE;
706 }
707
708 /* Align down to a PDE boundary */
709 MmSizeOfPagedPoolInBytes = ROUND_DOWN(MmSizeOfPagedPoolInBytes,
710 512 * PAGE_SIZE);
711 MmSizeOfPagedPoolInPages = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT;
712
713 /* This is where paged pool ends */
714 MmPagedPoolEnd = (PCHAR)MmPagedPoolStart + MmSizeOfPagedPoolInBytes - 1;
715
716 /* Sanity check */
717 ASSERT(MmPagedPoolEnd < MmNonPagedSystemStart);
718
719 /* setup a template PTE */
720 TmplPte.u.Long = 0;
721 TmplPte.u.Flush.Valid = 1;
722 TmplPte.u.Flush.Write = 1;
723
724 /* Make sure the PXE is valid */
725 Pte = MiAddressToPxe(MmPagedPoolStart);
726 if (!Pte->u.Flush.Valid)
727 {
728 /* Map it! */
729 TmplPte.u.Flush.PageFrameNumber = MmAllocPage(MC_SYSTEM);
730 *Pte = TmplPte;
731 }
732
733 /* Map all page directories (max 128) */
734 for (Pte = MiAddressToPpe(MmPagedPoolStart);
735 Pte <= MiAddressToPpe(MmPagedPoolEnd);
736 Pte++)
737 {
738 if (!Pte->u.Flush.Valid)
739 {
740 /* Map it! */
741 TmplPte.u.Flush.PageFrameNumber = MiEarlyAllocPage();
742 *Pte = TmplPte;
743 }
744 }
745
746 /* Create and map the first PTE for paged pool */
747 Pte = MxGetPte(MmPagedPoolStart);
748 TmplPte.u.Flush.PageFrameNumber = MiEarlyAllocPage();
749 *Pte = TmplPte;
750
751 /* Save the first and last paged pool PTE */
752 MmPagedPoolInfo.FirstPteForPagedPool = MiAddressToPte(MmPagedPoolStart);
753 MmPagedPoolInfo.LastPteForPagedPool = MiAddressToPte(MmPagedPoolEnd);
754
755 MmPagedPoolInfo.NextPdeForPagedPoolExpansion =
756 MiAddressToPde(MmPagedPoolStart) + 1;
757
758 // We keep track of each page via a bit, so check how big the bitmap will
759 // have to be (make sure to align our page count such that it fits nicely
760 // into a 4-byte aligned bitmap.
761
762 /* The size of the bitmap in bits is the size in pages */
763 BitMapSize = MmSizeOfPagedPoolInPages;
764
765 /* Calculate buffer size in bytes, aligned to 32 bits */
766 Size = sizeof(RTL_BITMAP) + ROUND_UP(BitMapSize, 32) / 8;
767
768 // Allocate the allocation bitmap, which tells us which regions have not yet
769 // been mapped into memory
770
771 MmPagedPoolInfo.PagedPoolAllocationMap =
772 ExAllocatePoolWithTag(NonPagedPool, Size, ' mM');
773 ASSERT(MmPagedPoolInfo.PagedPoolAllocationMap);
774
775 // Initialize it such that at first, only the first page's worth of PTEs is
776 // marked as allocated (incidentially, the first PDE we allocated earlier).
777 RtlInitializeBitMap(MmPagedPoolInfo.PagedPoolAllocationMap,
778 (PULONG)(MmPagedPoolInfo.PagedPoolAllocationMap + 1),
779 BitMapSize);
780 RtlSetAllBits(MmPagedPoolInfo.PagedPoolAllocationMap);
781 RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, 0, 512);
782
783 // We have a second bitmap, which keeps track of where allocations end.
784 // Given the allocation bitmap and a base address, we can therefore figure
785 // out which page is the last page of that allocation, and thus how big the
786 // entire allocation is.
787 MmPagedPoolInfo.EndOfPagedPoolBitmap =
788 ExAllocatePoolWithTag(NonPagedPool, Size, ' mM');
789 ASSERT(MmPagedPoolInfo.EndOfPagedPoolBitmap);
790
791 /* Initialize the bitmap */
792 RtlInitializeBitMap(MmPagedPoolInfo.EndOfPagedPoolBitmap,
793 (PULONG)(MmPagedPoolInfo.EndOfPagedPoolBitmap + 1),
794 BitMapSize);
795
796 /* No allocations, no allocation ends; clear all bits. */
797 RtlClearAllBits(MmPagedPoolInfo.EndOfPagedPoolBitmap);
798
799 /* Initialize the paged pool mutex */
800 KeInitializeGuardedMutex(&MmPagedPoolMutex);
801
802 /* Initialize the paged pool */
803 InitializePool(PagedPool, 0);
804 }
805
806
807 NTSTATUS
808 NTAPI
809 MmArmInitSystem_x(IN ULONG Phase,
810 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
811 {
812 if (Phase == 0)
813 {
814 MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned * PAGE_SIZE;
815 MmBootImageSize = ROUND_UP(MmBootImageSize, PAGE_SIZE);
816
817 /* Parse memory descriptors, find free pages */
818 MiEvaluateMemoryDescriptors(LoaderBlock);
819
820 /* Start PFN database at hardcoded address */
821 MmPfnDatabase = MI_PFN_DATABASE;
822
823 /* Prepare PFN database mappings */
824 MiPreparePfnDatabse(LoaderBlock);
825
826 /* Initialize the session space */
827 MiInitializeSessionSpace(LoaderBlock);
828
829 /* Initialize some mappings */
830 MiInitializePageTable();
831
832 /* Update the memory descriptor, to make sure the pages we used
833 won't get inserted into the PFN database */
834 MxOldFreeDescriptor = *MxFreeDescriptor;
835 MxFreeDescriptor->BasePage = MxFreePageBase;
836 MxFreeDescriptor->PageCount = MxFreePageCount;
837 }
838 else if (Phase == 1)
839 {
840 /* The PFN database was created, restore the free descriptor */
841 *MxFreeDescriptor = MxOldFreeDescriptor;
842
843 /* The pfn database is ready now */
844 MiPfnsInitialized = TRUE;
845
846 /* Initialize the nonpaged pool */
847 MiBuildNonPagedPool();
848
849 /* Initialize system PTE handling */
850 MiBuildSystemPteSpace();
851
852 /* Build the physical memory block */
853 MiBuildPhysicalMemoryBlock(LoaderBlock);
854
855 /* Size up paged pool and build the shadow system page directory */
856 //MiBuildPagedPool();
857
858 // This is the old stuff:
859 MmPagedPoolBase = (PVOID)((PCHAR)MmPagedPoolEnd + 1);
860 MmPagedPoolSize = MM_PAGED_POOL_SIZE;
861 ASSERT((PCHAR)MmPagedPoolBase + MmPagedPoolSize < (PCHAR)MmNonPagedSystemStart);
862
863
864 HalInitializeBios(0, LoaderBlock);
865 }
866
867 return STATUS_SUCCESS;
868 }
869
870 VOID
871 FASTCALL
872 MiSyncARM3WithROS(IN PVOID AddressStart,
873 IN PVOID AddressEnd)
874 {
875
876 }
877
878 NTSTATUS
879 NTAPI
880 MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
881 {
882 UNIMPLEMENTED;
883 return STATUS_NOT_IMPLEMENTED;
884 }