]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Drivers/CpuDxe/ArmV6/Mmu.c
ArmPkg/CpuDxe: Added support to not set a memory region with the same attribute
[mirror_edk2.git] / ArmPkg / Drivers / CpuDxe / ArmV6 / Mmu.c
index 38b709de15deb163a90813d9265e998deaf21969..474f105d229b05315141e7cc9f4527e24f14fd3d 100644 (file)
@@ -696,3 +696,185 @@ SetMemoryAttributes (
 \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 = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(*BaseAddress) >> 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 = TT_DESCRIPTOR_PAGE_BASE_ADDRESS (*BaseAddress) >> 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 ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE) {\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