*\r
* Copyright (c) 2011-2016, 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
-* which accompanies this distribution. The full text of the license may be found at\r
-* http://opensource.org/licenses/bsd-license.php\r
-*\r
-* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+* SPDX-License-Identifier: BSD-2-Clause-Patent\r
*\r
**/\r
\r
#define ID_MMFR0_SHR_IMP_HW_COHERENT 1\r
#define ID_MMFR0_SHR_IGNORED 0xf\r
\r
-#define CACHE_ATTRIBUTE_MASK (EFI_MEMORY_UC | \\r
- EFI_MEMORY_WC | \\r
- EFI_MEMORY_WT | \\r
- EFI_MEMORY_WB | \\r
- EFI_MEMORY_UCE | \\r
- EFI_MEMORY_WP)\r
-\r
UINTN\r
EFIAPI\r
ArmReadIdMmfr0 (\r
VOID\r
);\r
\r
-UINT32\r
-ConvertSectionAttributesToPageAttributes (\r
- IN UINT32 SectionAttributes,\r
- IN BOOLEAN IsLargePage\r
- )\r
-{\r
- UINT32 PageAttributes;\r
-\r
- PageAttributes = 0;\r
- PageAttributes |= TT_DESCRIPTOR_CONVERT_TO_PAGE_CACHE_POLICY (SectionAttributes, IsLargePage);\r
- PageAttributes |= TT_DESCRIPTOR_CONVERT_TO_PAGE_AP (SectionAttributes);\r
- PageAttributes |= TT_DESCRIPTOR_CONVERT_TO_PAGE_XN (SectionAttributes, IsLargePage);\r
- PageAttributes |= TT_DESCRIPTOR_CONVERT_TO_PAGE_NG (SectionAttributes);\r
- PageAttributes |= TT_DESCRIPTOR_CONVERT_TO_PAGE_S (SectionAttributes);\r
-\r
- return PageAttributes;\r
-}\r
-\r
STATIC\r
BOOLEAN\r
PreferNonshareableMemory (\r
UINT32 SectionDescriptor;\r
UINT32 TranslationTable;\r
UINT32 BaseSectionAddress;\r
+ UINT32 FirstPageOffset;\r
\r
switch (Attributes) {\r
case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK:\r
case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK:\r
PageAttributes = TT_DESCRIPTOR_PAGE_WRITE_BACK;\r
break;\r
+ case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK_NONSHAREABLE:\r
+ case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK_NONSHAREABLE:\r
+ PageAttributes = TT_DESCRIPTOR_PAGE_WRITE_BACK;\r
+ PageAttributes &= ~TT_DESCRIPTOR_PAGE_S_SHARED;\r
+ break;\r
case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH:\r
case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_THROUGH:\r
PageAttributes = TT_DESCRIPTOR_PAGE_WRITE_THROUGH;\r
// Case where a virtual memory map descriptor overlapped a section entry\r
\r
// Allocate a Level2 Page Table for this Section\r
- TranslationTable = (UINTN)AllocatePages(EFI_SIZE_TO_PAGES(TRANSLATION_TABLE_PAGE_SIZE + TRANSLATION_TABLE_PAGE_ALIGNMENT));\r
- TranslationTable = ((UINTN)TranslationTable + TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK) & ~TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK;\r
+ TranslationTable = (UINTN)AllocateAlignedPages (\r
+ EFI_SIZE_TO_PAGES (TRANSLATION_TABLE_PAGE_SIZE),\r
+ TRANSLATION_TABLE_PAGE_ALIGNMENT);\r
\r
// Translate the Section Descriptor into Page Descriptor\r
SectionDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE | ConvertSectionAttributesToPageAttributes (*SectionEntry, FALSE);\r
\r
BaseSectionAddress = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(*SectionEntry);\r
\r
+ //\r
+ // Make sure we are not inadvertently hitting in the caches\r
+ // when populating the page tables\r
+ //\r
+ InvalidateDataCacheRange ((VOID *)TranslationTable,\r
+ TRANSLATION_TABLE_PAGE_SIZE);\r
+\r
// Populate the new Level2 Page Table for the section\r
PageEntry = (UINT32*)TranslationTable;\r
for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) {\r
return;\r
}\r
} else {\r
- TranslationTable = (UINTN)AllocatePages(EFI_SIZE_TO_PAGES(TRANSLATION_TABLE_PAGE_SIZE + TRANSLATION_TABLE_PAGE_ALIGNMENT));\r
- TranslationTable = ((UINTN)TranslationTable + TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK) & ~TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK;\r
-\r
+ TranslationTable = (UINTN)AllocateAlignedPages (\r
+ EFI_SIZE_TO_PAGES (TRANSLATION_TABLE_PAGE_SIZE),\r
+ TRANSLATION_TABLE_PAGE_ALIGNMENT);\r
+ //\r
+ // Make sure we are not inadvertently hitting in the caches\r
+ // when populating the page tables\r
+ //\r
+ InvalidateDataCacheRange ((VOID *)TranslationTable,\r
+ TRANSLATION_TABLE_PAGE_SIZE);\r
ZeroMem ((VOID *)TranslationTable, TRANSLATION_TABLE_PAGE_SIZE);\r
\r
*SectionEntry = (TranslationTable & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) |\r
TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE;\r
}\r
\r
- PageEntry = ((UINT32 *)(TranslationTable) + ((PhysicalBase & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT));\r
+ FirstPageOffset = (PhysicalBase & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
+ PageEntry = (UINT32 *)TranslationTable + FirstPageOffset;\r
Pages = RemainLength / TT_DESCRIPTOR_PAGE_SIZE;\r
\r
+ ASSERT (FirstPageOffset + Pages <= TRANSLATION_TABLE_PAGE_COUNT);\r
+\r
for (Index = 0; Index < Pages; Index++) {\r
*PageEntry++ = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(PhysicalBase) | PageAttributes;\r
PhysicalBase += TT_DESCRIPTOR_PAGE_SIZE;\r
}\r
\r
+ //\r
+ // Invalidate again to ensure that any line fetches that may have occurred\r
+ // [speculatively] since the previous invalidate are evicted again.\r
+ //\r
+ ArmDataMemoryBarrier ();\r
+ InvalidateDataCacheRange ((UINT32 *)TranslationTable + FirstPageOffset,\r
+ RemainLength / TT_DESCRIPTOR_PAGE_SIZE * sizeof (*PageEntry));\r
}\r
\r
STATIC\r
UINT32 Attributes;\r
UINT32 PhysicalBase;\r
UINT64 RemainLength;\r
+ UINT32 PageMapLength;\r
\r
ASSERT(MemoryRegion->Length > 0);\r
\r
return;\r
}\r
\r
- PhysicalBase = MemoryRegion->PhysicalBase;\r
+ PhysicalBase = (UINT32)MemoryRegion->PhysicalBase;\r
RemainLength = MIN(MemoryRegion->Length, SIZE_4GB - PhysicalBase);\r
\r
switch (MemoryRegion->Attributes) {\r
case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK:\r
Attributes = TT_DESCRIPTOR_SECTION_WRITE_BACK(0);\r
break;\r
+ case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK_NONSHAREABLE:\r
+ Attributes = TT_DESCRIPTOR_SECTION_WRITE_BACK(0);\r
+ Attributes &= ~TT_DESCRIPTOR_SECTION_S_SHARED;\r
+ break;\r
case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH:\r
Attributes = TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0);\r
break;\r
case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK:\r
Attributes = TT_DESCRIPTOR_SECTION_WRITE_BACK(1);\r
break;\r
+ case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK_NONSHAREABLE:\r
+ Attributes = TT_DESCRIPTOR_SECTION_WRITE_BACK(1);\r
+ Attributes &= ~TT_DESCRIPTOR_SECTION_S_SHARED;\r
+ break;\r
case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_THROUGH:\r
Attributes = TT_DESCRIPTOR_SECTION_WRITE_THROUGH(1);\r
break;\r
SectionEntry = TRANSLATION_TABLE_ENTRY_FOR_VIRTUAL_ADDRESS(TranslationTable, MemoryRegion->VirtualBase);\r
\r
while (RemainLength != 0) {\r
- if (PhysicalBase % TT_DESCRIPTOR_SECTION_SIZE == 0) {\r
- if (RemainLength >= TT_DESCRIPTOR_SECTION_SIZE) {\r
- // Case: Physical address aligned on the Section Size (1MB) && the length is greater than the Section Size\r
- *SectionEntry++ = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(PhysicalBase) | Attributes;\r
- PhysicalBase += TT_DESCRIPTOR_SECTION_SIZE;\r
- } else {\r
- // Case: Physical address aligned on the Section Size (1MB) && the length does not fill a section\r
- PopulateLevel2PageTable (SectionEntry++, PhysicalBase, RemainLength, MemoryRegion->Attributes);\r
-\r
- // It must be the last entry\r
- break;\r
- }\r
+ if (PhysicalBase % TT_DESCRIPTOR_SECTION_SIZE == 0 &&\r
+ RemainLength >= TT_DESCRIPTOR_SECTION_SIZE) {\r
+ // Case: Physical address aligned on the Section Size (1MB) && the length\r
+ // is greater than the Section Size\r
+ *SectionEntry = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(PhysicalBase) | Attributes;\r
+\r
+ //\r
+ // Issue a DMB to ensure that the page table entry update made it to\r
+ // memory before we issue the invalidate, otherwise, a subsequent\r
+ // speculative fetch could observe the old value.\r
+ //\r
+ ArmDataMemoryBarrier ();\r
+ ArmInvalidateDataCacheEntryByMVA ((UINTN)SectionEntry++);\r
+\r
+ PhysicalBase += TT_DESCRIPTOR_SECTION_SIZE;\r
+ RemainLength -= TT_DESCRIPTOR_SECTION_SIZE;\r
} else {\r
+ PageMapLength = MIN ((UINT32)RemainLength, TT_DESCRIPTOR_SECTION_SIZE -\r
+ (PhysicalBase % TT_DESCRIPTOR_SECTION_SIZE));\r
+\r
+ // Case: Physical address aligned on the Section Size (1MB) && the length\r
+ // does not fill a section\r
// Case: Physical address NOT aligned on the Section Size (1MB)\r
- PopulateLevel2PageTable (SectionEntry++, PhysicalBase, RemainLength, MemoryRegion->Attributes);\r
- // Aligned the address\r
- PhysicalBase = (PhysicalBase + TT_DESCRIPTOR_SECTION_SIZE) & ~(TT_DESCRIPTOR_SECTION_SIZE-1);\r
+ PopulateLevel2PageTable (SectionEntry, PhysicalBase, PageMapLength,\r
+ MemoryRegion->Attributes);\r
+\r
+ //\r
+ // Issue a DMB to ensure that the page table entry update made it to\r
+ // memory before we issue the invalidate, otherwise, a subsequent\r
+ // speculative fetch could observe the old value.\r
+ //\r
+ ArmDataMemoryBarrier ();\r
+ ArmInvalidateDataCacheEntryByMVA ((UINTN)SectionEntry++);\r
\r
// If it is the last entry\r
if (RemainLength < TT_DESCRIPTOR_SECTION_SIZE) {\r
break;\r
}\r
+\r
+ PhysicalBase += PageMapLength;\r
+ RemainLength -= PageMapLength;\r
}\r
- RemainLength -= TT_DESCRIPTOR_SECTION_SIZE;\r
}\r
}\r
\r
OUT UINTN *TranslationTableSize OPTIONAL\r
)\r
{\r
- VOID* TranslationTable;\r
- ARM_MEMORY_REGION_ATTRIBUTES TranslationTableAttribute;\r
+ VOID *TranslationTable;\r
UINT32 TTBRAttributes;\r
\r
- // Allocate pages for translation table.\r
- TranslationTable = AllocatePages (EFI_SIZE_TO_PAGES (TRANSLATION_TABLE_SECTION_SIZE + TRANSLATION_TABLE_SECTION_ALIGNMENT));\r
+ TranslationTable = AllocateAlignedPages (\r
+ EFI_SIZE_TO_PAGES (TRANSLATION_TABLE_SECTION_SIZE),\r
+ TRANSLATION_TABLE_SECTION_ALIGNMENT);\r
if (TranslationTable == NULL) {\r
return RETURN_OUT_OF_RESOURCES;\r
}\r
- TranslationTable = (VOID*)(((UINTN)TranslationTable + TRANSLATION_TABLE_SECTION_ALIGNMENT_MASK) & ~TRANSLATION_TABLE_SECTION_ALIGNMENT_MASK);\r
\r
if (TranslationTableBase != NULL) {\r
*TranslationTableBase = TranslationTable;\r
*TranslationTableSize = TRANSLATION_TABLE_SECTION_SIZE;\r
}\r
\r
+ //\r
+ // Make sure we are not inadvertently hitting in the caches\r
+ // when populating the page tables\r
+ //\r
+ InvalidateDataCacheRange (TranslationTable, TRANSLATION_TABLE_SECTION_SIZE);\r
ZeroMem (TranslationTable, TRANSLATION_TABLE_SECTION_SIZE);\r
\r
- // By default, mark the translation table as belonging to a uncached region\r
- TranslationTableAttribute = ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED;\r
while (MemoryTable->Length != 0) {\r
- // Find the memory attribute for the Translation Table\r
- if (((UINTN)TranslationTable >= MemoryTable->PhysicalBase) && ((UINTN)TranslationTable <= MemoryTable->PhysicalBase - 1 + MemoryTable->Length)) {\r
- TranslationTableAttribute = MemoryTable->Attributes;\r
- }\r
-\r
FillTranslationTable (TranslationTable, MemoryTable);\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
- TTBRAttributes = ArmHasMpExtensions () ? TTBR_MP_NON_CACHEABLE : TTBR_NON_CACHEABLE;\r
- } else if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK) ||\r
- (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK)) {\r
- TTBRAttributes = ArmHasMpExtensions () ? TTBR_MP_WRITE_BACK_ALLOC : TTBR_WRITE_BACK_ALLOC;\r
- } else if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH) ||\r
- (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_THROUGH)) {\r
- TTBRAttributes = ArmHasMpExtensions () ? TTBR_MP_WRITE_THROUGH : TTBR_WRITE_THROUGH;\r
- } else {\r
- ASSERT (0); // No support has been found for the attributes of the memory region that the translation table belongs to.\r
- return RETURN_UNSUPPORTED;\r
- }\r
-\r
+ TTBRAttributes = ArmHasMpExtensions () ? TTBR_MP_WRITE_BACK_ALLOC\r
+ : TTBR_WRITE_BACK_ALLOC;\r
if (TTBRAttributes & TTBR_SHAREABLE) {\r
if (PreferNonshareableMemory ()) {\r
TTBRAttributes ^= TTBR_SHAREABLE;\r
}\r
}\r
\r
- ArmCleanInvalidateDataCache ();\r
- ArmInvalidateInstructionCache ();\r
-\r
- ArmDisableDataCache ();\r
- ArmDisableInstructionCache();\r
- // TLBs are also invalidated when calling ArmDisableMmu()\r
- ArmDisableMmu ();\r
-\r
- // Make sure nothing sneaked into the cache\r
- ArmCleanInvalidateDataCache ();\r
- ArmInvalidateInstructionCache ();\r
-\r
- ArmSetTTBR0 ((VOID *)(UINTN)(((UINTN)TranslationTable & ~TRANSLATION_TABLE_SECTION_ALIGNMENT_MASK) | (TTBRAttributes & 0x7F)));\r
+ ArmSetTTBR0 ((VOID *)((UINTN)TranslationTable | TTBRAttributes));\r
\r
//\r
// The TTBCR register value is undefined at reset in the Non-Secure world.\r
ArmEnableMmu();\r
return RETURN_SUCCESS;\r
}\r
-\r
-STATIC\r
-EFI_STATUS\r
-ConvertSectionToPages (\r
- IN EFI_PHYSICAL_ADDRESS BaseAddress\r
- )\r
-{\r
- UINT32 FirstLevelIdx;\r
- UINT32 SectionDescriptor;\r
- UINT32 PageTableDescriptor;\r
- UINT32 PageDescriptor;\r
- UINT32 Index;\r
-\r
- volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
- volatile ARM_PAGE_TABLE_ENTRY *PageTable;\r
-\r
- DEBUG ((EFI_D_PAGE, "Converting section at 0x%x to pages\n", (UINTN)BaseAddress));\r
-\r
- // Obtain page table base\r
- FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
-\r
- // Calculate index into first level translation table for start of modification\r
- FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
- ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
-\r
- // Get section attributes and convert to page attributes\r
- SectionDescriptor = FirstLevelTable[FirstLevelIdx];\r
- PageDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE | ConvertSectionAttributesToPageAttributes (SectionDescriptor, FALSE);\r
-\r
- // Allocate a page table for the 4KB entries (we use up a full page even though we only need 1KB)\r
- PageTable = (volatile ARM_PAGE_TABLE_ENTRY *)AllocatePages (1);\r
- if (PageTable == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- // Write the page table entries out\r
- for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) {\r
- PageTable[Index] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseAddress + (Index << 12)) | PageDescriptor;\r
- }\r
-\r
- // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks\r
- WriteBackInvalidateDataCacheRange ((VOID *)PageTable, TT_DESCRIPTOR_PAGE_SIZE);\r
-\r
- // Formulate page table entry, Domain=0, NS=0\r
- PageTableDescriptor = (((UINTN)PageTable) & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) | TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE;\r
-\r
- // Write the page table entry out, replacing section entry\r
- FirstLevelTable[FirstLevelIdx] = PageTableDescriptor;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-STATIC\r
-EFI_STATUS\r
-UpdatePageEntries (\r
- IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
- IN UINT64 Length,\r
- IN UINT64 Attributes,\r
- IN EFI_PHYSICAL_ADDRESS VirtualMask,\r
- OUT BOOLEAN *FlushTlbs OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 EntryValue;\r
- UINT32 EntryMask;\r
- UINT32 FirstLevelIdx;\r
- UINT32 Offset;\r
- UINT32 NumPageEntries;\r
- UINT32 Descriptor;\r
- UINT32 p;\r
- UINT32 PageTableIndex;\r
- UINT32 PageTableEntry;\r
- UINT32 CurrentPageTableEntry;\r
- VOID *Mva;\r
-\r
- volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
- volatile ARM_PAGE_TABLE_ENTRY *PageTable;\r
-\r
- Status = EFI_SUCCESS;\r
-\r
- // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)\r
- // EntryValue: values at bit positions specified by EntryMask\r
- EntryMask = TT_DESCRIPTOR_PAGE_TYPE_MASK | TT_DESCRIPTOR_PAGE_AP_MASK;\r
- if (Attributes & EFI_MEMORY_XP) {\r
- EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE_XN;\r
- } else {\r
- EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE;\r
- }\r
-\r
- // Although the PI spec is unclear on this, the GCD guarantees that only\r
- // one Attribute bit is set at a time, so the order of the conditionals below\r
- // is irrelevant. If no memory attribute is specified, we preserve whatever\r
- // memory type is set in the page tables, and update the permission attributes\r
- // only.\r
- if (Attributes & EFI_MEMORY_UC) {\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
- // map to strongly ordered\r
- EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
- } else if (Attributes & EFI_MEMORY_WC) {\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
- // map to normal non-cachable\r
- EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
- } else if (Attributes & EFI_MEMORY_WT) {\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
- // write through with no-allocate\r
- EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
- } else if (Attributes & EFI_MEMORY_WB) {\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
- // write back (with allocate)\r
- EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
- } else if (Attributes & CACHE_ATTRIBUTE_MASK) {\r
- // catch unsupported memory type attributes\r
- ASSERT (FALSE);\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- if (Attributes & EFI_MEMORY_RO) {\r
- EntryValue |= TT_DESCRIPTOR_PAGE_AP_RO_RO;\r
- } else {\r
- EntryValue |= TT_DESCRIPTOR_PAGE_AP_RW_RW;\r
- }\r
-\r
- // Obtain page table base\r
- FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
-\r
- // Calculate number of 4KB page table entries to change\r
- NumPageEntries = Length / TT_DESCRIPTOR_PAGE_SIZE;\r
-\r
- // Iterate for the number of 4KB pages to change\r
- Offset = 0;\r
- for(p = 0; p < NumPageEntries; p++) {\r
- // Calculate index into first level translation table for page table value\r
-\r
- FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress + Offset) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
- ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
-\r
- // Read the descriptor from the first level page table\r
- Descriptor = FirstLevelTable[FirstLevelIdx];\r
-\r
- // Does this descriptor need to be converted from section entry to 4K pages?\r
- if (!TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(Descriptor)) {\r
- Status = ConvertSectionToPages (FirstLevelIdx << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
- if (EFI_ERROR(Status)) {\r
- // Exit for loop\r
- break;\r
- }\r
-\r
- // Re-read descriptor\r
- Descriptor = FirstLevelTable[FirstLevelIdx];\r
- if (FlushTlbs != NULL) {\r
- *FlushTlbs = TRUE;\r
- }\r
- }\r
-\r
- // Obtain page table base address\r
- PageTable = (ARM_PAGE_TABLE_ENTRY *)TT_DESCRIPTOR_PAGE_BASE_ADDRESS(Descriptor);\r
-\r
- // Calculate index into the page table\r
- PageTableIndex = ((BaseAddress + Offset) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
- ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
-\r
- // Get the entry\r
- CurrentPageTableEntry = PageTable[PageTableIndex];\r
-\r
- // Mask off appropriate fields\r
- PageTableEntry = CurrentPageTableEntry & ~EntryMask;\r
-\r
- // Mask in new attributes and/or permissions\r
- PageTableEntry |= EntryValue;\r
-\r
- if (VirtualMask != 0) {\r
- // Make this virtual address point at a physical page\r
- PageTableEntry &= ~VirtualMask;\r
- }\r
-\r
- if (CurrentPageTableEntry != PageTableEntry) {\r
- Mva = (VOID *)(UINTN)((((UINTN)FirstLevelIdx) << TT_DESCRIPTOR_SECTION_BASE_SHIFT) + (PageTableIndex << TT_DESCRIPTOR_PAGE_BASE_SHIFT));\r
-\r
- // Clean/invalidate the cache for this page, but only\r
- // if we are modifying the memory type attributes\r
- if (((CurrentPageTableEntry ^ PageTableEntry) & TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK) != 0) {\r
- WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE);\r
- }\r
-\r
- // Only need to update if we are changing the entry\r
- PageTable[PageTableIndex] = PageTableEntry;\r
- ArmUpdateTranslationTableEntry ((VOID *)&PageTable[PageTableIndex], Mva);\r
- }\r
-\r
- Status = EFI_SUCCESS;\r
- Offset += TT_DESCRIPTOR_PAGE_SIZE;\r
-\r
- } // End first level translation table loop\r
-\r
- return Status;\r
-}\r
-\r
-STATIC\r
-EFI_STATUS\r
-UpdateSectionEntries (\r
- IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
- IN UINT64 Length,\r
- IN UINT64 Attributes,\r
- IN EFI_PHYSICAL_ADDRESS VirtualMask\r
- )\r
-{\r
- EFI_STATUS Status = EFI_SUCCESS;\r
- UINT32 EntryMask;\r
- UINT32 EntryValue;\r
- UINT32 FirstLevelIdx;\r
- UINT32 NumSections;\r
- UINT32 i;\r
- UINT32 CurrentDescriptor;\r
- UINT32 Descriptor;\r
- VOID *Mva;\r
- volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
-\r
- // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)\r
- // EntryValue: values at bit positions specified by EntryMask\r
-\r
- // Make sure we handle a section range that is unmapped\r
- EntryMask = TT_DESCRIPTOR_SECTION_TYPE_MASK | TT_DESCRIPTOR_SECTION_XN_MASK |\r
- TT_DESCRIPTOR_SECTION_AP_MASK;\r
- EntryValue = TT_DESCRIPTOR_SECTION_TYPE_SECTION;\r
-\r
- // Although the PI spec is unclear on this, the GCD guarantees that only\r
- // one Attribute bit is set at a time, so the order of the conditionals below\r
- // is irrelevant. If no memory attribute is specified, we preserve whatever\r
- // memory type is set in the page tables, and update the permission attributes\r
- // only.\r
- if (Attributes & EFI_MEMORY_UC) {\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
- // map to strongly ordered\r
- EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
- } else if (Attributes & EFI_MEMORY_WC) {\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
- // map to normal non-cachable\r
- EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
- } else if (Attributes & EFI_MEMORY_WT) {\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
- // write through with no-allocate\r
- EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
- } else if (Attributes & EFI_MEMORY_WB) {\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
- // write back (with allocate)\r
- EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
- } else if (Attributes & CACHE_ATTRIBUTE_MASK) {\r
- // catch unsupported memory type attributes\r
- ASSERT (FALSE);\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- if (Attributes & EFI_MEMORY_RO) {\r
- EntryValue |= TT_DESCRIPTOR_SECTION_AP_RO_RO;\r
- } else {\r
- EntryValue |= TT_DESCRIPTOR_SECTION_AP_RW_RW;\r
- }\r
-\r
- if (Attributes & EFI_MEMORY_XP) {\r
- EntryValue |= TT_DESCRIPTOR_SECTION_XN_MASK;\r
- }\r
-\r
- // obtain page table base\r
- FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
-\r
- // calculate index into first level translation table for start of modification\r
- FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
- ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
-\r
- // calculate number of 1MB first level entries this applies to\r
- NumSections = Length / TT_DESCRIPTOR_SECTION_SIZE;\r
-\r
- // iterate through each descriptor\r
- for(i=0; i<NumSections; i++) {\r
- CurrentDescriptor = FirstLevelTable[FirstLevelIdx + i];\r
-\r
- // has this descriptor already been coverted to pages?\r
- if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(CurrentDescriptor)) {\r
- // forward this 1MB range to page table function instead\r
- Status = UpdatePageEntries (\r
- (FirstLevelIdx + i) << TT_DESCRIPTOR_SECTION_BASE_SHIFT,\r
- TT_DESCRIPTOR_SECTION_SIZE,\r
- Attributes,\r
- VirtualMask,\r
- NULL);\r
- } else {\r
- // still a section entry\r
-\r
- // mask off appropriate fields\r
- Descriptor = CurrentDescriptor & ~EntryMask;\r
-\r
- // mask in new attributes and/or permissions\r
- Descriptor |= EntryValue;\r
- if (VirtualMask != 0) {\r
- Descriptor &= ~VirtualMask;\r
- }\r
-\r
- if (CurrentDescriptor != Descriptor) {\r
- Mva = (VOID *)(UINTN)(((UINTN)FirstLevelTable) << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
-\r
- // Clean/invalidate the cache for this section, but only\r
- // if we are modifying the memory type attributes\r
- if (((CurrentDescriptor ^ Descriptor) & TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK) != 0) {\r
- WriteBackInvalidateDataCacheRange (Mva, SIZE_1MB);\r
- }\r
-\r
- // Only need to update if we are changing the descriptor\r
- FirstLevelTable[FirstLevelIdx + i] = Descriptor;\r
- ArmUpdateTranslationTableEntry ((VOID *)&FirstLevelTable[FirstLevelIdx + i], Mva);\r
- }\r
-\r
- Status = EFI_SUCCESS;\r
- }\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-ArmSetMemoryAttributes (\r
- IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
- IN UINT64 Length,\r
- IN UINT64 Attributes,\r
- IN EFI_PHYSICAL_ADDRESS VirtualMask\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT64 ChunkLength;\r
- BOOLEAN FlushTlbs;\r
-\r
- if (Length == 0) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- FlushTlbs = FALSE;\r
- while (Length > 0) {\r
- if ((BaseAddress % TT_DESCRIPTOR_SECTION_SIZE == 0) &&\r
- Length >= TT_DESCRIPTOR_SECTION_SIZE) {\r
-\r
- ChunkLength = Length - Length % TT_DESCRIPTOR_SECTION_SIZE;\r
-\r
- DEBUG ((DEBUG_PAGE,\r
- "SetMemoryAttributes(): MMU section 0x%lx length 0x%lx to %lx\n",\r
- BaseAddress, ChunkLength, Attributes));\r
-\r
- Status = UpdateSectionEntries (BaseAddress, ChunkLength, Attributes,\r
- VirtualMask);\r
-\r
- FlushTlbs = TRUE;\r
- } else {\r
-\r
- //\r
- // Process page by page until the next section boundary, but only if\r
- // we have more than a section's worth of area to deal with after that.\r
- //\r
- ChunkLength = TT_DESCRIPTOR_SECTION_SIZE -\r
- (BaseAddress % TT_DESCRIPTOR_SECTION_SIZE);\r
- if (ChunkLength + TT_DESCRIPTOR_SECTION_SIZE > Length) {\r
- ChunkLength = Length;\r
- }\r
-\r
- DEBUG ((DEBUG_PAGE,\r
- "SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n",\r
- BaseAddress, ChunkLength, Attributes));\r
-\r
- Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes,\r
- VirtualMask, &FlushTlbs);\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
-\r
- BaseAddress += ChunkLength;\r
- Length -= ChunkLength;\r
- }\r
-\r
- if (FlushTlbs) {\r
- ArmInvalidateTlb ();\r
- }\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-ArmSetMemoryRegionNoExec (\r
- IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
- IN UINT64 Length\r
- )\r
-{\r
- return EFI_UNSUPPORTED;\r
-}\r
-\r
-EFI_STATUS\r
-ArmClearMemoryRegionNoExec (\r
- IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
- IN UINT64 Length\r
- )\r
-{\r
- return EFI_UNSUPPORTED;\r
-}\r
-\r
-EFI_STATUS\r
-ArmSetMemoryRegionReadOnly (\r
- IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
- IN UINT64 Length\r
- )\r
-{\r
- return EFI_UNSUPPORTED;\r
-}\r
-\r
-EFI_STATUS\r
-ArmClearMemoryRegionReadOnly (\r
- IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
- IN UINT64 Length\r
- )\r
-{\r
- return EFI_UNSUPPORTED;\r
-}\r
-\r
-RETURN_STATUS\r
-EFIAPI\r
-ArmMmuBaseLibConstructor (\r
- VOID\r
- )\r
-{\r
- return RETURN_SUCCESS;\r
-}\r