OSDN Git Service

arm64: mm: allow enforcing of strict break-before-make for page tables
authorWill Deacon <will.deacon@arm.com>
Fri, 29 Aug 2014 17:28:54 +0000 (18:28 +0100)
committerPrasad Sodagudi <psodagud@codeaurora.org>
Fri, 24 Feb 2017 17:42:33 +0000 (09:42 -0800)
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: Will Deacon <will.deacon@arm.com>
Signed-off-by: Prasad Sodagudi <psodagud@codeaurora.org>
arch/arm64/Kconfig.debug
arch/arm64/include/asm/pgtable.h

index 6236b3e..a96db6b 100644 (file)
@@ -122,6 +122,9 @@ config KERNEL_TEXT_RDONLY
 
           If unsure, say N.
 
+config ARM64_STRICT_BREAK_BEFORE_MAKE
+       bool "Enforce strict break-before-make on page table updates "
+
 source "drivers/hwtracing/coresight/Kconfig"
 
 endmenu
index 9a09ccf..72b1c3f 100644 (file)
@@ -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>
 
@@ -229,6 +230,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
+
        *ptep = pte;
 
        /*