diff options
author | oliviermartin <oliviermartin@6f19259b-4bc3-4df7-8a09-765794883524> | 2011-03-31 11:23:55 +0000 |
---|---|---|
committer | oliviermartin <oliviermartin@6f19259b-4bc3-4df7-8a09-765794883524> | 2011-03-31 11:23:55 +0000 |
commit | 2cf4b60895f8af5be3fa33231974dc3cb143b53c (patch) | |
tree | 22bccbdbdc269e4ae916ae61e06bd8eade04c3f1 /ArmPkg | |
parent | 2ed2ed29c27dc488dcfa602059847a168941e593 (diff) | |
download | edk2-2cf4b60895f8af5be3fa33231974dc3cb143b53c.tar.gz edk2-2cf4b60895f8af5be3fa33231974dc3cb143b53c.tar.bz2 edk2-2cf4b60895f8af5be3fa33231974dc3cb143b53c.zip |
ArmPkg/Mmu: Support page size granularity in the initial MMU setting
Formerly, it was only possible to use section size granularity for the
translation table regions.
This change allows to define initial translation table regions with
4K-byte granularty (page size granularity).
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11467 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'ArmPkg')
-rw-r--r-- | ArmPkg/Drivers/CpuDxe/Mmu.c | 223 | ||||
-rw-r--r-- | ArmPkg/Include/Chipset/ArmV7.h | 30 | ||||
-rw-r--r-- | ArmPkg/Library/ArmLib/ArmV7/ArmV7Mmu.c | 140 |
3 files changed, 353 insertions, 40 deletions
diff --git a/ArmPkg/Drivers/CpuDxe/Mmu.c b/ArmPkg/Drivers/CpuDxe/Mmu.c index 9ba5c83448..89bf88ed3b 100644 --- a/ArmPkg/Drivers/CpuDxe/Mmu.c +++ b/ArmPkg/Drivers/CpuDxe/Mmu.c @@ -88,6 +88,70 @@ SectionToGcdAttributes ( return EFI_SUCCESS;
}
+EFI_STATUS
+PageToGcdAttributes (
+ IN UINT32 PageAttributes,
+ OUT UINT64 *GcdAttributes
+ )
+{
+ *GcdAttributes = 0;
+
+ // determine cacheability attributes
+ switch(PageAttributes & TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK) {
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED:
+ *GcdAttributes |= EFI_MEMORY_UC;
+ break;
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_SHAREABLE_DEVICE:
+ *GcdAttributes |= EFI_MEMORY_UC;
+ break;
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC:
+ *GcdAttributes |= EFI_MEMORY_WT;
+ break;
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_NO_ALLOC:
+ *GcdAttributes |= EFI_MEMORY_WB;
+ break;
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE:
+ *GcdAttributes |= EFI_MEMORY_WC;
+ break;
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC:
+ *GcdAttributes |= EFI_MEMORY_WB;
+ break;
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_SHAREABLE_DEVICE:
+ *GcdAttributes |= EFI_MEMORY_UC;
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ // determine protection attributes
+ switch(PageAttributes & TT_DESCRIPTOR_PAGE_AP_MASK) {
+ case TT_DESCRIPTOR_PAGE_AP_NO_NO: // no read, no write
+ //*GcdAttributes |= EFI_MEMORY_WP | EFI_MEMORY_RP;
+ break;
+
+ case TT_DESCRIPTOR_PAGE_AP_RW_NO:
+ case TT_DESCRIPTOR_PAGE_AP_RW_RW:
+ // normal read/write access, do not add additional attributes
+ break;
+
+ // read only cases map to write-protect
+ case TT_DESCRIPTOR_PAGE_AP_RO_NO:
+ case TT_DESCRIPTOR_PAGE_AP_RO_RO:
+ *GcdAttributes |= EFI_MEMORY_WP;
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ // now process eXectue Never attribute
+ if ((PageAttributes & TT_DESCRIPTOR_PAGE_XN_MASK) != 0 ) {
+ *GcdAttributes |= EFI_MEMORY_XP;
+ }
+
+ return EFI_SUCCESS;
+}
+
/**
Searches memory descriptors covered by given memory range.
@@ -215,6 +279,81 @@ SetGcdMemorySpaceAttributes ( return EFI_SUCCESS;
}
+EFI_STATUS
+SyncCacheConfigPage (
+ IN UINT32 SectionIndex,
+ IN UINT32 FirstLevelDescriptor,
+ IN UINTN NumberOfDescriptors,
+ IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
+ IN OUT EFI_PHYSICAL_ADDRESS *NextRegionBase,
+ IN OUT UINT64 *NextRegionLength,
+ IN OUT UINT32 *NextSectionAttributes
+ )
+{
+ EFI_STATUS Status;
+ UINT32 i;
+ volatile ARM_PAGE_TABLE_ENTRY *SecondLevelTable;
+ UINT32 NextPageAttributes = 0;
+ UINT32 PageAttributes = 0;
+ UINT32 BaseAddress;
+ UINT64 GcdAttributes;
+
+ // Get the Base Address from FirstLevelDescriptor;
+ BaseAddress = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(SectionIndex << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
+
+ // Convert SectionAttributes into PageAttributes
+ NextPageAttributes =
+ TT_DESCRIPTOR_CONVERT_TO_PAGE_CACHE_POLICY(*NextSectionAttributes,0) |
+ TT_DESCRIPTOR_CONVERT_TO_PAGE_AP(*NextSectionAttributes);
+
+ // obtain page table base
+ SecondLevelTable = (ARM_PAGE_TABLE_ENTRY *)(FirstLevelDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);
+
+ for (i=0; i < TRANSLATION_TABLE_PAGE_COUNT; i++) {
+ if ((SecondLevelTable[i] & TT_DESCRIPTOR_PAGE_TYPE_MASK) == TT_DESCRIPTOR_PAGE_TYPE_PAGE) {
+ // extract attributes (cacheability and permissions)
+ PageAttributes = SecondLevelTable[i] & (TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK | TT_DESCRIPTOR_PAGE_AP_MASK);
+
+ if (NextPageAttributes == 0) {
+ // start on a new region
+ *NextRegionLength = 0;
+ *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);
+ NextPageAttributes = PageAttributes;
+ } else if (PageAttributes != NextPageAttributes) {
+ // Convert Section Attributes into GCD Attributes
+ Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);
+ ASSERT_EFI_ERROR (Status);
+
+ // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);
+
+ // start on a new region
+ *NextRegionLength = 0;
+ *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);
+ NextPageAttributes = PageAttributes;
+ }
+ } else if (NextPageAttributes != 0) {
+ // Convert Page Attributes into GCD Attributes
+ Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);
+ ASSERT_EFI_ERROR (Status);
+
+ // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);
+
+ *NextRegionLength = 0;
+ *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);
+ NextPageAttributes = 0;
+ }
+ *NextRegionLength += TT_DESCRIPTOR_PAGE_SIZE;
+ }
+
+ // Convert back PageAttributes into SectionAttributes
+ *NextSectionAttributes =
+ TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY(NextPageAttributes,0) |
+ TT_DESCRIPTOR_CONVERT_TO_SECTION_AP(NextPageAttributes);
+
+ return EFI_SUCCESS;
+}
EFI_STATUS
SyncCacheConfig (
@@ -223,12 +362,11 @@ SyncCacheConfig ( {
EFI_STATUS Status;
UINT32 i;
- UINT32 Descriptor;
- UINT32 SectionAttributes;
EFI_PHYSICAL_ADDRESS NextRegionBase;
UINT64 NextRegionLength;
+ UINT32 NextSectionAttributes = 0;
+ UINT32 SectionAttributes = 0;
UINT64 GcdAttributes;
- UINT32 NextRegionAttributes = 0;
volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
UINTN NumberOfDescriptors;
EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
@@ -256,46 +394,71 @@ SyncCacheConfig ( // obtain page table base
FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)(ArmGetTTBR0BaseAddress ());
+ // Get the first region
+ NextSectionAttributes = FirstLevelTable[0] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);
// iterate through each 1MB descriptor
NextRegionBase = NextRegionLength = 0;
- for (i=0; i< TRANSLATION_TABLE_SECTION_COUNT; i++) {
-
- // obtain existing descriptor and make sure it contains a valid Base Address even if it is a fault section
- Descriptor = FirstLevelTable[i] | TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
-
- // extract attributes (cacheability and permissions)
- SectionAttributes = Descriptor & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);
-
- // do we already have an existing region (or are we about to finish)?
- // Skip the first entry, and make sure we close on the last entry
- if ( (NextRegionLength > 0) || (i == (TRANSLATION_TABLE_SECTION_COUNT-1)) ) {
- // attributes are changing, update attributes in GCD
- if (SectionAttributes != NextRegionAttributes) {
-
- // convert section entry attributes to GCD bitmask
- Status = SectionToGcdAttributes (NextRegionAttributes, &GcdAttributes);
+ for (i=0; i < TRANSLATION_TABLE_SECTION_COUNT; i++) {
+ if ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) {
+ // extract attributes (cacheability and permissions)
+ SectionAttributes = FirstLevelTable[i] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);
+
+ if (NextSectionAttributes == 0) {
+ // start on a new region
+ NextRegionLength = 0;
+ NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
+ NextSectionAttributes = SectionAttributes;
+ } else if (SectionAttributes != NextSectionAttributes) {
+ // Convert Section Attributes into GCD Attributes
+ Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);
ASSERT_EFI_ERROR (Status);
// update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);
-
// start on a new region
NextRegionLength = 0;
- NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(Descriptor);
+ NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
+ NextSectionAttributes = SectionAttributes;
}
- }
+ NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;
+ } else if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(FirstLevelTable[i])) {
+ Status = SyncCacheConfigPage (
+ i,FirstLevelTable[i],
+ &NumberOfDescriptors, &MemorySpaceMap,
+ &NextRegionBase,&NextRegionLength,&NextSectionAttributes);
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ // We do not support yet 16MB sections
+ ASSERT ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) != TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION);
- // starting a new region?
- if (NextRegionLength == 0) {
- NextRegionAttributes = SectionAttributes;
- }
+ // start on a new region
+ if (NextSectionAttributes != 0) {
+ // Convert Section Attributes into GCD Attributes
+ Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);
+ ASSERT_EFI_ERROR (Status);
- NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;
+ // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);
+ NextRegionLength = 0;
+ NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
+ NextSectionAttributes = 0;
+ }
+ NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;
+ }
} // section entry loop
+ if (NextSectionAttributes != 0) {
+ // Convert Section Attributes into GCD Attributes
+ Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);
+ ASSERT_EFI_ERROR (Status);
+
+ // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);
+ }
+
return EFI_SUCCESS;
}
@@ -591,7 +754,7 @@ ConvertSectionToPages ( UINT32 SectionDescriptor;
UINT32 PageTableDescriptor;
UINT32 PageDescriptor;
- UINT32 i;
+ UINT32 Index;
volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
volatile ARM_PAGE_TABLE_ENTRY *PageTable;
@@ -623,8 +786,8 @@ ConvertSectionToPages ( PageTable = (volatile ARM_PAGE_TABLE_ENTRY *)(UINTN)PageTableAddr;
// write the page table entries out
- for (i=0; i < TRANSLATION_TABLE_PAGE_COUNT; i++) {
- PageTable[i] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseAddress + (i << 12)) | PageDescriptor;
+ for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) {
+ PageTable[Index] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseAddress + (Index << 12)) | PageDescriptor;
}
// flush d-cache so descriptors make it back to uncached memory for subsequent table walks
diff --git a/ArmPkg/Include/Chipset/ArmV7.h b/ArmPkg/Include/Chipset/ArmV7.h index b9d7430580..6a63cceabb 100644 --- a/ArmPkg/Include/Chipset/ArmV7.h +++ b/ArmPkg/Include/Chipset/ArmV7.h @@ -122,6 +122,8 @@ #define TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC ((1UL << 12) | (1UL << 3) | (1UL << 2))
#define TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_SHAREABLE_DEVICE ((2UL << 12) | (0UL << 3) | (0UL << 2))
+#define TT_DESCRIPTOR_PAGE_SIZE (0x00001000)
+
#define TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK ((3UL << 6) | (1UL << 3) | (1UL << 2))
#define TT_DESCRIPTOR_PAGE_CACHEABLE_MASK (1UL << 3)
#define TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED ((0UL << 6) | (0UL << 3) | (0UL << 2))
@@ -151,6 +153,13 @@ (((Desc) & TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK) & TT_DESCRIPTOR_LARGEPAGE_CACHE_POLICY_MASK): \
(((((Desc) & (0x3 << 12)) >> 6) | (Desc & (0x3 << 2)))))
+#define TT_DESCRIPTOR_CONVERT_TO_SECTION_AP(Desc) ((((Desc) & TT_DESCRIPTOR_PAGE_AP_MASK) << 6) & TT_DESCRIPTOR_SECTION_AP_MASK)
+
+#define TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY(Desc,IsLargePage) (IsLargePage? \
+ (((Desc) & TT_DESCRIPTOR_LARGEPAGE_CACHE_POLICY_MASK) & TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK): \
+ (((((Desc) & (0x3 << 6)) << 6) | (Desc & (0x3 << 2)))))
+
+
#define TT_DESCRIPTOR_SECTION_DOMAIN_MASK (0x0FUL << 5)
#define TT_DESCRIPTOR_SECTION_DOMAIN(a) (((a) & 0x0FUL) << 5)
@@ -193,6 +202,27 @@ TT_DESCRIPTOR_SECTION_AP_RW_RW | \
TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE)
+#define TT_DESCRIPTOR_PAGE_WRITE_BACK (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
+ TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
+ TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
+ TT_DESCRIPTOR_PAGE_AP_RW_RW | \
+ TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC)
+#define TT_DESCRIPTOR_PAGE_WRITE_THROUGH (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
+ TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
+ TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
+ TT_DESCRIPTOR_PAGE_AP_RW_RW | \
+ TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC)
+#define TT_DESCRIPTOR_PAGE_DEVICE (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
+ TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
+ TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
+ TT_DESCRIPTOR_PAGE_AP_RW_RW | \
+ TT_DESCRIPTOR_PAGE_CACHE_POLICY_SHAREABLE_DEVICE)
+#define TT_DESCRIPTOR_PAGE_UNCACHED (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
+ TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
+ TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
+ TT_DESCRIPTOR_PAGE_AP_RW_RW | \
+ TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE)
+
// Cortex A9 feature bit definitions
#define A9_FEATURE_PARITY (1<<9)
#define A9_FEATURE_AOW (1<<8)
diff --git a/ArmPkg/Library/ArmLib/ArmV7/ArmV7Mmu.c b/ArmPkg/Library/ArmLib/ArmV7/ArmV7Mmu.c index 9bb3c2690f..3ba66d62bf 100644 --- a/ArmPkg/Library/ArmLib/ArmV7/ArmV7Mmu.c +++ b/ArmPkg/Library/ArmLib/ArmV7/ArmV7Mmu.c @@ -19,21 +19,119 @@ #include <Library/MemoryAllocationLib.h>
#include <Library/ArmLib.h>
#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
#include "ArmV7Lib.h"
#include "ArmLibPrivate.h"
VOID
+PopulateLevel2PageTable (
+ IN UINT32 *SectionEntry,
+ IN UINT32 PhysicalBase,
+ IN UINT32 RemainLength,
+ IN ARM_MEMORY_REGION_ATTRIBUTES Attributes
+ ) {
+ UINT32* PageEntry;
+ UINT32 Pages;
+ UINT32 Index;
+ UINT32 PageAttributes;
+ UINT32 SectionDescriptor;
+ UINT32 TranslationTable;
+ UINT32 BaseSectionAddress;
+
+ switch (Attributes) {
+ case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK:
+ case ARM_MEMORY_REGION_ATTRIBUTE_SECURE_WRITE_BACK:
+ PageAttributes = TT_DESCRIPTOR_PAGE_WRITE_BACK;
+ break;
+ case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH:
+ case ARM_MEMORY_REGION_ATTRIBUTE_SECURE_WRITE_THROUGH:
+ PageAttributes = TT_DESCRIPTOR_PAGE_WRITE_THROUGH;
+ break;
+ case ARM_MEMORY_REGION_ATTRIBUTE_DEVICE:
+ case ARM_MEMORY_REGION_ATTRIBUTE_SECURE_DEVICE:
+ PageAttributes = TT_DESCRIPTOR_PAGE_DEVICE;
+ break;
+ case ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED:
+ case ARM_MEMORY_REGION_ATTRIBUTE_SECURE_UNCACHED_UNBUFFERED:
+ PageAttributes = TT_DESCRIPTOR_PAGE_UNCACHED;
+ break;
+ default:
+ PageAttributes = TT_DESCRIPTOR_PAGE_UNCACHED;
+ break;
+ }
+
+ // Check if the Section Entry has already been populated. Otherwise attach a
+ // Level 2 Translation Table to it
+ if (*SectionEntry != 0) {
+ // The entry must be a page table. Otherwise it exists an overlapping in the memory map
+ if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(*SectionEntry)) {
+ TranslationTable = *SectionEntry & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK;
+ } else if ((*SectionEntry & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) {
+ // Case where a virtual memory map descriptor overlapped a section entry
+
+ // Allocate a Level2 Page Table for this Section
+ TranslationTable = (UINTN)AllocatePages(EFI_SIZE_TO_PAGES(TRANSLATION_TABLE_PAGE_SIZE + TRANSLATION_TABLE_PAGE_ALIGNMENT));
+ TranslationTable = ((UINTN)TranslationTable + TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK) & ~TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK;
+
+ // Translate the Section Descriptor into Page Descriptor
+ SectionDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE;
+ SectionDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_CACHE_POLICY(*SectionEntry,0);
+ SectionDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_AP(*SectionEntry);
+ SectionDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_XN(*SectionEntry,0);
+ SectionDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_NG(*SectionEntry);
+ SectionDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_S(*SectionEntry);
+
+ BaseSectionAddress = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(*SectionEntry);
+
+ // Populate the new Level2 Page Table for the section
+ PageEntry = (UINT32*)TranslationTable;
+ for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) {
+ PageEntry[Index] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseSectionAddress + (Index << 12)) | SectionDescriptor;
+ }
+
+ // Overwrite the section entry to point to the new Level2 Translation Table
+ *SectionEntry = (TranslationTable & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) |
+ (IS_ARM_MEMORY_REGION_ATTRIBUTES_SECURE(Attributes) ? (1 << 3) : 0) |
+ TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE;
+ } else {
+ // We do not support the other section type (16MB Section)
+ ASSERT(0);
+ return;
+ }
+ } else {
+ TranslationTable = (UINTN)AllocatePages(EFI_SIZE_TO_PAGES(TRANSLATION_TABLE_PAGE_SIZE + TRANSLATION_TABLE_PAGE_ALIGNMENT));
+ TranslationTable = ((UINTN)TranslationTable + TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK) & ~TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK;
+
+ ZeroMem ((VOID *)TranslationTable, TRANSLATION_TABLE_PAGE_SIZE);
+
+ *SectionEntry = (TranslationTable & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) |
+ (IS_ARM_MEMORY_REGION_ATTRIBUTES_SECURE(Attributes) ? (1 << 3) : 0) |
+ TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE;
+ }
+
+ PageEntry = ((UINT32 *)(TranslationTable) + ((PhysicalBase & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT));
+ Pages = RemainLength / TT_DESCRIPTOR_PAGE_SIZE;
+
+ for (Index = 0; Index < Pages; Index++) {
+ *PageEntry++ = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(PhysicalBase) | PageAttributes;
+ PhysicalBase += TT_DESCRIPTOR_PAGE_SIZE;
+ }
+
+}
+
+VOID
FillTranslationTable (
IN UINT32 *TranslationTable,
IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryRegion
)
{
- UINT32 *Entry;
- UINTN Sections;
- UINTN Index;
+ UINT32 *SectionEntry;
UINT32 Attributes;
UINT32 PhysicalBase = MemoryRegion->PhysicalBase;
+ UINT32 RemainLength = MemoryRegion->Length;
+ ASSERT(MemoryRegion->Length > 0);
+
switch (MemoryRegion->Attributes) {
case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK:
Attributes = TT_DESCRIPTOR_SECTION_WRITE_BACK(0);
@@ -64,12 +162,34 @@ FillTranslationTable ( break;
}
- Entry = TRANSLATION_TABLE_ENTRY_FOR_VIRTUAL_ADDRESS(TranslationTable, MemoryRegion->VirtualBase);
- Sections = MemoryRegion->Length / TT_DESCRIPTOR_SECTION_SIZE;
-
- for (Index = 0; Index < Sections; Index++) {
- *Entry++ = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(PhysicalBase) | Attributes;
- PhysicalBase += TT_DESCRIPTOR_SECTION_SIZE;
+ // Get the first section entry for this mapping
+ SectionEntry = TRANSLATION_TABLE_ENTRY_FOR_VIRTUAL_ADDRESS(TranslationTable, MemoryRegion->VirtualBase);
+
+ while (RemainLength != 0) {
+ if (PhysicalBase % TT_DESCRIPTOR_SECTION_SIZE == 0) {
+ if (RemainLength >= TT_DESCRIPTOR_SECTION_SIZE) {
+ // Case: Physical address aligned on the Section Size (1MB) && the length is greater than the Section Size
+ *SectionEntry++ = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(PhysicalBase) | Attributes;
+ PhysicalBase += TT_DESCRIPTOR_SECTION_SIZE;
+ } else {
+ // Case: Physical address aligned on the Section Size (1MB) && the length does not fill a section
+ PopulateLevel2PageTable(SectionEntry++,PhysicalBase,RemainLength,MemoryRegion->Attributes);
+
+ // It must be the last entry
+ break;
+ }
+ } else {
+ // Case: Physical address NOT aligned on the Section Size (1MB)
+ PopulateLevel2PageTable(SectionEntry++,PhysicalBase,RemainLength,MemoryRegion->Attributes);
+ // Aligned the address
+ PhysicalBase = (PhysicalBase + TT_DESCRIPTOR_SECTION_SIZE) & ~(TT_DESCRIPTOR_SECTION_SIZE-1);
+
+ // If it is the last entry
+ if (RemainLength < TT_DESCRIPTOR_SECTION_SIZE) {
+ break;
+ }
+ }
+ RemainLength -= TT_DESCRIPTOR_SECTION_SIZE;
}
}
@@ -111,7 +231,7 @@ ArmConfigureMmu ( ArmCleanInvalidateDataCache();
ArmInvalidateInstructionCache();
- TranslationTableAttribute = 0;
+ TranslationTableAttribute = (ARM_MEMORY_REGION_ATTRIBUTES)0;
while (MemoryTable->Length != 0) {
// Find the memory attribute for the Translation Table
if ((TranslationTable >= MemoryTable->PhysicalBase) && (TranslationTable < MemoryTable->PhysicalBase + MemoryTable->Length)) {
|