diff --git a/ArmPkg/Include/Library/ArmLib.h b/ArmPkg/Include/Library/ArmLib.h index 15f610d82e..1689f0072d 100644 --- a/ArmPkg/Include/Library/ArmLib.h +++ b/ArmPkg/Include/Library/ArmLib.h @@ -613,4 +613,10 @@ ArmClearMemoryRegionReadOnly ( IN UINT64 Length ); +VOID +ArmReplaceLiveTranslationEntry ( + IN UINT64 *Entry, + IN UINT64 Value + ); + #endif // __ARM_LIB__ diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf index dd585dea91..58684e8492 100644 --- a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf @@ -17,9 +17,10 @@ INF_VERSION = 0x00010005 BASE_NAME = AArch64Lib FILE_GUID = ef20ddf5-b334-47b3-94cf-52ff44c29138 - MODULE_TYPE = DXE_DRIVER + MODULE_TYPE = BASE VERSION_STRING = 1.0 LIBRARY_CLASS = ArmLib + CONSTRUCTOR = AArch64LibConstructor [Sources.AARCH64] AArch64Lib.c @@ -31,6 +32,7 @@ ../Common/AArch64/ArmLibSupport.S ../Common/ArmLib.c + AArch64LibConstructor.c [Packages] ArmPkg/ArmPkg.dec @@ -38,6 +40,7 @@ [LibraryClasses] MemoryAllocationLib + CacheMaintenanceLib [Protocols] gEfiCpuArchProtocolGuid diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64LibConstructor.c b/ArmPkg/Library/ArmLib/AArch64/AArch64LibConstructor.c new file mode 100644 index 0000000000..d2d0d3c15e --- /dev/null +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64LibConstructor.c @@ -0,0 +1,36 @@ +#/* @file +# +# 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 + +#include +#include + +RETURN_STATUS +EFIAPI +AArch64LibConstructor ( + VOID + ) +{ + extern UINT32 ArmReplaceLiveTranslationEntrySize; + + // + // The ArmReplaceLiveTranslationEntry () helper function may be invoked + // with the MMU off so we have to ensure that it gets cleaned to the PoC + // + WriteBackDataCacheRange (ArmReplaceLiveTranslationEntry, + ArmReplaceLiveTranslationEntrySize); + + return RETURN_SUCCESS; +} diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c b/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c index 918957d4ff..48ca827184 100644 --- a/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c @@ -167,6 +167,20 @@ GetRootTranslationTableInfo ( } } +STATIC +VOID +ReplaceLiveEntry ( + IN UINT64 *Entry, + IN UINT64 Value + ) +{ + if (!ArmMmuEnabled ()) { + *Entry = Value; + } else { + ArmReplaceLiveTranslationEntry (Entry, Value); + } +} + STATIC VOID LookupAddresstoRootTable ( @@ -330,7 +344,8 @@ GetBlockEntryListFromAddress ( } // Fill the BlockEntry with the new TranslationTable - *BlockEntry = ((UINTN)TranslationTable & TT_ADDRESS_MASK_DESCRIPTION_TABLE) | TableAttributes | TT_TYPE_TABLE_ENTRY; + ReplaceLiveEntry (BlockEntry, + ((UINTN)TranslationTable & TT_ADDRESS_MASK_DESCRIPTION_TABLE) | TableAttributes | TT_TYPE_TABLE_ENTRY); } } else { if (IndexLevel != PageLevel) { diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S b/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S index 1a3023b794..43f7a795ac 100644 --- a/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S @@ -56,6 +56,8 @@ GCC_ASM_EXPORT (ArmReadIdPfr1) GCC_ASM_EXPORT (ArmWriteHcr) GCC_ASM_EXPORT (ArmReadHcr) GCC_ASM_EXPORT (ArmReadCurrentEL) +GCC_ASM_EXPORT (ArmReplaceLiveTranslationEntry) +GCC_ASM_EXPORT (ArmReplaceLiveTranslationEntrySize) .set CTRL_M_BIT, (1 << 0) .set CTRL_A_BIT, (1 << 1) @@ -481,4 +483,64 @@ ASM_PFX(ArmReadCurrentEL): mrs x0, CurrentEL ret + + .macro __replace_entry, el + + // disable the MMU + mrs x8, sctlr_el\el + bic x9, x8, #CTRL_M_BIT + msr sctlr_el\el, x9 + isb + + // write updated entry + str x1, [x0] + + // invalidate again to get rid of stale clean cachelines that may + // have been filled speculatively since the last invalidate + dmb sy + dc ivac, x0 + + // flush the TLBs + .if \el == 1 + tlbi vmalle1 + .else + tlbi alle\el + .endif + dsb sy + + // re-enable the MMU + msr sctlr_el\el, x8 + isb + .endm + +//VOID +//ArmReplaceLiveTranslationEntry ( +// IN UINT64 *Entry, +// IN UINT64 Value +// ) +ASM_PFX(ArmReplaceLiveTranslationEntry): + + // disable interrupts + mrs x2, daif + msr daifset, #0xf + isb + + // clean and invalidate first so that we don't clobber + // adjacent entries that are dirty in the caches + dc civac, x0 + dsb ish + + EL1_OR_EL2_OR_EL3(x3) +1:__replace_entry 1 + b 4f +2:__replace_entry 2 + b 4f +3:__replace_entry 3 + +4:msr daif, x2 + ret + +ASM_PFX(ArmReplaceLiveTranslationEntrySize): + .long . - ArmReplaceLiveTranslationEntry + ASM_FUNCTION_REMOVE_IF_UNREFERENCED