Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d08f50e9 authored by Will Deacon's avatar Will Deacon Committed by Venkata Narendra Kumar Gutta
Browse files

arm64: mm: allow enforcing of strict break-before-make for page tables

The ARM ARM strongly recommends using break-before-make when updating
page table entries in the following circumstances:

  * A change of the memory type.
  * A change of the cacheability attributes.
  * A change of the output address (OA), if the OA of at least one of
    the old translation table entry and the new translation table entry
    is writable.

This patch adds a debug option to the kernel so that we can detect
break-before-make violations in set_pte and print a warning.

Change-Id: I038fd175d880355419b0795bf9967efea767e681
Git-commit: 07eea9d556ab76995119f0d034cf5f8280be278f
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git


Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarVenkata Narendra Kumar Gutta <vnkgutta@codeaurora.org>
parent 96b8cb6b
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -96,6 +96,9 @@ config ARM64_RELOC_TEST
	depends on m
	tristate "Relocation testing module"

config ARM64_STRICT_BREAK_BEFORE_MAKE
	bool "Enforce strict break-before-make on page table updates "

source "drivers/hwtracing/coresight/Kconfig"

endmenu
+29 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <asm/bug.h>
#include <asm/proc-fns.h>

#include <asm/bug.h>
#include <asm/memory.h>
#include <asm/pgtable-hwdef.h>
#include <asm/pgtable-prot.h>
@@ -218,6 +219,34 @@ static inline pmd_t pmd_mkcont(pmd_t pmd)

static inline void set_pte(pte_t *ptep, pte_t pte)
{
#ifdef CONFIG_ARM64_STRICT_BREAK_BEFORE_MAKE
	pteval_t old = pte_val(*ptep);
	pteval_t new = pte_val(pte);

	/* Only problematic if valid -> valid */
	if (!(old & new & PTE_VALID))
		goto pte_ok;

	/* Changing attributes should go via an invalid entry */
	if (WARN_ON((old & PTE_ATTRINDX_MASK) != (new & PTE_ATTRINDX_MASK)))
		goto pte_bad;

	/* Change of OA is only an issue if one mapping is writable */
	if (!(old & new & PTE_RDONLY) &&
	    WARN_ON(pte_pfn(*ptep) != pte_pfn(pte)))
		goto pte_bad;

	goto pte_ok;

pte_bad:
	*ptep = __pte(0);
	dsb(ishst);
	asm("tlbi	vmalle1is");
	dsb(ish);
	isb();
pte_ok:
#endif

	WRITE_ONCE(*ptep, pte);

	/*