From patchwork Tue Apr 12 06:57:46 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 65587 Delivered-To: patch@linaro.org Received: by 10.140.93.198 with SMTP id d64csp1756416qge; Mon, 11 Apr 2016 23:57:54 -0700 (PDT) X-Received: by 10.66.194.227 with SMTP id hz3mr2378958pac.85.1460444274759; Mon, 11 Apr 2016 23:57:54 -0700 (PDT) Return-Path: Received: from ml01.01.org (ml01.01.org. [2001:19d0:306:5::1]) by mx.google.com with ESMTPS id pl6si8536244pac.48.2016.04.11.23.57.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 11 Apr 2016 23:57:54 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) client-ip=2001:19d0:306:5::1; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail (p=NONE dis=NONE) header.from=linaro.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id C54841A22F2; Mon, 11 Apr 2016 23:57:53 -0700 (PDT) X-Original-To: edk2-devel@lists.01.org Delivered-To: edk2-devel@lists.01.org Received: from mail-wm0-x229.google.com (mail-wm0-x229.google.com [IPv6:2a00:1450:400c:c09::229]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 9760E1A22F0 for ; Mon, 11 Apr 2016 23:57:52 -0700 (PDT) Received: by mail-wm0-x229.google.com with SMTP id u206so14493546wme.1 for ; Mon, 11 Apr 2016 23:57:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=B4v22AuuqTQmrXOx9NDTq30z0j+6bRxZZACwgPlBaWU=; b=L6PGNAY2vP0lL/NLZJw5h28TogCq6k3SCEq2E5oH4JR2tMZjUzgWP/Jz5SE7X1xewR tlkPRL271a2Go0M9PKwDJtbdPsiXFYuIT4nU394yhRK5s80Bj1rSXq1sbX+Kz6ex6J6f GwviXI35wHdgeo07EeERhpZZ9+ICNrBP+5phU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=B4v22AuuqTQmrXOx9NDTq30z0j+6bRxZZACwgPlBaWU=; b=bC2RJSd9X5NfkEVP06J5eCkLNr4dMyB44dEzz5kiDS4xOgghCSAoUAtE2x1z+PRRal l9+uJwjFVbJfzMJSLF3t3ISHUkZ3qlTtZdA5cGMOIozVvieK1ZclH1JesC2d67CoK6z9 efO9nEb1cbkJaFw5UKhslSwIxYLZMm/TE9djey5ebfcEirm76+aSyq1lRjJUXTPKp8dy ZvZ2l99hZ0q60aIS6s9ycJ1TWsyUQY0RWyWytiYM91M5NU+kdCY9RwpHCm/KiUd7dcrI EICQhgmq9tP62yXFpGOB1RdxDMnTn7zYH1pZ04jRD7KpKxeZh3GdlQXUyF0rUCE8Pm5w xq6w== X-Gm-Message-State: AOPr4FXhC1joTHqRacFP5SYUEs/AE8p9FkM5N7WZgRg2e4EKzOdOf6hx5bKtgLD1mC1JUK8q X-Received: by 10.194.179.227 with SMTP id dj3mr1643111wjc.50.1460444270953; Mon, 11 Apr 2016 23:57:50 -0700 (PDT) Received: from localhost.localdomain ([195.55.142.58]) by smtp.gmail.com with ESMTPSA id q62sm21211042wmg.12.2016.04.11.23.57.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 11 Apr 2016 23:57:49 -0700 (PDT) From: Ard Biesheuvel To: edk2-devel@lists.01.org, mark.rutland@arm.com, leif.lindholm@linaro.org Date: Tue, 12 Apr 2016 08:57:46 +0200 Message-Id: <1460444266-10166-1-git-send-email-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.5.0 Subject: [edk2] [PATCH v3] ArmPkg/AArch64Mmu: disable MMU during page table manipulations X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: heyi.guo@linaro.org, ryan.harkin@linaro.org, Ard Biesheuvel MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" On ARM, manipulating live page tables is cumbersome since the architecture mandates the use of break-before-make, i.e., replacing a block entry with a table entry requires an intermediate step via an invalid entry, or TLB conflicts may occur. Since it is not generally feasible to decide in the page table manipulation routines whether such an invalid entry will result in those routines themselves to become unavailable, use a function that is callable with the MMU off (i.e., a leaf function that does not access the stack) to perform the change of a block entry into a table entry. Note that the opposite should never occur, i.e., table entries are never coalesced into block entries. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel --- ArmPkg/Include/Library/ArmLib.h | 6 +++ ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf | 5 +- ArmPkg/Library/ArmLib/AArch64/AArch64LibConstructor.c | 36 +++++++++++++ ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c | 17 +++++- ArmPkg/Library/ArmLib/AArch64/AArch64Support.S | 57 ++++++++++++++++++++ 5 files changed, 119 insertions(+), 2 deletions(-) -- 2.5.0 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel diff --git a/ArmPkg/Include/Library/ArmLib.h b/ArmPkg/Include/Library/ArmLib.h index 15f610d82e1d..1689f0072db6 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 dd585dea91fb..58684e8492f2 100644 --- a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf @@ -17,9 +17,10 @@ [Defines] 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 @@ [Sources.AARCH64] ../Common/AArch64/ArmLibSupport.S ../Common/ArmLib.c + AArch64LibConstructor.c [Packages] ArmPkg/ArmPkg.dec @@ -38,6 +40,7 @@ [Packages] [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 000000000000..d2d0d3c15ee3 --- /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 b7d23c6f3286..2cc6fc45aecf 100644 --- a/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c @@ -169,6 +169,20 @@ GetRootTranslationTableInfo ( STATIC VOID +ReplaceLiveEntry ( + IN UINT64 *Entry, + IN UINT64 Value + ) +{ + if (!ArmMmuEnabled ()) { + *Entry = Value; + } else { + ArmReplaceLiveTranslationEntry (Entry, Value); + } +} + +STATIC +VOID LookupAddresstoRootTable ( IN UINT64 MaxAddress, OUT UINTN *T0SZ, @@ -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 1a3023b79487..9cb51d4fa283 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,59 @@ ASM_PFX(ArmReadCurrentEL): mrs x0, CurrentEL ret + // write an entry and invalidate it in the caches + .macro __set_entry, reg + str \reg, [x0] + dmb sy + dc ivac, x0 + dsb sy + .endm + + .macro __replace_entry, el + mrs x8, sctlr_el\el + bic x9, x8, #CTRL_M_BIT // Clear MMU enable bit + msr sctlr_el\el, x9 + isb + + __set_entry xzr // write invalid entry + .if \el == 1 + tlbi vmalle1 + .else + tlbi alle\el + .endif + dsb sy + __set_entry x1 // write updated entry + 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