summaryrefslogtreecommitdiffstats
path: root/ArmPkg/Library/ArmMmuLib/Arm
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2016-06-15 18:49:09 +0200
committerArd Biesheuvel <ard.biesheuvel@linaro.org>2016-07-07 14:33:47 +0200
commitd7f03464b246b4111c8e21ba3dcd7b4a7b85fa7f (patch)
tree1c9e4a9e5e0b59d38216d3de6e892a7c550a5062 /ArmPkg/Library/ArmMmuLib/Arm
parent12728e1137d37debdf6b98a8b8689106b4584908 (diff)
downloadedk2-d7f03464b246b4111c8e21ba3dcd7b4a7b85fa7f.tar.gz
edk2-d7f03464b246b4111c8e21ba3dcd7b4a7b85fa7f.tar.bz2
edk2-d7f03464b246b4111c8e21ba3dcd7b4a7b85fa7f.zip
ArmPkg: introduce base ArmMmuLib implementation
This base library encapsulates the MMU manipulation routines that have been factored out of ArmLib. The functionality covers initial creation of the 1:1 mapping in the page tables, and remapping regions to change permissions or cacheability attributes. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
Diffstat (limited to 'ArmPkg/Library/ArmMmuLib/Arm')
-rw-r--r--ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c452
-rw-r--r--ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibV7Support.S35
-rw-r--r--ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibV7Support.asm32
3 files changed, 519 insertions, 0 deletions
diff --git a/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c
new file mode 100644
index 0000000000..4b6f4ce392
--- /dev/null
+++ b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c
@@ -0,0 +1,452 @@
+/** @file
+* File managing the MMU for ARMv7 architecture
+*
+* Copyright (c) 2011-2016, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+#include <Chipset/ArmV7.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ArmLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+
+#define ID_MMFR0_SHARELVL_SHIFT 12
+#define ID_MMFR0_SHARELVL_MASK 0xf
+#define ID_MMFR0_SHARELVL_ONE 0
+#define ID_MMFR0_SHARELVL_TWO 1
+
+#define ID_MMFR0_INNERSHR_SHIFT 28
+#define ID_MMFR0_INNERSHR_MASK 0xf
+#define ID_MMFR0_OUTERSHR_SHIFT 8
+#define ID_MMFR0_OUTERSHR_MASK 0xf
+
+#define ID_MMFR0_SHR_IMP_UNCACHED 0
+#define ID_MMFR0_SHR_IMP_HW_COHERENT 1
+#define ID_MMFR0_SHR_IGNORED 0xf
+
+UINTN
+EFIAPI
+ArmReadIdMmfr0 (
+ VOID
+ );
+
+BOOLEAN
+EFIAPI
+ArmHasMpExtensions (
+ VOID
+ );
+
+UINT32
+ConvertSectionAttributesToPageAttributes (
+ IN UINT32 SectionAttributes,
+ IN BOOLEAN IsLargePage
+ )
+{
+ UINT32 PageAttributes;
+
+ PageAttributes = 0;
+ PageAttributes |= TT_DESCRIPTOR_CONVERT_TO_PAGE_CACHE_POLICY (SectionAttributes, IsLargePage);
+ PageAttributes |= TT_DESCRIPTOR_CONVERT_TO_PAGE_AP (SectionAttributes);
+ PageAttributes |= TT_DESCRIPTOR_CONVERT_TO_PAGE_XN (SectionAttributes, IsLargePage);
+ PageAttributes |= TT_DESCRIPTOR_CONVERT_TO_PAGE_NG (SectionAttributes);
+ PageAttributes |= TT_DESCRIPTOR_CONVERT_TO_PAGE_S (SectionAttributes);
+
+ return PageAttributes;
+}
+
+STATIC
+BOOLEAN
+PreferNonshareableMemory (
+ VOID
+ )
+{
+ UINTN Mmfr;
+ UINTN Val;
+
+ if (FeaturePcdGet (PcdNormalMemoryNonshareableOverride)) {
+ return TRUE;
+ }
+
+ //
+ // Check whether the innermost level of shareability (the level we will use
+ // by default to map normal memory) is implemented with hardware coherency
+ // support. Otherwise, revert to mapping as non-shareable.
+ //
+ Mmfr = ArmReadIdMmfr0 ();
+ switch ((Mmfr >> ID_MMFR0_SHARELVL_SHIFT) & ID_MMFR0_SHARELVL_MASK) {
+ case ID_MMFR0_SHARELVL_ONE:
+ // one level of shareability
+ Val = (Mmfr >> ID_MMFR0_OUTERSHR_SHIFT) & ID_MMFR0_OUTERSHR_MASK;
+ break;
+ case ID_MMFR0_SHARELVL_TWO:
+ // two levels of shareability
+ Val = (Mmfr >> ID_MMFR0_INNERSHR_SHIFT) & ID_MMFR0_INNERSHR_MASK;
+ break;
+ default:
+ // unexpected value -> shareable is the safe option
+ ASSERT (FALSE);
+ return FALSE;
+ }
+ return Val != ID_MMFR0_SHR_IMP_HW_COHERENT;
+}
+
+STATIC
+VOID
+PopulateLevel2PageTable (
+ IN UINT32 *SectionEntry,
+ IN UINT32 PhysicalBase,
+ IN UINT32 RemainLength,
+ IN ARM_MEMORY_REGION_ATTRIBUTES Attributes
+ )
+{
+ UINT32* PageEntry;
+ UINT32 Pages;
+ UINT32 Index;
+ UINT32 PageAttributes;
+ UINT32 SectionDescriptor;
+ UINT32 TranslationTable;
+ UINT32 BaseSectionAddress;
+
+ switch (Attributes) {
+ case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK:
+ case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK:
+ PageAttributes = TT_DESCRIPTOR_PAGE_WRITE_BACK;
+ break;
+ case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH:
+ case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_THROUGH:
+ PageAttributes = TT_DESCRIPTOR_PAGE_WRITE_THROUGH;
+ break;
+ case ARM_MEMORY_REGION_ATTRIBUTE_DEVICE:
+ case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_DEVICE:
+ PageAttributes = TT_DESCRIPTOR_PAGE_DEVICE;
+ break;
+ case ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED:
+ case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_UNCACHED_UNBUFFERED:
+ PageAttributes = TT_DESCRIPTOR_PAGE_UNCACHED;
+ break;
+ default:
+ PageAttributes = TT_DESCRIPTOR_PAGE_UNCACHED;
+ break;
+ }
+
+ if (PreferNonshareableMemory ()) {
+ PageAttributes &= ~TT_DESCRIPTOR_PAGE_S_SHARED;
+ }
+
+ // Check if the Section Entry has already been populated. Otherwise attach a
+ // Level 2 Translation Table to it
+ if (*SectionEntry != 0) {
+ // The entry must be a page table. Otherwise it exists an overlapping in the memory map
+ if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(*SectionEntry)) {
+ TranslationTable = *SectionEntry & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK;
+ } else if ((*SectionEntry & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) {
+ // Case where a virtual memory map descriptor overlapped a section entry
+
+ // Allocate a Level2 Page Table for this Section
+ TranslationTable = (UINTN)AllocatePages(EFI_SIZE_TO_PAGES(TRANSLATION_TABLE_PAGE_SIZE + TRANSLATION_TABLE_PAGE_ALIGNMENT));
+ TranslationTable = ((UINTN)TranslationTable + TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK) & ~TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK;
+
+ // Translate the Section Descriptor into Page Descriptor
+ SectionDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE | ConvertSectionAttributesToPageAttributes (*SectionEntry, FALSE);
+
+ BaseSectionAddress = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(*SectionEntry);
+
+ // Populate the new Level2 Page Table for the section
+ PageEntry = (UINT32*)TranslationTable;
+ for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) {
+ PageEntry[Index] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseSectionAddress + (Index << 12)) | SectionDescriptor;
+ }
+
+ // Overwrite the section entry to point to the new Level2 Translation Table
+ *SectionEntry = (TranslationTable & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) |
+ (IS_ARM_MEMORY_REGION_ATTRIBUTES_SECURE(Attributes) ? (1 << 3) : 0) |
+ TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE;
+ } else {
+ // We do not support the other section type (16MB Section)
+ ASSERT(0);
+ return;
+ }
+ } else {
+ TranslationTable = (UINTN)AllocatePages(EFI_SIZE_TO_PAGES(TRANSLATION_TABLE_PAGE_SIZE + TRANSLATION_TABLE_PAGE_ALIGNMENT));
+ TranslationTable = ((UINTN)TranslationTable + TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK) & ~TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK;
+
+ ZeroMem ((VOID *)TranslationTable, TRANSLATION_TABLE_PAGE_SIZE);
+
+ *SectionEntry = (TranslationTable & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) |
+ (IS_ARM_MEMORY_REGION_ATTRIBUTES_SECURE(Attributes) ? (1 << 3) : 0) |
+ TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE;
+ }
+
+ PageEntry = ((UINT32 *)(TranslationTable) + ((PhysicalBase & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT));
+ Pages = RemainLength / TT_DESCRIPTOR_PAGE_SIZE;
+
+ for (Index = 0; Index < Pages; Index++) {
+ *PageEntry++ = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(PhysicalBase) | PageAttributes;
+ PhysicalBase += TT_DESCRIPTOR_PAGE_SIZE;
+ }
+
+}
+
+STATIC
+VOID
+FillTranslationTable (
+ IN UINT32 *TranslationTable,
+ IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryRegion
+ )
+{
+ UINT32 *SectionEntry;
+ UINT32 Attributes;
+ UINT32 PhysicalBase;
+ UINT64 RemainLength;
+
+ ASSERT(MemoryRegion->Length > 0);
+
+ if (MemoryRegion->PhysicalBase >= SIZE_4GB) {
+ return;
+ }
+
+ PhysicalBase = MemoryRegion->PhysicalBase;
+ RemainLength = MIN(MemoryRegion->Length, SIZE_4GB - PhysicalBase);
+
+ switch (MemoryRegion->Attributes) {
+ case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK:
+ Attributes = TT_DESCRIPTOR_SECTION_WRITE_BACK(0);
+ break;
+ case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH:
+ Attributes = TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0);
+ break;
+ case ARM_MEMORY_REGION_ATTRIBUTE_DEVICE:
+ Attributes = TT_DESCRIPTOR_SECTION_DEVICE(0);
+ break;
+ case ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED:
+ Attributes = TT_DESCRIPTOR_SECTION_UNCACHED(0);
+ break;
+ case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK:
+ Attributes = TT_DESCRIPTOR_SECTION_WRITE_BACK(1);
+ break;
+ case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_THROUGH:
+ Attributes = TT_DESCRIPTOR_SECTION_WRITE_THROUGH(1);
+ break;
+ case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_DEVICE:
+ Attributes = TT_DESCRIPTOR_SECTION_DEVICE(1);
+ break;
+ case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_UNCACHED_UNBUFFERED:
+ Attributes = TT_DESCRIPTOR_SECTION_UNCACHED(1);
+ break;
+ default:
+ Attributes = TT_DESCRIPTOR_SECTION_UNCACHED(0);
+ break;
+ }
+
+ if (PreferNonshareableMemory ()) {
+ Attributes &= ~TT_DESCRIPTOR_SECTION_S_SHARED;
+ }
+
+ // Get the first section entry for this mapping
+ SectionEntry = TRANSLATION_TABLE_ENTRY_FOR_VIRTUAL_ADDRESS(TranslationTable, MemoryRegion->VirtualBase);
+
+ while (RemainLength != 0) {
+ if (PhysicalBase % TT_DESCRIPTOR_SECTION_SIZE == 0) {
+ if (RemainLength >= TT_DESCRIPTOR_SECTION_SIZE) {
+ // Case: Physical address aligned on the Section Size (1MB) && the length is greater than the Section Size
+ *SectionEntry++ = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(PhysicalBase) | Attributes;
+ PhysicalBase += TT_DESCRIPTOR_SECTION_SIZE;
+ } else {
+ // Case: Physical address aligned on the Section Size (1MB) && the length does not fill a section
+ PopulateLevel2PageTable (SectionEntry++, PhysicalBase, RemainLength, MemoryRegion->Attributes);
+
+ // It must be the last entry
+ break;
+ }
+ } else {
+ // Case: Physical address NOT aligned on the Section Size (1MB)
+ PopulateLevel2PageTable (SectionEntry++, PhysicalBase, RemainLength, MemoryRegion->Attributes);
+ // Aligned the address
+ PhysicalBase = (PhysicalBase + TT_DESCRIPTOR_SECTION_SIZE) & ~(TT_DESCRIPTOR_SECTION_SIZE-1);
+
+ // If it is the last entry
+ if (RemainLength < TT_DESCRIPTOR_SECTION_SIZE) {
+ break;
+ }
+ }
+ RemainLength -= TT_DESCRIPTOR_SECTION_SIZE;
+ }
+}
+
+RETURN_STATUS
+EFIAPI
+ArmConfigureMmu (
+ IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryTable,
+ OUT VOID **TranslationTableBase OPTIONAL,
+ OUT UINTN *TranslationTableSize OPTIONAL
+ )
+{
+ VOID* TranslationTable;
+ ARM_MEMORY_REGION_ATTRIBUTES TranslationTableAttribute;
+ UINT32 TTBRAttributes;
+
+ // Allocate pages for translation table.
+ TranslationTable = AllocatePages (EFI_SIZE_TO_PAGES (TRANSLATION_TABLE_SECTION_SIZE + TRANSLATION_TABLE_SECTION_ALIGNMENT));
+ if (TranslationTable == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ TranslationTable = (VOID*)(((UINTN)TranslationTable + TRANSLATION_TABLE_SECTION_ALIGNMENT_MASK) & ~TRANSLATION_TABLE_SECTION_ALIGNMENT_MASK);
+
+ if (TranslationTableBase != NULL) {
+ *TranslationTableBase = TranslationTable;
+ }
+
+ if (TranslationTableSize != NULL) {
+ *TranslationTableSize = TRANSLATION_TABLE_SECTION_SIZE;
+ }
+
+ ZeroMem (TranslationTable, TRANSLATION_TABLE_SECTION_SIZE);
+
+ // By default, mark the translation table as belonging to a uncached region
+ TranslationTableAttribute = ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED;
+ while (MemoryTable->Length != 0) {
+ // Find the memory attribute for the Translation Table
+ if (((UINTN)TranslationTable >= MemoryTable->PhysicalBase) && ((UINTN)TranslationTable <= MemoryTable->PhysicalBase - 1 + MemoryTable->Length)) {
+ TranslationTableAttribute = MemoryTable->Attributes;
+ }
+
+ FillTranslationTable (TranslationTable, MemoryTable);
+ MemoryTable++;
+ }
+
+ // Translate the Memory Attributes into Translation Table Register Attributes
+ if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED) ||
+ (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_UNCACHED_UNBUFFERED)) {
+ TTBRAttributes = ArmHasMpExtensions () ? TTBR_MP_NON_CACHEABLE : TTBR_NON_CACHEABLE;
+ } else if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK) ||
+ (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK)) {
+ TTBRAttributes = ArmHasMpExtensions () ? TTBR_MP_WRITE_BACK_ALLOC : TTBR_WRITE_BACK_ALLOC;
+ } else if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH) ||
+ (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_THROUGH)) {
+ TTBRAttributes = ArmHasMpExtensions () ? TTBR_MP_WRITE_THROUGH : TTBR_WRITE_THROUGH;
+ } else {
+ ASSERT (0); // No support has been found for the attributes of the memory region that the translation table belongs to.
+ return RETURN_UNSUPPORTED;
+ }
+
+ if (TTBRAttributes & TTBR_SHAREABLE) {
+ if (PreferNonshareableMemory ()) {
+ TTBRAttributes ^= TTBR_SHAREABLE;
+ } else {
+ //
+ // Unlike the S bit in the short descriptors, which implies inner shareable
+ // on an implementation that supports two levels, the meaning of the S bit
+ // in the TTBR depends on the NOS bit, which defaults to Outer Shareable.
+ // However, we should only set this bit after we have confirmed that the
+ // implementation supports multiple levels, or else the NOS bit is UNK/SBZP
+ //
+ if (((ArmReadIdMmfr0 () >> 12) & 0xf) != 0) {
+ TTBRAttributes |= TTBR_NOT_OUTER_SHAREABLE;
+ }
+ }
+ }
+
+ ArmCleanInvalidateDataCache ();
+ ArmInvalidateInstructionCache ();
+
+ ArmDisableDataCache ();
+ ArmDisableInstructionCache();
+ // TLBs are also invalidated when calling ArmDisableMmu()
+ ArmDisableMmu ();
+
+ // Make sure nothing sneaked into the cache
+ ArmCleanInvalidateDataCache ();
+ ArmInvalidateInstructionCache ();
+
+ ArmSetTTBR0 ((VOID *)(UINTN)(((UINTN)TranslationTable & ~TRANSLATION_TABLE_SECTION_ALIGNMENT_MASK) | (TTBRAttributes & 0x7F)));
+
+ //
+ // The TTBCR register value is undefined at reset in the Non-Secure world.
+ // Writing 0 has the effect of:
+ // Clearing EAE: Use short descriptors, as mandated by specification.
+ // Clearing PD0 and PD1: Translation Table Walk Disable is off.
+ // Clearing N: Perform all translation table walks through TTBR0.
+ // (0 is the default reset value in systems not implementing
+ // the Security Extensions.)
+ //
+ ArmSetTTBCR (0);
+
+ ArmSetDomainAccessControl (DOMAIN_ACCESS_CONTROL_NONE(15) |
+ DOMAIN_ACCESS_CONTROL_NONE(14) |
+ DOMAIN_ACCESS_CONTROL_NONE(13) |
+ DOMAIN_ACCESS_CONTROL_NONE(12) |
+ DOMAIN_ACCESS_CONTROL_NONE(11) |
+ DOMAIN_ACCESS_CONTROL_NONE(10) |
+ DOMAIN_ACCESS_CONTROL_NONE( 9) |
+ DOMAIN_ACCESS_CONTROL_NONE( 8) |
+ DOMAIN_ACCESS_CONTROL_NONE( 7) |
+ DOMAIN_ACCESS_CONTROL_NONE( 6) |
+ DOMAIN_ACCESS_CONTROL_NONE( 5) |
+ DOMAIN_ACCESS_CONTROL_NONE( 4) |
+ DOMAIN_ACCESS_CONTROL_NONE( 3) |
+ DOMAIN_ACCESS_CONTROL_NONE( 2) |
+ DOMAIN_ACCESS_CONTROL_NONE( 1) |
+ DOMAIN_ACCESS_CONTROL_CLIENT(0));
+
+ ArmEnableInstructionCache();
+ ArmEnableDataCache();
+ ArmEnableMmu();
+ return RETURN_SUCCESS;
+}
+
+RETURN_STATUS
+ArmSetMemoryRegionNoExec (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ return RETURN_UNSUPPORTED;
+}
+
+RETURN_STATUS
+ArmClearMemoryRegionNoExec (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ return RETURN_UNSUPPORTED;
+}
+
+RETURN_STATUS
+ArmSetMemoryRegionReadOnly (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ return RETURN_UNSUPPORTED;
+}
+
+RETURN_STATUS
+ArmClearMemoryRegionReadOnly (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ return RETURN_UNSUPPORTED;
+}
+
+RETURN_STATUS
+EFIAPI
+ArmMmuBaseLibConstructor (
+ VOID
+ )
+{
+ return RETURN_SUCCESS;
+}
diff --git a/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibV7Support.S b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibV7Support.S
new file mode 100644
index 0000000000..c89ee5e40b
--- /dev/null
+++ b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibV7Support.S
@@ -0,0 +1,35 @@
+#------------------------------------------------------------------------------
+#
+# Copyright (c) 2016, Linaro Limited. All rights reserved.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#------------------------------------------------------------------------------
+
+#include <AsmMacroIoLib.h>
+
+.text
+.align 2
+
+GCC_ASM_EXPORT (ArmReadIdMmfr0)
+GCC_ASM_EXPORT (ArmHasMpExtensions)
+
+#------------------------------------------------------------------------------
+
+ASM_PFX (ArmHasMpExtensions):
+ mrc p15,0,R0,c0,c0,5
+ // Get Multiprocessing extension (bit31)
+ lsr R0, R0, #31
+ bx LR
+
+ASM_PFX(ArmReadIdMmfr0):
+ mrc p15, 0, r0, c0, c1, 4 @ Read ID_MMFR0 Register
+ bx lr
+
+ASM_FUNCTION_REMOVE_IF_UNREFERENCED
diff --git a/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibV7Support.asm b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibV7Support.asm
new file mode 100644
index 0000000000..4078394dcd
--- /dev/null
+++ b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibV7Support.asm
@@ -0,0 +1,32 @@
+//------------------------------------------------------------------------------
+//
+// Copyright (c) 2016, Linaro Limited. All rights reserved.
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+//------------------------------------------------------------------------------
+
+
+
+ INCLUDE AsmMacroExport.inc
+
+
+//------------------------------------------------------------------------------
+
+ RVCT_ASM_EXPORT ArmHasMpExtensions
+ mrc p15,0,R0,c0,c0,5
+ // Get Multiprocessing extension (bit31)
+ lsr R0, R0, #31
+ bx LR
+
+ RVCT_ASM_EXPORT ArmReadIdMmfr0
+ mrc p15, 0, r0, c0, c1, 4 ; Read ID_MMFR0 Register
+ bx lr
+
+ END