... 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>
---
ArmPkg/Drivers/CpuDxe/Arm/Mmu.c | 368 --------------------
ArmPkg/Drivers/CpuDxe/CpuDxe.h | 14 +-
ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c | 2 +-
ArmPkg/Include/Library/ArmMmuLib.h | 8 +
ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c | 2 +-
ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c | 368 ++++++++++++++++++++
6 files changed, 379 insertions(+), 383 deletions(-)
diff --git a/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c b/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
index 6322d301060e..b985dd743f02 100644
--- a/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
+++ b/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
@@ -343,374 +343,6 @@ SyncCacheConfig (
return EFI_SUCCESS;
}
-
-
-EFI_STATUS
-UpdatePageEntries (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 Attributes,
- IN EFI_PHYSICAL_ADDRESS VirtualMask
- )
-{
- 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 we can safely use a switch statement
- if ((Attributes & EFI_MEMORY_UC) != 0) {
- // 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) != 0) {
- // 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) != 0) {
- // 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) != 0) {
- // 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
- }
-
- 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];
- }
-
- // 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));
- if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) {
- // The current section mapping is cacheable so Clean/Invalidate the MVA of the page
- // Note assumes switch(Attributes), not ARMv7 possibilities
- 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;
-}
-
-
-
-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 we can safely use a switch statement
- if ((Attributes & EFI_MEMORY_UC) != 0) {
- // 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) != 0) {
- // 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) != 0) {
- // 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) != 0) {
- // 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
- }
-
- if ((Attributes & EFI_MEMORY_RO) != 0) {
- EntryValue |= TT_DESCRIPTOR_SECTION_AP_RO_RO;
- } else {
- EntryValue |= TT_DESCRIPTOR_SECTION_AP_RW_RW;
- }
-
- if ((Attributes & EFI_MEMORY_XP) != 0) {
- 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);
- } 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);
- if ((CurrentDescriptor & TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) == TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) {
- // The current section mapping is cacheable so Clean/Invalidate the MVA of the section
- // Note assumes switch(Attributes), not ARMv7 possabilities
- 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
-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;
-
- 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 | DEBUG_INFO,
- "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 | DEBUG_INFO,
- "SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n",
- BaseAddress, ChunkLength, Attributes));
-
- Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes,
- VirtualMask);
- }
-
- if (EFI_ERROR (Status)) {
- break;
- }
-
- BaseAddress += ChunkLength;
- Length -= ChunkLength;
- }
-
- if (FlushTlbs) {
- ArmInvalidateTlb ();
- }
- return Status;
-}
-
UINT64
EfiAttributeToArmAttribute (
IN UINT64 EfiAttributes
diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
index a46db8d25754..a0f71e69ec09 100644
--- a/ArmPkg/Drivers/CpuDxe/CpuDxe.h
+++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
@@ -19,6 +19,7 @@
#include <Uefi.h>
#include <Library/ArmLib.h>
+#include <Library/ArmMmuLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
@@ -112,11 +113,6 @@ SyncCacheConfig (
IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
);
-EFI_STATUS
-ConvertSectionToPages (
- IN EFI_PHYSICAL_ADDRESS BaseAddress
- );
-
/**
* Publish ARM Processor Data table in UEFI SYSTEM Table.
* @param HobStart Pointer to the beginning of the HOB List from PEI.
@@ -132,14 +128,6 @@ PublishArmProcessorTable(
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)
UINT64
EfiAttributeToArmAttribute (
diff --git a/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c b/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
index 0f36a058407a..d0a3fedd3aa7 100644
--- a/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
+++ b/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
@@ -210,7 +210,7 @@ CpuSetMemoryAttributes (
if (EFI_ERROR (Status) || (RegionArmAttributes != ArmAttributes) ||
((BaseAddress + Length) > (RegionBaseAddress + RegionLength)))
{
- return SetMemoryAttributes (BaseAddress, Length, EfiAttributes, 0);
+ return ArmSetMemoryAttributes (BaseAddress, Length, EfiAttributes, 0);
} else {
return EFI_SUCCESS;
}
diff --git a/ArmPkg/Include/Library/ArmMmuLib.h b/ArmPkg/Include/Library/ArmMmuLib.h
index c1d43872d548..d3a302fa8125 100644
--- a/ArmPkg/Include/Library/ArmMmuLib.h
+++ b/ArmPkg/Include/Library/ArmMmuLib.h
@@ -62,4 +62,12 @@ ArmReplaceLiveTranslationEntry (
IN UINT64 Value
);
+EFI_STATUS
+ArmSetMemoryAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes,
+ IN EFI_PHYSICAL_ADDRESS VirtualMask
+ );
+
#endif
diff --git a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c
index df170d20a2c2..77f108971f3e 100644
--- a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c
+++ b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c
@@ -447,7 +447,7 @@ GcdAttributeToPageAttribute (
}
EFI_STATUS
-SetMemoryAttributes (
+ArmSetMemoryAttributes (
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length,
IN UINT64 Attributes,
diff --git a/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c
index 4b6f4ce392b7..93980d6d12db 100644
--- a/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c
+++ b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c
@@ -16,6 +16,7 @@
#include <Uefi.h>
#include <Chipset/ArmV7.h>
#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/ArmLib.h>
#include <Library/BaseLib.h>
@@ -36,6 +37,12 @@
#define ID_MMFR0_SHR_IMP_HW_COHERENT 1
#define ID_MMFR0_SHR_IGNORED 0xf
+// First Level Descriptors
+typedef UINT32 ARM_FIRST_LEVEL_DESCRIPTOR;
+
+// Second Level Descriptors
+typedef UINT32 ARM_PAGE_TABLE_ENTRY;
+
UINTN
EFIAPI
ArmReadIdMmfr0 (
@@ -406,6 +413,367 @@ ArmConfigureMmu (
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
+ )
+{
+ 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 we can safely use a switch statement
+ if ((Attributes & EFI_MEMORY_UC) != 0) {
+ // 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) != 0) {
+ // 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) != 0) {
+ // 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) != 0) {
+ // 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
+ }
+
+ 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];
+ }
+
+ // 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));
+ if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) {
+ // The current section mapping is cacheable so Clean/Invalidate the MVA of the page
+ // Note assumes switch(Attributes), not ARMv7 possibilities
+ 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 we can safely use a switch statement
+ if ((Attributes & EFI_MEMORY_UC) != 0) {
+ // 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) != 0) {
+ // 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) != 0) {
+ // 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) != 0) {
+ // 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
+ }
+
+ if ((Attributes & EFI_MEMORY_RO) != 0) {
+ EntryValue |= TT_DESCRIPTOR_SECTION_AP_RO_RO;
+ } else {
+ EntryValue |= TT_DESCRIPTOR_SECTION_AP_RW_RW;
+ }
+
+ if ((Attributes & EFI_MEMORY_XP) != 0) {
+ 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);
+ } 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);
+ if ((CurrentDescriptor & TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) == TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) {
+ // The current section mapping is cacheable so Clean/Invalidate the MVA of the section
+ // Note assumes switch(Attributes), not ARMv7 possabilities
+ 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;
+
+ 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 | DEBUG_INFO,
+ "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 | DEBUG_INFO,
+ "SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n",
+ BaseAddress, ChunkLength, Attributes));
+
+ Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes,
+ VirtualMask);
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ BaseAddress += ChunkLength;
+ Length -= ChunkLength;
+ }
+
+ if (FlushTlbs) {
+ ArmInvalidateTlb ();
+ }
+ return Status;
+}
+
RETURN_STATUS
ArmSetMemoryRegionNoExec (
IN EFI_PHYSICAL_ADDRESS BaseAddress,
--
2.7.4
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
n Wed, Mar 01, 2017 at 04:31:40PM +0000, Ard Biesheuvel wrote:
> ... 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>
> ---
> ArmPkg/Drivers/CpuDxe/Arm/Mmu.c | 368 --------------------
> ArmPkg/Drivers/CpuDxe/CpuDxe.h | 14 +-
> ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c | 2 +-
> ArmPkg/Include/Library/ArmMmuLib.h | 8 +
> ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c | 2 +-
> ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c | 368 ++++++++++++++++++++
> 6 files changed, 379 insertions(+), 383 deletions(-)
>
> diff --git a/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c b/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
> index 6322d301060e..b985dd743f02 100644
> --- a/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
> +++ b/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
> @@ -343,374 +343,6 @@ SyncCacheConfig (
> return EFI_SUCCESS;
> }
>
> -
> -
> -EFI_STATUS
> -UpdatePageEntries (
> - IN EFI_PHYSICAL_ADDRESS BaseAddress,
> - IN UINT64 Length,
> - IN UINT64 Attributes,
> - IN EFI_PHYSICAL_ADDRESS VirtualMask
> - )
> -{
> - 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 we can safely use a switch statement
> - if ((Attributes & EFI_MEMORY_UC) != 0) {
> - // 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) != 0) {
> - // 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) != 0) {
> - // 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) != 0) {
> - // 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
> - }
> -
> - 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];
> - }
> -
> - // 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));
> - if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) {
> - // The current section mapping is cacheable so Clean/Invalidate the MVA of the page
> - // Note assumes switch(Attributes), not ARMv7 possibilities
> - 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;
> -}
> -
> -
> -
> -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 we can safely use a switch statement
> - if ((Attributes & EFI_MEMORY_UC) != 0) {
> - // 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) != 0) {
> - // 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) != 0) {
> - // 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) != 0) {
> - // 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
> - }
> -
> - if ((Attributes & EFI_MEMORY_RO) != 0) {
> - EntryValue |= TT_DESCRIPTOR_SECTION_AP_RO_RO;
> - } else {
> - EntryValue |= TT_DESCRIPTOR_SECTION_AP_RW_RW;
> - }
> -
> - if ((Attributes & EFI_MEMORY_XP) != 0) {
> - 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);
> - } 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);
> - if ((CurrentDescriptor & TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) == TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) {
> - // The current section mapping is cacheable so Clean/Invalidate the MVA of the section
> - // Note assumes switch(Attributes), not ARMv7 possabilities
> - 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
> -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;
> -
> - 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 | DEBUG_INFO,
> - "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 | DEBUG_INFO,
> - "SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n",
> - BaseAddress, ChunkLength, Attributes));
> -
> - Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes,
> - VirtualMask);
> - }
> -
> - if (EFI_ERROR (Status)) {
> - break;
> - }
> -
> - BaseAddress += ChunkLength;
> - Length -= ChunkLength;
> - }
> -
> - if (FlushTlbs) {
> - ArmInvalidateTlb ();
> - }
> - return Status;
> -}
> -
> UINT64
> EfiAttributeToArmAttribute (
> IN UINT64 EfiAttributes
> diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
> index a46db8d25754..a0f71e69ec09 100644
> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.h
> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
> @@ -19,6 +19,7 @@
> #include <Uefi.h>
>
> #include <Library/ArmLib.h>
> +#include <Library/ArmMmuLib.h>
> #include <Library/BaseMemoryLib.h>
> #include <Library/DebugLib.h>
> #include <Library/PcdLib.h>
> @@ -112,11 +113,6 @@ SyncCacheConfig (
> IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
> );
>
> -EFI_STATUS
> -ConvertSectionToPages (
> - IN EFI_PHYSICAL_ADDRESS BaseAddress
> - );
> -
> /**
> * Publish ARM Processor Data table in UEFI SYSTEM Table.
> * @param HobStart Pointer to the beginning of the HOB List from PEI.
> @@ -132,14 +128,6 @@ PublishArmProcessorTable(
> 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)
> UINT64
> EfiAttributeToArmAttribute (
> diff --git a/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c b/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
> index 0f36a058407a..d0a3fedd3aa7 100644
> --- a/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
> +++ b/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
> @@ -210,7 +210,7 @@ CpuSetMemoryAttributes (
> if (EFI_ERROR (Status) || (RegionArmAttributes != ArmAttributes) ||
> ((BaseAddress + Length) > (RegionBaseAddress + RegionLength)))
> {
> - return SetMemoryAttributes (BaseAddress, Length, EfiAttributes, 0);
> + return ArmSetMemoryAttributes (BaseAddress, Length, EfiAttributes, 0);
> } else {
> return EFI_SUCCESS;
> }
> diff --git a/ArmPkg/Include/Library/ArmMmuLib.h b/ArmPkg/Include/Library/ArmMmuLib.h
> index c1d43872d548..d3a302fa8125 100644
> --- a/ArmPkg/Include/Library/ArmMmuLib.h
> +++ b/ArmPkg/Include/Library/ArmMmuLib.h
> @@ -62,4 +62,12 @@ ArmReplaceLiveTranslationEntry (
> IN UINT64 Value
> );
>
> +EFI_STATUS
> +ArmSetMemoryAttributes (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINT64 Length,
> + IN UINT64 Attributes,
> + IN EFI_PHYSICAL_ADDRESS VirtualMask
> + );
> +
> #endif
> diff --git a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c
> index df170d20a2c2..77f108971f3e 100644
> --- a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c
> +++ b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c
> @@ -447,7 +447,7 @@ GcdAttributeToPageAttribute (
> }
>
> EFI_STATUS
> -SetMemoryAttributes (
> +ArmSetMemoryAttributes (
> IN EFI_PHYSICAL_ADDRESS BaseAddress,
> IN UINT64 Length,
> IN UINT64 Attributes,
> diff --git a/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c
> index 4b6f4ce392b7..93980d6d12db 100644
> --- a/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c
> +++ b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c
> @@ -16,6 +16,7 @@
> #include <Uefi.h>
> #include <Chipset/ArmV7.h>
> #include <Library/BaseMemoryLib.h>
> +#include <Library/CacheMaintenanceLib.h>
> #include <Library/MemoryAllocationLib.h>
> #include <Library/ArmLib.h>
> #include <Library/BaseLib.h>
> @@ -36,6 +37,12 @@
> #define ID_MMFR0_SHR_IMP_HW_COHERENT 1
> #define ID_MMFR0_SHR_IGNORED 0xf
>
> +// First Level Descriptors
> +typedef UINT32 ARM_FIRST_LEVEL_DESCRIPTOR;
> +
> +// Second Level Descriptors
> +typedef UINT32 ARM_PAGE_TABLE_ENTRY;
> +
Copied from ArmPkg/Drivers/CpuDxe/Arm/Mmu.c, but not deleted there.
Can it be, or can it be moved out into a header somewhere?
No other comments.
/
Leif
> UINTN
> EFIAPI
> ArmReadIdMmfr0 (
> @@ -406,6 +413,367 @@ ArmConfigureMmu (
> 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
> + )
> +{
> + 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 we can safely use a switch statement
> + if ((Attributes & EFI_MEMORY_UC) != 0) {
> + // 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) != 0) {
> + // 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) != 0) {
> + // 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) != 0) {
> + // 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
> + }
> +
> + 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];
> + }
> +
> + // 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));
> + if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) {
> + // The current section mapping is cacheable so Clean/Invalidate the MVA of the page
> + // Note assumes switch(Attributes), not ARMv7 possibilities
> + 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 we can safely use a switch statement
> + if ((Attributes & EFI_MEMORY_UC) != 0) {
> + // 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) != 0) {
> + // 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) != 0) {
> + // 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) != 0) {
> + // 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
> + }
> +
> + if ((Attributes & EFI_MEMORY_RO) != 0) {
> + EntryValue |= TT_DESCRIPTOR_SECTION_AP_RO_RO;
> + } else {
> + EntryValue |= TT_DESCRIPTOR_SECTION_AP_RW_RW;
> + }
> +
> + if ((Attributes & EFI_MEMORY_XP) != 0) {
> + 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);
> + } 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);
> + if ((CurrentDescriptor & TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) == TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) {
> + // The current section mapping is cacheable so Clean/Invalidate the MVA of the section
> + // Note assumes switch(Attributes), not ARMv7 possabilities
> + 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;
> +
> + 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 | DEBUG_INFO,
> + "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 | DEBUG_INFO,
> + "SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n",
> + BaseAddress, ChunkLength, Attributes));
> +
> + Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes,
> + VirtualMask);
> + }
> +
> + if (EFI_ERROR (Status)) {
> + break;
> + }
> +
> + BaseAddress += ChunkLength;
> + Length -= ChunkLength;
> + }
> +
> + if (FlushTlbs) {
> + ArmInvalidateTlb ();
> + }
> + return Status;
> +}
> +
> RETURN_STATUS
> ArmSetMemoryRegionNoExec (
> IN EFI_PHYSICAL_ADDRESS BaseAddress,
> --
> 2.7.4
>
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
On 6 March 2017 at 17:03, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> n Wed, Mar 01, 2017 at 04:31:40PM +0000, Ard Biesheuvel wrote:
>> ... 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>
>> ---
>> ArmPkg/Drivers/CpuDxe/Arm/Mmu.c | 368 --------------------
>> ArmPkg/Drivers/CpuDxe/CpuDxe.h | 14 +-
>> ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c | 2 +-
>> ArmPkg/Include/Library/ArmMmuLib.h | 8 +
>> ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c | 2 +-
>> ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c | 368 ++++++++++++++++++++
>> 6 files changed, 379 insertions(+), 383 deletions(-)
>>
>> diff --git a/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c b/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
>> index 6322d301060e..b985dd743f02 100644
>> --- a/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
>> +++ b/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
>> @@ -343,374 +343,6 @@ SyncCacheConfig (
>> return EFI_SUCCESS;
>> }
>>
>> -
>> -
>> -EFI_STATUS
>> -UpdatePageEntries (
>> - IN EFI_PHYSICAL_ADDRESS BaseAddress,
>> - IN UINT64 Length,
>> - IN UINT64 Attributes,
>> - IN EFI_PHYSICAL_ADDRESS VirtualMask
>> - )
>> -{
>> - 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 we can safely use a switch statement
>> - if ((Attributes & EFI_MEMORY_UC) != 0) {
>> - // 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) != 0) {
>> - // 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) != 0) {
>> - // 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) != 0) {
>> - // 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
>> - }
>> -
>> - 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];
>> - }
>> -
>> - // 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));
>> - if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) {
>> - // The current section mapping is cacheable so Clean/Invalidate the MVA of the page
>> - // Note assumes switch(Attributes), not ARMv7 possibilities
>> - 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;
>> -}
>> -
>> -
>> -
>> -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 we can safely use a switch statement
>> - if ((Attributes & EFI_MEMORY_UC) != 0) {
>> - // 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) != 0) {
>> - // 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) != 0) {
>> - // 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) != 0) {
>> - // 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
>> - }
>> -
>> - if ((Attributes & EFI_MEMORY_RO) != 0) {
>> - EntryValue |= TT_DESCRIPTOR_SECTION_AP_RO_RO;
>> - } else {
>> - EntryValue |= TT_DESCRIPTOR_SECTION_AP_RW_RW;
>> - }
>> -
>> - if ((Attributes & EFI_MEMORY_XP) != 0) {
>> - 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);
>> - } 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);
>> - if ((CurrentDescriptor & TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) == TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) {
>> - // The current section mapping is cacheable so Clean/Invalidate the MVA of the section
>> - // Note assumes switch(Attributes), not ARMv7 possabilities
>> - 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
>> -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;
>> -
>> - 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 | DEBUG_INFO,
>> - "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 | DEBUG_INFO,
>> - "SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n",
>> - BaseAddress, ChunkLength, Attributes));
>> -
>> - Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes,
>> - VirtualMask);
>> - }
>> -
>> - if (EFI_ERROR (Status)) {
>> - break;
>> - }
>> -
>> - BaseAddress += ChunkLength;
>> - Length -= ChunkLength;
>> - }
>> -
>> - if (FlushTlbs) {
>> - ArmInvalidateTlb ();
>> - }
>> - return Status;
>> -}
>> -
>> UINT64
>> EfiAttributeToArmAttribute (
>> IN UINT64 EfiAttributes
>> diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
>> index a46db8d25754..a0f71e69ec09 100644
>> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.h
>> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
>> @@ -19,6 +19,7 @@
>> #include <Uefi.h>
>>
>> #include <Library/ArmLib.h>
>> +#include <Library/ArmMmuLib.h>
>> #include <Library/BaseMemoryLib.h>
>> #include <Library/DebugLib.h>
>> #include <Library/PcdLib.h>
>> @@ -112,11 +113,6 @@ SyncCacheConfig (
>> IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
>> );
>>
>> -EFI_STATUS
>> -ConvertSectionToPages (
>> - IN EFI_PHYSICAL_ADDRESS BaseAddress
>> - );
>> -
>> /**
>> * Publish ARM Processor Data table in UEFI SYSTEM Table.
>> * @param HobStart Pointer to the beginning of the HOB List from PEI.
>> @@ -132,14 +128,6 @@ PublishArmProcessorTable(
>> 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)
>> UINT64
>> EfiAttributeToArmAttribute (
>> diff --git a/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c b/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
>> index 0f36a058407a..d0a3fedd3aa7 100644
>> --- a/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
>> +++ b/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
>> @@ -210,7 +210,7 @@ CpuSetMemoryAttributes (
>> if (EFI_ERROR (Status) || (RegionArmAttributes != ArmAttributes) ||
>> ((BaseAddress + Length) > (RegionBaseAddress + RegionLength)))
>> {
>> - return SetMemoryAttributes (BaseAddress, Length, EfiAttributes, 0);
>> + return ArmSetMemoryAttributes (BaseAddress, Length, EfiAttributes, 0);
>> } else {
>> return EFI_SUCCESS;
>> }
>> diff --git a/ArmPkg/Include/Library/ArmMmuLib.h b/ArmPkg/Include/Library/ArmMmuLib.h
>> index c1d43872d548..d3a302fa8125 100644
>> --- a/ArmPkg/Include/Library/ArmMmuLib.h
>> +++ b/ArmPkg/Include/Library/ArmMmuLib.h
>> @@ -62,4 +62,12 @@ ArmReplaceLiveTranslationEntry (
>> IN UINT64 Value
>> );
>>
>> +EFI_STATUS
>> +ArmSetMemoryAttributes (
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>> + IN UINT64 Length,
>> + IN UINT64 Attributes,
>> + IN EFI_PHYSICAL_ADDRESS VirtualMask
>> + );
>> +
>> #endif
>> diff --git a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c
>> index df170d20a2c2..77f108971f3e 100644
>> --- a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c
>> +++ b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c
>> @@ -447,7 +447,7 @@ GcdAttributeToPageAttribute (
>> }
>>
>> EFI_STATUS
>> -SetMemoryAttributes (
>> +ArmSetMemoryAttributes (
>> IN EFI_PHYSICAL_ADDRESS BaseAddress,
>> IN UINT64 Length,
>> IN UINT64 Attributes,
>> diff --git a/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c
>> index 4b6f4ce392b7..93980d6d12db 100644
>> --- a/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c
>> +++ b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c
>> @@ -16,6 +16,7 @@
>> #include <Uefi.h>
>> #include <Chipset/ArmV7.h>
>> #include <Library/BaseMemoryLib.h>
>> +#include <Library/CacheMaintenanceLib.h>
>> #include <Library/MemoryAllocationLib.h>
>> #include <Library/ArmLib.h>
>> #include <Library/BaseLib.h>
>> @@ -36,6 +37,12 @@
>> #define ID_MMFR0_SHR_IMP_HW_COHERENT 1
>> #define ID_MMFR0_SHR_IGNORED 0xf
>>
>> +// First Level Descriptors
>> +typedef UINT32 ARM_FIRST_LEVEL_DESCRIPTOR;
>> +
>> +// Second Level Descriptors
>> +typedef UINT32 ARM_PAGE_TABLE_ENTRY;
>> +
>
> Copied from ArmPkg/Drivers/CpuDxe/Arm/Mmu.c, but not deleted there.
> Can it be, or can it be moved out into a header somewhere?
>
> No other comments.
>
It is used in both places, so I'd need to put in in a header file
ArmPkg/Include/Chipset/ArmV7Mmu.h comes to mind ...
>> UINTN
>> EFIAPI
>> ArmReadIdMmfr0 (
>> @@ -406,6 +413,367 @@ ArmConfigureMmu (
>> 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
>> + )
>> +{
>> + 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 we can safely use a switch statement
>> + if ((Attributes & EFI_MEMORY_UC) != 0) {
>> + // 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) != 0) {
>> + // 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) != 0) {
>> + // 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) != 0) {
>> + // 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
>> + }
>> +
>> + 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];
>> + }
>> +
>> + // 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));
>> + if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) {
>> + // The current section mapping is cacheable so Clean/Invalidate the MVA of the page
>> + // Note assumes switch(Attributes), not ARMv7 possibilities
>> + 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 we can safely use a switch statement
>> + if ((Attributes & EFI_MEMORY_UC) != 0) {
>> + // 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) != 0) {
>> + // 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) != 0) {
>> + // 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) != 0) {
>> + // 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
>> + }
>> +
>> + if ((Attributes & EFI_MEMORY_RO) != 0) {
>> + EntryValue |= TT_DESCRIPTOR_SECTION_AP_RO_RO;
>> + } else {
>> + EntryValue |= TT_DESCRIPTOR_SECTION_AP_RW_RW;
>> + }
>> +
>> + if ((Attributes & EFI_MEMORY_XP) != 0) {
>> + 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);
>> + } 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);
>> + if ((CurrentDescriptor & TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) == TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) {
>> + // The current section mapping is cacheable so Clean/Invalidate the MVA of the section
>> + // Note assumes switch(Attributes), not ARMv7 possabilities
>> + 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;
>> +
>> + 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 | DEBUG_INFO,
>> + "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 | DEBUG_INFO,
>> + "SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n",
>> + BaseAddress, ChunkLength, Attributes));
>> +
>> + Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes,
>> + VirtualMask);
>> + }
>> +
>> + if (EFI_ERROR (Status)) {
>> + break;
>> + }
>> +
>> + BaseAddress += ChunkLength;
>> + Length -= ChunkLength;
>> + }
>> +
>> + if (FlushTlbs) {
>> + ArmInvalidateTlb ();
>> + }
>> + return Status;
>> +}
>> +
>> RETURN_STATUS
>> ArmSetMemoryRegionNoExec (
>> IN EFI_PHYSICAL_ADDRESS BaseAddress,
>> --
>> 2.7.4
>>
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
On Mon, Mar 06, 2017 at 05:05:58PM +0100, Ard Biesheuvel wrote:
> >> diff --git a/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c
> >> index 4b6f4ce392b7..93980d6d12db 100644
> >> --- a/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c
> >> +++ b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c
> >> @@ -16,6 +16,7 @@
> >> #include <Uefi.h>
> >> #include <Chipset/ArmV7.h>
> >> #include <Library/BaseMemoryLib.h>
> >> +#include <Library/CacheMaintenanceLib.h>
> >> #include <Library/MemoryAllocationLib.h>
> >> #include <Library/ArmLib.h>
> >> #include <Library/BaseLib.h>
> >> @@ -36,6 +37,12 @@
> >> #define ID_MMFR0_SHR_IMP_HW_COHERENT 1
> >> #define ID_MMFR0_SHR_IGNORED 0xf
> >>
> >> +// First Level Descriptors
> >> +typedef UINT32 ARM_FIRST_LEVEL_DESCRIPTOR;
> >> +
> >> +// Second Level Descriptors
> >> +typedef UINT32 ARM_PAGE_TABLE_ENTRY;
> >> +
> >
> > Copied from ArmPkg/Drivers/CpuDxe/Arm/Mmu.c, but not deleted there.
> > Can it be, or can it be moved out into a header somewhere?
> >
> > No other comments.
> >
>
> It is used in both places, so I'd need to put in in a header file
>
> ArmPkg/Include/Chipset/ArmV7Mmu.h comes to mind ...
Works for me.
If you fold that in:
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
/
Leif
> >> UINTN
> >> EFIAPI
> >> ArmReadIdMmfr0 (
> >> @@ -406,6 +413,367 @@ ArmConfigureMmu (
> >> 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
> >> + )
> >> +{
> >> + 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 we can safely use a switch statement
> >> + if ((Attributes & EFI_MEMORY_UC) != 0) {
> >> + // 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) != 0) {
> >> + // 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) != 0) {
> >> + // 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) != 0) {
> >> + // 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
> >> + }
> >> +
> >> + 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];
> >> + }
> >> +
> >> + // 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));
> >> + if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) {
> >> + // The current section mapping is cacheable so Clean/Invalidate the MVA of the page
> >> + // Note assumes switch(Attributes), not ARMv7 possibilities
> >> + 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 we can safely use a switch statement
> >> + if ((Attributes & EFI_MEMORY_UC) != 0) {
> >> + // 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) != 0) {
> >> + // 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) != 0) {
> >> + // 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) != 0) {
> >> + // 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
> >> + }
> >> +
> >> + if ((Attributes & EFI_MEMORY_RO) != 0) {
> >> + EntryValue |= TT_DESCRIPTOR_SECTION_AP_RO_RO;
> >> + } else {
> >> + EntryValue |= TT_DESCRIPTOR_SECTION_AP_RW_RW;
> >> + }
> >> +
> >> + if ((Attributes & EFI_MEMORY_XP) != 0) {
> >> + 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);
> >> + } 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);
> >> + if ((CurrentDescriptor & TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) == TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) {
> >> + // The current section mapping is cacheable so Clean/Invalidate the MVA of the section
> >> + // Note assumes switch(Attributes), not ARMv7 possabilities
> >> + 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;
> >> +
> >> + 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 | DEBUG_INFO,
> >> + "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 | DEBUG_INFO,
> >> + "SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n",
> >> + BaseAddress, ChunkLength, Attributes));
> >> +
> >> + Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes,
> >> + VirtualMask);
> >> + }
> >> +
> >> + if (EFI_ERROR (Status)) {
> >> + break;
> >> + }
> >> +
> >> + BaseAddress += ChunkLength;
> >> + Length -= ChunkLength;
> >> + }
> >> +
> >> + if (FlushTlbs) {
> >> + ArmInvalidateTlb ();
> >> + }
> >> + return Status;
> >> +}
> >> +
> >> RETURN_STATUS
> >> ArmSetMemoryRegionNoExec (
> >> IN EFI_PHYSICAL_ADDRESS BaseAddress,
> >> --
> >> 2.7.4
> >>
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
© 2016 - 2026 Red Hat, Inc.