Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>\r
Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>\r
Portions copyright (c) 2011-2013, ARM Ltd. All rights reserved.<BR>\r
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
// Get the first entry of the table\r
FirstEntry = *FirstLevelTableAddress;\r
\r
- if ((FirstEntry & TT_TYPE_MASK) == TT_TYPE_TABLE_ENTRY) {\r
+ if ((TableLevel != 3) && (FirstEntry & TT_TYPE_MASK) == TT_TYPE_TABLE_ENTRY) {\r
// Only valid for Levels 0, 1 and 2\r
- ASSERT (TableLevel < 3);\r
\r
// Get the attribute of the subsequent table\r
return GetFirstPageAttribute ((UINT64*)(FirstEntry & TT_ADDRESS_MASK_DESCRIPTION_TABLE), TableLevel + 1);\r
SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors,\r
*StartGcdRegion,\r
(BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel))) - *StartGcdRegion,\r
- PageAttributeToGcdAttribute (EntryAttribute));\r
+ PageAttributeToGcdAttribute (*PrevEntryAttribute));\r
}\r
\r
// Start of the new region\r
\r
return EFI_SUCCESS;\r
}\r
+\r
+UINT64\r
+EfiAttributeToArmAttribute (\r
+ IN UINT64 EfiAttributes\r
+ )\r
+{\r
+ UINT64 ArmAttributes;\r
+\r
+ switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {\r
+ case EFI_MEMORY_UC:\r
+ if (ArmReadCurrentEL () == AARCH64_EL2) {\r
+ ArmAttributes = TT_ATTR_INDX_DEVICE_MEMORY | TT_XN_MASK;\r
+ } else {\r
+ ArmAttributes = TT_ATTR_INDX_DEVICE_MEMORY | TT_UXN_MASK | TT_PXN_MASK;\r
+ }\r
+ break;\r
+ case EFI_MEMORY_WC:\r
+ ArmAttributes = TT_ATTR_INDX_MEMORY_NON_CACHEABLE;\r
+ break;\r
+ case EFI_MEMORY_WT:\r
+ ArmAttributes = TT_ATTR_INDX_MEMORY_WRITE_THROUGH | TT_SH_INNER_SHAREABLE;\r
+ break;\r
+ case EFI_MEMORY_WB:\r
+ ArmAttributes = TT_ATTR_INDX_MEMORY_WRITE_BACK | TT_SH_INNER_SHAREABLE;\r
+ break;\r
+ default:\r
+ ArmAttributes = TT_ATTR_INDX_MASK;\r
+ }\r
+\r
+ // Set the access flag to match the block attributes\r
+ ArmAttributes |= TT_AF;\r
+\r
+ // Determine protection attributes\r
+ if (EfiAttributes & EFI_MEMORY_RO) {\r
+ ArmAttributes |= TT_AP_RO_RO;\r
+ }\r
+\r
+ // Process eXecute Never attribute\r
+ if (EfiAttributes & EFI_MEMORY_XP) {\r
+ ArmAttributes |= TT_PXN_MASK;\r
+ }\r
+\r
+ return ArmAttributes;\r
+}\r
+\r
+// This function will recursively go down the page table to find the first block address linked to 'BaseAddress'.\r
+// And then the function will identify the size of the region that has the same page table attribute.\r
+EFI_STATUS\r
+GetMemoryRegionRec (\r
+ IN UINT64 *TranslationTable,\r
+ IN UINTN TableLevel,\r
+ IN UINT64 *LastBlockEntry,\r
+ IN OUT UINTN *BaseAddress,\r
+ OUT UINTN *RegionLength,\r
+ OUT UINTN *RegionAttributes\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 *NextTranslationTable;\r
+ UINT64 *BlockEntry;\r
+ UINT64 BlockEntryType;\r
+ UINT64 EntryType;\r
+\r
+ if (TableLevel != 3) {\r
+ BlockEntryType = TT_TYPE_BLOCK_ENTRY;\r
+ } else {\r
+ BlockEntryType = TT_TYPE_BLOCK_ENTRY_LEVEL3;\r
+ }\r
+\r
+ // Find the block entry linked to the Base Address\r
+ BlockEntry = (UINT64*)TT_GET_ENTRY_FOR_ADDRESS (TranslationTable, TableLevel, *BaseAddress);\r
+ EntryType = *BlockEntry & TT_TYPE_MASK;\r
+\r
+ if ((TableLevel < 3) && (EntryType == TT_TYPE_TABLE_ENTRY)) {\r
+ NextTranslationTable = (UINT64*)(*BlockEntry & TT_ADDRESS_MASK_DESCRIPTION_TABLE);\r
+\r
+ // The entry is a page table, so we go to the next level\r
+ Status = GetMemoryRegionRec (\r
+ NextTranslationTable, // Address of the next level page table\r
+ TableLevel + 1, // Next Page Table level\r
+ (UINTN*)TT_LAST_BLOCK_ADDRESS(NextTranslationTable, TT_ENTRY_COUNT),\r
+ BaseAddress, RegionLength, RegionAttributes);\r
+\r
+ // In case of 'Success', it means the end of the block region has been found into the upper\r
+ // level translation table\r
+ if (!EFI_ERROR(Status)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ // Now we processed the table move to the next entry\r
+ BlockEntry++;\r
+ } else if (EntryType == BlockEntryType) {\r
+ // We have found the BlockEntry attached to the address. We save its start address (the start\r
+ // address might be before the 'BaseAdress') and attributes\r
+ *BaseAddress = *BaseAddress & ~(TT_ADDRESS_AT_LEVEL(TableLevel) - 1);\r
+ *RegionLength = 0;\r
+ *RegionAttributes = *BlockEntry & TT_ATTRIBUTES_MASK;\r
+ } else {\r
+ // We have an 'Invalid' entry\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ while (BlockEntry <= LastBlockEntry) {\r
+ if ((*BlockEntry & TT_ATTRIBUTES_MASK) == *RegionAttributes) {\r
+ *RegionLength = *RegionLength + TT_BLOCK_ENTRY_SIZE_AT_LEVEL(TableLevel);\r
+ } else {\r
+ // In case we have found the end of the region we return success\r
+ return EFI_SUCCESS;\r
+ }\r
+ BlockEntry++;\r
+ }\r
+\r
+ // If we have reached the end of the TranslationTable and we have not found the end of the region then\r
+ // we return EFI_NOT_FOUND.\r
+ // The caller will continue to look for the memory region at its level\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+EFI_STATUS\r
+GetMemoryRegion (\r
+ IN OUT UINTN *BaseAddress,\r
+ OUT UINTN *RegionLength,\r
+ OUT UINTN *RegionAttributes\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 *TranslationTable;\r
+ UINTN TableLevel;\r
+ UINTN EntryCount;\r
+ UINTN T0SZ;\r
+\r
+ ASSERT ((BaseAddress != NULL) && (RegionLength != NULL) && (RegionAttributes != NULL));\r
+\r
+ TranslationTable = ArmGetTTBR0BaseAddress ();\r
+\r
+ T0SZ = ArmGetTCR () & TCR_T0SZ_MASK;\r
+ // Get the Table info from T0SZ\r
+ GetRootTranslationTableInfo (T0SZ, &TableLevel, &EntryCount);\r
+\r
+ Status = GetMemoryRegionRec (TranslationTable, TableLevel,\r
+ (UINTN*)TT_LAST_BLOCK_ADDRESS(TranslationTable, EntryCount),\r
+ BaseAddress, RegionLength, RegionAttributes);\r
+\r
+ // If the region continues up to the end of the root table then GetMemoryRegionRec()\r
+ // will return EFI_NOT_FOUND\r
+ if (Status == EFI_NOT_FOUND) {\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return Status;\r
+ }\r
+}\r