mirror of
https://github.com/acidanthera/audk.git
synced 2025-07-31 01:24:12 +02:00
ArmPkg: move ARM version of SetMemoryAttributes to ArmMmuLib
... where it belongs, since AARCH64 already keeps it there, and non DXE users of ArmMmuLib (such as DxeIpl, for the non-executable stack) may need its functionality as well. While at it, rename SetMemoryAttributes to ArmSetMemoryAttributes, and make any functions that are not exported STATIC. Also, replace an explicit gBS->AllocatePages() call [which is DXE specific] with MemoryAllocationLib::AllocatePages(). Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
This commit is contained in:
parent
f49ea03de7
commit
521f3cedac
@ -19,19 +19,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||||||
#include <Library/MemoryAllocationLib.h>
|
#include <Library/MemoryAllocationLib.h>
|
||||||
#include "CpuDxe.h"
|
#include "CpuDxe.h"
|
||||||
|
|
||||||
#define CACHE_ATTRIBUTE_MASK (EFI_MEMORY_UC | \
|
|
||||||
EFI_MEMORY_WC | \
|
|
||||||
EFI_MEMORY_WT | \
|
|
||||||
EFI_MEMORY_WB | \
|
|
||||||
EFI_MEMORY_UCE | \
|
|
||||||
EFI_MEMORY_WP)
|
|
||||||
|
|
||||||
// First Level Descriptors
|
|
||||||
typedef UINT32 ARM_FIRST_LEVEL_DESCRIPTOR;
|
|
||||||
|
|
||||||
// Second Level Descriptors
|
|
||||||
typedef UINT32 ARM_PAGE_TABLE_ENTRY;
|
|
||||||
|
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
SectionToGcdAttributes (
|
SectionToGcdAttributes (
|
||||||
IN UINT32 SectionAttributes,
|
IN UINT32 SectionAttributes,
|
||||||
@ -350,403 +337,6 @@ SyncCacheConfig (
|
|||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
EFI_STATUS
|
|
||||||
UpdatePageEntries (
|
|
||||||
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
|
||||||
IN UINT64 Length,
|
|
||||||
IN UINT64 Attributes,
|
|
||||||
IN EFI_PHYSICAL_ADDRESS VirtualMask,
|
|
||||||
OUT BOOLEAN *FlushTlbs OPTIONAL
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EFI_STATUS Status;
|
|
||||||
UINT32 EntryValue;
|
|
||||||
UINT32 EntryMask;
|
|
||||||
UINT32 FirstLevelIdx;
|
|
||||||
UINT32 Offset;
|
|
||||||
UINT32 NumPageEntries;
|
|
||||||
UINT32 Descriptor;
|
|
||||||
UINT32 p;
|
|
||||||
UINT32 PageTableIndex;
|
|
||||||
UINT32 PageTableEntry;
|
|
||||||
UINT32 CurrentPageTableEntry;
|
|
||||||
VOID *Mva;
|
|
||||||
|
|
||||||
volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
|
|
||||||
volatile ARM_PAGE_TABLE_ENTRY *PageTable;
|
|
||||||
|
|
||||||
Status = EFI_SUCCESS;
|
|
||||||
|
|
||||||
// EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)
|
|
||||||
// EntryValue: values at bit positions specified by EntryMask
|
|
||||||
EntryMask = TT_DESCRIPTOR_PAGE_TYPE_MASK | TT_DESCRIPTOR_PAGE_AP_MASK;
|
|
||||||
if ((Attributes & EFI_MEMORY_XP) != 0) {
|
|
||||||
EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE_XN;
|
|
||||||
} else {
|
|
||||||
EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Although the PI spec is unclear on this, the GCD guarantees that only
|
|
||||||
// one Attribute bit is set at a time, so the order of the conditionals below
|
|
||||||
// is irrelevant. If no memory attribute is specified, we preserve whatever
|
|
||||||
// memory type is set in the page tables, and update the permission attributes
|
|
||||||
// only.
|
|
||||||
if (Attributes & EFI_MEMORY_UC) {
|
|
||||||
// modify cacheability attributes
|
|
||||||
EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;
|
|
||||||
// map to strongly ordered
|
|
||||||
EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0
|
|
||||||
} else if (Attributes & EFI_MEMORY_WC) {
|
|
||||||
// modify cacheability attributes
|
|
||||||
EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;
|
|
||||||
// map to normal non-cachable
|
|
||||||
EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0
|
|
||||||
} else if (Attributes & EFI_MEMORY_WT) {
|
|
||||||
// modify cacheability attributes
|
|
||||||
EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;
|
|
||||||
// write through with no-allocate
|
|
||||||
EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0
|
|
||||||
} else if (Attributes & EFI_MEMORY_WB) {
|
|
||||||
// modify cacheability attributes
|
|
||||||
EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;
|
|
||||||
// write back (with allocate)
|
|
||||||
EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1
|
|
||||||
} else if (Attributes & CACHE_ATTRIBUTE_MASK) {
|
|
||||||
// catch unsupported memory type attributes
|
|
||||||
ASSERT (FALSE);
|
|
||||||
return EFI_UNSUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((Attributes & EFI_MEMORY_RO) != 0) {
|
|
||||||
EntryValue |= TT_DESCRIPTOR_PAGE_AP_RO_RO;
|
|
||||||
} else {
|
|
||||||
EntryValue |= TT_DESCRIPTOR_PAGE_AP_RW_RW;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtain page table base
|
|
||||||
FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();
|
|
||||||
|
|
||||||
// Calculate number of 4KB page table entries to change
|
|
||||||
NumPageEntries = Length / TT_DESCRIPTOR_PAGE_SIZE;
|
|
||||||
|
|
||||||
// Iterate for the number of 4KB pages to change
|
|
||||||
Offset = 0;
|
|
||||||
for(p = 0; p < NumPageEntries; p++) {
|
|
||||||
// Calculate index into first level translation table for page table value
|
|
||||||
|
|
||||||
FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress + Offset) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;
|
|
||||||
ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);
|
|
||||||
|
|
||||||
// Read the descriptor from the first level page table
|
|
||||||
Descriptor = FirstLevelTable[FirstLevelIdx];
|
|
||||||
|
|
||||||
// Does this descriptor need to be converted from section entry to 4K pages?
|
|
||||||
if (!TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(Descriptor)) {
|
|
||||||
Status = ConvertSectionToPages (FirstLevelIdx << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
|
|
||||||
if (EFI_ERROR(Status)) {
|
|
||||||
// Exit for loop
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Re-read descriptor
|
|
||||||
Descriptor = FirstLevelTable[FirstLevelIdx];
|
|
||||||
if (FlushTlbs != NULL) {
|
|
||||||
*FlushTlbs = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtain page table base address
|
|
||||||
PageTable = (ARM_PAGE_TABLE_ENTRY *)TT_DESCRIPTOR_PAGE_BASE_ADDRESS(Descriptor);
|
|
||||||
|
|
||||||
// Calculate index into the page table
|
|
||||||
PageTableIndex = ((BaseAddress + Offset) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;
|
|
||||||
ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);
|
|
||||||
|
|
||||||
// Get the entry
|
|
||||||
CurrentPageTableEntry = PageTable[PageTableIndex];
|
|
||||||
|
|
||||||
// Mask off appropriate fields
|
|
||||||
PageTableEntry = CurrentPageTableEntry & ~EntryMask;
|
|
||||||
|
|
||||||
// Mask in new attributes and/or permissions
|
|
||||||
PageTableEntry |= EntryValue;
|
|
||||||
|
|
||||||
if (VirtualMask != 0) {
|
|
||||||
// Make this virtual address point at a physical page
|
|
||||||
PageTableEntry &= ~VirtualMask;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CurrentPageTableEntry != PageTableEntry) {
|
|
||||||
Mva = (VOID *)(UINTN)((((UINTN)FirstLevelIdx) << TT_DESCRIPTOR_SECTION_BASE_SHIFT) + (PageTableIndex << TT_DESCRIPTOR_PAGE_BASE_SHIFT));
|
|
||||||
|
|
||||||
// Only need to update if we are changing the entry
|
|
||||||
PageTable[PageTableIndex] = PageTableEntry;
|
|
||||||
ArmUpdateTranslationTableEntry ((VOID *)&PageTable[PageTableIndex], Mva);
|
|
||||||
|
|
||||||
// Clean/invalidate the cache for this page, but only
|
|
||||||
// if we are modifying the memory type attributes
|
|
||||||
if (((CurrentPageTableEntry ^ PageTableEntry) & TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK) != 0) {
|
|
||||||
WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = EFI_SUCCESS;
|
|
||||||
Offset += TT_DESCRIPTOR_PAGE_SIZE;
|
|
||||||
|
|
||||||
} // End first level translation table loop
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
EFI_STATUS
|
|
||||||
UpdateSectionEntries (
|
|
||||||
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
|
||||||
IN UINT64 Length,
|
|
||||||
IN UINT64 Attributes,
|
|
||||||
IN EFI_PHYSICAL_ADDRESS VirtualMask
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EFI_STATUS Status = EFI_SUCCESS;
|
|
||||||
UINT32 EntryMask;
|
|
||||||
UINT32 EntryValue;
|
|
||||||
UINT32 FirstLevelIdx;
|
|
||||||
UINT32 NumSections;
|
|
||||||
UINT32 i;
|
|
||||||
UINT32 CurrentDescriptor;
|
|
||||||
UINT32 Descriptor;
|
|
||||||
VOID *Mva;
|
|
||||||
volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
|
|
||||||
|
|
||||||
// EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)
|
|
||||||
// EntryValue: values at bit positions specified by EntryMask
|
|
||||||
|
|
||||||
// Make sure we handle a section range that is unmapped
|
|
||||||
EntryMask = TT_DESCRIPTOR_SECTION_TYPE_MASK | TT_DESCRIPTOR_SECTION_XN_MASK |
|
|
||||||
TT_DESCRIPTOR_SECTION_AP_MASK;
|
|
||||||
EntryValue = TT_DESCRIPTOR_SECTION_TYPE_SECTION;
|
|
||||||
|
|
||||||
// Although the PI spec is unclear on this, the GCD guarantees that only
|
|
||||||
// one Attribute bit is set at a time, so the order of the conditionals below
|
|
||||||
// is irrelevant. If no memory attribute is specified, we preserve whatever
|
|
||||||
// memory type is set in the page tables, and update the permission attributes
|
|
||||||
// only.
|
|
||||||
if (Attributes & EFI_MEMORY_UC) {
|
|
||||||
// modify cacheability attributes
|
|
||||||
EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;
|
|
||||||
// map to strongly ordered
|
|
||||||
EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0
|
|
||||||
} else if (Attributes & EFI_MEMORY_WC) {
|
|
||||||
// modify cacheability attributes
|
|
||||||
EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;
|
|
||||||
// map to normal non-cachable
|
|
||||||
EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0
|
|
||||||
} else if (Attributes & EFI_MEMORY_WT) {
|
|
||||||
// modify cacheability attributes
|
|
||||||
EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;
|
|
||||||
// write through with no-allocate
|
|
||||||
EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0
|
|
||||||
} else if (Attributes & EFI_MEMORY_WB) {
|
|
||||||
// modify cacheability attributes
|
|
||||||
EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;
|
|
||||||
// write back (with allocate)
|
|
||||||
EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1
|
|
||||||
} else if (Attributes & CACHE_ATTRIBUTE_MASK) {
|
|
||||||
// catch unsupported memory type attributes
|
|
||||||
ASSERT (FALSE);
|
|
||||||
return EFI_UNSUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Attributes & EFI_MEMORY_RO) {
|
|
||||||
EntryValue |= TT_DESCRIPTOR_SECTION_AP_RO_RO;
|
|
||||||
} else {
|
|
||||||
EntryValue |= TT_DESCRIPTOR_SECTION_AP_RW_RW;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Attributes & EFI_MEMORY_XP) {
|
|
||||||
EntryValue |= TT_DESCRIPTOR_SECTION_XN_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// obtain page table base
|
|
||||||
FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();
|
|
||||||
|
|
||||||
// calculate index into first level translation table for start of modification
|
|
||||||
FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;
|
|
||||||
ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);
|
|
||||||
|
|
||||||
// calculate number of 1MB first level entries this applies to
|
|
||||||
NumSections = Length / TT_DESCRIPTOR_SECTION_SIZE;
|
|
||||||
|
|
||||||
// iterate through each descriptor
|
|
||||||
for(i=0; i<NumSections; i++) {
|
|
||||||
CurrentDescriptor = FirstLevelTable[FirstLevelIdx + i];
|
|
||||||
|
|
||||||
// has this descriptor already been coverted to pages?
|
|
||||||
if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(CurrentDescriptor)) {
|
|
||||||
// forward this 1MB range to page table function instead
|
|
||||||
Status = UpdatePageEntries (
|
|
||||||
(FirstLevelIdx + i) << TT_DESCRIPTOR_SECTION_BASE_SHIFT,
|
|
||||||
TT_DESCRIPTOR_SECTION_SIZE,
|
|
||||||
Attributes,
|
|
||||||
VirtualMask,
|
|
||||||
NULL);
|
|
||||||
} else {
|
|
||||||
// still a section entry
|
|
||||||
|
|
||||||
// mask off appropriate fields
|
|
||||||
Descriptor = CurrentDescriptor & ~EntryMask;
|
|
||||||
|
|
||||||
// mask in new attributes and/or permissions
|
|
||||||
Descriptor |= EntryValue;
|
|
||||||
if (VirtualMask != 0) {
|
|
||||||
Descriptor &= ~VirtualMask;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CurrentDescriptor != Descriptor) {
|
|
||||||
Mva = (VOID *)(UINTN)(((UINTN)FirstLevelTable) << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
|
|
||||||
|
|
||||||
// Only need to update if we are changing the descriptor
|
|
||||||
FirstLevelTable[FirstLevelIdx + i] = Descriptor;
|
|
||||||
ArmUpdateTranslationTableEntry ((VOID *)&FirstLevelTable[FirstLevelIdx + i], Mva);
|
|
||||||
|
|
||||||
// Clean/invalidate the cache for this section, but only
|
|
||||||
// if we are modifying the memory type attributes
|
|
||||||
if (((CurrentDescriptor ^ Descriptor) & TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK) != 0) {
|
|
||||||
WriteBackInvalidateDataCacheRange (Mva, SIZE_1MB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = EFI_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
EFI_STATUS
|
|
||||||
ConvertSectionToPages (
|
|
||||||
IN EFI_PHYSICAL_ADDRESS BaseAddress
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EFI_STATUS Status;
|
|
||||||
EFI_PHYSICAL_ADDRESS PageTableAddr;
|
|
||||||
UINT32 FirstLevelIdx;
|
|
||||||
UINT32 SectionDescriptor;
|
|
||||||
UINT32 PageTableDescriptor;
|
|
||||||
UINT32 PageDescriptor;
|
|
||||||
UINT32 Index;
|
|
||||||
|
|
||||||
volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
|
|
||||||
volatile ARM_PAGE_TABLE_ENTRY *PageTable;
|
|
||||||
|
|
||||||
DEBUG ((EFI_D_PAGE, "Converting section at 0x%x to pages\n", (UINTN)BaseAddress));
|
|
||||||
|
|
||||||
// Obtain page table base
|
|
||||||
FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();
|
|
||||||
|
|
||||||
// Calculate index into first level translation table for start of modification
|
|
||||||
FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;
|
|
||||||
ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);
|
|
||||||
|
|
||||||
// Get section attributes and convert to page attributes
|
|
||||||
SectionDescriptor = FirstLevelTable[FirstLevelIdx];
|
|
||||||
PageDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE | ConvertSectionAttributesToPageAttributes (SectionDescriptor, FALSE);
|
|
||||||
|
|
||||||
// Allocate a page table for the 4KB entries (we use up a full page even though we only need 1KB)
|
|
||||||
Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, 1, &PageTableAddr);
|
|
||||||
if (EFI_ERROR(Status)) {
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
PageTable = (volatile ARM_PAGE_TABLE_ENTRY *)(UINTN)PageTableAddr;
|
|
||||||
|
|
||||||
// Write the page table entries out
|
|
||||||
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
|
|
||||||
WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)PageTableAddr, TT_DESCRIPTOR_PAGE_SIZE);
|
|
||||||
|
|
||||||
// Formulate page table entry, Domain=0, NS=0
|
|
||||||
PageTableDescriptor = (((UINTN)PageTableAddr) & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) | TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE;
|
|
||||||
|
|
||||||
// Write the page table entry out, replacing section entry
|
|
||||||
FirstLevelTable[FirstLevelIdx] = PageTableDescriptor;
|
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
EFI_STATUS
|
|
||||||
SetMemoryAttributes (
|
|
||||||
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
|
||||||
IN UINT64 Length,
|
|
||||||
IN UINT64 Attributes,
|
|
||||||
IN EFI_PHYSICAL_ADDRESS VirtualMask
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EFI_STATUS Status;
|
|
||||||
UINT64 ChunkLength;
|
|
||||||
BOOLEAN FlushTlbs;
|
|
||||||
|
|
||||||
if (Length == 0) {
|
|
||||||
return EFI_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
FlushTlbs = FALSE;
|
|
||||||
while (Length > 0) {
|
|
||||||
if ((BaseAddress % TT_DESCRIPTOR_SECTION_SIZE == 0) &&
|
|
||||||
Length >= TT_DESCRIPTOR_SECTION_SIZE) {
|
|
||||||
|
|
||||||
ChunkLength = Length - Length % TT_DESCRIPTOR_SECTION_SIZE;
|
|
||||||
|
|
||||||
DEBUG ((DEBUG_PAGE,
|
|
||||||
"SetMemoryAttributes(): MMU section 0x%lx length 0x%lx to %lx\n",
|
|
||||||
BaseAddress, ChunkLength, Attributes));
|
|
||||||
|
|
||||||
Status = UpdateSectionEntries (BaseAddress, ChunkLength, Attributes,
|
|
||||||
VirtualMask);
|
|
||||||
|
|
||||||
FlushTlbs = TRUE;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Process page by page until the next section boundary, but only if
|
|
||||||
// we have more than a section's worth of area to deal with after that.
|
|
||||||
//
|
|
||||||
ChunkLength = TT_DESCRIPTOR_SECTION_SIZE -
|
|
||||||
(BaseAddress % TT_DESCRIPTOR_SECTION_SIZE);
|
|
||||||
if (ChunkLength + TT_DESCRIPTOR_SECTION_SIZE > Length) {
|
|
||||||
ChunkLength = Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG ((DEBUG_PAGE,
|
|
||||||
"SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n",
|
|
||||||
BaseAddress, ChunkLength, Attributes));
|
|
||||||
|
|
||||||
Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes,
|
|
||||||
VirtualMask, &FlushTlbs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseAddress += ChunkLength;
|
|
||||||
Length -= ChunkLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FlushTlbs) {
|
|
||||||
ArmInvalidateTlb ();
|
|
||||||
}
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT64
|
UINT64
|
||||||
EfiAttributeToArmAttribute (
|
EfiAttributeToArmAttribute (
|
||||||
IN UINT64 EfiAttributes
|
IN UINT64 EfiAttributes
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <Uefi.h>
|
#include <Uefi.h>
|
||||||
|
|
||||||
#include <Library/ArmLib.h>
|
#include <Library/ArmLib.h>
|
||||||
|
#include <Library/ArmMmuLib.h>
|
||||||
#include <Library/BaseMemoryLib.h>
|
#include <Library/BaseMemoryLib.h>
|
||||||
#include <Library/DebugLib.h>
|
#include <Library/DebugLib.h>
|
||||||
#include <Library/PcdLib.h>
|
#include <Library/PcdLib.h>
|
||||||
@ -112,11 +113,6 @@ SyncCacheConfig (
|
|||||||
IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
|
IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
|
||||||
);
|
);
|
||||||
|
|
||||||
EFI_STATUS
|
|
||||||
ConvertSectionToPages (
|
|
||||||
IN EFI_PHYSICAL_ADDRESS BaseAddress
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publish ARM Processor Data table in UEFI SYSTEM Table.
|
* Publish ARM Processor Data table in UEFI SYSTEM Table.
|
||||||
* @param HobStart Pointer to the beginning of the HOB List from PEI.
|
* @param HobStart Pointer to the beginning of the HOB List from PEI.
|
||||||
@ -132,14 +128,6 @@ PublishArmProcessorTable(
|
|||||||
VOID
|
VOID
|
||||||
);
|
);
|
||||||
|
|
||||||
EFI_STATUS
|
|
||||||
SetMemoryAttributes (
|
|
||||||
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
|
||||||
IN UINT64 Length,
|
|
||||||
IN UINT64 Attributes,
|
|
||||||
IN EFI_PHYSICAL_ADDRESS VirtualMask
|
|
||||||
);
|
|
||||||
|
|
||||||
// The ARM Attributes might be defined on 64-bit (case of the long format description table)
|
// The ARM Attributes might be defined on 64-bit (case of the long format description table)
|
||||||
UINT64
|
UINT64
|
||||||
EfiAttributeToArmAttribute (
|
EfiAttributeToArmAttribute (
|
||||||
|
@ -210,7 +210,7 @@ CpuSetMemoryAttributes (
|
|||||||
if (EFI_ERROR (Status) || (RegionArmAttributes != ArmAttributes) ||
|
if (EFI_ERROR (Status) || (RegionArmAttributes != ArmAttributes) ||
|
||||||
((BaseAddress + Length) > (RegionBaseAddress + RegionLength)))
|
((BaseAddress + Length) > (RegionBaseAddress + RegionLength)))
|
||||||
{
|
{
|
||||||
return SetMemoryAttributes (BaseAddress, Length, EfiAttributes, 0);
|
return ArmSetMemoryAttributes (BaseAddress, Length, EfiAttributes, 0);
|
||||||
} else {
|
} else {
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -229,6 +229,12 @@
|
|||||||
TT_DESCRIPTOR_PAGE_AP_RW_RW | \
|
TT_DESCRIPTOR_PAGE_AP_RW_RW | \
|
||||||
TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE)
|
TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE)
|
||||||
|
|
||||||
|
// First Level Descriptors
|
||||||
|
typedef UINT32 ARM_FIRST_LEVEL_DESCRIPTOR;
|
||||||
|
|
||||||
|
// Second Level Descriptors
|
||||||
|
typedef UINT32 ARM_PAGE_TABLE_ENTRY;
|
||||||
|
|
||||||
UINT32
|
UINT32
|
||||||
ConvertSectionAttributesToPageAttributes (
|
ConvertSectionAttributesToPageAttributes (
|
||||||
IN UINT32 SectionAttributes,
|
IN UINT32 SectionAttributes,
|
||||||
|
@ -62,4 +62,12 @@ ArmReplaceLiveTranslationEntry (
|
|||||||
IN UINT64 Value
|
IN UINT64 Value
|
||||||
);
|
);
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
ArmSetMemoryAttributes (
|
||||||
|
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||||
|
IN UINT64 Length,
|
||||||
|
IN UINT64 Attributes,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS VirtualMask
|
||||||
|
);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -447,7 +447,7 @@ GcdAttributeToPageAttribute (
|
|||||||
}
|
}
|
||||||
|
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
SetMemoryAttributes (
|
ArmSetMemoryAttributes (
|
||||||
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||||
IN UINT64 Length,
|
IN UINT64 Length,
|
||||||
IN UINT64 Attributes,
|
IN UINT64 Attributes,
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <Uefi.h>
|
#include <Uefi.h>
|
||||||
#include <Chipset/ArmV7.h>
|
#include <Chipset/ArmV7.h>
|
||||||
#include <Library/BaseMemoryLib.h>
|
#include <Library/BaseMemoryLib.h>
|
||||||
|
#include <Library/CacheMaintenanceLib.h>
|
||||||
#include <Library/MemoryAllocationLib.h>
|
#include <Library/MemoryAllocationLib.h>
|
||||||
#include <Library/ArmLib.h>
|
#include <Library/ArmLib.h>
|
||||||
#include <Library/BaseLib.h>
|
#include <Library/BaseLib.h>
|
||||||
@ -36,6 +37,13 @@
|
|||||||
#define ID_MMFR0_SHR_IMP_HW_COHERENT 1
|
#define ID_MMFR0_SHR_IMP_HW_COHERENT 1
|
||||||
#define ID_MMFR0_SHR_IGNORED 0xf
|
#define ID_MMFR0_SHR_IGNORED 0xf
|
||||||
|
|
||||||
|
#define CACHE_ATTRIBUTE_MASK (EFI_MEMORY_UC | \
|
||||||
|
EFI_MEMORY_WC | \
|
||||||
|
EFI_MEMORY_WT | \
|
||||||
|
EFI_MEMORY_WB | \
|
||||||
|
EFI_MEMORY_UCE | \
|
||||||
|
EFI_MEMORY_WP)
|
||||||
|
|
||||||
UINTN
|
UINTN
|
||||||
EFIAPI
|
EFIAPI
|
||||||
ArmReadIdMmfr0 (
|
ArmReadIdMmfr0 (
|
||||||
@ -406,6 +414,395 @@ ArmConfigureMmu (
|
|||||||
return RETURN_SUCCESS;
|
return RETURN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STATIC
|
||||||
|
EFI_STATUS
|
||||||
|
ConvertSectionToPages (
|
||||||
|
IN EFI_PHYSICAL_ADDRESS BaseAddress
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINT32 FirstLevelIdx;
|
||||||
|
UINT32 SectionDescriptor;
|
||||||
|
UINT32 PageTableDescriptor;
|
||||||
|
UINT32 PageDescriptor;
|
||||||
|
UINT32 Index;
|
||||||
|
|
||||||
|
volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
|
||||||
|
volatile ARM_PAGE_TABLE_ENTRY *PageTable;
|
||||||
|
|
||||||
|
DEBUG ((EFI_D_PAGE, "Converting section at 0x%x to pages\n", (UINTN)BaseAddress));
|
||||||
|
|
||||||
|
// Obtain page table base
|
||||||
|
FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();
|
||||||
|
|
||||||
|
// Calculate index into first level translation table for start of modification
|
||||||
|
FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;
|
||||||
|
ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);
|
||||||
|
|
||||||
|
// Get section attributes and convert to page attributes
|
||||||
|
SectionDescriptor = FirstLevelTable[FirstLevelIdx];
|
||||||
|
PageDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE | ConvertSectionAttributesToPageAttributes (SectionDescriptor, FALSE);
|
||||||
|
|
||||||
|
// Allocate a page table for the 4KB entries (we use up a full page even though we only need 1KB)
|
||||||
|
PageTable = (volatile ARM_PAGE_TABLE_ENTRY *)AllocatePages (1);
|
||||||
|
if (PageTable == NULL) {
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the page table entries out
|
||||||
|
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
|
||||||
|
WriteBackInvalidateDataCacheRange ((VOID *)PageTable, TT_DESCRIPTOR_PAGE_SIZE);
|
||||||
|
|
||||||
|
// Formulate page table entry, Domain=0, NS=0
|
||||||
|
PageTableDescriptor = (((UINTN)PageTable) & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) | TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE;
|
||||||
|
|
||||||
|
// Write the page table entry out, replacing section entry
|
||||||
|
FirstLevelTable[FirstLevelIdx] = PageTableDescriptor;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC
|
||||||
|
EFI_STATUS
|
||||||
|
UpdatePageEntries (
|
||||||
|
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||||
|
IN UINT64 Length,
|
||||||
|
IN UINT64 Attributes,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS VirtualMask,
|
||||||
|
OUT BOOLEAN *FlushTlbs OPTIONAL
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
UINT32 EntryValue;
|
||||||
|
UINT32 EntryMask;
|
||||||
|
UINT32 FirstLevelIdx;
|
||||||
|
UINT32 Offset;
|
||||||
|
UINT32 NumPageEntries;
|
||||||
|
UINT32 Descriptor;
|
||||||
|
UINT32 p;
|
||||||
|
UINT32 PageTableIndex;
|
||||||
|
UINT32 PageTableEntry;
|
||||||
|
UINT32 CurrentPageTableEntry;
|
||||||
|
VOID *Mva;
|
||||||
|
|
||||||
|
volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
|
||||||
|
volatile ARM_PAGE_TABLE_ENTRY *PageTable;
|
||||||
|
|
||||||
|
Status = EFI_SUCCESS;
|
||||||
|
|
||||||
|
// EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)
|
||||||
|
// EntryValue: values at bit positions specified by EntryMask
|
||||||
|
EntryMask = TT_DESCRIPTOR_PAGE_TYPE_MASK | TT_DESCRIPTOR_PAGE_AP_MASK;
|
||||||
|
if (Attributes & EFI_MEMORY_XP) {
|
||||||
|
EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE_XN;
|
||||||
|
} else {
|
||||||
|
EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Although the PI spec is unclear on this, the GCD guarantees that only
|
||||||
|
// one Attribute bit is set at a time, so the order of the conditionals below
|
||||||
|
// is irrelevant. If no memory attribute is specified, we preserve whatever
|
||||||
|
// memory type is set in the page tables, and update the permission attributes
|
||||||
|
// only.
|
||||||
|
if (Attributes & EFI_MEMORY_UC) {
|
||||||
|
// modify cacheability attributes
|
||||||
|
EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;
|
||||||
|
// map to strongly ordered
|
||||||
|
EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0
|
||||||
|
} else if (Attributes & EFI_MEMORY_WC) {
|
||||||
|
// modify cacheability attributes
|
||||||
|
EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;
|
||||||
|
// map to normal non-cachable
|
||||||
|
EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0
|
||||||
|
} else if (Attributes & EFI_MEMORY_WT) {
|
||||||
|
// modify cacheability attributes
|
||||||
|
EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;
|
||||||
|
// write through with no-allocate
|
||||||
|
EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0
|
||||||
|
} else if (Attributes & EFI_MEMORY_WB) {
|
||||||
|
// modify cacheability attributes
|
||||||
|
EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;
|
||||||
|
// write back (with allocate)
|
||||||
|
EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1
|
||||||
|
} else if (Attributes & CACHE_ATTRIBUTE_MASK) {
|
||||||
|
// catch unsupported memory type attributes
|
||||||
|
ASSERT (FALSE);
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Attributes & EFI_MEMORY_RO) {
|
||||||
|
EntryValue |= TT_DESCRIPTOR_PAGE_AP_RO_RO;
|
||||||
|
} else {
|
||||||
|
EntryValue |= TT_DESCRIPTOR_PAGE_AP_RW_RW;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtain page table base
|
||||||
|
FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();
|
||||||
|
|
||||||
|
// Calculate number of 4KB page table entries to change
|
||||||
|
NumPageEntries = Length / TT_DESCRIPTOR_PAGE_SIZE;
|
||||||
|
|
||||||
|
// Iterate for the number of 4KB pages to change
|
||||||
|
Offset = 0;
|
||||||
|
for(p = 0; p < NumPageEntries; p++) {
|
||||||
|
// Calculate index into first level translation table for page table value
|
||||||
|
|
||||||
|
FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress + Offset) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;
|
||||||
|
ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);
|
||||||
|
|
||||||
|
// Read the descriptor from the first level page table
|
||||||
|
Descriptor = FirstLevelTable[FirstLevelIdx];
|
||||||
|
|
||||||
|
// Does this descriptor need to be converted from section entry to 4K pages?
|
||||||
|
if (!TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(Descriptor)) {
|
||||||
|
Status = ConvertSectionToPages (FirstLevelIdx << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
|
||||||
|
if (EFI_ERROR(Status)) {
|
||||||
|
// Exit for loop
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-read descriptor
|
||||||
|
Descriptor = FirstLevelTable[FirstLevelIdx];
|
||||||
|
if (FlushTlbs != NULL) {
|
||||||
|
*FlushTlbs = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtain page table base address
|
||||||
|
PageTable = (ARM_PAGE_TABLE_ENTRY *)TT_DESCRIPTOR_PAGE_BASE_ADDRESS(Descriptor);
|
||||||
|
|
||||||
|
// Calculate index into the page table
|
||||||
|
PageTableIndex = ((BaseAddress + Offset) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;
|
||||||
|
ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);
|
||||||
|
|
||||||
|
// Get the entry
|
||||||
|
CurrentPageTableEntry = PageTable[PageTableIndex];
|
||||||
|
|
||||||
|
// Mask off appropriate fields
|
||||||
|
PageTableEntry = CurrentPageTableEntry & ~EntryMask;
|
||||||
|
|
||||||
|
// Mask in new attributes and/or permissions
|
||||||
|
PageTableEntry |= EntryValue;
|
||||||
|
|
||||||
|
if (VirtualMask != 0) {
|
||||||
|
// Make this virtual address point at a physical page
|
||||||
|
PageTableEntry &= ~VirtualMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CurrentPageTableEntry != PageTableEntry) {
|
||||||
|
Mva = (VOID *)(UINTN)((((UINTN)FirstLevelIdx) << TT_DESCRIPTOR_SECTION_BASE_SHIFT) + (PageTableIndex << TT_DESCRIPTOR_PAGE_BASE_SHIFT));
|
||||||
|
|
||||||
|
// Clean/invalidate the cache for this page, but only
|
||||||
|
// if we are modifying the memory type attributes
|
||||||
|
if (((CurrentPageTableEntry ^ PageTableEntry) & TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK) != 0) {
|
||||||
|
WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only need to update if we are changing the entry
|
||||||
|
PageTable[PageTableIndex] = PageTableEntry;
|
||||||
|
ArmUpdateTranslationTableEntry ((VOID *)&PageTable[PageTableIndex], Mva);
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = EFI_SUCCESS;
|
||||||
|
Offset += TT_DESCRIPTOR_PAGE_SIZE;
|
||||||
|
|
||||||
|
} // End first level translation table loop
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC
|
||||||
|
EFI_STATUS
|
||||||
|
UpdateSectionEntries (
|
||||||
|
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||||
|
IN UINT64 Length,
|
||||||
|
IN UINT64 Attributes,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS VirtualMask
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status = EFI_SUCCESS;
|
||||||
|
UINT32 EntryMask;
|
||||||
|
UINT32 EntryValue;
|
||||||
|
UINT32 FirstLevelIdx;
|
||||||
|
UINT32 NumSections;
|
||||||
|
UINT32 i;
|
||||||
|
UINT32 CurrentDescriptor;
|
||||||
|
UINT32 Descriptor;
|
||||||
|
VOID *Mva;
|
||||||
|
volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
|
||||||
|
|
||||||
|
// EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)
|
||||||
|
// EntryValue: values at bit positions specified by EntryMask
|
||||||
|
|
||||||
|
// Make sure we handle a section range that is unmapped
|
||||||
|
EntryMask = TT_DESCRIPTOR_SECTION_TYPE_MASK | TT_DESCRIPTOR_SECTION_XN_MASK |
|
||||||
|
TT_DESCRIPTOR_SECTION_AP_MASK;
|
||||||
|
EntryValue = TT_DESCRIPTOR_SECTION_TYPE_SECTION;
|
||||||
|
|
||||||
|
// Although the PI spec is unclear on this, the GCD guarantees that only
|
||||||
|
// one Attribute bit is set at a time, so the order of the conditionals below
|
||||||
|
// is irrelevant. If no memory attribute is specified, we preserve whatever
|
||||||
|
// memory type is set in the page tables, and update the permission attributes
|
||||||
|
// only.
|
||||||
|
if (Attributes & EFI_MEMORY_UC) {
|
||||||
|
// modify cacheability attributes
|
||||||
|
EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;
|
||||||
|
// map to strongly ordered
|
||||||
|
EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0
|
||||||
|
} else if (Attributes & EFI_MEMORY_WC) {
|
||||||
|
// modify cacheability attributes
|
||||||
|
EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;
|
||||||
|
// map to normal non-cachable
|
||||||
|
EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0
|
||||||
|
} else if (Attributes & EFI_MEMORY_WT) {
|
||||||
|
// modify cacheability attributes
|
||||||
|
EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;
|
||||||
|
// write through with no-allocate
|
||||||
|
EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0
|
||||||
|
} else if (Attributes & EFI_MEMORY_WB) {
|
||||||
|
// modify cacheability attributes
|
||||||
|
EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;
|
||||||
|
// write back (with allocate)
|
||||||
|
EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1
|
||||||
|
} else if (Attributes & CACHE_ATTRIBUTE_MASK) {
|
||||||
|
// catch unsupported memory type attributes
|
||||||
|
ASSERT (FALSE);
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Attributes & EFI_MEMORY_RO) {
|
||||||
|
EntryValue |= TT_DESCRIPTOR_SECTION_AP_RO_RO;
|
||||||
|
} else {
|
||||||
|
EntryValue |= TT_DESCRIPTOR_SECTION_AP_RW_RW;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Attributes & EFI_MEMORY_XP) {
|
||||||
|
EntryValue |= TT_DESCRIPTOR_SECTION_XN_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// obtain page table base
|
||||||
|
FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();
|
||||||
|
|
||||||
|
// calculate index into first level translation table for start of modification
|
||||||
|
FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;
|
||||||
|
ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);
|
||||||
|
|
||||||
|
// calculate number of 1MB first level entries this applies to
|
||||||
|
NumSections = Length / TT_DESCRIPTOR_SECTION_SIZE;
|
||||||
|
|
||||||
|
// iterate through each descriptor
|
||||||
|
for(i=0; i<NumSections; i++) {
|
||||||
|
CurrentDescriptor = FirstLevelTable[FirstLevelIdx + i];
|
||||||
|
|
||||||
|
// has this descriptor already been coverted to pages?
|
||||||
|
if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(CurrentDescriptor)) {
|
||||||
|
// forward this 1MB range to page table function instead
|
||||||
|
Status = UpdatePageEntries (
|
||||||
|
(FirstLevelIdx + i) << TT_DESCRIPTOR_SECTION_BASE_SHIFT,
|
||||||
|
TT_DESCRIPTOR_SECTION_SIZE,
|
||||||
|
Attributes,
|
||||||
|
VirtualMask,
|
||||||
|
NULL);
|
||||||
|
} else {
|
||||||
|
// still a section entry
|
||||||
|
|
||||||
|
// mask off appropriate fields
|
||||||
|
Descriptor = CurrentDescriptor & ~EntryMask;
|
||||||
|
|
||||||
|
// mask in new attributes and/or permissions
|
||||||
|
Descriptor |= EntryValue;
|
||||||
|
if (VirtualMask != 0) {
|
||||||
|
Descriptor &= ~VirtualMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CurrentDescriptor != Descriptor) {
|
||||||
|
Mva = (VOID *)(UINTN)(((UINTN)FirstLevelTable) << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
|
||||||
|
|
||||||
|
// Clean/invalidate the cache for this section, but only
|
||||||
|
// if we are modifying the memory type attributes
|
||||||
|
if (((CurrentDescriptor ^ Descriptor) & TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK) != 0) {
|
||||||
|
WriteBackInvalidateDataCacheRange (Mva, SIZE_1MB);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only need to update if we are changing the descriptor
|
||||||
|
FirstLevelTable[FirstLevelIdx + i] = Descriptor;
|
||||||
|
ArmUpdateTranslationTableEntry ((VOID *)&FirstLevelTable[FirstLevelIdx + i], Mva);
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
ArmSetMemoryAttributes (
|
||||||
|
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||||
|
IN UINT64 Length,
|
||||||
|
IN UINT64 Attributes,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS VirtualMask
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
UINT64 ChunkLength;
|
||||||
|
BOOLEAN FlushTlbs;
|
||||||
|
|
||||||
|
if (Length == 0) {
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
FlushTlbs = FALSE;
|
||||||
|
while (Length > 0) {
|
||||||
|
if ((BaseAddress % TT_DESCRIPTOR_SECTION_SIZE == 0) &&
|
||||||
|
Length >= TT_DESCRIPTOR_SECTION_SIZE) {
|
||||||
|
|
||||||
|
ChunkLength = Length - Length % TT_DESCRIPTOR_SECTION_SIZE;
|
||||||
|
|
||||||
|
DEBUG ((DEBUG_PAGE,
|
||||||
|
"SetMemoryAttributes(): MMU section 0x%lx length 0x%lx to %lx\n",
|
||||||
|
BaseAddress, ChunkLength, Attributes));
|
||||||
|
|
||||||
|
Status = UpdateSectionEntries (BaseAddress, ChunkLength, Attributes,
|
||||||
|
VirtualMask);
|
||||||
|
|
||||||
|
FlushTlbs = TRUE;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Process page by page until the next section boundary, but only if
|
||||||
|
// we have more than a section's worth of area to deal with after that.
|
||||||
|
//
|
||||||
|
ChunkLength = TT_DESCRIPTOR_SECTION_SIZE -
|
||||||
|
(BaseAddress % TT_DESCRIPTOR_SECTION_SIZE);
|
||||||
|
if (ChunkLength + TT_DESCRIPTOR_SECTION_SIZE > Length) {
|
||||||
|
ChunkLength = Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG ((DEBUG_PAGE,
|
||||||
|
"SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n",
|
||||||
|
BaseAddress, ChunkLength, Attributes));
|
||||||
|
|
||||||
|
Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes,
|
||||||
|
VirtualMask, &FlushTlbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseAddress += ChunkLength;
|
||||||
|
Length -= ChunkLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FlushTlbs) {
|
||||||
|
ArmInvalidateTlb ();
|
||||||
|
}
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
ArmSetMemoryRegionNoExec (
|
ArmSetMemoryRegionNoExec (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user