[CMAKE]
[reactos.git] / 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 PxePhysicalAddress;
377 MMPTE TmplPte, *Pte;
378 PFN_NUMBER PxePfn;
379
380 /* HACK: don't use freeldr debug print anymore */
381 //FrLdrDbgPrint = NoDbgPrint;
382
383 /* Get current directory base */
384 PxePfn = ((PMMPTE)PXE_SELFMAP)->u.Hard.PageFrameNumber;
385 PxePhysicalAddress = PxePfn << PAGE_SHIFT;
386 ASSERT(PxePhysicalAddress == __readcr3());
387
388 /* Set directory base for the system process */
389 PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PxePhysicalAddress;
390
391 /* Enable global pages */
392 __writecr4(__readcr4() | CR4_PGE);
393 ASSERT(__readcr4() & CR4_PGE);
394
395 /* Enable no execute */
396 __writemsr(X86_MSR_EFER, __readmsr(X86_MSR_EFER) | EFER_NXE);
397
398 /* Loop the user mode PXEs */
399 for (Pte = MiAddressToPxe(0);
400 Pte <= MiAddressToPxe(MmHighestUserAddress);
401 Pte++)
402 {
403 /* Zero the PXE, clear all mappings */
404 Pte->u.Long = 0;
405 }
406
407 /* Flush the TLB */
408 KeFlushCurrentTb();
409
410 /* Set up a template PTE */
411 TmplPte.u.Long = 0;
412 TmplPte.u.Flush.Valid = 1;
413 TmplPte.u.Flush.Write = 1;
414 HyperTemplatePte = TmplPte;
415
416 /* Create PDPTs (72 KB) for shared system address space,
417 * skip page tables and hyperspace */
418
419 /* Loop the PXEs */
420 for (Pte = MiAddressToPxe((PVOID)(HYPER_SPACE_END + 1));
421 Pte <= MiAddressToPxe(MI_HIGHEST_SYSTEM_ADDRESS);
422 Pte++)
423 {
424 /* Is the PXE already valid? */
425 if (!Pte->u.Hard.Valid)
426 {
427 /* It's not Initialize it */
428 TmplPte.u.Flush.PageFrameNumber = MiEarlyAllocPage(0);
429 *Pte = TmplPte;
430
431 /* Zero the page. The PXE is the PTE for the PDPT. */
432 RtlZeroMemory(MiPteToAddress(Pte), PAGE_SIZE);
433 }
434 }
435
436 /* Setup the mapping PTEs */
437 MmFirstReservedMappingPte = MxGetPte((PVOID)MI_MAPPING_RANGE_START);
438 MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
439 MmLastReservedMappingPte = MiAddressToPte((PVOID)MI_MAPPING_RANGE_END);
440
441 #ifdef _WINKD_
442 /* Setup debug mapping PTE */
443 MmDebugPte = MxGetPte(MI_DEBUG_MAPPING);
444 #endif
445 }
446
447 VOID
448 NTAPI
449 MiBuildNonPagedPool(VOID)
450 {
451 PMMPTE Pte;
452 PFN_COUNT PageCount;
453
454 /* Check if this is a machine with less than 256MB of RAM, and no overide */
455 if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) &&
456 !(MmSizeOfNonPagedPoolInBytes))
457 {
458 /* Force the non paged pool to be 2MB so we can reduce RAM usage */
459 MmSizeOfNonPagedPoolInBytes = 2 * 1024 * 1024;
460 }
461
462 /* Check if the user gave a ridicuously large nonpaged pool RAM size */
463 if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) >
464 (MmNumberOfPhysicalPages * 7 / 8))
465 {
466 /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */
467 MmSizeOfNonPagedPoolInBytes = 0;
468 }
469
470 /* Check if no registry setting was set, or if the setting was too low */
471 if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize)
472 {
473 /* Start with the minimum (256 KB) and add 32 KB for each MB above 4 */
474 MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize;
475 MmSizeOfNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
476 256 * MmMinAdditionNonPagedPoolPerMb;
477 }
478
479 /* Check if the registy setting or our dynamic calculation was too high */
480 if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE)
481 {
482 /* Set it to the maximum */
483 MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE;
484 }
485
486 /* Check if a percentage cap was set through the registry */
487 if (MmMaximumNonPagedPoolPercent)
488 {
489 /* Don't feel like supporting this right now */
490 UNIMPLEMENTED;
491 }
492
493 /* Page-align the nonpaged pool size */
494 MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1);
495
496 /* Now, check if there was a registry size for the maximum size */
497 if (!MmMaximumNonPagedPoolInBytes)
498 {
499 /* Start with the default (1MB) and add 400 KB for each MB above 4 */
500 MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool;
501 MmMaximumNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
502 256 * MmMaxAdditionNonPagedPoolPerMb;
503 }
504
505 /* Don't let the maximum go too high */
506 if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE)
507 {
508 /* Set it to the upper limit */
509 MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE;
510 }
511
512 /* Put non paged pool to the end of the region */
513 MmNonPagedPoolStart = (PCHAR)MmNonPagedPoolEnd - MmMaximumNonPagedPoolInBytes;
514
515 /* Make sure it doesn't collide with the PFN database */
516 if ((PCHAR)MmNonPagedPoolStart < (PCHAR)MmPfnDatabase + MxPfnSizeInBytes)
517 {
518 /* Put non paged pool after the PFN database */
519 MmNonPagedPoolStart = (PCHAR)MmPfnDatabase + MxPfnSizeInBytes;
520 MmMaximumNonPagedPoolInBytes = (ULONG64)MmNonPagedPoolEnd -
521 (ULONG64)MmNonPagedPoolStart;
522 }
523
524 ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolStart));
525
526 /* Calculate the nonpaged pool expansion start region */
527 MmNonPagedPoolExpansionStart = (PCHAR)MmNonPagedPoolStart +
528 MmSizeOfNonPagedPoolInBytes;
529 ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolExpansionStart));
530
531 /* Map the nonpaged pool */
532 PageCount = (MmSizeOfNonPagedPoolInBytes + PAGE_SIZE - 1) / PAGE_SIZE;
533 MxMapPageRange(MmNonPagedPoolStart, PageCount);
534
535 /* Loop the non paged pool extension PTEs */
536 for (Pte = MiAddressToPte(MmNonPagedPoolExpansionStart);
537 Pte <= MiAddressToPte(MmNonPagedPoolEnd);
538 Pte++)
539 {
540 /* Create PXE, PPE, PDE and zero the PTE */
541 MxGetPte(MiPteToAddress(Pte))->u.Long = 0;
542 }
543
544 /* Initialize the ARM3 nonpaged pool */
545 MiInitializeNonPagedPool();
546
547 /* Initialize the nonpaged pool */
548 InitializePool(NonPagedPool, 0);
549 }
550
551 VOID
552 NTAPI
553 MiBuildSystemPteSpace()
554 {
555 PMMPTE Pte, StartPte, EndPte;
556
557 /* Use the default numer of system PTEs */
558 MmNumberOfSystemPtes = MI_NUMBER_SYSTEM_PTES;
559
560 /* System PTE pool is below the PFN database */
561 MiNonPagedSystemSize = (MmNumberOfSystemPtes + 1) * PAGE_SIZE;
562 MmNonPagedSystemStart = (PCHAR)MmPfnDatabase - MiNonPagedSystemSize;
563 MmNonPagedSystemStart = MM_ROUND_DOWN(MmNonPagedSystemStart, 512 * PAGE_SIZE);
564
565 /* Don't let it go below the minimum */
566 if (MmNonPagedSystemStart < (PVOID)MI_NON_PAGED_SYSTEM_START_MIN)
567 {
568 /* This is a hard-coded limit in the Windows NT address space */
569 MmNonPagedSystemStart = (PVOID)MI_NON_PAGED_SYSTEM_START_MIN;
570
571 /* Reduce the amount of system PTEs to reach this point */
572 MmNumberOfSystemPtes = ((ULONG64)MmPfnDatabase -
573 (ULONG64)MmNonPagedSystemStart) >>
574 PAGE_SHIFT;
575 MmNumberOfSystemPtes--;
576 ASSERT(MmNumberOfSystemPtes > 1000);
577 }
578
579 /* Set the range of system PTEs */
580 StartPte = MiAddressToPte(MI_SYSTEM_PTE_START);
581 EndPte = StartPte + MmNumberOfSystemPtes - 1;
582
583 /* Loop the system PTEs */
584 for (Pte = StartPte; Pte <= EndPte; Pte++)
585 {
586 /* Create PXE, PPE, PDE and zero the PTE */
587 MxGetPte(MiPteToAddress(Pte))->u.Long = 0;
588 }
589
590 /* Create the system PTE space */
591 Pte = MiAddressToPte(MI_SYSTEM_PTE_START);
592 MiInitializeSystemPtes(Pte, MmNumberOfSystemPtes, SystemPteSpace);
593
594 /* Reserve system PTEs for zeroing PTEs and clear them */
595 MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES, SystemPteSpace);
596 RtlZeroMemory(MiFirstReservedZeroingPte, MI_ZERO_PTES * sizeof(MMPTE));
597
598 /* Set the counter to maximum */
599 MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
600 }
601
602 VOID
603 NTAPI
604 MiBuildPhysicalMemoryBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
605 {
606 PPHYSICAL_MEMORY_DESCRIPTOR Buffer;
607 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
608 PLIST_ENTRY ListEntry;
609 PFN_NUMBER NextPage = -1;
610 PULONG Bitmap;
611 ULONG Runs = 0;
612 ULONG Size;
613
614 /* Calculate size for the PFN bitmap */
615 Size = ROUND_UP(MmHighestPhysicalPage + 1, sizeof(ULONG));
616
617 /* Allocate the PFN bitmap */
618 Bitmap = ExAllocatePoolWithTag(NonPagedPool, Size, ' mM');
619
620 /* Allocate enough memory for the physical memory block */
621 Buffer = ExAllocatePoolWithTag(NonPagedPool,
622 sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
623 sizeof(PHYSICAL_MEMORY_RUN) *
624 (MiNumberDescriptors - 1),
625 'lMmM');
626 if (!Bitmap || !Buffer)
627 {
628 /* This is critical */
629 KeBugCheckEx(INSTALL_MORE_MEMORY,
630 MmNumberOfPhysicalPages,
631 MmLowestPhysicalPage,
632 MmHighestPhysicalPage,
633 0x101);
634 }
635
636 /* Initialize the bitmap and clear all bits */
637 RtlInitializeBitMap(&MiPfnBitMap, Bitmap, MmHighestPhysicalPage + 1);
638 RtlClearAllBits(&MiPfnBitMap);
639
640 /* Loop the memory descriptors */
641 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
642 ListEntry != &LoaderBlock->MemoryDescriptorListHead;
643 ListEntry = ListEntry->Flink)
644 {
645 /* Get the memory descriptor */
646 Descriptor = CONTAINING_RECORD(ListEntry,
647 MEMORY_ALLOCATION_DESCRIPTOR,
648 ListEntry);
649
650 /* Skip pages that are not part of the PFN database */
651 if (!MiIncludeType[Descriptor->MemoryType])
652 {
653 continue;
654 }
655
656 /* Does the memory block begin where the last ended? */
657 if (Descriptor->BasePage == NextPage)
658 {
659 /* Add it to the current run */
660 Buffer->Run[Runs - 1].PageCount += Descriptor->PageCount;
661 }
662 else
663 {
664 /* Create a new run */
665 Runs++;
666 Buffer->Run[Runs - 1].BasePage = Descriptor->BasePage;
667 Buffer->Run[Runs - 1].PageCount = Descriptor->PageCount;
668 }
669
670 /* Set the bits in the PFN bitmap */
671 RtlSetBits(&MiPfnBitMap, Descriptor->BasePage, Descriptor->PageCount);
672
673 /* Set the next page */
674 NextPage = Descriptor->BasePage + Descriptor->PageCount;
675 }
676
677 // FIXME: allocate a buffer of better size
678
679 Buffer->NumberOfRuns = Runs;
680 Buffer->NumberOfPages = MmNumberOfPhysicalPages;
681 MmPhysicalMemoryBlock = Buffer;
682 }
683
684 VOID
685 NTAPI
686 MiBuildPagedPool_x(VOID)
687 {
688 PMMPTE Pte;
689 MMPTE TmplPte;
690 ULONG Size, BitMapSize;
691
692 /* Default size for paged pool is 4 times non paged pool */
693 MmSizeOfPagedPoolInBytes = 4 * MmMaximumNonPagedPoolInBytes;
694
695 /* Make sure it doesn't overflow */
696 if (MmSizeOfPagedPoolInBytes > ((ULONG64)MmNonPagedSystemStart -
697 (ULONG64)MmPagedPoolStart))
698 {
699 MmSizeOfPagedPoolInBytes = (ULONG64)MmNonPagedSystemStart -
700 (ULONG64)MmPagedPoolStart;
701 }
702
703 /* Make sure paged pool is big enough */
704 if (MmSizeOfPagedPoolInBytes < MI_MIN_INIT_PAGED_POOLSIZE)
705 {
706 MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE;
707 }
708
709 /* Align down to a PDE boundary */
710 MmSizeOfPagedPoolInBytes = ROUND_DOWN(MmSizeOfPagedPoolInBytes,
711 512 * PAGE_SIZE);
712 MmSizeOfPagedPoolInPages = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT;
713
714 /* This is where paged pool ends */
715 MmPagedPoolEnd = (PCHAR)MmPagedPoolStart + MmSizeOfPagedPoolInBytes - 1;
716
717 /* Sanity check */
718 ASSERT(MmPagedPoolEnd < MmNonPagedSystemStart);
719
720 /* setup a template PTE */
721 TmplPte.u.Long = 0;
722 TmplPte.u.Flush.Valid = 1;
723 TmplPte.u.Flush.Write = 1;
724
725 /* Make sure the PXE is valid */
726 Pte = MiAddressToPxe(MmPagedPoolStart);
727 if (!Pte->u.Flush.Valid)
728 {
729 /* Map it! */
730 TmplPte.u.Flush.PageFrameNumber = MmAllocPage(MC_SYSTEM);
731 *Pte = TmplPte;
732 }
733
734 /* Map all page directories (max 128) */
735 for (Pte = MiAddressToPpe(MmPagedPoolStart);
736 Pte <= MiAddressToPpe(MmPagedPoolEnd);
737 Pte++)
738 {
739 if (!Pte->u.Flush.Valid)
740 {
741 /* Map it! */
742 TmplPte.u.Flush.PageFrameNumber = MiEarlyAllocPage();
743 *Pte = TmplPte;
744 }
745 }
746
747 /* Create and map the first PTE for paged pool */
748 Pte = MxGetPte(MmPagedPoolStart);
749 TmplPte.u.Flush.PageFrameNumber = MiEarlyAllocPage();
750 *Pte = TmplPte;
751
752 /* Save the first and last paged pool PTE */
753 MmPagedPoolInfo.FirstPteForPagedPool = MiAddressToPte(MmPagedPoolStart);
754 MmPagedPoolInfo.LastPteForPagedPool = MiAddressToPte(MmPagedPoolEnd);
755
756 MmPagedPoolInfo.NextPdeForPagedPoolExpansion =
757 MiAddressToPde(MmPagedPoolStart) + 1;
758
759 // We keep track of each page via a bit, so check how big the bitmap will
760 // have to be (make sure to align our page count such that it fits nicely
761 // into a 4-byte aligned bitmap.
762
763 /* The size of the bitmap in bits is the size in pages */
764 BitMapSize = MmSizeOfPagedPoolInPages;
765
766 /* Calculate buffer size in bytes, aligned to 32 bits */
767 Size = sizeof(RTL_BITMAP) + ROUND_UP(BitMapSize, 32) / 8;
768
769 // Allocate the allocation bitmap, which tells us which regions have not yet
770 // been mapped into memory
771
772 MmPagedPoolInfo.PagedPoolAllocationMap =
773 ExAllocatePoolWithTag(NonPagedPool, Size, ' mM');
774 ASSERT(MmPagedPoolInfo.PagedPoolAllocationMap);
775
776 // Initialize it such that at first, only the first page's worth of PTEs is
777 // marked as allocated (incidentially, the first PDE we allocated earlier).
778 RtlInitializeBitMap(MmPagedPoolInfo.PagedPoolAllocationMap,
779 (PULONG)(MmPagedPoolInfo.PagedPoolAllocationMap + 1),
780 BitMapSize);
781 RtlSetAllBits(MmPagedPoolInfo.PagedPoolAllocationMap);
782 RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, 0, 512);
783
784 // We have a second bitmap, which keeps track of where allocations end.
785 // Given the allocation bitmap and a base address, we can therefore figure
786 // out which page is the last page of that allocation, and thus how big the
787 // entire allocation is.
788 MmPagedPoolInfo.EndOfPagedPoolBitmap =
789 ExAllocatePoolWithTag(NonPagedPool, Size, ' mM');
790 ASSERT(MmPagedPoolInfo.EndOfPagedPoolBitmap);
791
792 /* Initialize the bitmap */
793 RtlInitializeBitMap(MmPagedPoolInfo.EndOfPagedPoolBitmap,
794 (PULONG)(MmPagedPoolInfo.EndOfPagedPoolBitmap + 1),
795 BitMapSize);
796
797 /* No allocations, no allocation ends; clear all bits. */
798 RtlClearAllBits(MmPagedPoolInfo.EndOfPagedPoolBitmap);
799
800 /* Initialize the paged pool mutex */
801 KeInitializeGuardedMutex(&MmPagedPoolMutex);
802
803 /* Initialize the paged pool */
804 InitializePool(PagedPool, 0);
805 }
806
807
808 NTSTATUS
809 NTAPI
810 MmArmInitSystem_x(IN ULONG Phase,
811 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
812 {
813 if (Phase == 0)
814 {
815 MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned * PAGE_SIZE;
816 MmBootImageSize = ROUND_UP(MmBootImageSize, PAGE_SIZE);
817
818 /* Parse memory descriptors, find free pages */
819 MiEvaluateMemoryDescriptors(LoaderBlock);
820
821 /* Start PFN database at hardcoded address */
822 MmPfnDatabase = MI_PFN_DATABASE;
823
824 /* Prepare PFN database mappings */
825 MiPreparePfnDatabse(LoaderBlock);
826
827 /* Initialize the session space */
828 MiInitializeSessionSpace(LoaderBlock);
829
830 /* Initialize some mappings */
831 MiInitializePageTable();
832
833 /* Update the memory descriptor, to make sure the pages we used
834 won't get inserted into the PFN database */
835 MxOldFreeDescriptor = *MxFreeDescriptor;
836 MxFreeDescriptor->BasePage = MxFreePageBase;
837 MxFreeDescriptor->PageCount = MxFreePageCount;
838 }
839 else if (Phase == 1)
840 {
841 /* The PFN database was created, restore the free descriptor */
842 *MxFreeDescriptor = MxOldFreeDescriptor;
843
844 /* The pfn database is ready now */
845 MiPfnsInitialized = TRUE;
846
847 /* Initialize the nonpaged pool */
848 MiBuildNonPagedPool();
849
850 /* Initialize system PTE handling */
851 MiBuildSystemPteSpace();
852
853 /* Build the physical memory block */
854 MiBuildPhysicalMemoryBlock(LoaderBlock);
855
856 /* Size up paged pool and build the shadow system page directory */
857 //MiBuildPagedPool();
858
859 // This is the old stuff:
860 //MmPagedPoolBase = (PVOID)((PCHAR)MmPagedPoolEnd + 1);
861 //MmPagedPoolSize = MM_PAGED_POOL_SIZE;
862 //ASSERT((PCHAR)MmPagedPoolBase + MmPagedPoolSize < (PCHAR)MmNonPagedSystemStart);
863
864
865 HalInitializeBios(0, LoaderBlock);
866 }
867
868 return STATUS_SUCCESS;
869 }
870
871 VOID
872 FASTCALL
873 MiSyncARM3WithROS(IN PVOID AddressStart,
874 IN PVOID AddressEnd)
875 {
876
877 }
878
879 NTSTATUS
880 NTAPI
881 MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
882 {
883 UNIMPLEMENTED;
884 return STATUS_NOT_IMPLEMENTED;
885 }