From d5788777bcc75936cc0e6acb540a5ee6ac77866b Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 7 Jan 2019 08:15:01 +0100 Subject: [PATCH] ArmPkg/ArmMmuLib AARCH64: get rid of needless TLB invalidation Currently, we always invalidate the TLBs entirely after making any modification to the page tables. Now that we have introduced strict memory permissions in quite a number of places, such modifications occur much more often, and it is better for performance to flush only those TLB entries that are actually affected by the changes. At the same time, relax some system wide data synchronization barriers to non-shared. When running in UEFI, we don't share virtual address translations with other masters, unless we are running under virt, but in that case, the host will upgrade them as appropriate (by setting an override at EL2) Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Ard Biesheuvel Reviewed-by: Leif Lindholm --- ArmPkg/Include/Library/ArmMmuLib.h | 3 ++- ArmPkg/Library/ArmLib/AArch64/ArmLibSupport.S | 6 +++--- .../Library/ArmMmuLib/AArch64/ArmMmuLibCore.c | 16 +++++++--------- .../ArmMmuLib/AArch64/ArmMmuLibReplaceEntry.S | 18 ++++++++++-------- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/ArmPkg/Include/Library/ArmMmuLib.h b/ArmPkg/Include/Library/ArmMmuLib.h index fb7fd00641..220039a779 100644 --- a/ArmPkg/Include/Library/ArmMmuLib.h +++ b/ArmPkg/Include/Library/ArmMmuLib.h @@ -59,7 +59,8 @@ VOID EFIAPI ArmReplaceLiveTranslationEntry ( IN UINT64 *Entry, - IN UINT64 Value + IN UINT64 Value, + IN UINT64 RegionStart ); EFI_STATUS diff --git a/ArmPkg/Library/ArmLib/AArch64/ArmLibSupport.S b/ArmPkg/Library/ArmLib/AArch64/ArmLibSupport.S index b7173e00b0..175fb58206 100644 --- a/ArmPkg/Library/ArmLib/AArch64/ArmLibSupport.S +++ b/ArmPkg/Library/ArmLib/AArch64/ArmLibSupport.S @@ -124,15 +124,15 @@ ASM_FUNC(ArmSetMAIR) // IN VOID *MVA // X1 // ); ASM_FUNC(ArmUpdateTranslationTableEntry) - dc civac, x0 // Clean and invalidate data line - dsb sy + dsb nshst + lsr x1, x1, #12 EL1_OR_EL2_OR_EL3(x0) 1: tlbi vaae1, x1 // TLB Invalidate VA , EL1 b 4f 2: tlbi vae2, x1 // TLB Invalidate VA , EL2 b 4f 3: tlbi vae3, x1 // TLB Invalidate VA , EL3 -4: dsb sy +4: dsb nsh isb ret diff --git a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c index d66df3e17a..3498f520e3 100644 --- a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c +++ b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c @@ -129,13 +129,14 @@ STATIC VOID ReplaceLiveEntry ( IN UINT64 *Entry, - IN UINT64 Value + IN UINT64 Value, + IN UINT64 RegionStart ) { if (!ArmMmuEnabled ()) { *Entry = Value; } else { - ArmReplaceLiveTranslationEntry (Entry, Value); + ArmReplaceLiveTranslationEntry (Entry, Value, RegionStart); } } @@ -296,7 +297,8 @@ GetBlockEntryListFromAddress ( // Fill the BlockEntry with the new TranslationTable ReplaceLiveEntry (BlockEntry, - ((UINTN)TranslationTable & TT_ADDRESS_MASK_DESCRIPTION_TABLE) | TableAttributes | TT_TYPE_TABLE_ENTRY); + (UINTN)TranslationTable | TableAttributes | TT_TYPE_TABLE_ENTRY, + RegionStart); } } else { if (IndexLevel != PageLevel) { @@ -375,6 +377,8 @@ UpdateRegionMapping ( *BlockEntry &= BlockEntryMask; *BlockEntry |= (RegionStart & TT_ADDRESS_MASK_BLOCK_ENTRY) | Attributes | Type; + ArmUpdateTranslationTableEntry (BlockEntry, (VOID *)RegionStart); + // Go to the next BlockEntry RegionStart += BlockEntrySize; RegionLength -= BlockEntrySize; @@ -487,9 +491,6 @@ ArmSetMemoryAttributes ( return Status; } - // Invalidate all TLB entries so changes are synced - ArmInvalidateTlb (); - return EFI_SUCCESS; } @@ -512,9 +513,6 @@ SetMemoryRegionAttribute ( return Status; } - // Invalidate all TLB entries so changes are synced - ArmInvalidateTlb (); - return EFI_SUCCESS; } diff --git a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibReplaceEntry.S b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibReplaceEntry.S index 90192df24f..8b447e3d66 100644 --- a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibReplaceEntry.S +++ b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibReplaceEntry.S @@ -32,13 +32,14 @@ dmb sy dc ivac, x0 - // flush the TLBs + // flush translations for the target address from the TLBs + lsr x2, x2, #12 .if \el == 1 - tlbi vmalle1 + tlbi vaae1, x2 .else - tlbi alle\el + tlbi vae\el, x2 .endif - dsb sy + dsb nsh // re-enable the MMU msr sctlr_el\el, x8 @@ -48,19 +49,20 @@ //VOID //ArmReplaceLiveTranslationEntry ( // IN UINT64 *Entry, -// IN UINT64 Value +// IN UINT64 Value, +// IN UINT64 Address // ) ASM_FUNC(ArmReplaceLiveTranslationEntry) // disable interrupts - mrs x2, daif + mrs x4, 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 + dsb nsh EL1_OR_EL2_OR_EL3(x3) 1:__replace_entry 1 @@ -69,7 +71,7 @@ ASM_FUNC(ArmReplaceLiveTranslationEntry) b 4f 3:__replace_entry 3 -4:msr daif, x2 +4:msr daif, x4 ret ASM_GLOBAL ASM_PFX(ArmReplaceLiveTranslationEntrySize) -- 2.39.2