summaryrefslogtreecommitdiffstats
path: root/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c')
-rw-r--r--ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c291
1 files changed, 161 insertions, 130 deletions
diff --git a/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c b/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c
index 838803aa9b..8997b7f61f 100644
--- a/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c
+++ b/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c
@@ -13,7 +13,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Library/MemoryAllocationLib.h>
#include "CpuDxe.h"
-#define INVALID_ENTRY ((UINT32)~0)
+#define INVALID_ENTRY ((UINT32)~0)
#define MIN_T0SZ 16
#define BITS_PER_LEVEL 9
@@ -21,49 +21,52 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
STATIC
VOID
GetRootTranslationTableInfo (
- IN UINTN T0SZ,
- OUT UINTN *RootTableLevel,
- OUT UINTN *RootTableEntryCount
+ IN UINTN T0SZ,
+ OUT UINTN *RootTableLevel,
+ OUT UINTN *RootTableEntryCount
)
{
- *RootTableLevel = (T0SZ - MIN_T0SZ) / BITS_PER_LEVEL;
- *RootTableEntryCount = TT_ENTRY_COUNT >> (T0SZ - MIN_T0SZ) % BITS_PER_LEVEL;
+ *RootTableLevel = (T0SZ - MIN_T0SZ) / BITS_PER_LEVEL;
+ *RootTableEntryCount = TT_ENTRY_COUNT >> (T0SZ - MIN_T0SZ) % BITS_PER_LEVEL;
}
STATIC
UINT64
PageAttributeToGcdAttribute (
- IN UINT64 PageAttributes
+ IN UINT64 PageAttributes
)
{
UINT64 GcdAttributes;
switch (PageAttributes & TT_ATTR_INDX_MASK) {
- case TT_ATTR_INDX_DEVICE_MEMORY:
- GcdAttributes = EFI_MEMORY_UC;
- break;
- case TT_ATTR_INDX_MEMORY_NON_CACHEABLE:
- GcdAttributes = EFI_MEMORY_WC;
- break;
- case TT_ATTR_INDX_MEMORY_WRITE_THROUGH:
- GcdAttributes = EFI_MEMORY_WT;
- break;
- case TT_ATTR_INDX_MEMORY_WRITE_BACK:
- GcdAttributes = EFI_MEMORY_WB;
- break;
- default:
- DEBUG ((DEBUG_ERROR,
- "PageAttributeToGcdAttribute: PageAttributes:0x%lX not supported.\n",
- PageAttributes));
- ASSERT (0);
- // The Global Coherency Domain (GCD) value is defined as a bit set.
- // Returning 0 means no attribute has been set.
- GcdAttributes = 0;
+ case TT_ATTR_INDX_DEVICE_MEMORY:
+ GcdAttributes = EFI_MEMORY_UC;
+ break;
+ case TT_ATTR_INDX_MEMORY_NON_CACHEABLE:
+ GcdAttributes = EFI_MEMORY_WC;
+ break;
+ case TT_ATTR_INDX_MEMORY_WRITE_THROUGH:
+ GcdAttributes = EFI_MEMORY_WT;
+ break;
+ case TT_ATTR_INDX_MEMORY_WRITE_BACK:
+ GcdAttributes = EFI_MEMORY_WB;
+ break;
+ default:
+ DEBUG ((
+ DEBUG_ERROR,
+ "PageAttributeToGcdAttribute: PageAttributes:0x%lX not supported.\n",
+ PageAttributes
+ ));
+ ASSERT (0);
+ // The Global Coherency Domain (GCD) value is defined as a bit set.
+ // Returning 0 means no attribute has been set.
+ GcdAttributes = 0;
}
// Determine protection attributes
if (((PageAttributes & TT_AP_MASK) == TT_AP_NO_RO) ||
- ((PageAttributes & TT_AP_MASK) == TT_AP_RO_RO)) {
+ ((PageAttributes & TT_AP_MASK) == TT_AP_RO_RO))
+ {
// Read only cases map to write-protect
GcdAttributes |= EFI_MEMORY_RO;
}
@@ -80,19 +83,19 @@ STATIC
UINT64
GetFirstPageAttribute (
IN UINT64 *FirstLevelTableAddress,
- IN UINTN TableLevel
+ IN UINTN TableLevel
)
{
- UINT64 FirstEntry;
+ UINT64 FirstEntry;
// Get the first entry of the table
FirstEntry = *FirstLevelTableAddress;
- if ((TableLevel != 3) && (FirstEntry & TT_TYPE_MASK) == TT_TYPE_TABLE_ENTRY) {
+ if ((TableLevel != 3) && ((FirstEntry & TT_TYPE_MASK) == TT_TYPE_TABLE_ENTRY)) {
// Only valid for Levels 0, 1 and 2
// Get the attribute of the subsequent table
- return GetFirstPageAttribute ((UINT64*)(FirstEntry & TT_ADDRESS_MASK_DESCRIPTION_TABLE), TableLevel + 1);
+ return GetFirstPageAttribute ((UINT64 *)(FirstEntry & TT_ADDRESS_MASK_DESCRIPTION_TABLE), TableLevel + 1);
} else if (((FirstEntry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY) ||
((TableLevel == 3) && ((FirstEntry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY_LEVEL3)))
{
@@ -105,25 +108,25 @@ GetFirstPageAttribute (
STATIC
UINT64
GetNextEntryAttribute (
- IN UINT64 *TableAddress,
+ IN UINT64 *TableAddress,
IN UINTN EntryCount,
IN UINTN TableLevel,
IN UINT64 BaseAddress,
- IN OUT UINT32 *PrevEntryAttribute,
- IN OUT UINT64 *StartGcdRegion
+ IN OUT UINT32 *PrevEntryAttribute,
+ IN OUT UINT64 *StartGcdRegion
)
{
- UINTN Index;
- UINT64 Entry;
- UINT32 EntryAttribute;
- UINT32 EntryType;
- EFI_STATUS Status;
- UINTN NumberOfDescriptors;
+ UINTN Index;
+ UINT64 Entry;
+ UINT32 EntryAttribute;
+ UINT32 EntryType;
+ EFI_STATUS Status;
+ UINTN NumberOfDescriptors;
EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
// Get the memory space map from GCD
MemorySpaceMap = NULL;
- Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
+ Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
ASSERT_EFI_ERROR (Status);
// We cannot get more than 3-level page table
@@ -132,24 +135,28 @@ GetNextEntryAttribute (
// While the top level table might not contain TT_ENTRY_COUNT entries;
// the subsequent ones should be filled up
for (Index = 0; Index < EntryCount; Index++) {
- Entry = TableAddress[Index];
- EntryType = Entry & TT_TYPE_MASK;
+ Entry = TableAddress[Index];
+ EntryType = Entry & TT_TYPE_MASK;
EntryAttribute = Entry & TT_ATTR_INDX_MASK;
// If Entry is a Table Descriptor type entry then go through the sub-level table
if ((EntryType == TT_TYPE_BLOCK_ENTRY) ||
- ((TableLevel == 3) && (EntryType == TT_TYPE_BLOCK_ENTRY_LEVEL3))) {
+ ((TableLevel == 3) && (EntryType == TT_TYPE_BLOCK_ENTRY_LEVEL3)))
+ {
if ((*PrevEntryAttribute == INVALID_ENTRY) || (EntryAttribute != *PrevEntryAttribute)) {
if (*PrevEntryAttribute != INVALID_ENTRY) {
// Update GCD with the last region
- SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors,
- *StartGcdRegion,
- (BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel))) - *StartGcdRegion,
- PageAttributeToGcdAttribute (*PrevEntryAttribute));
+ SetGcdMemorySpaceAttributes (
+ MemorySpaceMap,
+ NumberOfDescriptors,
+ *StartGcdRegion,
+ (BaseAddress + (Index * TT_ADDRESS_AT_LEVEL (TableLevel))) - *StartGcdRegion,
+ PageAttributeToGcdAttribute (*PrevEntryAttribute)
+ );
}
// Start of the new region
- *StartGcdRegion = BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel));
+ *StartGcdRegion = BaseAddress + (Index * TT_ADDRESS_AT_LEVEL (TableLevel));
*PrevEntryAttribute = EntryAttribute;
} else {
continue;
@@ -159,20 +166,27 @@ GetNextEntryAttribute (
ASSERT (TableLevel < 3);
// Increase the level number and scan the sub-level table
- GetNextEntryAttribute ((UINT64*)(Entry & TT_ADDRESS_MASK_DESCRIPTION_TABLE),
- TT_ENTRY_COUNT, TableLevel + 1,
- (BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel))),
- PrevEntryAttribute, StartGcdRegion);
+ GetNextEntryAttribute (
+ (UINT64 *)(Entry & TT_ADDRESS_MASK_DESCRIPTION_TABLE),
+ TT_ENTRY_COUNT,
+ TableLevel + 1,
+ (BaseAddress + (Index * TT_ADDRESS_AT_LEVEL (TableLevel))),
+ PrevEntryAttribute,
+ StartGcdRegion
+ );
} else {
if (*PrevEntryAttribute != INVALID_ENTRY) {
// Update GCD with the last region
- SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors,
- *StartGcdRegion,
- (BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel))) - *StartGcdRegion,
- PageAttributeToGcdAttribute (*PrevEntryAttribute));
+ SetGcdMemorySpaceAttributes (
+ MemorySpaceMap,
+ NumberOfDescriptors,
+ *StartGcdRegion,
+ (BaseAddress + (Index * TT_ADDRESS_AT_LEVEL (TableLevel))) - *StartGcdRegion,
+ PageAttributeToGcdAttribute (*PrevEntryAttribute)
+ );
// Start of the new region
- *StartGcdRegion = BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel));
+ *StartGcdRegion = BaseAddress + (Index * TT_ADDRESS_AT_LEVEL (TableLevel));
*PrevEntryAttribute = INVALID_ENTRY;
}
}
@@ -180,25 +194,25 @@ GetNextEntryAttribute (
FreePool (MemorySpaceMap);
- return BaseAddress + (EntryCount * TT_ADDRESS_AT_LEVEL(TableLevel));
+ return BaseAddress + (EntryCount * TT_ADDRESS_AT_LEVEL (TableLevel));
}
EFI_STATUS
SyncCacheConfig (
- IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
+ IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
)
{
- EFI_STATUS Status;
- UINT32 PageAttribute;
- UINT64 *FirstLevelTableAddress;
- UINTN TableLevel;
- UINTN TableCount;
- UINTN NumberOfDescriptors;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
- UINTN Tcr;
- UINTN T0SZ;
- UINT64 BaseAddressGcdRegion;
- UINT64 EndAddressGcdRegion;
+ EFI_STATUS Status;
+ UINT32 PageAttribute;
+ UINT64 *FirstLevelTableAddress;
+ UINTN TableLevel;
+ UINTN TableCount;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+ UINTN Tcr;
+ UINTN T0SZ;
+ UINT64 BaseAddressGcdRegion;
+ UINT64 EndAddressGcdRegion;
// This code assumes MMU is enabled and filed with section translations
ASSERT (ArmMmuEnabled ());
@@ -207,7 +221,7 @@ SyncCacheConfig (
// Get the memory space map from GCD
//
MemorySpaceMap = NULL;
- Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
+ Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
ASSERT_EFI_ERROR (Status);
// The GCD implementation maintains its own copy of the state of memory space attributes. GCD needs
@@ -217,7 +231,7 @@ SyncCacheConfig (
// with a way for GCD to query the CPU Arch. driver of the existing memory space attributes instead.
// Obtain page table base
- FirstLevelTableAddress = (UINT64*)(ArmGetTTBR0BaseAddress ());
+ FirstLevelTableAddress = (UINT64 *)(ArmGetTTBR0BaseAddress ());
// Get Translation Control Register value
Tcr = ArmGetTCR ();
@@ -232,17 +246,24 @@ SyncCacheConfig (
// We scan from the start of the memory map (ie: at the address 0x0)
BaseAddressGcdRegion = 0x0;
- EndAddressGcdRegion = GetNextEntryAttribute (FirstLevelTableAddress,
- TableCount, TableLevel,
- BaseAddressGcdRegion,
- &PageAttribute, &BaseAddressGcdRegion);
+ EndAddressGcdRegion = GetNextEntryAttribute (
+ FirstLevelTableAddress,
+ TableCount,
+ TableLevel,
+ BaseAddressGcdRegion,
+ &PageAttribute,
+ &BaseAddressGcdRegion
+ );
// Update GCD with the last region if valid
if (PageAttribute != INVALID_ENTRY) {
- SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors,
- BaseAddressGcdRegion,
- EndAddressGcdRegion - BaseAddressGcdRegion,
- PageAttributeToGcdAttribute (PageAttribute));
+ SetGcdMemorySpaceAttributes (
+ MemorySpaceMap,
+ NumberOfDescriptors,
+ BaseAddressGcdRegion,
+ EndAddressGcdRegion - BaseAddressGcdRegion,
+ PageAttributeToGcdAttribute (PageAttribute)
+ );
}
FreePool (MemorySpaceMap);
@@ -252,30 +273,31 @@ SyncCacheConfig (
UINT64
EfiAttributeToArmAttribute (
- IN UINT64 EfiAttributes
+ IN UINT64 EfiAttributes
)
{
- UINT64 ArmAttributes;
+ UINT64 ArmAttributes;
switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {
- case EFI_MEMORY_UC:
- if (ArmReadCurrentEL () == AARCH64_EL2) {
- ArmAttributes = TT_ATTR_INDX_DEVICE_MEMORY | TT_XN_MASK;
- } else {
- ArmAttributes = TT_ATTR_INDX_DEVICE_MEMORY | TT_UXN_MASK | TT_PXN_MASK;
- }
- break;
- case EFI_MEMORY_WC:
- ArmAttributes = TT_ATTR_INDX_MEMORY_NON_CACHEABLE;
- break;
- case EFI_MEMORY_WT:
- ArmAttributes = TT_ATTR_INDX_MEMORY_WRITE_THROUGH | TT_SH_INNER_SHAREABLE;
- break;
- case EFI_MEMORY_WB:
- ArmAttributes = TT_ATTR_INDX_MEMORY_WRITE_BACK | TT_SH_INNER_SHAREABLE;
- break;
- default:
- ArmAttributes = TT_ATTR_INDX_MASK;
+ case EFI_MEMORY_UC:
+ if (ArmReadCurrentEL () == AARCH64_EL2) {
+ ArmAttributes = TT_ATTR_INDX_DEVICE_MEMORY | TT_XN_MASK;
+ } else {
+ ArmAttributes = TT_ATTR_INDX_DEVICE_MEMORY | TT_UXN_MASK | TT_PXN_MASK;
+ }
+
+ break;
+ case EFI_MEMORY_WC:
+ ArmAttributes = TT_ATTR_INDX_MEMORY_NON_CACHEABLE;
+ break;
+ case EFI_MEMORY_WT:
+ ArmAttributes = TT_ATTR_INDX_MEMORY_WRITE_THROUGH | TT_SH_INNER_SHAREABLE;
+ break;
+ case EFI_MEMORY_WB:
+ ArmAttributes = TT_ATTR_INDX_MEMORY_WRITE_BACK | TT_SH_INNER_SHAREABLE;
+ break;
+ default:
+ ArmAttributes = TT_ATTR_INDX_MASK;
}
// Set the access flag to match the block attributes
@@ -298,19 +320,19 @@ EfiAttributeToArmAttribute (
// And then the function will identify the size of the region that has the same page table attribute.
EFI_STATUS
GetMemoryRegionRec (
- IN UINT64 *TranslationTable,
- IN UINTN TableLevel,
- IN UINT64 *LastBlockEntry,
- IN OUT UINTN *BaseAddress,
- OUT UINTN *RegionLength,
- OUT UINTN *RegionAttributes
+ IN UINT64 *TranslationTable,
+ IN UINTN TableLevel,
+ IN UINT64 *LastBlockEntry,
+ IN OUT UINTN *BaseAddress,
+ OUT UINTN *RegionLength,
+ OUT UINTN *RegionAttributes
)
{
- EFI_STATUS Status;
- UINT64 *NextTranslationTable;
- UINT64 *BlockEntry;
- UINT64 BlockEntryType;
- UINT64 EntryType;
+ EFI_STATUS Status;
+ UINT64 *NextTranslationTable;
+ UINT64 *BlockEntry;
+ UINT64 BlockEntryType;
+ UINT64 EntryType;
if (TableLevel != 3) {
BlockEntryType = TT_TYPE_BLOCK_ENTRY;
@@ -319,22 +341,25 @@ GetMemoryRegionRec (
}
// Find the block entry linked to the Base Address
- BlockEntry = (UINT64*)TT_GET_ENTRY_FOR_ADDRESS (TranslationTable, TableLevel, *BaseAddress);
- EntryType = *BlockEntry & TT_TYPE_MASK;
+ BlockEntry = (UINT64 *)TT_GET_ENTRY_FOR_ADDRESS (TranslationTable, TableLevel, *BaseAddress);
+ EntryType = *BlockEntry & TT_TYPE_MASK;
if ((TableLevel < 3) && (EntryType == TT_TYPE_TABLE_ENTRY)) {
- NextTranslationTable = (UINT64*)(*BlockEntry & TT_ADDRESS_MASK_DESCRIPTION_TABLE);
+ NextTranslationTable = (UINT64 *)(*BlockEntry & TT_ADDRESS_MASK_DESCRIPTION_TABLE);
// The entry is a page table, so we go to the next level
Status = GetMemoryRegionRec (
- NextTranslationTable, // Address of the next level page table
- TableLevel + 1, // Next Page Table level
- (UINTN*)TT_LAST_BLOCK_ADDRESS(NextTranslationTable, TT_ENTRY_COUNT),
- BaseAddress, RegionLength, RegionAttributes);
+ NextTranslationTable, // Address of the next level page table
+ TableLevel + 1, // Next Page Table level
+ (UINTN *)TT_LAST_BLOCK_ADDRESS (NextTranslationTable, TT_ENTRY_COUNT),
+ BaseAddress,
+ RegionLength,
+ RegionAttributes
+ );
// In case of 'Success', it means the end of the block region has been found into the upper
// level translation table
- if (!EFI_ERROR(Status)) {
+ if (!EFI_ERROR (Status)) {
return EFI_SUCCESS;
}
@@ -343,7 +368,7 @@ GetMemoryRegionRec (
} else if (EntryType == BlockEntryType) {
// We have found the BlockEntry attached to the address. We save its start address (the start
// address might be before the 'BaseAddress') and attributes
- *BaseAddress = *BaseAddress & ~(TT_ADDRESS_AT_LEVEL(TableLevel) - 1);
+ *BaseAddress = *BaseAddress & ~(TT_ADDRESS_AT_LEVEL (TableLevel) - 1);
*RegionLength = 0;
*RegionAttributes = *BlockEntry & TT_ATTRIBUTES_MASK;
} else {
@@ -353,11 +378,12 @@ GetMemoryRegionRec (
while (BlockEntry <= LastBlockEntry) {
if ((*BlockEntry & TT_ATTRIBUTES_MASK) == *RegionAttributes) {
- *RegionLength = *RegionLength + TT_BLOCK_ENTRY_SIZE_AT_LEVEL(TableLevel);
+ *RegionLength = *RegionLength + TT_BLOCK_ENTRY_SIZE_AT_LEVEL (TableLevel);
} else {
// In case we have found the end of the region we return success
return EFI_SUCCESS;
}
+
BlockEntry++;
}
@@ -369,13 +395,13 @@ GetMemoryRegionRec (
EFI_STATUS
GetMemoryRegion (
- IN OUT UINTN *BaseAddress,
- OUT UINTN *RegionLength,
- OUT UINTN *RegionAttributes
+ IN OUT UINTN *BaseAddress,
+ OUT UINTN *RegionLength,
+ OUT UINTN *RegionAttributes
)
{
EFI_STATUS Status;
- UINT64 *TranslationTable;
+ UINT64 *TranslationTable;
UINTN TableLevel;
UINTN EntryCount;
UINTN T0SZ;
@@ -388,9 +414,14 @@ GetMemoryRegion (
// Get the Table info from T0SZ
GetRootTranslationTableInfo (T0SZ, &TableLevel, &EntryCount);
- Status = GetMemoryRegionRec (TranslationTable, TableLevel,
- (UINTN*)TT_LAST_BLOCK_ADDRESS(TranslationTable, EntryCount),
- BaseAddress, RegionLength, RegionAttributes);
+ Status = GetMemoryRegionRec (
+ TranslationTable,
+ TableLevel,
+ (UINTN *)TT_LAST_BLOCK_ADDRESS (TranslationTable, EntryCount),
+ BaseAddress,
+ RegionLength,
+ RegionAttributes
+ );
// If the region continues up to the end of the root table then GetMemoryRegionRec()
// will return EFI_NOT_FOUND