summaryrefslogtreecommitdiffstats
path: root/ArmPkg/Drivers/CpuDxe/AArch64
diff options
context:
space:
mode:
authorOlivier Martin <olivier.martin@arm.com>2013-08-19 17:38:39 +0000
committeroliviermartin <oliviermartin@6f19259b-4bc3-4df7-8a09-765794883524>2013-08-19 17:38:39 +0000
commit2e969d2e9e98820a136002699ff1d02ba2a2f551 (patch)
treefdf387ac24723db8d90c9482d9c7ed853c70389d /ArmPkg/Drivers/CpuDxe/AArch64
parent6adbd5b4d255b15f1f2feb2e956a2fdd0683a2e2 (diff)
downloadedk2-2e969d2e9e98820a136002699ff1d02ba2a2f551.tar.gz
edk2-2e969d2e9e98820a136002699ff1d02ba2a2f551.tar.bz2
edk2-2e969d2e9e98820a136002699ff1d02ba2a2f551.zip
ArmPkg/CpuDxe: Added support to not set a memory region with the same attribute
Changing the attribute implies some cache management (clean & invalidate). Preventing the cache management should improve the performance. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Olivier Martin <olivier.martin@arm.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14568 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'ArmPkg/Drivers/CpuDxe/AArch64')
-rw-r--r--ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c146
1 files changed, 146 insertions, 0 deletions
diff --git a/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c b/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c
index 40a4c1b0aa..72f9b3cc63 100644
--- a/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c
+++ b/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c
@@ -194,3 +194,149 @@ SyncCacheConfig (
return EFI_SUCCESS;
}
+
+UINT64
+EfiAttributeToArmAttribute (
+ IN UINT64 EfiAttributes
+ )
+{
+ UINT64 ArmAttributes;
+
+ switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {
+ case EFI_MEMORY_UC:
+ ArmAttributes = TT_ATTR_INDX_DEVICE_MEMORY;
+ break;
+ case EFI_MEMORY_WC:
+ ArmAttributes = TT_ATTR_INDX_MEMORY_NON_CACHEABLE;
+ break;
+ case EFI_MEMORY_WT:
+ ArmAttributes = TT_ATTR_INDX_MEMORY_WRITE_THROUGH;
+ break;
+ case EFI_MEMORY_WB:
+ ArmAttributes = TT_ATTR_INDX_MEMORY_WRITE_BACK;
+ break;
+ default:
+ DEBUG ((EFI_D_ERROR, "EfiAttributeToArmAttribute: 0x%lX attributes is not supported.\n", EfiAttributes));
+ ASSERT (0);
+ ArmAttributes = TT_ATTR_INDX_DEVICE_MEMORY;
+ }
+
+ // Set the access flag to match the block attributes
+ ArmAttributes |= TT_AF;
+
+ // Determine protection attributes
+ if (EfiAttributes & EFI_MEMORY_WP) {
+ ArmAttributes |= TT_AP_RO_RO;
+ }
+
+ // Process eXecute Never attribute
+ if (EfiAttributes & EFI_MEMORY_XP) {
+ ArmAttributes |= TT_PXN_MASK;
+ }
+
+ return ArmAttributes;
+}
+
+// This function will recursively go down the page table to find the first block address linked to 'BaseAddress'.
+// 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
+ )
+{
+ EFI_STATUS Status;
+ UINT64 *NextTranslationTable;
+ UINT64 *BlockEntry;
+ UINT64 BlockEntryType;
+ UINT64 EntryType;
+
+ if (TableLevel != 3) {
+ BlockEntryType = TT_TYPE_BLOCK_ENTRY;
+ } else {
+ BlockEntryType = TT_TYPE_BLOCK_ENTRY_LEVEL3;
+ }
+
+ // Find the block entry linked to the Base Address
+ BlockEntry = (UINT64*)TT_GET_ENTRY_FOR_ADDRESS (TranslationTable, TableLevel, *BaseAddress);
+ EntryType = *BlockEntry & TT_TYPE_MASK;
+
+ if (EntryType == TT_TYPE_TABLE_ENTRY) {
+ 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);
+
+ // 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)) {
+ return EFI_SUCCESS;
+ }
+ } 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 'BaseAdress') and attributes
+ *BaseAddress = *BaseAddress & ~(TT_ADDRESS_AT_LEVEL(TableLevel) - 1);
+ *RegionLength = 0;
+ *RegionAttributes = *BlockEntry & TT_ATTRIBUTES_MASK;
+ } else {
+ // We have an 'Invalid' entry
+ return EFI_UNSUPPORTED;
+ }
+
+ while (BlockEntry <= LastBlockEntry) {
+ if ((*BlockEntry & TT_ATTRIBUTES_MASK) == *RegionAttributes) {
+ *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++;
+ }
+
+ // If we have reached the end of the TranslationTable and we have not found the end of the region then
+ // we return EFI_NOT_FOUND.
+ // The caller will continue to look for the memory region at its level
+ return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+GetMemoryRegion (
+ IN OUT UINTN *BaseAddress,
+ OUT UINTN *RegionLength,
+ OUT UINTN *RegionAttributes
+ )
+{
+ EFI_STATUS Status;
+ UINT64 *TranslationTable;
+ UINTN TableLevel;
+ UINTN EntryCount;
+ UINTN T0SZ;
+
+ ASSERT ((BaseAddress != NULL) && (RegionLength != NULL) && (RegionAttributes != NULL));
+
+ TranslationTable = ArmGetTTBR0BaseAddress ();
+
+ T0SZ = ArmGetTCR () & TCR_T0SZ_MASK;
+ // Get the Table info from T0SZ
+ GetRootTranslationTableInfo (T0SZ, &TableLevel, &EntryCount);
+
+ 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
+ if (Status == EFI_NOT_FOUND) {
+ return EFI_SUCCESS;
+ } else {
+ return Status;
+ }
+}