// Second Level Descriptors\r
typedef UINT32 ARM_PAGE_TABLE_ENTRY;\r
\r
-EFI_STATUS \r
+EFI_STATUS\r
SectionToGcdAttributes (\r
IN UINT32 SectionAttributes,\r
OUT UINT64 *GcdAttributes\r
\r
// Calculate number of 4KB page table entries to change\r
NumPageEntries = Length / TT_DESCRIPTOR_PAGE_SIZE;\r
- \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
+\r
FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress + Offset) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
\r
Status = ConvertSectionToPages (FirstLevelIdx << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
if (EFI_ERROR(Status)) {\r
// Exit for loop\r
- break; \r
- } \r
- \r
+ break;\r
+ }\r
+\r
// Re-read descriptor\r
Descriptor = FirstLevelTable[FirstLevelIdx];\r
}\r
// Make this virtual address point at a physical page\r
PageTableEntry &= ~VirtualMask;\r
}\r
- \r
+\r
if (CurrentPageTableEntry != PageTableEntry) {\r
Mva = (VOID *)(UINTN)((((UINTN)FirstLevelIdx) << TT_DESCRIPTOR_SECTION_BASE_SHIFT) + (PageTableIndex << TT_DESCRIPTOR_PAGE_BASE_SHIFT));\r
if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) {\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
+ // 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
+\r
} // End first level translation table loop\r
\r
return Status;\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
+ // Make sure we handle a section range that is unmapped\r
EntryMask = TT_DESCRIPTOR_SECTION_TYPE_MASK;\r
EntryValue = TT_DESCRIPTOR_SECTION_TYPE_SECTION;\r
\r
\r
// calculate number of 1MB first level entries this applies to\r
NumSections = Length / TT_DESCRIPTOR_SECTION_SIZE;\r
- \r
+\r
// iterate through each descriptor\r
for(i=0; i<NumSections; i++) {\r
CurrentDescriptor = FirstLevelTable[FirstLevelIdx + i];\r
Status = UpdatePageEntries ((FirstLevelIdx + i) << TT_DESCRIPTOR_SECTION_BASE_SHIFT, TT_DESCRIPTOR_SECTION_SIZE, Attributes, VirtualMask);\r
} else {\r
// still a section entry\r
- \r
+\r
// mask off appropriate fields\r
Descriptor = CurrentDescriptor & ~EntryMask;\r
\r
WriteBackInvalidateDataCacheRange (Mva, SIZE_1MB);\r
}\r
\r
- // Only need to update if we are changing the descriptor \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
return Status;\r
}\r
\r
-EFI_STATUS \r
+EFI_STATUS\r
ConvertSectionToPages (\r
IN EFI_PHYSICAL_ADDRESS BaseAddress\r
)\r
)\r
{\r
EFI_STATUS Status;\r
- \r
+\r
if(((BaseAddress & 0xFFFFF) == 0) && ((Length & 0xFFFFF) == 0)) {\r
// Is the base and length a multiple of 1 MB?\r
DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU section 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));\r
\r
return Status;\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
+ // Map to strongly ordered\r
+ ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
+ break;\r
+\r
+ case EFI_MEMORY_WC:\r
+ // Map to normal non-cachable\r
+ ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
+ break;\r
+\r
+ case EFI_MEMORY_WT:\r
+ // Write through with no-allocate\r
+ ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
+ break;\r
+\r
+ case EFI_MEMORY_WB:\r
+ // Write back (with allocate)\r
+ ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
+ break;\r
+\r
+ case EFI_MEMORY_WP:\r
+ case EFI_MEMORY_XP:\r
+ case EFI_MEMORY_RP:\r
+ case EFI_MEMORY_UCE:\r
+ default:\r
+ // Cannot be implemented UEFI definition unclear for ARM\r
+ // Cause a page fault if these ranges are accessed.\r
+ ArmAttributes = TT_DESCRIPTOR_SECTION_TYPE_FAULT;\r
+ DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): Unsupported attribute %x will page fault on access\n", EfiAttributes));\r
+ break;\r
+ }\r
+\r
+ // Determine protection attributes\r
+ if (EfiAttributes & EFI_MEMORY_WP) {\r
+ ArmAttributes |= TT_DESCRIPTOR_SECTION_AP_RO_RO;\r
+ } else {\r
+ ArmAttributes |= TT_DESCRIPTOR_SECTION_AP_RW_RW;\r
+ }\r
+\r
+ // Determine eXecute Never attribute\r
+ if (EfiAttributes & EFI_MEMORY_XP) {\r
+ ArmAttributes |= TT_DESCRIPTOR_SECTION_XN_MASK;\r
+ }\r
+\r
+ return ArmAttributes;\r
+}\r
+\r
+EFI_STATUS\r
+GetMemoryRegionPage (\r
+ IN UINT32 *PageTable,\r
+ IN OUT UINTN *BaseAddress,\r
+ OUT UINTN *RegionLength,\r
+ OUT UINTN *RegionAttributes\r
+ )\r
+{\r
+ UINT32 PageAttributes;\r
+ UINT32 TableIndex;\r
+ UINT32 PageDescriptor;\r
+\r
+ // Convert the section attributes into page attributes\r
+ PageAttributes = ConvertSectionAttributesToPageAttributes (*RegionAttributes, 0);\r
+\r
+ // Calculate index into first level translation table for start of modification\r
+ TableIndex = ((*BaseAddress) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
+ ASSERT (TableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
+\r
+ // Go through the page table to find the end of the section\r
+ for (; TableIndex < TRANSLATION_TABLE_PAGE_COUNT; TableIndex++) {\r
+ // Get the section at the given index\r
+ PageDescriptor = PageTable[TableIndex];\r
+\r
+ if ((PageDescriptor & TT_DESCRIPTOR_PAGE_TYPE_MASK) == TT_DESCRIPTOR_PAGE_TYPE_FAULT) {\r
+ // Case: End of the boundary of the region\r
+ return EFI_SUCCESS;\r
+ } else if ((PageDescriptor & TT_DESCRIPTOR_PAGE_TYPE_PAGE) == TT_DESCRIPTOR_PAGE_TYPE_PAGE) {\r
+ if ((PageDescriptor & TT_DESCRIPTOR_PAGE_ATTRIBUTE_MASK) == PageAttributes) {\r
+ *RegionLength = *RegionLength + TT_DESCRIPTOR_PAGE_SIZE;\r
+ } else {\r
+ // Case: End of the boundary of the region\r
+ return EFI_SUCCESS;\r
+ }\r
+ } else {\r
+ // We do not support Large Page yet. We return EFI_SUCCESS that means end of the region.\r
+ ASSERT(0);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\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
+ UINT32 TableIndex;\r
+ UINT32 PageAttributes;\r
+ UINT32 PageTableIndex;\r
+ UINT32 SectionDescriptor;\r
+ ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
+ UINT32 *PageTable;\r
+\r
+ // Initialize the arguments\r
+ *RegionLength = 0;\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
+ TableIndex = TT_DESCRIPTOR_SECTION_BASE_ADDRESS (*BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
+ ASSERT (TableIndex < TRANSLATION_TABLE_SECTION_COUNT);\r
+\r
+ // Get the section at the given index\r
+ SectionDescriptor = FirstLevelTable[TableIndex];\r
+\r
+ // If 'BaseAddress' belongs to the section then round it to the section boundary\r
+ if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||\r
+ ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION))\r
+ {\r
+ *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_SECTION_BASE_ADDRESS_MASK;\r
+ *RegionAttributes = SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK;\r
+ } else {\r
+ // Otherwise, we round it to the page boundary\r
+ *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK;\r
+\r
+ // Get the attribute at the page table level (Level 2)\r
+ PageTable = (UINT32*)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);\r
+\r
+ // Calculate index into first level translation table for start of modification\r
+ PageTableIndex = ((*BaseAddress) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
+ ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
+\r
+ PageAttributes = PageTable[PageTableIndex] & TT_DESCRIPTOR_PAGE_ATTRIBUTE_MASK;\r
+ *RegionAttributes = TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY (PageAttributes, 0) |\r
+ TT_DESCRIPTOR_CONVERT_TO_SECTION_AP (PageAttributes);\r
+ }\r
+\r
+ for (;TableIndex < TRANSLATION_TABLE_SECTION_COUNT; TableIndex++) {\r
+ // Get the section at the given index\r
+ SectionDescriptor = FirstLevelTable[TableIndex];\r
+\r
+ // If the entry is a level-2 page table then we scan it to find the end of the region\r
+ if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE (SectionDescriptor)) {\r
+ // Extract the page table location from the descriptor\r
+ PageTable = (UINT32*)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);\r
+\r
+ // Scan the page table to find the end of the region.\r
+ Status = GetMemoryRegionPage (PageTable, BaseAddress, RegionLength, RegionAttributes);\r
+\r
+ // If we have found the end of the region (Status == EFI_SUCCESS) then we exit the for-loop\r
+ if (Status == EFI_SUCCESS) {\r
+ break;\r
+ }\r
+ } else if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||\r
+ ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION)) {\r
+ if ((SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK) != *RegionAttributes) {\r
+ // If the attributes of the section differ from the one targeted then we exit the loop\r
+ break;\r
+ } else {\r
+ *RegionLength = *RegionLength + TT_DESCRIPTOR_SECTION_SIZE;\r
+ }\r
+ } else {\r
+ // If we are on an invalid section then it means it is the end of our section.\r
+ break;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r