2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/mm/i386/mmx86.c
5 * PURPOSE: Boot Library Memory Manager x86-Specific Code
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
14 #define PTE_BASE 0xC0000000
17 // Specific PDE/PTE macros to be used inside the boot library environment
19 #define MiAddressToPte(x) ((PMMPTE)(((((ULONG)(x)) >> 12) << 2) + (ULONG_PTR)MmPteBase))
20 #define MiAddressToPde(x) ((PMMPDE)(((((ULONG)(x)) >> 22) << 2) + (ULONG_PTR)MmPdeBase))
21 #define MiAddressToPteOffset(x) ((((ULONG)(x)) << 10) >> 22)
22 #define MiAddressToPdeOffset(x) (((ULONG)(x)) / (1024 * PAGE_SIZE))
24 /* DATA VARIABLES ************************************************************/
26 ULONG_PTR MmArchKsegBase
;
27 ULONG_PTR MmArchKsegBias
;
28 ULONG MmArchLargePageSize
;
29 BL_ADDRESS_RANGE MmArchKsegAddressRange
;
30 ULONG_PTR MmArchTopOfApplicationAddressSpace
;
31 PHYSICAL_ADDRESS Mmx86SelfMapBase
;
32 ULONG MmDeferredMappingCount
;
34 PULONG MmArchReferencePage
;
37 ULONG MmArchReferencePageSize
;
45 (*PBL_MM_RELOCATE_SELF_MAP
) (
50 (*PBL_MM_MOVE_VIRTUAL_ADDRESS_RANGE
) (
51 _In_ PVOID DestinationAddress
,
52 _In_ PVOID SourceAddress
,
57 (*PBL_MM_ZERO_VIRTUAL_ADDRESS_RANGE
) (
58 _In_ PVOID DestinationAddress
,
63 (*PBL_MM_DESTROY_SELF_MAP
) (
68 (*PBL_MM_FLUSH_TLB_ENTRY
) (
69 _In_ PVOID VirtualAddress
78 (*PBL_MM_UNMAP_VIRTUAL_ADDRESS
) (
79 _In_ PVOID VirtualAddress
,
84 (*PBL_MM_REMAP_VIRTUAL_ADDRESS
) (
85 _In_ PPHYSICAL_ADDRESS PhysicalAddress
,
86 _Out_ PVOID VirtualAddress
,
88 _In_ ULONG CacheAttributes
92 (*PBL_MM_MAP_PHYSICAL_ADDRESS
) (
93 _In_ PHYSICAL_ADDRESS PhysicalAddress
,
94 _Out_ PVOID VirtualAddress
,
96 _In_ ULONG CacheAttributes
100 (*PBL_MM_TRANSLATE_VIRTUAL_ADDRESS
) (
101 _In_ PVOID VirtualAddress
,
102 _Out_ PPHYSICAL_ADDRESS PhysicalAddress
,
103 _Out_opt_ PULONG CacheAttributes
106 PBL_MM_TRANSLATE_VIRTUAL_ADDRESS Mmx86TranslateVirtualAddress
;
107 PBL_MM_MAP_PHYSICAL_ADDRESS Mmx86MapPhysicalAddress
;
108 PBL_MM_REMAP_VIRTUAL_ADDRESS Mmx86RemapVirtualAddress
;
109 PBL_MM_UNMAP_VIRTUAL_ADDRESS Mmx86UnmapVirtualAddress
;
110 PBL_MM_FLUSH_TLB Mmx86FlushTlb
;
111 PBL_MM_FLUSH_TLB_ENTRY Mmx86FlushTlbEntry
;
112 PBL_MM_DESTROY_SELF_MAP Mmx86DestroySelfMap
;
114 PBL_MM_RELOCATE_SELF_MAP BlMmRelocateSelfMap
;
115 PBL_MM_FLUSH_TLB BlMmFlushTlb
;
116 PBL_MM_MOVE_VIRTUAL_ADDRESS_RANGE BlMmMoveVirtualAddressRange
;
117 PBL_MM_ZERO_VIRTUAL_ADDRESS_RANGE BlMmZeroVirtualAddressRange
;
119 PBL_MM_FLUSH_TLB Mmx86FlushTlb
;
121 /* FUNCTIONS *****************************************************************/
124 BlMmIsTranslationEnabled (
128 /* Return if paging is on */
129 return ((CurrentExecutionContext
) &&
130 (CurrentExecutionContext
->ContextFlags
& BL_CONTEXT_PAGING_ON
));
143 MmDefRelocateSelfMap (
147 if (MmPteBase
!= (PVOID
)PTE_BASE
)
149 EfiPrintf(L
"Supposed to relocate CR3\r\n");
154 MmDefMoveVirtualAddressRange (
155 _In_ PVOID DestinationAddress
,
156 _In_ PVOID SourceAddress
,
160 EfiPrintf(L
"Supposed to move shit\r\n");
161 return STATUS_NOT_IMPLEMENTED
;
165 MmDefZeroVirtualAddressRange (
166 _In_ PVOID DestinationAddress
,
170 EfiPrintf(L
"Supposed to zero shit\r\n");
171 return STATUS_NOT_IMPLEMENTED
;
175 MmArchTranslateVirtualAddress (
176 _In_ PVOID VirtualAddress
,
177 _Out_opt_ PPHYSICAL_ADDRESS PhysicalAddress
,
178 _Out_opt_ PULONG CachingFlags
181 PBL_MEMORY_DESCRIPTOR Descriptor
;
183 /* Check if paging is on */
184 if ((CurrentExecutionContext
) &&
185 (CurrentExecutionContext
->ContextFlags
& BL_CONTEXT_PAGING_ON
))
187 /* Yes -- we have to translate this from virtual */
188 return Mmx86TranslateVirtualAddress(VirtualAddress
,
193 /* Look in all descriptors except truncated and firmware ones */
194 Descriptor
= MmMdFindDescriptor(BL_MM_INCLUDE_NO_FIRMWARE_MEMORY
&
195 ~BL_MM_INCLUDE_TRUNCATED_MEMORY
,
196 BL_MM_REMOVE_PHYSICAL_REGION_FLAG
,
197 (ULONG_PTR
)VirtualAddress
>> PAGE_SHIFT
);
199 /* Return the virtual address as the physical address */
202 PhysicalAddress
->HighPart
= 0;
203 PhysicalAddress
->LowPart
= (ULONG_PTR
)VirtualAddress
;
206 /* There's no caching on physical memory */
212 /* Success is if we found a descriptor */
213 return Descriptor
!= NULL
;
217 MmDefpDestroySelfMap (
221 EfiPrintf(L
"No destroy\r\n");
225 MmDefpFlushTlbEntry (
226 _In_ PVOID VirtualAddress
230 __invlpg(VirtualAddress
);
239 __writecr3(__readcr3());
243 MmDefpUnmapVirtualAddress (
244 _In_ PVOID VirtualAddress
,
248 EfiPrintf(L
"No unmap\r\n");
249 return STATUS_NOT_IMPLEMENTED
;
253 MmDefpRemapVirtualAddress (
254 _In_ PPHYSICAL_ADDRESS PhysicalAddress
,
255 _Out_ PVOID VirtualAddress
,
257 _In_ ULONG CacheAttributes
260 EfiPrintf(L
"No remap\r\n");
261 return STATUS_NOT_IMPLEMENTED
;
265 MmDefpMapPhysicalAddress (
266 _In_ PHYSICAL_ADDRESS PhysicalAddress
,
267 _In_ PVOID VirtualAddress
,
269 _In_ ULONG CacheAttributes
273 ULONG i
, PageCount
, PdeOffset
;
274 ULONGLONG CurrentAddress
;
278 PHYSICAL_ADDRESS PageTableAddress
;
281 /* Check if paging is on yet */
282 Enabled
= BlMmIsTranslationEnabled();
284 /* Get the physical address aligned */
285 CurrentAddress
= (PhysicalAddress
.QuadPart
>> PAGE_SHIFT
) << PAGE_SHIFT
;
287 /* Get the number of pages and loop through each one */
288 PageCount
= Size
>> PAGE_SHIFT
;
289 for (i
= 0; i
< PageCount
; i
++)
291 /* Check if translation already exists for this page */
292 if (Mmx86TranslateVirtualAddress(VirtualAddress
, NULL
, NULL
))
294 /* Ignore it and move to the next one */
295 VirtualAddress
= (PVOID
)((ULONG_PTR
)VirtualAddress
+ PAGE_SIZE
);
296 CurrentAddress
+= PAGE_SIZE
;
300 /* Get the PDE offset */
301 PdeOffset
= MiAddressToPdeOffset(VirtualAddress
);
303 /* Check if paging is actually turned on */
306 /* Get the PDE entry using the self-map */
307 Pde
= MiAddressToPde(VirtualAddress
);
311 /* Get it using our physical mappings */
312 Pde
= &MmPdpt
[PdeOffset
];
313 PageTable
= (PMMPDE
)(Pde
->u
.Hard
.PageFrameNumber
<< PAGE_SHIFT
);
316 /* Check if we don't yet have a PDE */
317 if (!Pde
->u
.Hard
.Valid
)
319 /* Allocate a page table */
320 Status
= MmPapAllocatePhysicalPagesInRange(&PageTableAddress
,
321 BlLoaderPageDirectory
,
325 &MmMdlUnmappedAllocated
,
328 if (!NT_SUCCESS(Status
))
330 EfiPrintf(L
"PDE alloc failed!\r\n");
332 return STATUS_NO_MEMORY
;
335 /* This is our page table */
336 PageTable
= (PVOID
)(ULONG_PTR
)PageTableAddress
.QuadPart
;
338 /* Build the PDE for it */
339 Pde
->u
.Hard
.PageFrameNumber
= PageTableAddress
.QuadPart
>> PAGE_SHIFT
;
340 Pde
->u
.Hard
.Write
= 1;
341 Pde
->u
.Hard
.CacheDisable
= 1;
342 Pde
->u
.Hard
.WriteThrough
= 1;
343 Pde
->u
.Hard
.Valid
= 1;
345 /* Check if paging is enabled */
348 /* Then actually, get the page table's virtual address */
349 PageTable
= (PVOID
)PAGE_ROUND_DOWN(MiAddressToPte(VirtualAddress
));
355 /* Zero out the page table */
356 RtlZeroMemory(PageTable
, PAGE_SIZE
);
358 /* Reset caching attributes now */
359 Pde
->u
.Hard
.CacheDisable
= 0;
360 Pde
->u
.Hard
.WriteThrough
= 0;
362 /* Check for paging again */
365 /* Flush the TLB entry for the page table only */
366 Mmx86FlushTlbEntry(PageTable
);
370 /* Add a reference to this page table */
371 MmArchReferencePage
[PdeOffset
]++;
373 /* Check if a physical address was given */
374 if (PhysicalAddress
.QuadPart
!= -1)
376 /* Check if paging is turned on */
379 /* Get the PTE using the self-map */
380 Pte
= MiAddressToPte(VirtualAddress
);
384 /* Get the PTE using physical addressing */
385 Pte
= &PageTable
[MiAddressToPteOffset(VirtualAddress
)];
388 /* Build a valid PTE for it */
389 Pte
->u
.Hard
.PageFrameNumber
= CurrentAddress
>> PAGE_SHIFT
;
390 Pte
->u
.Hard
.Write
= 1;
391 Pte
->u
.Hard
.Valid
= 1;
393 /* Check if this is uncached */
394 if (CacheAttributes
== BlMemoryUncached
)
397 Pte
->u
.Hard
.CacheDisable
= 1;
398 Pte
->u
.Hard
.WriteThrough
= 1;
400 else if (CacheAttributes
== BlMemoryWriteThrough
)
402 /* It's write-through, set the flag */
403 Pte
->u
.Hard
.WriteThrough
= 1;
407 /* Move to the next physical/virtual address */
408 VirtualAddress
= (PVOID
)((ULONG_PTR
)VirtualAddress
+ PAGE_SIZE
);
409 CurrentAddress
+= PAGE_SIZE
;
413 return STATUS_SUCCESS
;
417 MmDefpTranslateVirtualAddress (
418 _In_ PVOID VirtualAddress
,
419 _Out_ PPHYSICAL_ADDRESS PhysicalAddress
,
420 _Out_opt_ PULONG CacheAttributes
428 /* Is there no page directory yet? */
434 /* Is paging enabled? */
435 Enabled
= BlMmIsTranslationEnabled();
437 /* Check if paging is actually turned on */
440 /* Get the PDE entry using the self-map */
441 Pde
= MiAddressToPde(VirtualAddress
);
445 /* Get it using our physical mappings */
446 Pde
= &MmPdpt
[MiAddressToPdeOffset(VirtualAddress
)];
449 /* Is the PDE valid? */
450 if (!Pde
->u
.Hard
.Valid
)
455 /* Check if paging is turned on */
458 /* Get the PTE using the self-map */
459 Pte
= MiAddressToPte(VirtualAddress
);
463 /* Get the PTE using physical addressing */
464 PageTable
= (PMMPTE
)(Pde
->u
.Hard
.PageFrameNumber
<< PAGE_SHIFT
);
465 Pte
= &PageTable
[MiAddressToPteOffset(VirtualAddress
)];
468 /* Is the PTE valid? */
469 if (!Pte
->u
.Hard
.Valid
)
474 /* Does caller want the physical address? */
478 PhysicalAddress
->QuadPart
= (Pte
->u
.Hard
.PageFrameNumber
<< PAGE_SHIFT
) +
479 BYTE_OFFSET(VirtualAddress
);
482 /* Does caller want cache attributes? */
485 /* Not yet -- lie and say it's cached */
486 EfiPrintf(L
"Cache checking not yet enabled\r\n");
487 *CacheAttributes
= BlMemoryWriteBack
;
495 MmMapPhysicalAddress (
496 _Inout_ PPHYSICAL_ADDRESS PhysicalAddressPtr
,
497 _Inout_ PVOID
* VirtualAddressPtr
,
498 _Inout_ PULONGLONG SizePtr
,
499 _In_ ULONG CacheAttributes
503 ULONGLONG PhysicalAddress
;
504 PVOID VirtualAddress
;
505 PHYSICAL_ADDRESS TranslatedAddress
;
506 ULONG_PTR CurrentAddress
, VirtualAddressEnd
;
509 /* Fail if any parameters are missing */
510 if (!(PhysicalAddressPtr
) || !(VirtualAddressPtr
) || !(SizePtr
))
512 return STATUS_INVALID_PARAMETER
;
515 /* Fail if the size is over 32-bits */
517 if (Size
> 0xFFFFFFFF)
519 return STATUS_INVALID_PARAMETER
;
522 /* Nothing to do if we're in physical mode */
523 if (MmTranslationType
== BlNone
)
525 return STATUS_SUCCESS
;
528 /* Can't use virtual memory in real mode */
529 if (CurrentExecutionContext
->Mode
== BlRealMode
)
531 return STATUS_UNSUCCESSFUL
;
534 /* Capture the current virtual and physical addresses */
535 VirtualAddress
= *VirtualAddressPtr
;
536 PhysicalAddress
= PhysicalAddressPtr
->QuadPart
;
538 /* Check if a physical address was requested */
539 if (PhysicalAddress
!= 0xFFFFFFFF)
541 /* Round down the base addresses */
542 PhysicalAddress
= PAGE_ROUND_DOWN(PhysicalAddress
);
543 VirtualAddress
= (PVOID
)PAGE_ROUND_DOWN(VirtualAddress
);
545 /* Round up the size */
546 Size
= ROUND_TO_PAGES(PhysicalAddressPtr
->QuadPart
-
550 /* Loop every virtual page */
551 CurrentAddress
= (ULONG_PTR
)VirtualAddress
;
552 VirtualAddressEnd
= CurrentAddress
+ Size
- 1;
553 while (CurrentAddress
< VirtualAddressEnd
)
555 /* Get the physical page of this virtual page */
556 if (MmArchTranslateVirtualAddress((PVOID
)CurrentAddress
,
560 /* Make sure the physical page of the virtual page, matches our page */
561 if (TranslatedAddress
.QuadPart
!=
563 (CurrentAddress
- (ULONG_PTR
)VirtualAddress
)))
565 /* There is an existing virtual mapping for a different address */
566 EfiPrintf(L
"Existing mapping exists: %lx vs %lx\r\n",
567 TranslatedAddress
.QuadPart
,
568 PhysicalAddress
+ (CurrentAddress
- (ULONG_PTR
)VirtualAddress
));
570 return STATUS_INVALID_PARAMETER
;
574 /* Try the next one */
575 CurrentAddress
+= PAGE_SIZE
;
579 /* Aactually do the mapping */
580 TranslatedAddress
.QuadPart
= PhysicalAddress
;
581 Status
= Mmx86MapPhysicalAddress(TranslatedAddress
,
585 if (!NT_SUCCESS(Status
))
587 EfiPrintf(L
"Failed to map!: %lx\r\n", Status
);
592 /* Return aligned/fixed up output parameters */
593 PhysicalAddressPtr
->QuadPart
= PhysicalAddress
;
594 *VirtualAddressPtr
= VirtualAddress
;
597 /* Flush the TLB if paging is enabled */
598 if (BlMmIsTranslationEnabled())
604 return STATUS_SUCCESS
;
608 Mmx86MapInitStructure (
609 _In_ PVOID VirtualAddress
,
611 _In_ PHYSICAL_ADDRESS PhysicalAddress
616 /* Make a virtual mapping for this physical address */
617 Status
= MmMapPhysicalAddress(&PhysicalAddress
, &VirtualAddress
, &Size
, 0);
618 if (!NT_SUCCESS(Status
))
623 /* Nothing else to do if we're not in paging mode */
624 if (MmTranslationType
== BlNone
)
626 return STATUS_SUCCESS
;
629 /* Otherwise, remove this region from the list of free virtual ranges */
630 Status
= MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual
,
631 BL_MM_REMOVE_VIRTUAL_REGION_FLAG
,
632 (ULONG_PTR
)VirtualAddress
>> PAGE_SHIFT
,
635 if (!NT_SUCCESS(Status
))
637 /* Unmap the address if that failed */
638 MmUnmapVirtualAddress(&VirtualAddress
, &Size
);
641 /* Return back to caller */
647 _In_ PBL_MEMORY_DESCRIPTOR_LIST DescriptorList
,
648 _In_opt_ ULONG MaxCount
651 ULONGLONG EndPage
, VirtualEndPage
;
652 PBL_MEMORY_DESCRIPTOR MemoryDescriptor
;
653 PLIST_ENTRY NextEntry
;
655 /* If no maximum was provided, use essentially infinite */
658 MaxCount
= 0xFFFFFFFF;
661 /* Loop the list as long as there's entries and max isn't reached */
662 NextEntry
= DescriptorList
->First
->Flink
;
663 while ((NextEntry
!= DescriptorList
->First
) && (MaxCount
--))
665 /* Get the descriptor */
666 MemoryDescriptor
= CONTAINING_RECORD(NextEntry
,
667 BL_MEMORY_DESCRIPTOR
,
670 /* Get the descriptor end page, and see if it was virtually mapepd */
671 EndPage
= MemoryDescriptor
->BasePage
+ MemoryDescriptor
->PageCount
;
672 if (MemoryDescriptor
->VirtualPage
)
674 /* Get the virtual end page too, then */
675 VirtualEndPage
= MemoryDescriptor
->VirtualPage
+
676 MemoryDescriptor
->PageCount
;
683 /* Print out the descriptor, physical range, virtual range, and type */
684 EfiPrintf(L
"%p - [%08llx-%08llx @ %08llx-%08llx]:%x\r\n",
686 MemoryDescriptor
->BasePage
<< PAGE_SHIFT
,
687 (EndPage
<< PAGE_SHIFT
) - 1,
688 MemoryDescriptor
->VirtualPage
<< PAGE_SHIFT
,
689 VirtualEndPage
? (VirtualEndPage
<< PAGE_SHIFT
) - 1 : 0,
690 (ULONG
)MemoryDescriptor
->Type
);
693 NextEntry
= NextEntry
->Flink
;
698 Mmx86pMapMemoryRegions (
700 _In_ PBL_MEMORY_DATA MemoryData
704 ULONG DescriptorCount
;
705 PBL_MEMORY_DESCRIPTOR Descriptor
;
707 PHYSICAL_ADDRESS PhysicalAddress
;
710 PVOID VirtualAddress
;
711 BL_MEMORY_DESCRIPTOR_LIST FirmwareMdl
;
712 PLIST_ENTRY Head
, NextEntry
;
714 /* Check which phase this is */
717 /* In phase 1 we don't initialize deferred mappings */
722 /* Don't do anything if there's nothing to initialize */
723 if (!MmDeferredMappingCount
)
725 return STATUS_SUCCESS
;
728 /* We'll do deferred descriptors in phase 2 */
733 * Because BL supports cross x86-x64 application launches and a LIST_ENTRY
734 * is of variable size, care must be taken here to ensure that we see a
735 * consistent view of descriptors. BL uses some offset magic to figure out
736 * where the data actually starts, since everything is ULONGLONG past the
739 FinalOffset
= MemoryData
->MdListOffset
+ MemoryData
->DescriptorOffset
;
740 Descriptor
= (PBL_MEMORY_DESCRIPTOR
)((ULONG_PTR
)MemoryData
+ FinalOffset
-
741 FIELD_OFFSET(BL_MEMORY_DESCRIPTOR
, BasePage
));
743 /* Scan all of them */
744 DescriptorCount
= MemoryData
->DescriptorCount
;
745 while (DescriptorCount
!= 0)
747 /* Ignore application data */
748 if (Descriptor
->Type
!= BlApplicationData
)
750 /* If this is a ramdisk, do it in phase 2 */
751 if ((Descriptor
->Type
== BlLoaderRamDisk
) == DoDeferred
)
753 /* Get the current physical address and size */
754 PhysicalAddress
.QuadPart
= Descriptor
->BasePage
<< PAGE_SHIFT
;
755 Size
= Descriptor
->PageCount
<< PAGE_SHIFT
;
757 /* Check if it was already mapped */
758 if (Descriptor
->VirtualPage
)
760 /* Use the existing address */
761 VirtualAddress
= (PVOID
)(ULONG_PTR
)(Descriptor
->VirtualPage
<< PAGE_SHIFT
);
765 /* Use the physical address */
766 VirtualAddress
= (PVOID
)(ULONG_PTR
)PhysicalAddress
.QuadPart
;
769 /* Crete the mapping */
770 Status
= Mmx86MapInitStructure(VirtualAddress
,
773 if (!NT_SUCCESS(Status
))
779 /* Check if we're in phase 1 and deferring RAM disk */
780 if ((Phase
== 1) && (Descriptor
->Type
== BlLoaderRamDisk
))
782 MmDeferredMappingCount
++;
786 /* Move on to the next descriptor */
788 Descriptor
= (PBL_MEMORY_DESCRIPTOR
)((ULONG_PTR
)Descriptor
+ MemoryData
->DescriptorSize
);
791 /* In phase 1, also do UEFI mappings */
794 /* Get the memory map */
795 MmMdInitializeListHead(&FirmwareMdl
);
796 Status
= MmFwGetMemoryMap(&FirmwareMdl
, BL_MM_FLAG_REQUEST_COALESCING
);
797 if (!NT_SUCCESS(Status
))
802 /* Iterate over it */
803 Head
= FirmwareMdl
.First
;
804 NextEntry
= Head
->Flink
;
805 while (NextEntry
!= Head
)
807 /* Check if this is a UEFI-related descriptor, unless it's the self-map page */
808 Descriptor
= CONTAINING_RECORD(NextEntry
, BL_MEMORY_DESCRIPTOR
, ListEntry
);
809 if (((Descriptor
->Type
== BlEfiBootMemory
) ||
810 (Descriptor
->Type
== BlEfiRuntimeCodeMemory
) ||
811 (Descriptor
->Type
== BlEfiRuntimeDataMemory
) || // WINBUG?
812 (Descriptor
->Type
== BlLoaderMemory
)) &&
813 ((Descriptor
->BasePage
<< PAGE_SHIFT
) != Mmx86SelfMapBase
.QuadPart
))
815 /* Identity-map it */
816 PhysicalAddress
.QuadPart
= Descriptor
->BasePage
<< PAGE_SHIFT
;
817 Status
= Mmx86MapInitStructure((PVOID
)((ULONG_PTR
)Descriptor
->BasePage
<< PAGE_SHIFT
),
818 Descriptor
->PageCount
<< PAGE_SHIFT
,
820 if (!NT_SUCCESS(Status
))
826 /* Move to the next descriptor */
827 NextEntry
= NextEntry
->Flink
;
831 NextEntry
= Head
->Flink
;
832 while (NextEntry
!= Head
)
834 /* Get the descriptor */
835 Descriptor
= CONTAINING_RECORD(NextEntry
, BL_MEMORY_DESCRIPTOR
, ListEntry
);
837 /* Skip to the next entry before we free */
838 NextEntry
= NextEntry
->Flink
;
840 /* Remove and free it */
841 MmMdRemoveDescriptorFromList(&FirmwareMdl
, Descriptor
);
842 MmMdFreeDescriptor(Descriptor
);
846 /* All library mappings identity mapped now */
847 return STATUS_SUCCESS
;
851 Mmx86InitializeMemoryMap (
853 _In_ PBL_MEMORY_DATA MemoryData
858 KDESCRIPTOR Gdt
, Idt
;
860 PHYSICAL_ADDRESS PhysicalAddress
;
862 /* If this is phase 2, map the memory regions */
865 return Mmx86pMapMemoryRegions(Phase
, MemoryData
);
868 /* Get the application image base/size */
869 Status
= BlGetApplicationBaseAndSize(&ImageBase
, &ImageSize
);
870 if (!NT_SUCCESS(Status
))
875 /* Map the image back at the same place */
876 PhysicalAddress
.QuadPart
= (ULONG_PTR
)ImageBase
;
877 Status
= Mmx86MapInitStructure(ImageBase
, ImageSize
, PhysicalAddress
);
878 if (!NT_SUCCESS(Status
))
883 /* Map the first 4MB of memory */
884 PhysicalAddress
.QuadPart
= 0;
885 Status
= Mmx86MapInitStructure(NULL
, 4 * 1024 * 1024, PhysicalAddress
);
886 if (!NT_SUCCESS(Status
))
893 PhysicalAddress
.QuadPart
= Gdt
.Base
;
894 Status
= Mmx86MapInitStructure((PVOID
)Gdt
.Base
, Gdt
.Limit
+ 1, PhysicalAddress
);
895 if (!NT_SUCCESS(Status
))
902 PhysicalAddress
.QuadPart
= Idt
.Base
;
903 Status
= Mmx86MapInitStructure((PVOID
)Idt
.Base
, Idt
.Limit
+ 1, PhysicalAddress
);
904 if (!NT_SUCCESS(Status
))
909 /* Map the reference page */
910 PhysicalAddress
.QuadPart
= (ULONG_PTR
)MmArchReferencePage
;
911 Status
= Mmx86MapInitStructure(MmArchReferencePage
,
912 MmArchReferencePageSize
,
914 if (!NT_SUCCESS(Status
))
920 return Mmx86pMapMemoryRegions(Phase
, MemoryData
);
924 MmDefInitializeTranslation (
925 _In_ PBL_MEMORY_DATA MemoryData
,
926 _In_ BL_TRANSLATION_TYPE TranslationType
930 PHYSICAL_ADDRESS PhysicalAddress
;
933 /* Set the global function pointers for memory translation */
934 Mmx86TranslateVirtualAddress
= MmDefpTranslateVirtualAddress
;
935 Mmx86MapPhysicalAddress
= MmDefpMapPhysicalAddress
;
936 Mmx86UnmapVirtualAddress
= MmDefpUnmapVirtualAddress
;
937 Mmx86RemapVirtualAddress
= MmDefpRemapVirtualAddress
;
938 Mmx86FlushTlb
= MmDefpFlushTlb
;
939 Mmx86FlushTlbEntry
= MmDefpFlushTlbEntry
;
940 Mmx86DestroySelfMap
= MmDefpDestroySelfMap
;
942 /* Check what mode we're currently in */
943 if (TranslationType
== BlVirtual
)
945 EfiPrintf(L
"Virtual->Virtual not yet supported\r\n");
946 return STATUS_NOT_IMPLEMENTED
;
948 else if (TranslationType
!= BlNone
)
950 /* Not even Windows supports PAE->Virtual downgrade */
951 return STATUS_NOT_IMPLEMENTED
;
954 /* The None->Virtual case */
956 Mmx86SelfMapBase
.QuadPart
= 0;
957 MmArchReferencePage
= NULL
;
959 /* Truncate all memory above 4GB so that we don't use it */
960 Status
= MmPaTruncateMemory(0x100000);
961 if (!NT_SUCCESS(Status
))
966 /* Allocate a page directory */
967 Status
= MmPapAllocatePhysicalPagesInRange(&PhysicalAddress
,
968 BlLoaderPageDirectory
,
972 &MmMdlUnmappedAllocated
,
975 if (!NT_SUCCESS(Status
))
980 /* Zero out the page directory */
981 MmPdpt
= (PVOID
)PhysicalAddress
.LowPart
;
982 RtlZeroMemory(MmPdpt
, PAGE_SIZE
);
984 /* Set the page size */
985 MmArchReferencePageSize
= PAGE_SIZE
;
987 /* Allocate the self-map page */
988 Status
= MmPapAllocatePhysicalPagesInRange(&PhysicalAddress
,
989 BlLoaderReferencePage
,
993 &MmMdlUnmappedAllocated
,
996 if (!NT_SUCCESS(Status
))
1001 /* Set the reference page */
1002 MmArchReferencePage
= (PVOID
)PhysicalAddress
.LowPart
;
1005 RtlZeroMemory(MmArchReferencePage
, MmArchReferencePageSize
);
1007 /* Allocate 4MB worth of self-map pages */
1008 Status
= MmPaReserveSelfMapPages(&Mmx86SelfMapBase
,
1009 (4 * 1024 * 1024) >> PAGE_SHIFT
,
1010 (4 * 1024 * 1024) >> PAGE_SHIFT
);
1011 if (!NT_SUCCESS(Status
))
1017 RtlZeroMemory((PVOID
)Mmx86SelfMapBase
.LowPart
, 4 * 1024 * 1024);
1018 EfiPrintf(L
"PDPT at 0x%p Reference Page at 0x%p Self-map at 0x%p\r\n",
1019 MmPdpt
, MmArchReferencePage
, Mmx86SelfMapBase
.LowPart
);
1021 /* Align PTE base to 4MB region */
1022 MmPteBase
= (PVOID
)(Mmx86SelfMapBase
.LowPart
& ~0x3FFFFF);
1024 /* The PDE is the PTE of the PTE base */
1025 MmPdeBase
= MiAddressToPte(MmPteBase
);
1026 PdeIndex
= MiAddressToPdeOffset(MmPdeBase
);
1027 MmPdpt
[PdeIndex
].u
.Hard
.Valid
= 1;
1028 MmPdpt
[PdeIndex
].u
.Hard
.Write
= 1;
1029 MmPdpt
[PdeIndex
].u
.Hard
.PageFrameNumber
= (ULONG_PTR
)MmPdpt
>> PAGE_SHIFT
;
1030 MmArchReferencePage
[PdeIndex
]++;
1032 /* Remove PTE_BASE from free virtual memory */
1033 Status
= MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual
,
1034 BL_MM_REMOVE_VIRTUAL_REGION_FLAG
,
1035 PTE_BASE
>> PAGE_SHIFT
,
1036 (4 * 1024 * 1024) >> PAGE_SHIFT
,
1038 if (!NT_SUCCESS(Status
))
1043 /* Remove HAL_HEAP from free virtual memory */
1044 Status
= MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual
,
1045 BL_MM_REMOVE_VIRTUAL_REGION_FLAG
,
1046 MM_HAL_VA_START
>> PAGE_SHIFT
,
1047 (4 * 1024 * 1024) >> PAGE_SHIFT
,
1049 if (!NT_SUCCESS(Status
))
1054 /* Initialize the virtual->physical memory mappings */
1055 Status
= Mmx86InitializeMemoryMap(1, MemoryData
);
1056 if (!NT_SUCCESS(Status
))
1061 /* Turn on paging with the new CR3 */
1062 __writecr3((ULONG_PTR
)MmPdpt
);
1063 BlpArchEnableTranslation();
1064 EfiPrintf(L
"Paging... %d\r\n", BlMmIsTranslationEnabled());
1066 /* Return success */
1070 /* Free reference page if we allocated it */
1071 if (MmArchReferencePage
)
1073 PhysicalAddress
.QuadPart
= (ULONG_PTR
)MmArchReferencePage
;
1074 BlMmFreePhysicalPages(PhysicalAddress
);
1077 /* Free page directory if we allocated it */
1080 PhysicalAddress
.QuadPart
= (ULONG_PTR
)MmPdpt
;
1081 BlMmFreePhysicalPages(PhysicalAddress
);
1084 /* Free the self map if we allocated it */
1085 if (Mmx86SelfMapBase
.QuadPart
)
1087 MmPaReleaseSelfMapPages(Mmx86SelfMapBase
);
1097 _In_ PBL_MEMORY_DATA MemoryData
,
1098 _In_ BL_TRANSLATION_TYPE TranslationType
,
1099 _In_ BL_TRANSLATION_TYPE RequestedTranslationType
1103 ULONGLONG IncreaseUserVa
, PerfCounter
, CpuRandom
;
1106 /* For phase 2, just map deferred regions */
1109 return Mmx86pMapMemoryRegions(2, MemoryData
);
1112 /* What translation type are we switching to? */
1113 switch (RequestedTranslationType
)
1115 /* Physical memory */
1118 /* Initialize everything to default/null values */
1119 MmArchLargePageSize
= 1;
1122 MmArchKsegAddressRange
.Minimum
= 0;
1123 MmArchKsegAddressRange
.Maximum
= (ULONGLONG
)~0;
1124 MmArchTopOfApplicationAddressSpace
= 0;
1125 Mmx86SelfMapBase
.QuadPart
= 0;
1127 /* Set stub functions */
1128 BlMmRelocateSelfMap
= MmArchNullFunction
;
1129 BlMmFlushTlb
= MmArchNullFunction
;
1132 Status
= STATUS_SUCCESS
;
1137 /* Set the large page size to 1024 pages (4MB) */
1138 MmArchLargePageSize
= (4 * 1024 * 1024) / PAGE_SIZE
;
1140 /* Check if /USERVA option was used */
1141 Status
= BlGetBootOptionInteger(BlpApplicationEntry
.BcdData
,
1142 BcdOSLoaderInteger_IncreaseUserVa
,
1144 if (NT_SUCCESS(Status
) && (IncreaseUserVa
))
1146 /* Yes -- load the kernel at 0xE0000000 instead */
1147 MmArchKsegBase
= 0xE0000000;
1151 /* Nope, load at the standard 2GB split */
1152 MmArchKsegBase
= 0x80000000;
1155 /* Check if CPUID 01h is supported */
1157 if (BlArchIsCpuIdFunctionSupported(1))
1160 BlArchCpuId(1, 0, &CpuInfo
);
1162 /* Check if RDRAND is supported */
1163 if (CpuInfo
.Ecx
& 0x40000000)
1165 EfiPrintf(L
"Your CPU can do RDRAND! Good for you!\r\n");
1171 PerfCounter
= BlArchGetPerformanceCounter();
1173 _rotl16(PerfCounter
, 5);
1175 /* Set the address range */
1176 MmArchKsegAddressRange
.Minimum
= 0;
1177 MmArchKsegAddressRange
.Maximum
= (ULONGLONG
)~0;
1179 /* Set the KASLR bias */
1180 MmArchKsegBias
= ((PerfCounter
^ CpuRandom
) & 0xFFF) << 12;
1182 MmArchKsegBase
+= MmArchKsegBias
;
1184 /* Set the kernel range */
1185 MmArchKsegAddressRange
.Minimum
= MmArchKsegBase
;
1186 MmArchKsegAddressRange
.Maximum
= (ULONGLONG
)~0;
1188 /* Set the boot application top maximum */
1189 MmArchTopOfApplicationAddressSpace
= 0x70000000 - 1; // Windows bug
1191 /* Initialize virtual address space translation */
1192 Status
= MmDefInitializeTranslation(MemoryData
, TranslationType
);
1193 if (NT_SUCCESS(Status
))
1195 /* Set stub functions */
1196 BlMmRelocateSelfMap
= MmDefRelocateSelfMap
;
1197 BlMmFlushTlb
= Mmx86FlushTlb
;
1198 BlMmMoveVirtualAddressRange
= MmDefMoveVirtualAddressRange
;
1199 BlMmZeroVirtualAddressRange
= MmDefZeroVirtualAddressRange
;
1205 /* We don't support PAE */
1206 Status
= STATUS_NOT_SUPPORTED
;
1211 /* Invalid architecture type*/
1212 Status
= STATUS_INVALID_PARAMETER
;
1216 /* Back to caller */