25STATIC ARM_REPLACE_LIVE_TRANSLATION_ENTRY mReplaceLiveEntryFunc = ArmReplaceLiveTranslationEntry;
37 if (ArmReadCurrentEL () == AARCH64_EL2) {
38 return (ArmReadHcr () & ARM_HCR_E2H) != 0;
46ArmMemoryAttributeToPageAttribute (
47 IN ARM_MEMORY_REGION_ATTRIBUTES Attributes
53 case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK_RO:
54 Permissions = TT_AP_NO_RO;
57 case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK_XP:
58 case ARM_MEMORY_REGION_ATTRIBUTE_DEVICE:
60 Permissions = TT_XN_MASK;
62 Permissions = TT_UXN_MASK | TT_PXN_MASK;
72 case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK_NONSHAREABLE:
73 return TT_ATTR_INDX_MEMORY_WRITE_BACK | Permissions;
75 case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK:
76 case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK_RO:
77 case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK_XP:
78 return TT_ATTR_INDX_MEMORY_WRITE_BACK | TT_SH_INNER_SHAREABLE | Permissions;
80 case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH:
81 return TT_ATTR_INDX_MEMORY_WRITE_THROUGH | TT_SH_INNER_SHAREABLE;
84 case ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED:
85 return TT_ATTR_INDX_MEMORY_NON_CACHEABLE | Permissions;
89 case ARM_MEMORY_REGION_ATTRIBUTE_DEVICE:
90 return TT_ATTR_INDX_DEVICE_MEMORY | Permissions;
96#define BITS_PER_LEVEL 9
97#define MAX_VA_BITS_48 48
105 IN BOOLEAN Lpa2Enabled
109 *Entry &= ~(TT_ADDRESS_MASK_BLOCK_ENTRY_LPA2 | TT_UPPER_ADDRESS_MASK);
110 *Entry |= ((
UINTN)Address & TT_ADDRESS_MASK_BLOCK_ENTRY_LPA2) | (((
UINTN)Address >> 50) << 8);
112 *Entry &= ~TT_ADDRESS_MASK_BLOCK_ENTRY;
113 *Entry |= (Address & TT_ADDRESS_MASK_BLOCK_ENTRY);
121 IN BOOLEAN Lpa2Enabled
125 return (Entry & TT_ADDRESS_MASK_BLOCK_ENTRY_LPA2) | ((Entry & TT_UPPER_ADDRESS_MASK) << (50 - 8));
127 return Entry & TT_ADDRESS_MASK_BLOCK_ENTRY;
133GetRootTableEntryCount (
137 return TT_ENTRY_COUNT >> (T0SZ - MIN_T0SZ) % BITS_PER_LEVEL;
148 RootTableLevel = (T0SZ < MIN_T0SZ) ? -1 : (
INTN)(T0SZ - MIN_T0SZ) / BITS_PER_LEVEL;
151 return RootTableLevel;
159 IN UINT64 RegionStart,
161 IN BOOLEAN IsLiveBlockMapping
175 if (!IsLiveBlockMapping || !ArmMmuEnabled ()) {
179 ArmUpdateTranslationTableEntry (Entry, (
VOID *)(
UINTN)RegionStart);
186 if ((((RegionStart ^ (
UINTN)mReplaceLiveEntryFunc) & ~BlockMask) == 0) ||
187 (((RegionStart ^ (
UINTN)Entry) & ~BlockMask) == 0))
190 DEBUG ((DEBUG_WARN,
"%a: splitting block entry with MMU disabled\n", __func__));
193 mReplaceLiveEntryFunc (Entry, Value, RegionStart, DisableMmu);
199FreePageTablesRecursive (
200 IN UINT64 *TranslationTable,
202 IN BOOLEAN Lpa2Enabled
210 for (Index = 0; Index < TT_ENTRY_COUNT; Index++) {
211 if ((TranslationTable[Index] & TT_TYPE_MASK) == TT_TYPE_TABLE_ENTRY) {
212 FreePageTablesRecursive (
213 (
VOID *)GetOutputAddress (
214 TranslationTable[Index],
235 return (Entry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY_LEVEL3;
238 return (Entry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY;
256 return (Entry & TT_TYPE_MASK) == TT_TYPE_TABLE_ENTRY;
261UpdateRegionMappingRecursive (
262 IN UINT64 RegionStart,
264 IN UINT64 AttributeSetMask,
265 IN UINT64 AttributeClearMask,
266 IN UINT64 *PageTable,
268 IN BOOLEAN IsRootTable,
269 IN BOOLEAN TableIsLive,
270 IN BOOLEAN Lpa2Enabled
278 VOID *TranslationTable;
280 BOOLEAN NextTableIsLive;
282 ASSERT (((RegionStart | RegionEnd) & EFI_PAGE_MASK) == 0);
284 BlockShift = (Level + 1) * BITS_PER_LEVEL + MIN_T0SZ;
285 BlockMask = MAX_UINT64 >> BlockShift;
289 "%a(%d): %llx - %llx set %lx clr %lx\n",
298 for ( ; RegionStart < RegionEnd; RegionStart = BlockEnd) {
299 BlockEnd =
MIN (RegionEnd, (RegionStart | BlockMask) + 1);
300 Entry = &PageTable[(RegionStart >> (64 - BlockShift)) & (TT_ENTRY_COUNT - 1)];
315 if ((Level <= 0) || (((RegionStart | BlockEnd) & BlockMask) != 0) ||
316 ((Level < 3) && (((UINT64)PageTable & ~BlockMask) == RegionStart)) ||
317 IsTableEntry (*Entry, Level))
321 if (!IsTableEntry (*Entry, Level)) {
326 if (IsBlockEntry (*Entry, Level) &&
327 ((*Entry & TT_ATTRIBUTES_MASK & ~AttributeClearMask) == AttributeSetMask))
337 if (TranslationTable ==
NULL) {
338 return EFI_OUT_OF_RESOURCES;
341 if (!ArmMmuEnabled ()) {
349 ZeroMem (TranslationTable, EFI_PAGE_SIZE);
351 if (IsBlockEntry (*Entry, Level)) {
356 Status = UpdateRegionMappingRecursive (
357 RegionStart & ~BlockMask,
358 (RegionStart | BlockMask) + 1,
359 *Entry & TT_ATTRIBUTES_MASK,
367 if (EFI_ERROR (Status)) {
378 NextTableIsLive =
FALSE;
380 TranslationTable = (
VOID *)GetOutputAddress (*Entry, Lpa2Enabled);
381 NextTableIsLive = TableIsLive;
387 Status = UpdateRegionMappingRecursive (
398 if (EFI_ERROR (Status)) {
399 if (!IsTableEntry (*Entry, Level)) {
407 FreePageTablesRecursive (TranslationTable, Level + 1, Lpa2Enabled);
413 if (!IsTableEntry (*Entry, Level)) {
414 EntryValue = TT_TYPE_TABLE_ENTRY;
415 SetOutputAddress (&EntryValue, (
UINTN)TranslationTable, Lpa2Enabled);
422 TableIsLive && IsBlockEntry (*Entry, Level)
426 EntryValue = (*Entry & AttributeClearMask) | AttributeSetMask;
428 SetOutputAddress (&EntryValue, RegionStart, Lpa2Enabled);
429 EntryValue |= (Level == 3) ? TT_TYPE_BLOCK_ENTRY_LEVEL3
430 : TT_TYPE_BLOCK_ENTRY;
432 ReplaceTableEntry (Entry, EntryValue, RegionStart, BlockMask,
FALSE);
442 IN UINT64 RegionStart,
443 IN UINT64 RegionLength,
444 IN UINT64 AttributeSetMask,
445 IN UINT64 AttributeClearMask,
446 IN UINT64 *RootTable,
447 IN BOOLEAN TableIsLive,
448 IN BOOLEAN Lpa2Enabled
453 if (((RegionStart | RegionLength) & EFI_PAGE_MASK) != 0) {
456 "%a RegionStart: 0x%llx or RegionLength: 0x%llx are not page aligned!\n",
461 return EFI_INVALID_PARAMETER;
464 T0SZ = ArmGetTCR () & TCR_T0SZ_MASK;
466 return UpdateRegionMappingRecursive (
468 RegionStart + RegionLength,
472 GetRootTableLevel (T0SZ),
481FillTranslationTable (
482 IN UINT64 *RootTable,
484 IN BOOLEAN Lpa2Enabled
487 return UpdateRegionMapping (
488 MemoryRegion->VirtualBase,
489 MemoryRegion->Length,
490 ArmMemoryAttributeToPageAttribute (MemoryRegion->Attributes) | TT_AF,
500GcdAttributeToPageAttribute (
501 IN UINT64 GcdAttributes
504 UINT64 PageAttributes;
506 switch (GcdAttributes & EFI_MEMORY_CACHETYPE_MASK) {
508 PageAttributes = TT_ATTR_INDX_DEVICE_MEMORY;
511 PageAttributes = TT_ATTR_INDX_MEMORY_NON_CACHEABLE;
514 PageAttributes = TT_ATTR_INDX_MEMORY_WRITE_THROUGH | TT_SH_INNER_SHAREABLE;
517 PageAttributes = TT_ATTR_INDX_MEMORY_WRITE_BACK | TT_SH_INNER_SHAREABLE;
520 PageAttributes = TT_ATTR_INDX_MASK;
524 if (((GcdAttributes & EFI_MEMORY_XP) != 0) ||
525 ((GcdAttributes & EFI_MEMORY_CACHETYPE_MASK) == EFI_MEMORY_UC))
528 PageAttributes |= TT_XN_MASK;
530 PageAttributes |= TT_UXN_MASK | TT_PXN_MASK;
534 if ((GcdAttributes & EFI_MEMORY_RO) != 0) {
535 PageAttributes |= TT_AP_NO_RO;
538 if ((GcdAttributes & EFI_MEMORY_RP) == 0) {
539 PageAttributes |= TT_AF;
542 return PageAttributes;
582 IN UINT64 Attributes,
583 IN UINT64 AttributeMask
586 UINT64 PageAttributes;
587 UINT64 PageAttributeMask;
589 PageAttributes = GcdAttributeToPageAttribute (Attributes);
590 PageAttributeMask = 0;
592 if ((Attributes & EFI_MEMORY_CACHETYPE_MASK) == 0) {
597 PageAttributes &= TT_AP_MASK | TT_UXN_MASK | TT_PXN_MASK | TT_AF;
598 PageAttributeMask = ~(TT_ADDRESS_MASK_BLOCK_ENTRY | TT_AP_MASK |
599 TT_PXN_MASK | TT_XN_MASK | TT_AF);
600 if (AttributeMask != 0) {
601 if (((AttributeMask & ~(UINT64)(EFI_MEMORY_RP|EFI_MEMORY_RO|EFI_MEMORY_XP)) != 0) ||
602 ((Attributes & ~AttributeMask) != 0))
604 return EFI_INVALID_PARAMETER;
608 PageAttributeMask |= GcdAttributeToPageAttribute (~AttributeMask) &
609 (TT_AP_MASK | TT_UXN_MASK | TT_PXN_MASK | TT_AF);
612 ASSERT (AttributeMask == 0);
613 if (AttributeMask != 0) {
614 return EFI_INVALID_PARAMETER;
618 return UpdateRegionMapping (
623 ArmGetTTBR0BaseAddress (),
633 OUT VOID **TranslationTableBase OPTIONAL,
634 OUT UINTN *TranslationTableSize OPTIONAL
637 VOID *TranslationTable;
638 UINTN MaxAddressBits;
641 UINTN RootTableEntryCount;
645 ASSERT (ArmReadCurrentEL () < AARCH64_EL3);
646 if (ArmReadCurrentEL () == AARCH64_EL3) {
647 return EFI_UNSUPPORTED;
650 if (MemoryTable ==
NULL) {
651 ASSERT (MemoryTable !=
NULL);
652 return EFI_INVALID_PARAMETER;
663 MaxAddressBits =
MIN (ArmGetPhysicalAddressBits (), MAX_VA_BITS);
665 MaxAddressBits =
MIN (ArmGetPhysicalAddressBits (), MAX_VA_BITS_48);
668 MaxAddress =
LShiftU64 (1ULL, MaxAddressBits) - 1;
670 T0SZ = 64 - MaxAddressBits;
671 RootTableEntryCount = GetRootTableEntryCount (T0SZ);
678 TCR = T0SZ | (1UL << 31) | (1UL << 23) | TCR_TG0_4KB;
681 if (MaxAddress < SIZE_4GB) {
683 }
else if (MaxAddress < SIZE_64GB) {
685 }
else if (MaxAddress < SIZE_1TB) {
687 }
else if (MaxAddress < SIZE_4TB) {
689 }
else if (MaxAddress < SIZE_16TB) {
691 }
else if (MaxAddress < SIZE_256TB) {
694 TCR |= TCR_PS_4PB | TCR_DS_NVHE;
698 "ArmConfigureMmu: The MaxAddress 0x%lX is not supported by this MMU configuration.\n",
702 return EFI_UNSUPPORTED;
706 TCR = T0SZ | TCR_TG0_4KB | TCR_TG1_4KB | TCR_EPD1;
709 if (MaxAddress < SIZE_4GB) {
711 }
else if (MaxAddress < SIZE_64GB) {
713 }
else if (MaxAddress < SIZE_1TB) {
715 }
else if (MaxAddress < SIZE_4TB) {
717 }
else if (MaxAddress < SIZE_16TB) {
719 }
else if (MaxAddress < SIZE_256TB) {
720 TCR |= TCR_IPS_256TB;
722 TCR |= TCR_IPS_4PB | TCR_DS;
726 "ArmConfigureMmu: The MaxAddress 0x%lX is not supported by this MMU configuration.\n",
730 return EFI_UNSUPPORTED;
743 TCR |= TCR_SH_INNER_SHAREABLE |
744 TCR_RGN_OUTER_WRITE_BACK_ALLOC |
745 TCR_RGN_INNER_WRITE_BACK_ALLOC;
752 if (TranslationTable ==
NULL) {
753 return EFI_OUT_OF_RESOURCES;
756 if (TranslationTableBase !=
NULL) {
757 *TranslationTableBase = TranslationTable;
760 if (TranslationTableSize !=
NULL) {
761 *TranslationTableSize = RootTableEntryCount *
sizeof (UINT64);
764 if (!ArmMmuEnabled ()) {
771 RootTableEntryCount *
sizeof (UINT64)
775 ZeroMem (TranslationTable, RootTableEntryCount *
sizeof (UINT64));
777 while (MemoryTable->Length != 0) {
778 Status = FillTranslationTable (TranslationTable, MemoryTable,
ArmLpa2Enabled ());
779 if (EFI_ERROR (Status)) {
780 goto FreeTranslationTable;
793 MAIR_ATTR (TT_ATTR_INDX_DEVICE_MEMORY, MAIR_ATTR_DEVICE_MEMORY) |
794 MAIR_ATTR (TT_ATTR_INDX_MEMORY_NON_CACHEABLE, MAIR_ATTR_NORMAL_MEMORY_NON_CACHEABLE) |
795 MAIR_ATTR (TT_ATTR_INDX_MEMORY_WRITE_THROUGH, MAIR_ATTR_NORMAL_MEMORY_WRITE_THROUGH) |
796 MAIR_ATTR (TT_ATTR_INDX_MEMORY_WRITE_BACK, MAIR_ATTR_NORMAL_MEMORY_WRITE_BACK)
799 if ((TCR & TCR_IPS_MASK) == TCR_IPS_4PB) {
802 (((
UINTN)TranslationTable & 0xffffffffffc0) |
803 (((
UINTN)TranslationTable >> 48) << 2))
806 ArmSetTTBR0 (TranslationTable);
809 if (!ArmMmuEnabled ()) {
810 ArmDisableAlignmentCheck ();
811 ArmEnableStackAlignmentCheck ();
812 ArmEnableInstructionCache ();
813 ArmEnableDataCache ();
842 ((TCR & TCR_DS_NVHE) != 0) :
843 ((TCR & TCR_DS) != 0);
848ArmMmuBaseLibConstructor (
852 extern UINT32 ArmReplaceLiveTranslationEntrySize;
857 mReplaceLiveEntryFunc = *(ARM_REPLACE_LIVE_TRANSLATION_ENTRY *)GET_GUID_HOB_DATA (Hob);
864 (
VOID *)(
UINTN)ArmReplaceLiveTranslationEntry,
865 ArmReplaceLiveTranslationEntrySize
BOOLEAN EFIAPI ArmHas52BitTgran4(VOID)
VOID *EFIAPI WriteBackDataCacheRange(IN VOID *Address, IN UINTN Length)
VOID *EFIAPI InvalidateDataCacheRange(IN VOID *Address, IN UINTN Length)
BOOLEAN ArmLpa2Enabled(VOID)
EFI_STATUS ArmSetMemoryAttributes(IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length, IN UINT64 Attributes, IN UINT64 AttributeMask)
STATIC BOOLEAN TranslationRegimeIsDual(VOID)
VOID *EFIAPI GetFirstGuidHob(IN CONST EFI_GUID *Guid)
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID EFIAPI FreePages(IN VOID *Buffer, IN UINTN Pages)
#define DEBUG(Expression)
VOID *EFIAPI AllocatePages(IN UINTN Pages)
UINT64 EFI_PHYSICAL_ADDRESS