/** @file\r
* File managing the MMU for ARMv8 architecture\r
*\r
-* Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
+* Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
*\r
* This program and the accompanying materials\r
* are licensed and made available under the terms and conditions of the BSD License\r
{\r
switch (Attributes) {\r
case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK:\r
- return TT_ATTR_INDX_MEMORY_WRITE_BACK;\r
- case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH:\r
- return TT_ATTR_INDX_MEMORY_WRITE_THROUGH;\r
- case ARM_MEMORY_REGION_ATTRIBUTE_DEVICE:\r
- return TT_ATTR_INDX_DEVICE_MEMORY;\r
- case ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED:\r
- return TT_ATTR_INDX_MEMORY_NON_CACHEABLE;\r
case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK:\r
- return TT_ATTR_INDX_MEMORY_WRITE_BACK;\r
+ return TT_ATTR_INDX_MEMORY_WRITE_BACK | TT_SH_INNER_SHAREABLE;\r
+\r
+ case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH:\r
case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_THROUGH:\r
- return TT_ATTR_INDX_MEMORY_WRITE_THROUGH;\r
- case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_DEVICE:\r
- return TT_ATTR_INDX_DEVICE_MEMORY;\r
+ return TT_ATTR_INDX_MEMORY_WRITE_THROUGH | TT_SH_INNER_SHAREABLE;\r
+\r
+ // Uncached and device mappings are treated as outer shareable by default,\r
+ case ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED:\r
case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_UNCACHED_UNBUFFERED:\r
return TT_ATTR_INDX_MEMORY_NON_CACHEABLE;\r
+\r
default:\r
ASSERT(0);\r
- return TT_ATTR_INDX_DEVICE_MEMORY;\r
+ case ARM_MEMORY_REGION_ATTRIBUTE_DEVICE:\r
+ case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_DEVICE:\r
+ if (ArmReadCurrentEL () == AARCH64_EL2)\r
+ return TT_ATTR_INDX_DEVICE_MEMORY | TT_TABLE_XN;\r
+ else\r
+ return TT_ATTR_INDX_DEVICE_MEMORY | TT_TABLE_UXN | TT_TABLE_PXN;\r
}\r
}\r
\r
return GcdAttributes;\r
}\r
\r
-UINT64\r
-GcdAttributeToPageAttribute (\r
- IN UINT64 GcdAttributes\r
- )\r
-{\r
- UINT64 PageAttributes;\r
-\r
- switch (GcdAttributes & 0xFF) {\r
- case EFI_MEMORY_UC:\r
- PageAttributes = TT_ATTR_INDX_DEVICE_MEMORY;\r
- break;\r
- case EFI_MEMORY_WC:\r
- PageAttributes = TT_ATTR_INDX_MEMORY_NON_CACHEABLE;\r
- break;\r
- case EFI_MEMORY_WT:\r
- PageAttributes = TT_ATTR_INDX_MEMORY_WRITE_THROUGH;\r
- break;\r
- case EFI_MEMORY_WB:\r
- PageAttributes = TT_ATTR_INDX_MEMORY_WRITE_BACK;\r
- break;\r
- default:\r
- DEBUG ((EFI_D_ERROR, "GcdAttributeToPageAttribute: 0x%X attributes is not supported.\n", GcdAttributes));\r
- ASSERT (0);\r
- // If no match has been found then we mark the memory as device memory.\r
- // The only side effect of using device memory should be a slow down in the performance.\r
- PageAttributes = TT_ATTR_INDX_DEVICE_MEMORY;\r
- }\r
-\r
- // Determine protection attributes\r
- if (GcdAttributes & EFI_MEMORY_WP) {\r
- // Read only cases map to write-protect\r
- PageAttributes |= TT_AP_RO_RO;\r
- }\r
-\r
- // Process eXecute Never attribute\r
- if (GcdAttributes & EFI_MEMORY_XP) {\r
- PageAttributes |= (TT_PXN_MASK | TT_UXN_MASK);\r
- }\r
-\r
- return PageAttributes;\r
-}\r
-\r
ARM_MEMORY_REGION_ATTRIBUTES\r
GcdAttributeToArmAttribute (\r
IN UINT64 GcdAttributes\r
IN UINT64 RegionStart,\r
OUT UINTN *TableLevel,\r
IN OUT UINT64 *BlockEntrySize,\r
- IN OUT UINT64 **LastBlockEntry\r
+ OUT UINT64 **LastBlockEntry\r
)\r
{\r
UINTN RootTableLevel;\r
UINTN RootTableEntryCount;\r
UINT64 *TranslationTable;\r
UINT64 *BlockEntry;\r
+ UINT64 *SubTableBlockEntry;\r
UINT64 BlockEntryAddress;\r
UINTN BaseAddressAlignment;\r
UINTN PageLevel;\r
BlockEntry = NULL;\r
\r
// Ensure the parameters are valid\r
- ASSERT (TableLevel && BlockEntrySize && LastBlockEntry);\r
+ if (!(TableLevel && BlockEntrySize && LastBlockEntry)) {\r
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);\r
+ return NULL;\r
+ }\r
\r
// Ensure the Region is aligned on 4KB boundary\r
- ASSERT ((RegionStart & (SIZE_4KB - 1)) == 0);\r
+ if ((RegionStart & (SIZE_4KB - 1)) != 0) {\r
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);\r
+ return NULL;\r
+ }\r
\r
- // Ensure the required size is aligned on 4KB boundary\r
- ASSERT ((*BlockEntrySize & (SIZE_4KB - 1)) == 0);\r
+ // Ensure the required size is aligned on 4KB boundary and not 0\r
+ if ((*BlockEntrySize & (SIZE_4KB - 1)) != 0 || *BlockEntrySize == 0) {\r
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);\r
+ return NULL;\r
+ }\r
\r
- //\r
- // Calculate LastBlockEntry from T0SZ - this is the last block entry of the root Translation table\r
- //\r
T0SZ = ArmGetTCR () & TCR_T0SZ_MASK;\r
// Get the Table info from T0SZ\r
GetRootTranslationTableInfo (T0SZ, &RootTableLevel, &RootTableEntryCount);\r
- // The last block of the root table depends on the number of entry in this table\r
- *LastBlockEntry = (UINT64*)((UINTN)RootTable + ((RootTableEntryCount - 1) * sizeof(UINT64)));\r
\r
// If the start address is 0x0 then we use the size of the region to identify the alignment\r
if (RegionStart == 0) {\r
// Identify the highest possible alignment for the Region Size\r
- for (BaseAddressAlignment = 0; BaseAddressAlignment < 64; BaseAddressAlignment++) {\r
- if ((1 << BaseAddressAlignment) & *BlockEntrySize) {\r
- break;\r
- }\r
- }\r
+ BaseAddressAlignment = LowBitSet64 (*BlockEntrySize);\r
} else {\r
// Identify the highest possible alignment for the Base Address\r
- for (BaseAddressAlignment = 0; BaseAddressAlignment < 64; BaseAddressAlignment++) {\r
- if ((1 << BaseAddressAlignment) & RegionStart) {\r
- break;\r
- }\r
- }\r
+ BaseAddressAlignment = LowBitSet64 (RegionStart);\r
}\r
\r
- // Identify the Page Level the RegionStart must belongs to\r
- PageLevel = 3 - ((BaseAddressAlignment - 12) / 9);\r
+ // Identify the Page Level the RegionStart must belong to. Note that PageLevel\r
+ // should be at least 1 since block translations are not supported at level 0\r
+ PageLevel = MAX (3 - ((BaseAddressAlignment - 12) / 9), 1);\r
\r
- // If the required size is smaller than the current block size then we need to go to the page bellow.\r
- if (*BlockEntrySize < TT_ADDRESS_AT_LEVEL(PageLevel)) {\r
+ // If the required size is smaller than the current block size then we need to go to the page below.\r
+ // The PageLevel was calculated on the Base Address alignment but did not take in account the alignment\r
+ // of the allocation size\r
+ while (*BlockEntrySize < TT_BLOCK_ENTRY_SIZE_AT_LEVEL (PageLevel)) {\r
// It does not fit so we need to go a page level above\r
PageLevel++;\r
}\r
\r
- // Expose the found PageLevel to the caller\r
- *TableLevel = PageLevel;\r
-\r
- // Now, we have the Table Level we can get the Block Size associated to this table\r
- *BlockEntrySize = TT_ADDRESS_AT_LEVEL(PageLevel);\r
-\r
//\r
// Get the Table Descriptor for the corresponding PageLevel. We need to decompose RegionStart to get appropriate entries\r
//\r
// Go to the next table\r
TranslationTable = (UINT64*)(*BlockEntry & TT_ADDRESS_MASK_DESCRIPTION_TABLE);\r
\r
- // If we are at the last level then update the output\r
+ // If we are at the last level then update the last level to next level\r
if (IndexLevel == PageLevel) {\r
- // And get the appropriate BlockEntry at the next level\r
- BlockEntry = (UINT64*)TT_GET_ENTRY_FOR_ADDRESS (TranslationTable, IndexLevel + 1, RegionStart);\r
-\r
- // Set the last block for this new table\r
- *LastBlockEntry = (UINT64*)((UINTN)TranslationTable + ((TT_ENTRY_COUNT - 1) * sizeof(UINT64)));\r
+ // Enter the next level\r
+ PageLevel++;\r
}\r
} else if ((*BlockEntry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY) {\r
// If we are not at the last level then we need to split this BlockEntry\r
if (Attributes & TT_PXN_MASK) {\r
TableAttributes = TT_TABLE_PXN;\r
}\r
- if (Attributes & TT_UXN_MASK) {\r
+ // XN maps to UXN in the EL1&0 translation regime\r
+ if (Attributes & TT_XN_MASK) {\r
TableAttributes = TT_TABLE_XN;\r
}\r
if (Attributes & TT_NS) {\r
// Shift back to right to set zero before the effective address\r
BlockEntryAddress = BlockEntryAddress << TT_ADDRESS_OFFSET_AT_LEVEL(IndexLevel);\r
\r
- // Set the correct entry type\r
- if (IndexLevel + 1 == 3) {\r
+ // Set the correct entry type for the next page level\r
+ if ((IndexLevel + 1) == 3) {\r
Attributes |= TT_TYPE_BLOCK_ENTRY_LEVEL3;\r
} else {\r
Attributes |= TT_TYPE_BLOCK_ENTRY;\r
}\r
\r
// Create a new translation table\r
- TranslationTable = (UINT64*)AllocatePages (EFI_SIZE_TO_PAGES((TT_ENTRY_COUNT * sizeof(UINT64)) + TT_ALIGNMENT_DESCRIPTION_TABLE));\r
+ TranslationTable = (UINT64*)AllocateAlignedPages (EFI_SIZE_TO_PAGES(TT_ENTRY_COUNT * sizeof(UINT64)), TT_ALIGNMENT_DESCRIPTION_TABLE);\r
if (TranslationTable == NULL) {\r
return NULL;\r
}\r
- TranslationTable = (UINT64*)((UINTN)TranslationTable & TT_ADDRESS_MASK_DESCRIPTION_TABLE);\r
-\r
- // Fill the new BlockEntry with the TranslationTable\r
- *BlockEntry = ((UINTN)TranslationTable & TT_ADDRESS_MASK_DESCRIPTION_TABLE) | TableAttributes | TT_TYPE_TABLE_ENTRY;\r
- // Update the last block entry with the newly created translation table\r
- *LastBlockEntry = (UINT64*)((UINTN)TranslationTable + ((TT_ENTRY_COUNT - 1) * sizeof(UINT64)));\r
\r
// Populate the newly created lower level table\r
- BlockEntry = TranslationTable;\r
+ SubTableBlockEntry = TranslationTable;\r
for (Index = 0; Index < TT_ENTRY_COUNT; Index++) {\r
- *BlockEntry = Attributes | (BlockEntryAddress + (Index << TT_ADDRESS_OFFSET_AT_LEVEL(IndexLevel + 1)));\r
- BlockEntry++;\r
+ *SubTableBlockEntry = Attributes | (BlockEntryAddress + (Index << TT_ADDRESS_OFFSET_AT_LEVEL(IndexLevel + 1)));\r
+ SubTableBlockEntry++;\r
}\r
- // Block Entry points at the beginning of the Translation Table\r
- BlockEntry = TranslationTable;\r
+\r
+ // Fill the BlockEntry with the new TranslationTable\r
+ *BlockEntry = ((UINTN)TranslationTable & TT_ADDRESS_MASK_DESCRIPTION_TABLE) | TableAttributes | TT_TYPE_TABLE_ENTRY;\r
}\r
} else {\r
- // Case of Invalid Entry and we are at a page level above of the one targetted.\r
if (IndexLevel != PageLevel) {\r
+ //\r
+ // Case when we have an Invalid Entry and we are at a page level above of the one targetted.\r
+ //\r
+\r
// Create a new translation table\r
- TranslationTable = (UINT64*)AllocatePages (EFI_SIZE_TO_PAGES((TT_ENTRY_COUNT * sizeof(UINT64)) + TT_ALIGNMENT_DESCRIPTION_TABLE));\r
+ TranslationTable = (UINT64*)AllocateAlignedPages (EFI_SIZE_TO_PAGES(TT_ENTRY_COUNT * sizeof(UINT64)), TT_ALIGNMENT_DESCRIPTION_TABLE);\r
if (TranslationTable == NULL) {\r
return NULL;\r
}\r
- TranslationTable = (UINT64*)((UINTN)TranslationTable & TT_ADDRESS_MASK_DESCRIPTION_TABLE);\r
\r
ZeroMem (TranslationTable, TT_ENTRY_COUNT * sizeof(UINT64));\r
\r
}\r
}\r
\r
+ // Expose the found PageLevel to the caller\r
+ *TableLevel = PageLevel;\r
+\r
+ // Now, we have the Table Level we can get the Block Size associated to this table\r
+ *BlockEntrySize = TT_BLOCK_ENTRY_SIZE_AT_LEVEL (PageLevel);\r
+\r
+ // The last block of the root table depends on the number of entry in this table,\r
+ // otherwise it is always the (TT_ENTRY_COUNT - 1)th entry in the table.\r
+ *LastBlockEntry = TT_LAST_BLOCK_ADDRESS(TranslationTable,\r
+ (PageLevel == RootTableLevel) ? RootTableEntryCount : TT_ENTRY_COUNT);\r
+\r
return BlockEntry;\r
}\r
\r
STATIC\r
RETURN_STATUS\r
-FillTranslationTable (\r
- IN UINT64 *RootTable,\r
- IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryRegion\r
+UpdateRegionMapping (\r
+ IN UINT64 *RootTable,\r
+ IN UINT64 RegionStart,\r
+ IN UINT64 RegionLength,\r
+ IN UINT64 Attributes,\r
+ IN UINT64 BlockEntryMask\r
)\r
{\r
- UINT64 Attributes;\r
UINT32 Type;\r
- UINT64 RegionStart;\r
- UINT64 RemainingRegionLength;\r
- UINT64 *BlockEntry;\r
- UINT64 *LastBlockEntry;\r
+ UINT64 *BlockEntry;\r
+ UINT64 *LastBlockEntry;\r
UINT64 BlockEntrySize;\r
UINTN TableLevel;\r
\r
// Ensure the Length is aligned on 4KB boundary\r
- ASSERT ((MemoryRegion->Length > 0) && ((MemoryRegion->Length & (SIZE_4KB - 1)) == 0));\r
-\r
- // Variable initialization\r
- Attributes = ArmMemoryAttributeToPageAttribute (MemoryRegion->Attributes) | TT_AF;\r
- RemainingRegionLength = MemoryRegion->Length;\r
- RegionStart = MemoryRegion->VirtualBase;\r
+ if ((RegionLength == 0) || ((RegionLength & (SIZE_4KB - 1)) != 0)) {\r
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);\r
+ return RETURN_INVALID_PARAMETER;\r
+ }\r
\r
do {\r
// Get the first Block Entry that matches the Virtual Address and also the information on the Table Descriptor\r
// such as the the size of the Block Entry and the address of the last BlockEntry of the Table Descriptor\r
- BlockEntrySize = RemainingRegionLength;\r
+ BlockEntrySize = RegionLength;\r
BlockEntry = GetBlockEntryListFromAddress (RootTable, RegionStart, &TableLevel, &BlockEntrySize, &LastBlockEntry);\r
if (BlockEntry == NULL) {\r
// GetBlockEntryListFromAddress() return NULL when it fails to allocate new pages from the Translation Tables\r
\r
do {\r
// Fill the Block Entry with attribute and output block address\r
- *BlockEntry = (RegionStart & TT_ADDRESS_MASK_BLOCK_ENTRY) | Attributes | Type;\r
+ *BlockEntry &= BlockEntryMask;\r
+ *BlockEntry |= (RegionStart & TT_ADDRESS_MASK_BLOCK_ENTRY) | Attributes | Type;\r
\r
// Go to the next BlockEntry\r
RegionStart += BlockEntrySize;\r
- RemainingRegionLength -= BlockEntrySize;\r
+ RegionLength -= BlockEntrySize;\r
BlockEntry++;\r
- } while ((RemainingRegionLength >= BlockEntrySize) && (BlockEntry <= LastBlockEntry));\r
- } while (RemainingRegionLength != 0);\r
+\r
+ // Break the inner loop when next block is a table\r
+ // Rerun GetBlockEntryListFromAddress to avoid page table memory leak\r
+ if (TableLevel != 3 &&\r
+ (*BlockEntry & TT_TYPE_MASK) == TT_TYPE_TABLE_ENTRY) {\r
+ break;\r
+ }\r
+ } while ((RegionLength >= BlockEntrySize) && (BlockEntry <= LastBlockEntry));\r
+ } while (RegionLength != 0);\r
\r
return RETURN_SUCCESS;\r
}\r
\r
+STATIC\r
+RETURN_STATUS\r
+FillTranslationTable (\r
+ IN UINT64 *RootTable,\r
+ IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryRegion\r
+ )\r
+{\r
+ return UpdateRegionMapping (\r
+ RootTable,\r
+ MemoryRegion->VirtualBase,\r
+ MemoryRegion->Length,\r
+ ArmMemoryAttributeToPageAttribute (MemoryRegion->Attributes) | TT_AF,\r
+ 0\r
+ );\r
+}\r
+\r
RETURN_STATUS\r
SetMemoryAttributes (\r
IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
IN UINT64 Attributes,\r
IN EFI_PHYSICAL_ADDRESS VirtualMask\r
)\r
-{
+{\r
RETURN_STATUS Status;\r
ARM_MEMORY_REGION_DESCRIPTOR MemoryRegion;\r
UINT64 *TranslationTable;\r
\r
TranslationTable = ArmGetTTBR0BaseAddress ();\r
\r
- Status = FillTranslationTable (TranslationTable, &MemoryRegion);
- if (RETURN_ERROR (Status)) {
- return Status;
+ Status = FillTranslationTable (TranslationTable, &MemoryRegion);\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
}\r
\r
- // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks\r
- // flush and invalidate pages\r
- ArmCleanInvalidateDataCache ();\r
+ // Invalidate all TLB entries so changes are synced\r
+ ArmInvalidateTlb ();\r
\r
- ArmInvalidateInstructionCache ();\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+STATIC\r
+RETURN_STATUS\r
+SetMemoryRegionAttribute (\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN UINT64 Attributes,\r
+ IN UINT64 BlockEntryMask\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ UINT64 *RootTable;\r
+\r
+ RootTable = ArmGetTTBR0BaseAddress ();\r
+\r
+ Status = UpdateRegionMapping (RootTable, BaseAddress, Length, Attributes, BlockEntryMask);\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
\r
// Invalidate all TLB entries so changes are synced\r
ArmInvalidateTlb ();\r
return RETURN_SUCCESS;\r
}\r
\r
+RETURN_STATUS\r
+ArmSetMemoryRegionNoExec (\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length\r
+ )\r
+{\r
+ UINT64 Val;\r
+\r
+ if (ArmReadCurrentEL () == AARCH64_EL1) {\r
+ Val = TT_PXN_MASK | TT_UXN_MASK;\r
+ } else {\r
+ Val = TT_XN_MASK;\r
+ }\r
+\r
+ return SetMemoryRegionAttribute (\r
+ BaseAddress,\r
+ Length,\r
+ Val,\r
+ ~TT_ADDRESS_MASK_BLOCK_ENTRY);\r
+}\r
+\r
+RETURN_STATUS\r
+ArmClearMemoryRegionNoExec (\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length\r
+ )\r
+{\r
+ UINT64 Mask;\r
+\r
+ // XN maps to UXN in the EL1&0 translation regime\r
+ Mask = ~(TT_ADDRESS_MASK_BLOCK_ENTRY | TT_PXN_MASK | TT_XN_MASK);\r
+\r
+ return SetMemoryRegionAttribute (\r
+ BaseAddress,\r
+ Length,\r
+ 0,\r
+ Mask);\r
+}\r
+\r
+RETURN_STATUS\r
+ArmSetMemoryRegionReadOnly (\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length\r
+ )\r
+{\r
+ return SetMemoryRegionAttribute (\r
+ BaseAddress,\r
+ Length,\r
+ TT_AP_RO_RO,\r
+ ~TT_ADDRESS_MASK_BLOCK_ENTRY);\r
+}\r
+\r
+RETURN_STATUS\r
+ArmClearMemoryRegionReadOnly (\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length\r
+ )\r
+{\r
+ return SetMemoryRegionAttribute (\r
+ BaseAddress,\r
+ Length,\r
+ TT_AP_NO_RO,\r
+ ~(TT_ADDRESS_MASK_BLOCK_ENTRY | TT_AP_MASK));\r
+}\r
+\r
RETURN_STATUS\r
EFIAPI\r
ArmConfigureMmu (\r
UINT64 TCR;\r
RETURN_STATUS Status;\r
\r
- ASSERT (MemoryTable != NULL);\r
+ if(MemoryTable == NULL) {\r
+ ASSERT (MemoryTable != NULL);\r
+ return RETURN_INVALID_PARAMETER;\r
+ }\r
\r
// Identify the highest address of the memory table\r
MaxAddress = MemoryTable->PhysicalBase + MemoryTable->Length - 1;\r
//\r
// Set TCR that allows us to retrieve T0SZ in the subsequent functions\r
//\r
- if ((ArmReadCurrentEL () == AARCH64_EL2) || (ArmReadCurrentEL () == AARCH64_EL3)) {\r
- //Note: Bits 23 and 31 are reserved bits in TCR_EL2 and TCR_EL3\r
+ // Ideally we will be running at EL2, but should support EL1 as well.\r
+ // UEFI should not run at EL3.\r
+ if (ArmReadCurrentEL () == AARCH64_EL2) {\r
+ //Note: Bits 23 and 31 are reserved(RES1) bits in TCR_EL2\r
TCR = T0SZ | (1UL << 31) | (1UL << 23) | TCR_TG0_4KB;\r
\r
// Set the Physical Address Size using MaxAddress\r
} else if (MaxAddress < SIZE_256TB) {\r
TCR |= TCR_PS_256TB;\r
} else {\r
- DEBUG ((EFI_D_ERROR, "ArmConfigureMmu: The MaxAddress 0x%lX is not supported by this MMU support.\n", MaxAddress));\r
+ DEBUG ((EFI_D_ERROR, "ArmConfigureMmu: The MaxAddress 0x%lX is not supported by this MMU configuration.\n", MaxAddress));\r
+ ASSERT (0); // Bigger than 48-bit memory space are not supported\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+ } else if (ArmReadCurrentEL () == AARCH64_EL1) {\r
+ // Due to Cortex-A57 erratum #822227 we must set TG1[1] == 1, regardless of EPD1.\r
+ TCR = T0SZ | TCR_TG0_4KB | TCR_TG1_4KB | TCR_EPD1;\r
+\r
+ // Set the Physical Address Size using MaxAddress\r
+ if (MaxAddress < SIZE_4GB) {\r
+ TCR |= TCR_IPS_4GB;\r
+ } else if (MaxAddress < SIZE_64GB) {\r
+ TCR |= TCR_IPS_64GB;\r
+ } else if (MaxAddress < SIZE_1TB) {\r
+ TCR |= TCR_IPS_1TB;\r
+ } else if (MaxAddress < SIZE_4TB) {\r
+ TCR |= TCR_IPS_4TB;\r
+ } else if (MaxAddress < SIZE_16TB) {\r
+ TCR |= TCR_IPS_16TB;\r
+ } else if (MaxAddress < SIZE_256TB) {\r
+ TCR |= TCR_IPS_256TB;\r
+ } else {\r
+ DEBUG ((EFI_D_ERROR, "ArmConfigureMmu: The MaxAddress 0x%lX is not supported by this MMU configuration.\n", MaxAddress));\r
ASSERT (0); // Bigger than 48-bit memory space are not supported\r
return RETURN_UNSUPPORTED;\r
}\r
} else {\r
- ASSERT (0); // Bigger than 48-bit memory space are not supported\r
+ ASSERT (0); // UEFI is only expected to run at EL2 and EL1, not EL3.\r
return RETURN_UNSUPPORTED;\r
}\r
\r
ArmSetTCR (TCR);\r
\r
// Allocate pages for translation table\r
- TranslationTablePageCount = EFI_SIZE_TO_PAGES((RootTableEntryCount * sizeof(UINT64)) + TT_ALIGNMENT_DESCRIPTION_TABLE);\r
- TranslationTable = AllocatePages (TranslationTablePageCount);\r
+ TranslationTablePageCount = EFI_SIZE_TO_PAGES(RootTableEntryCount * sizeof(UINT64));\r
+ TranslationTable = (UINT64*)AllocateAlignedPages (TranslationTablePageCount, TT_ALIGNMENT_DESCRIPTION_TABLE);\r
if (TranslationTable == NULL) {\r
return RETURN_OUT_OF_RESOURCES;\r
}\r
- TranslationTable = (VOID*)((UINTN)TranslationTable & TT_ADDRESS_MASK_DESCRIPTION_TABLE);\r
// We set TTBR0 just after allocating the table to retrieve its location from the subsequent\r
// functions without needing to pass this value across the functions. The MMU is only enabled\r
// after the translation tables are populated.\r
goto FREE_TRANSLATION_TABLE;\r
}\r
\r
+ // Set again TCR after getting the Translation Table attributes\r
+ ArmSetTCR (TCR);\r
+\r
ArmSetMAIR (MAIR_ATTR(TT_ATTR_INDX_DEVICE_MEMORY, MAIR_ATTR_DEVICE_MEMORY) | // mapped to EFI_MEMORY_UC\r
MAIR_ATTR(TT_ATTR_INDX_MEMORY_NON_CACHEABLE, MAIR_ATTR_NORMAL_MEMORY_NON_CACHEABLE) | // mapped to EFI_MEMORY_WC\r
MAIR_ATTR(TT_ATTR_INDX_MEMORY_WRITE_THROUGH, MAIR_ATTR_NORMAL_MEMORY_WRITE_THROUGH) | // mapped to EFI_MEMORY_WT\r