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
This commit is contained in:
oliviermartin 2011-03-31 11:23:55 +00:00
parent 2ed2ed29c2
commit 2cf4b60895
4 changed files with 354 additions and 62 deletions

View File

@ -88,6 +88,70 @@ SectionToGcdAttributes (
return EFI_SUCCESS; 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. Searches memory descriptors covered by given memory range.
@ -215,6 +279,81 @@ SetGcdMemorySpaceAttributes (
return EFI_SUCCESS; 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 EFI_STATUS
SyncCacheConfig ( SyncCacheConfig (
@ -223,12 +362,11 @@ SyncCacheConfig (
{ {
EFI_STATUS Status; EFI_STATUS Status;
UINT32 i; UINT32 i;
UINT32 Descriptor;
UINT32 SectionAttributes;
EFI_PHYSICAL_ADDRESS NextRegionBase; EFI_PHYSICAL_ADDRESS NextRegionBase;
UINT64 NextRegionLength; UINT64 NextRegionLength;
UINT32 NextSectionAttributes = 0;
UINT32 SectionAttributes = 0;
UINT64 GcdAttributes; UINT64 GcdAttributes;
UINT32 NextRegionAttributes = 0;
volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable; volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
UINTN NumberOfDescriptors; UINTN NumberOfDescriptors;
EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap; EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
@ -256,46 +394,71 @@ SyncCacheConfig (
// obtain page table base // obtain page table base
FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)(ArmGetTTBR0BaseAddress ()); 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 // iterate through each 1MB descriptor
NextRegionBase = NextRegionLength = 0; NextRegionBase = NextRegionLength = 0;
for (i=0; i < TRANSLATION_TABLE_SECTION_COUNT; i++) { for (i=0; i < TRANSLATION_TABLE_SECTION_COUNT; i++) {
if ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) {
// 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) // extract attributes (cacheability and permissions)
SectionAttributes = Descriptor & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK); SectionAttributes = FirstLevelTable[i] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);
// do we already have an existing region (or are we about to finish)? if (NextSectionAttributes == 0) {
// Skip the first entry, and make sure we close on the last entry // start on a new region
if ( (NextRegionLength > 0) || (i == (TRANSLATION_TABLE_SECTION_COUNT-1)) ) { NextRegionLength = 0;
// attributes are changing, update attributes in GCD NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
if (SectionAttributes != NextRegionAttributes) { NextSectionAttributes = SectionAttributes;
} else if (SectionAttributes != NextSectionAttributes) {
// convert section entry attributes to GCD bitmask // Convert Section Attributes into GCD Attributes
Status = SectionToGcdAttributes (NextRegionAttributes, &GcdAttributes); Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);
ASSERT_EFI_ERROR (Status); ASSERT_EFI_ERROR (Status);
// update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK) // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes); SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);
// start on a new region // start on a new region
NextRegionLength = 0; NextRegionLength = 0;
NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(Descriptor); NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
NextSectionAttributes = SectionAttributes;
} }
}
// starting a new region?
if (NextRegionLength == 0) {
NextRegionAttributes = SectionAttributes;
}
NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE; 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);
// start on a new region
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);
NextRegionLength = 0;
NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
NextSectionAttributes = 0;
}
NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;
}
} // section entry loop } // 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; return EFI_SUCCESS;
} }
@ -591,7 +754,7 @@ ConvertSectionToPages (
UINT32 SectionDescriptor; UINT32 SectionDescriptor;
UINT32 PageTableDescriptor; UINT32 PageTableDescriptor;
UINT32 PageDescriptor; UINT32 PageDescriptor;
UINT32 i; UINT32 Index;
volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable; volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
volatile ARM_PAGE_TABLE_ENTRY *PageTable; volatile ARM_PAGE_TABLE_ENTRY *PageTable;
@ -623,8 +786,8 @@ ConvertSectionToPages (
PageTable = (volatile ARM_PAGE_TABLE_ENTRY *)(UINTN)PageTableAddr; PageTable = (volatile ARM_PAGE_TABLE_ENTRY *)(UINTN)PageTableAddr;
// write the page table entries out // write the page table entries out
for (i=0; i < TRANSLATION_TABLE_PAGE_COUNT; i++) { for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) {
PageTable[i] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseAddress + (i << 12)) | PageDescriptor; 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 // flush d-cache so descriptors make it back to uncached memory for subsequent table walks

View File

@ -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_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_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_CACHE_POLICY_MASK ((3UL << 6) | (1UL << 3) | (1UL << 2))
#define TT_DESCRIPTOR_PAGE_CACHEABLE_MASK (1UL << 3) #define TT_DESCRIPTOR_PAGE_CACHEABLE_MASK (1UL << 3)
#define TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED ((0UL << 6) | (0UL << 3) | (0UL << 2)) #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) & TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK) & TT_DESCRIPTOR_LARGEPAGE_CACHE_POLICY_MASK): \
(((((Desc) & (0x3 << 12)) >> 6) | (Desc & (0x3 << 2))))) (((((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_MASK (0x0FUL << 5)
#define TT_DESCRIPTOR_SECTION_DOMAIN(a) (((a) & 0x0FUL) << 5) #define TT_DESCRIPTOR_SECTION_DOMAIN(a) (((a) & 0x0FUL) << 5)
@ -193,6 +202,27 @@
TT_DESCRIPTOR_SECTION_AP_RW_RW | \ TT_DESCRIPTOR_SECTION_AP_RW_RW | \
TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE) 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 // Cortex A9 feature bit definitions
#define A9_FEATURE_PARITY (1<<9) #define A9_FEATURE_PARITY (1<<9)
#define A9_FEATURE_AOW (1<<8) #define A9_FEATURE_AOW (1<<8)

View File

@ -19,20 +19,118 @@
#include <Library/MemoryAllocationLib.h> #include <Library/MemoryAllocationLib.h>
#include <Library/ArmLib.h> #include <Library/ArmLib.h>
#include <Library/BaseLib.h> #include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include "ArmV7Lib.h" #include "ArmV7Lib.h"
#include "ArmLibPrivate.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 VOID
FillTranslationTable ( FillTranslationTable (
IN UINT32 *TranslationTable, IN UINT32 *TranslationTable,
IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryRegion IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryRegion
) )
{ {
UINT32 *Entry; UINT32 *SectionEntry;
UINTN Sections;
UINTN Index;
UINT32 Attributes; UINT32 Attributes;
UINT32 PhysicalBase = MemoryRegion->PhysicalBase; UINT32 PhysicalBase = MemoryRegion->PhysicalBase;
UINT32 RemainLength = MemoryRegion->Length;
ASSERT(MemoryRegion->Length > 0);
switch (MemoryRegion->Attributes) { switch (MemoryRegion->Attributes) {
case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK: case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK:
@ -64,12 +162,34 @@ FillTranslationTable (
break; break;
} }
Entry = TRANSLATION_TABLE_ENTRY_FOR_VIRTUAL_ADDRESS(TranslationTable, MemoryRegion->VirtualBase); // Get the first section entry for this mapping
Sections = MemoryRegion->Length / TT_DESCRIPTOR_SECTION_SIZE; SectionEntry = TRANSLATION_TABLE_ENTRY_FOR_VIRTUAL_ADDRESS(TranslationTable, MemoryRegion->VirtualBase);
for (Index = 0; Index < Sections; Index++) { while (RemainLength != 0) {
*Entry++ = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(PhysicalBase) | Attributes; 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; 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(); ArmCleanInvalidateDataCache();
ArmInvalidateInstructionCache(); ArmInvalidateInstructionCache();
TranslationTableAttribute = 0; TranslationTableAttribute = (ARM_MEMORY_REGION_ATTRIBUTES)0;
while (MemoryTable->Length != 0) { while (MemoryTable->Length != 0) {
// Find the memory attribute for the Translation Table // Find the memory attribute for the Translation Table
if ((TranslationTable >= MemoryTable->PhysicalBase) && (TranslationTable < MemoryTable->PhysicalBase + MemoryTable->Length)) { if ((TranslationTable >= MemoryTable->PhysicalBase) && (TranslationTable < MemoryTable->PhysicalBase + MemoryTable->Length)) {

View File

@ -35,27 +35,6 @@
TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED) TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED)
// Small Page // Small Page
#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)
#define TT_DESCRIPTOR_PAGE_STRONGLY_ORDER (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \ #define TT_DESCRIPTOR_PAGE_STRONGLY_ORDER (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
TT_DESCRIPTOR_PAGE_NG_GLOBAL | \ TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \ TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \