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
->Mode
& 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 return STATUS_NO_MEMORY
;
333 /* This is our page table */
334 PageTable
= (PVOID
)(ULONG_PTR
)PageTableAddress
.QuadPart
;
336 /* Build the PDE for it */
337 Pde
->u
.Hard
.PageFrameNumber
= PageTableAddress
.QuadPart
>> PAGE_SHIFT
;
338 Pde
->u
.Hard
.Write
= 1;
339 Pde
->u
.Hard
.CacheDisable
= 1;
340 Pde
->u
.Hard
.WriteThrough
= 1;
341 Pde
->u
.Hard
.Valid
= 1;
343 /* Check if paging is enabled */
346 /* Then actually, get the page table's virtual address */
347 PageTable
= (PVOID
)PAGE_ROUND_DOWN(MiAddressToPte(VirtualAddress
));
353 /* Zero out the page table */
354 RtlZeroMemory(PageTable
, PAGE_SIZE
);
356 /* Reset caching attributes now */
357 Pde
->u
.Hard
.CacheDisable
= 0;
358 Pde
->u
.Hard
.WriteThrough
= 0;
360 /* Check for paging again */
363 /* Flush the TLB entry for the page table only */
364 Mmx86FlushTlbEntry(PageTable
);
368 /* Add a reference to this page table */
369 MmArchReferencePage
[PdeOffset
]++;
371 /* Check if a physical address was given */
372 if (PhysicalAddress
.QuadPart
!= -1)
374 /* Check if paging is turned on */
377 /* Get the PTE using the self-map */
378 Pte
= MiAddressToPte(VirtualAddress
);
382 /* Get the PTE using physical addressing */
383 Pte
= &PageTable
[MiAddressToPteOffset(VirtualAddress
)];
386 /* Build a valid PTE for it */
387 Pte
->u
.Hard
.PageFrameNumber
= CurrentAddress
>> PAGE_SHIFT
;
388 Pte
->u
.Hard
.Write
= 1;
389 Pte
->u
.Hard
.Valid
= 1;
391 /* Check if this is uncached */
392 if (CacheAttributes
== BlMemoryUncached
)
395 Pte
->u
.Hard
.CacheDisable
= 1;
396 Pte
->u
.Hard
.WriteThrough
= 1;
398 else if (CacheAttributes
== BlMemoryWriteThrough
)
400 /* It's write-through, set the flag */
401 Pte
->u
.Hard
.WriteThrough
= 1;
405 /* Move to the next physical/virtual address */
406 VirtualAddress
= (PVOID
)((ULONG_PTR
)VirtualAddress
+ PAGE_SIZE
);
407 CurrentAddress
+= PAGE_SIZE
;
411 return STATUS_SUCCESS
;
415 MmDefpTranslateVirtualAddress (
416 _In_ PVOID VirtualAddress
,
417 _Out_ PPHYSICAL_ADDRESS PhysicalAddress
,
418 _Out_opt_ PULONG CacheAttributes
426 /* Is there no page directory yet? */
432 /* Is paging enabled? */
433 Enabled
= BlMmIsTranslationEnabled();
435 /* Check if paging is actually turned on */
438 /* Get the PDE entry using the self-map */
439 Pde
= MiAddressToPde(VirtualAddress
);
443 /* Get it using our physical mappings */
444 Pde
= &MmPdpt
[MiAddressToPdeOffset(VirtualAddress
)];
447 /* Is the PDE valid? */
448 if (!Pde
->u
.Hard
.Valid
)
453 /* Check if paging is turned on */
456 /* Get the PTE using the self-map */
457 Pte
= MiAddressToPte(VirtualAddress
);
461 /* Get the PTE using physical addressing */
462 PageTable
= (PMMPTE
)(Pde
->u
.Hard
.PageFrameNumber
<< PAGE_SHIFT
);
463 Pte
= &PageTable
[MiAddressToPteOffset(VirtualAddress
)];
466 /* Is the PTE valid? */
467 if (!Pte
->u
.Hard
.Valid
)
472 /* Does caller want the physical address? */
476 PhysicalAddress
->QuadPart
= (Pte
->u
.Hard
.PageFrameNumber
<< PAGE_SHIFT
) +
477 BYTE_OFFSET(VirtualAddress
);
480 /* Does caller want cache attributes? */
483 /* Not yet -- lie and say it's cached */
484 EfiPrintf(L
"Cache checking not yet enabled\r\n");
485 *CacheAttributes
= BlMemoryWriteBack
;
493 MmMapPhysicalAddress (
494 _Inout_ PPHYSICAL_ADDRESS PhysicalAddressPtr
,
495 _Inout_ PVOID
* VirtualAddressPtr
,
496 _Inout_ PULONGLONG SizePtr
,
497 _In_ ULONG CacheAttributes
501 ULONGLONG PhysicalAddress
;
502 PVOID VirtualAddress
;
503 PHYSICAL_ADDRESS TranslatedAddress
;
504 ULONG_PTR CurrentAddress
, VirtualAddressEnd
;
507 /* Fail if any parameters are missing */
508 if (!(PhysicalAddressPtr
) || !(VirtualAddressPtr
) || !(SizePtr
))
510 return STATUS_INVALID_PARAMETER
;
513 /* Fail if the size is over 32-bits */
515 if (Size
> 0xFFFFFFFF)
517 return STATUS_INVALID_PARAMETER
;
520 /* Nothing to do if we're in physical mode */
521 if (MmTranslationType
== BlNone
)
523 return STATUS_SUCCESS
;
526 /* Can't use virtual memory in real mode */
527 if (CurrentExecutionContext
->Mode
== BlRealMode
)
529 return STATUS_UNSUCCESSFUL
;
532 /* Capture the current virtual and physical addresses */
533 VirtualAddress
= *VirtualAddressPtr
;
534 PhysicalAddress
= PhysicalAddressPtr
->QuadPart
;
536 /* Check if a physical address was requested */
537 if (PhysicalAddress
!= 0xFFFFFFFF)
539 /* Round down the base addresses */
540 PhysicalAddress
= PAGE_ROUND_DOWN(PhysicalAddress
);
541 VirtualAddress
= (PVOID
)PAGE_ROUND_DOWN(VirtualAddress
);
543 /* Round up the size */
544 Size
= ROUND_TO_PAGES(PhysicalAddressPtr
->QuadPart
-
548 /* Loop every virtual page */
549 CurrentAddress
= (ULONG_PTR
)VirtualAddress
;
550 VirtualAddressEnd
= CurrentAddress
+ Size
- 1;
551 while (CurrentAddress
< VirtualAddressEnd
)
553 /* Get the physical page of this virtual page */
554 if (MmArchTranslateVirtualAddress((PVOID
)CurrentAddress
,
558 /* Make sure the physical page of the virtual page, matches our page */
559 if (TranslatedAddress
.QuadPart
!=
561 (CurrentAddress
- (ULONG_PTR
)VirtualAddress
)))
563 /* There is an existing virtual mapping for a different address */
564 EfiPrintf(L
"Existing mapping exists: %lx vs %lx\r\n",
565 TranslatedAddress
.QuadPart
,
566 PhysicalAddress
+ (CurrentAddress
- (ULONG_PTR
)VirtualAddress
));
568 return STATUS_INVALID_PARAMETER
;
572 /* Try the next one */
573 CurrentAddress
+= PAGE_SIZE
;
577 /* Aactually do the mapping */
578 TranslatedAddress
.QuadPart
= PhysicalAddress
;
579 Status
= Mmx86MapPhysicalAddress(TranslatedAddress
,
583 if (!NT_SUCCESS(Status
))
585 EfiPrintf(L
"Failed to map!: %lx\r\n", Status
);
589 /* Return aligned/fixed up output parameters */
590 PhysicalAddressPtr
->QuadPart
= PhysicalAddress
;
591 *VirtualAddressPtr
= VirtualAddress
;
594 /* Flush the TLB if paging is enabled */
595 if (BlMmIsTranslationEnabled())
601 return STATUS_SUCCESS
;
605 Mmx86MapInitStructure (
606 _In_ PVOID VirtualAddress
,
608 _In_ PHYSICAL_ADDRESS PhysicalAddress
613 /* Make a virtual mapping for this physical address */
614 Status
= MmMapPhysicalAddress(&PhysicalAddress
, &VirtualAddress
, &Size
, 0);
615 if (!NT_SUCCESS(Status
))
620 /* Nothing else to do if we're not in paging mode */
621 if (MmTranslationType
== BlNone
)
623 return STATUS_SUCCESS
;
626 /* Otherwise, remove this region from the list of free virtual ranges */
627 Status
= MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual
,
628 BL_MM_REMOVE_VIRTUAL_REGION_FLAG
,
629 (ULONG_PTR
)VirtualAddress
>> PAGE_SHIFT
,
632 if (!NT_SUCCESS(Status
))
634 /* Unmap the address if that failed */
635 MmUnmapVirtualAddress(&VirtualAddress
, &Size
);
638 /* Return back to caller */
644 _In_ PBL_MEMORY_DESCRIPTOR_LIST DescriptorList
647 ULONGLONG EndPage
, VirtualEndPage
;
648 PBL_MEMORY_DESCRIPTOR MemoryDescriptor
;
649 PLIST_ENTRY NextEntry
;
651 NextEntry
= DescriptorList
->First
->Flink
;
652 while (NextEntry
!= DescriptorList
->First
)
654 MemoryDescriptor
= CONTAINING_RECORD(NextEntry
,
655 BL_MEMORY_DESCRIPTOR
,
658 EndPage
= MemoryDescriptor
->BasePage
+ MemoryDescriptor
->PageCount
;
659 if (MemoryDescriptor
->VirtualPage
!= 0)
661 VirtualEndPage
= MemoryDescriptor
->VirtualPage
+ MemoryDescriptor
->PageCount
;
668 EfiPrintf(L
"%p - [%08llx-%08llx @ %08llx-%08llx]:%x\r\n",
670 MemoryDescriptor
->BasePage
<< PAGE_SHIFT
,
671 (EndPage
<< PAGE_SHIFT
) - 1,
672 MemoryDescriptor
->VirtualPage
<< PAGE_SHIFT
,
673 VirtualEndPage
? (VirtualEndPage
<< PAGE_SHIFT
) - 1 : 0,
674 (ULONG
)MemoryDescriptor
->Type
);
676 NextEntry
= NextEntry
->Flink
;
681 Mmx86pMapMemoryRegions (
683 _In_ PBL_MEMORY_DATA MemoryData
687 ULONG DescriptorCount
;
688 PBL_MEMORY_DESCRIPTOR Descriptor
;
690 PHYSICAL_ADDRESS PhysicalAddress
;
693 PVOID VirtualAddress
;
694 BL_MEMORY_DESCRIPTOR_LIST FirmwareMdl
;
695 PLIST_ENTRY Head
, NextEntry
;
697 /* Check which phase this is */
700 /* In phase 1 we don't initialize deferred mappings */
705 /* Don't do anything if there's nothing to initialize */
706 if (!MmDeferredMappingCount
)
708 return STATUS_SUCCESS
;
711 /* We'll do deferred descriptors in phase 2 */
716 * Because BL supports cross x86-x64 application launches and a LIST_ENTRY
717 * is of variable size, care must be taken here to ensure that we see a
718 * consistent view of descriptors. BL uses some offset magic to figure out
719 * where the data actually starts, since everything is ULONGLONG past the
722 FinalOffset
= MemoryData
->MdListOffset
+ MemoryData
->DescriptorOffset
;
723 Descriptor
= (PBL_MEMORY_DESCRIPTOR
)((ULONG_PTR
)MemoryData
+ FinalOffset
-
724 FIELD_OFFSET(BL_MEMORY_DESCRIPTOR
, BasePage
));
726 /* Scan all of them */
727 DescriptorCount
= MemoryData
->DescriptorCount
;
728 while (DescriptorCount
!= 0)
730 /* Ignore application data */
731 if (Descriptor
->Type
!= BlApplicationData
)
733 /* If this is a ramdisk, do it in phase 2 */
734 if ((Descriptor
->Type
== BlLoaderRamDisk
) == DoDeferred
)
736 /* Get the current physical address and size */
737 PhysicalAddress
.QuadPart
= Descriptor
->BasePage
<< PAGE_SHIFT
;
738 Size
= Descriptor
->PageCount
<< PAGE_SHIFT
;
740 /* Check if it was already mapped */
741 if (Descriptor
->VirtualPage
)
743 /* Use the existing address */
744 VirtualAddress
= (PVOID
)(ULONG_PTR
)(Descriptor
->VirtualPage
<< PAGE_SHIFT
);
748 /* Use the physical address */
749 VirtualAddress
= (PVOID
)(ULONG_PTR
)PhysicalAddress
.QuadPart
;
752 /* Crete the mapping */
753 Status
= Mmx86MapInitStructure(VirtualAddress
,
756 if (!NT_SUCCESS(Status
))
762 /* Check if we're in phase 1 and deferring RAM disk */
763 if ((Phase
== 1) && (Descriptor
->Type
== BlLoaderRamDisk
))
765 MmDeferredMappingCount
++;
769 /* Move on to the next descriptor */
771 Descriptor
= (PBL_MEMORY_DESCRIPTOR
)((ULONG_PTR
)Descriptor
+ MemoryData
->DescriptorSize
);
774 /* In phase 1, also do UEFI mappings */
777 /* Get the memory map */
778 MmMdInitializeListHead(&FirmwareMdl
);
779 Status
= MmFwGetMemoryMap(&FirmwareMdl
, BL_MM_FLAG_REQUEST_COALESCING
);
780 if (!NT_SUCCESS(Status
))
785 /* Iterate over it */
786 Head
= FirmwareMdl
.First
;
787 NextEntry
= Head
->Flink
;
788 while (NextEntry
!= Head
)
790 /* Check if this is a UEFI-related descriptor, unless it's the self-map page */
791 Descriptor
= CONTAINING_RECORD(NextEntry
, BL_MEMORY_DESCRIPTOR
, ListEntry
);
792 if (((Descriptor
->Type
== BlEfiBootMemory
) ||
793 (Descriptor
->Type
== BlEfiRuntimeMemory
) ||
794 (Descriptor
->Type
== BlLoaderMemory
)) &&
795 ((Descriptor
->BasePage
<< PAGE_SHIFT
) != Mmx86SelfMapBase
.QuadPart
))
797 /* Identity-map it */
798 PhysicalAddress
.QuadPart
= Descriptor
->BasePage
<< PAGE_SHIFT
;
799 Status
= Mmx86MapInitStructure((PVOID
)((ULONG_PTR
)Descriptor
->BasePage
<< PAGE_SHIFT
),
800 Descriptor
->PageCount
<< PAGE_SHIFT
,
802 if (!NT_SUCCESS(Status
))
808 /* Move to the next descriptor */
809 NextEntry
= NextEntry
->Flink
;
813 NextEntry
= Head
->Flink
;
814 while (NextEntry
!= Head
)
816 /* Get the descriptor */
817 Descriptor
= CONTAINING_RECORD(NextEntry
, BL_MEMORY_DESCRIPTOR
, ListEntry
);
819 /* Skip to the next entry before we free */
820 NextEntry
= NextEntry
->Flink
;
822 /* Remove and free it */
823 MmMdRemoveDescriptorFromList(&FirmwareMdl
, Descriptor
);
824 MmMdFreeDescriptor(Descriptor
);
828 /* All library mappings identity mapped now */
829 return STATUS_SUCCESS
;
833 Mmx86InitializeMemoryMap (
835 _In_ PBL_MEMORY_DATA MemoryData
840 KDESCRIPTOR Gdt
, Idt
;
842 PHYSICAL_ADDRESS PhysicalAddress
;
844 /* If this is phase 2, map the memory regions */
847 return Mmx86pMapMemoryRegions(Phase
, MemoryData
);
850 /* Get the application image base/size */
851 Status
= BlGetApplicationBaseAndSize(&ImageBase
, &ImageSize
);
852 if (!NT_SUCCESS(Status
))
857 /* Map the image back at the same place */
858 PhysicalAddress
.QuadPart
= (ULONG_PTR
)ImageBase
;
859 Status
= Mmx86MapInitStructure(ImageBase
, ImageSize
, PhysicalAddress
);
860 if (!NT_SUCCESS(Status
))
865 /* Map the first 4MB of memory */
866 PhysicalAddress
.QuadPart
= 0;
867 Status
= Mmx86MapInitStructure(NULL
, 4 * 1024 * 1024, PhysicalAddress
);
868 if (!NT_SUCCESS(Status
))
875 PhysicalAddress
.QuadPart
= Gdt
.Base
;
876 Status
= Mmx86MapInitStructure((PVOID
)Gdt
.Base
, Gdt
.Limit
+ 1, PhysicalAddress
);
877 if (!NT_SUCCESS(Status
))
884 PhysicalAddress
.QuadPart
= Idt
.Base
;
885 Status
= Mmx86MapInitStructure((PVOID
)Idt
.Base
, Idt
.Limit
+ 1, PhysicalAddress
);
886 if (!NT_SUCCESS(Status
))
891 /* Map the reference page */
892 PhysicalAddress
.QuadPart
= (ULONG_PTR
)MmArchReferencePage
;
893 Status
= Mmx86MapInitStructure(MmArchReferencePage
,
894 MmArchReferencePageSize
,
896 if (!NT_SUCCESS(Status
))
902 return Mmx86pMapMemoryRegions(Phase
, MemoryData
);
906 MmDefInitializeTranslation (
907 _In_ PBL_MEMORY_DATA MemoryData
,
908 _In_ BL_TRANSLATION_TYPE TranslationType
912 PHYSICAL_ADDRESS PhysicalAddress
;
915 /* Set the global function pointers for memory translation */
916 Mmx86TranslateVirtualAddress
= MmDefpTranslateVirtualAddress
;
917 Mmx86MapPhysicalAddress
= MmDefpMapPhysicalAddress
;
918 Mmx86UnmapVirtualAddress
= MmDefpUnmapVirtualAddress
;
919 Mmx86RemapVirtualAddress
= MmDefpRemapVirtualAddress
;
920 Mmx86FlushTlb
= MmDefpFlushTlb
;
921 Mmx86FlushTlbEntry
= MmDefpFlushTlbEntry
;
922 Mmx86DestroySelfMap
= MmDefpDestroySelfMap
;
924 /* Check what mode we're currently in */
925 if (TranslationType
== BlVirtual
)
927 EfiPrintf(L
"Virtual->Virtual not yet supported\r\n");
928 return STATUS_NOT_IMPLEMENTED
;
930 else if (TranslationType
!= BlNone
)
932 /* Not even Windows supports PAE->Virtual downgrade */
933 return STATUS_NOT_IMPLEMENTED
;
936 /* The None->Virtual case */
938 Mmx86SelfMapBase
.QuadPart
= 0;
939 MmArchReferencePage
= NULL
;
941 /* Truncate all memory above 4GB so that we don't use it @TODO: FIXME */
942 EfiPrintf(L
"Warning: not truncating > 4GB memory. Don't boot with more than 4GB of RAM!\r\n");
943 //Status = MmPaTruncateMemory(0x100000);
944 Status
= STATUS_SUCCESS
;
945 if (!NT_SUCCESS(Status
))
950 /* Allocate a page directory */
951 Status
= MmPapAllocatePhysicalPagesInRange(&PhysicalAddress
,
952 BlLoaderPageDirectory
,
956 &MmMdlUnmappedAllocated
,
959 if (!NT_SUCCESS(Status
))
964 /* Zero out the page directory */
965 MmPdpt
= (PVOID
)PhysicalAddress
.LowPart
;
966 RtlZeroMemory(MmPdpt
, PAGE_SIZE
);
968 /* Set the page size */
969 MmArchReferencePageSize
= PAGE_SIZE
;
971 /* Allocate the self-map page */
972 Status
= MmPapAllocatePhysicalPagesInRange(&PhysicalAddress
,
973 BlLoaderReferencePage
,
977 &MmMdlUnmappedAllocated
,
980 if (!NT_SUCCESS(Status
))
985 /* Set the reference page */
986 MmArchReferencePage
= (PVOID
)PhysicalAddress
.LowPart
;
989 RtlZeroMemory(MmArchReferencePage
, MmArchReferencePageSize
);
991 /* Allocate 4MB worth of self-map pages */
992 Status
= MmPaReserveSelfMapPages(&Mmx86SelfMapBase
,
993 (4 * 1024 * 1024) >> PAGE_SHIFT
,
994 (4 * 1024 * 1024) >> PAGE_SHIFT
);
995 if (!NT_SUCCESS(Status
))
1001 RtlZeroMemory((PVOID
)Mmx86SelfMapBase
.LowPart
, 4 * 1024 * 1024);
1002 EfiPrintf(L
"PDPT at 0x%p Reference Page at 0x%p Self-map at 0x%p\r\n",
1003 MmPdpt
, MmArchReferencePage
, Mmx86SelfMapBase
.LowPart
);
1005 /* Align PTE base to 4MB region */
1006 MmPteBase
= (PVOID
)(Mmx86SelfMapBase
.LowPart
& ~0x3FFFFF);
1008 /* The PDE is the PTE of the PTE base */
1009 MmPdeBase
= MiAddressToPte(MmPteBase
);
1010 PdeIndex
= MiAddressToPdeOffset(MmPdeBase
);
1011 MmPdpt
[PdeIndex
].u
.Hard
.Valid
= 1;
1012 MmPdpt
[PdeIndex
].u
.Hard
.Write
= 1;
1013 MmPdpt
[PdeIndex
].u
.Hard
.PageFrameNumber
= (ULONG_PTR
)MmPdpt
>> PAGE_SHIFT
;
1014 MmArchReferencePage
[PdeIndex
]++;
1016 /* Remove PTE_BASE from free virtual memory */
1017 Status
= MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual
,
1018 BL_MM_REMOVE_VIRTUAL_REGION_FLAG
,
1019 PTE_BASE
>> PAGE_SHIFT
,
1020 (4 * 1024 * 1024) >> PAGE_SHIFT
,
1022 if (!NT_SUCCESS(Status
))
1027 /* Remove HAL_HEAP from free virtual memory */
1028 Status
= MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual
,
1029 BL_MM_REMOVE_VIRTUAL_REGION_FLAG
,
1030 MM_HAL_VA_START
>> PAGE_SHIFT
,
1031 (4 * 1024 * 1024) >> PAGE_SHIFT
,
1033 if (!NT_SUCCESS(Status
))
1038 /* Initialize the virtual->physical memory mappings */
1039 Status
= Mmx86InitializeMemoryMap(1, MemoryData
);
1040 if (!NT_SUCCESS(Status
))
1045 EfiPrintf(L
"Ready to turn on motherfucking paging, brah!\r\n");
1046 Status
= STATUS_NOT_IMPLEMENTED
;
1049 /* Free reference page if we allocated it */
1050 if (MmArchReferencePage
)
1052 PhysicalAddress
.QuadPart
= (ULONG_PTR
)MmArchReferencePage
;
1053 BlMmFreePhysicalPages(PhysicalAddress
);
1056 /* Free page directory if we allocated it */
1059 PhysicalAddress
.QuadPart
= (ULONG_PTR
)MmPdpt
;
1060 BlMmFreePhysicalPages(PhysicalAddress
);
1063 /* Free the self map if we allocated it */
1064 if (Mmx86SelfMapBase
.QuadPart
)
1066 MmPaReleaseSelfMapPages(Mmx86SelfMapBase
);
1076 _In_ PBL_MEMORY_DATA MemoryData
,
1077 _In_ BL_TRANSLATION_TYPE TranslationType
,
1078 _In_ BL_TRANSLATION_TYPE RequestedTranslationType
1082 ULONGLONG IncreaseUserVa
, PerfCounter
, CpuRandom
;
1085 /* For phase 2, just map deferred regions */
1088 return Mmx86pMapMemoryRegions(2, MemoryData
);
1091 /* What translation type are we switching to? */
1092 switch (RequestedTranslationType
)
1094 /* Physical memory */
1097 /* Initialize everything to default/null values */
1098 MmArchLargePageSize
= 1;
1101 MmArchKsegAddressRange
.Minimum
= 0;
1102 MmArchKsegAddressRange
.Maximum
= (ULONGLONG
)~0;
1103 MmArchTopOfApplicationAddressSpace
= 0;
1104 Mmx86SelfMapBase
.QuadPart
= 0;
1106 /* Set stub functions */
1107 BlMmRelocateSelfMap
= MmArchNullFunction
;
1108 BlMmFlushTlb
= MmArchNullFunction
;
1111 Status
= STATUS_SUCCESS
;
1116 /* Set the large page size to 1024 pages (4MB) */
1117 MmArchLargePageSize
= (4 * 1024 * 1024) / PAGE_SIZE
;
1119 /* Check if /USERVA option was used */
1120 Status
= BlGetBootOptionInteger(BlpApplicationEntry
.BcdData
,
1121 BcdOSLoaderInteger_IncreaseUserVa
,
1123 if (NT_SUCCESS(Status
) && (IncreaseUserVa
))
1125 /* Yes -- load the kernel at 0xE0000000 instead */
1126 MmArchKsegBase
= 0xE0000000;
1130 /* Nope, load at the standard 2GB split */
1131 MmArchKsegBase
= 0x80000000;
1134 /* Check if CPUID 01h is supported */
1136 if (BlArchIsCpuIdFunctionSupported(1))
1139 BlArchCpuId(1, 0, CpuInfo
);
1141 /* Check if RDRAND is supported */
1142 if (CpuInfo
[2] & 0x40000000)
1144 EfiPrintf(L
"Your CPU can do RDRAND! Good for you!\r\n");
1150 PerfCounter
= BlArchGetPerformanceCounter();
1152 _rotl16(PerfCounter
, 5);
1154 /* Set the address range */
1155 MmArchKsegAddressRange
.Minimum
= 0;
1156 MmArchKsegAddressRange
.Maximum
= (ULONGLONG
)~0;
1158 /* Set the KASLR bias */
1159 MmArchKsegBias
= ((PerfCounter
^ CpuRandom
) & 0xFFF) << 12;
1161 MmArchKsegBase
+= MmArchKsegBias
;
1163 /* Set the kernel range */
1164 MmArchKsegAddressRange
.Minimum
= MmArchKsegBase
;
1165 MmArchKsegAddressRange
.Maximum
= (ULONGLONG
)~0;
1167 /* Set the boot application top maximum */
1168 MmArchTopOfApplicationAddressSpace
= 0x70000000 - 1; // Windows bug
1170 /* Initialize virtual address space translation */
1171 Status
= MmDefInitializeTranslation(MemoryData
, TranslationType
);
1172 if (NT_SUCCESS(Status
))
1174 /* Set stub functions */
1175 BlMmRelocateSelfMap
= MmDefRelocateSelfMap
;
1176 BlMmFlushTlb
= Mmx86FlushTlb
;
1177 BlMmMoveVirtualAddressRange
= MmDefMoveVirtualAddressRange
;
1178 BlMmZeroVirtualAddressRange
= MmDefZeroVirtualAddressRange
;
1184 /* We don't support PAE */
1185 Status
= STATUS_NOT_SUPPORTED
;
1190 /* Invalid architecture type*/
1191 Status
= STATUS_INVALID_PARAMETER
;
1195 /* Back to caller */