)\r
{\r
VOID* TranslationTable;\r
+ VOID* TranslationTableBuffer;\r
UINT32 TranslationTableAttribute;\r
- ARM_MEMORY_REGION_DESCRIPTOR *MemoryTableEntry;\r
UINT64 MaxAddress;\r
- UINT64 TopAddress;\r
UINTN T0SZ;\r
UINTN RootTableEntryCount;\r
+ UINTN RootTableEntrySize;\r
UINT64 TCR;\r
RETURN_STATUS Status;\r
\r
return RETURN_INVALID_PARAMETER;\r
}\r
\r
- // Identify the highest address of the memory table\r
- MaxAddress = MemoryTable->PhysicalBase + MemoryTable->Length - 1;\r
- MemoryTableEntry = MemoryTable;\r
- while (MemoryTableEntry->Length != 0) {\r
- TopAddress = MemoryTableEntry->PhysicalBase + MemoryTableEntry->Length - 1;\r
- if (TopAddress > MaxAddress) {\r
- MaxAddress = TopAddress;\r
- }\r
- MemoryTableEntry++;\r
- }\r
+ // Cover the entire GCD memory space\r
+ MaxAddress = (1UL << PcdGet8 (PcdPrePiCpuMemorySize)) - 1;\r
\r
// Lookup the Table Level to get the information\r
LookupAddresstoRootTable (MaxAddress, &T0SZ, &RootTableEntryCount);\r
return RETURN_UNSUPPORTED;\r
}\r
\r
+ //\r
+ // Translation table walks are always cache coherent on ARMv8-A, so cache\r
+ // maintenance on page tables is never needed. Since there is a risk of\r
+ // loss of coherency when using mismatched attributes, and given that memory\r
+ // is mapped cacheable except for extraordinary cases (such as non-coherent\r
+ // DMA), have the page table walker perform cached accesses as well, and\r
+ // assert below that that matches the attributes we use for CPU accesses to\r
+ // the region.\r
+ //\r
+ TCR |= TCR_SH_INNER_SHAREABLE |\r
+ TCR_RGN_OUTER_WRITE_BACK_ALLOC |\r
+ TCR_RGN_INNER_WRITE_BACK_ALLOC;\r
+\r
// Set TCR\r
ArmSetTCR (TCR);\r
\r
- // Allocate pages for translation table\r
- TranslationTable = AllocatePages (1);\r
+ // Allocate pages for translation table. Pool allocations are 8 byte aligned,\r
+ // but we may require a higher alignment based on the size of the root table.\r
+ RootTableEntrySize = RootTableEntryCount * sizeof(UINT64);\r
+ if (RootTableEntrySize < EFI_PAGE_SIZE / 2) {\r
+ TranslationTableBuffer = AllocatePool (2 * RootTableEntrySize - 8);\r
+ //\r
+ // Naturally align the root table. Preserves possible NULL value\r
+ //\r
+ TranslationTable = (VOID *)((UINTN)(TranslationTableBuffer - 1) | (RootTableEntrySize - 1)) + 1;\r
+ } else {\r
+ TranslationTable = AllocatePages (1);\r
+ TranslationTableBuffer = NULL;\r
+ }\r
if (TranslationTable == NULL) {\r
return RETURN_OUT_OF_RESOURCES;\r
}\r
}\r
\r
if (TranslationTableSize != NULL) {\r
- *TranslationTableSize = RootTableEntryCount * sizeof(UINT64);\r
+ *TranslationTableSize = RootTableEntrySize;\r
}\r
\r
- ZeroMem (TranslationTable, RootTableEntryCount * sizeof(UINT64));\r
+ ZeroMem (TranslationTable, RootTableEntrySize);\r
\r
// Disable MMU and caches. ArmDisableMmu() also invalidates the TLBs\r
ArmDisableMmu ();\r
\r
TranslationTableAttribute = TT_ATTR_INDX_INVALID;\r
while (MemoryTable->Length != 0) {\r
- // Find the memory attribute for the Translation Table\r
- if (((UINTN)TranslationTable >= MemoryTable->PhysicalBase) &&\r
- ((UINTN)TranslationTable <= MemoryTable->PhysicalBase - 1 + MemoryTable->Length)) {\r
- TranslationTableAttribute = MemoryTable->Attributes;\r
- }\r
+\r
+ DEBUG_CODE_BEGIN ();\r
+ // Find the memory attribute for the Translation Table\r
+ if ((UINTN)TranslationTable >= MemoryTable->PhysicalBase &&\r
+ (UINTN)TranslationTable + RootTableEntrySize <= MemoryTable->PhysicalBase +\r
+ MemoryTable->Length) {\r
+ TranslationTableAttribute = MemoryTable->Attributes;\r
+ }\r
+ DEBUG_CODE_END ();\r
\r
Status = FillTranslationTable (TranslationTable, MemoryTable);\r
if (RETURN_ERROR (Status)) {\r
MemoryTable++;\r
}\r
\r
- // Translate the Memory Attributes into Translation Table Register Attributes\r
- if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED) ||\r
- (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_UNCACHED_UNBUFFERED)) {\r
- TCR |= TCR_SH_NON_SHAREABLE | TCR_RGN_OUTER_NON_CACHEABLE | TCR_RGN_INNER_NON_CACHEABLE;\r
- } else if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK) ||\r
- (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK)) {\r
- TCR |= TCR_SH_INNER_SHAREABLE | TCR_RGN_OUTER_WRITE_BACK_ALLOC | TCR_RGN_INNER_WRITE_BACK_ALLOC;\r
- } else if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH) ||\r
- (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_THROUGH)) {\r
- TCR |= TCR_SH_NON_SHAREABLE | TCR_RGN_OUTER_WRITE_THROUGH | TCR_RGN_INNER_WRITE_THROUGH;\r
- } else {\r
- // If we failed to find a mapping that contains the root translation table then it probably means the translation table\r
- // is not mapped in the given memory map.\r
- ASSERT (0);\r
- Status = RETURN_UNSUPPORTED;\r
- goto FREE_TRANSLATION_TABLE;\r
- }\r
-\r
- // Set again TCR after getting the Translation Table attributes\r
- ArmSetTCR (TCR);\r
+ ASSERT (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK ||\r
+ TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK);\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
return RETURN_SUCCESS;\r
\r
FREE_TRANSLATION_TABLE:\r
- FreePages (TranslationTable, 1);\r
+ if (TranslationTableBuffer != NULL) {\r
+ FreePool (TranslationTableBuffer);\r
+ } else {\r
+ FreePages (TranslationTable, 1);\r
+ }\r
return Status;\r
}\r
\r