From: Ard Biesheuvel <[email protected]>

Instead of blindly overwriting existing live entries with the contiguous
bit cleared when mapping DRAM regions, check whether the contiguous
region in question starts with a descriptor that has the valid bit set
and the contiguous bit cleared, and in that case, leave the contiguous
bit unset on the entire region. This permits the logic of mapping the
kernel's linear alias to be simplified in a subsequent patch.

Note that not setting the contiguous bit on any of the descriptors in
the contiguous region can only result in an invalid configuration if it
was already invalid to begin with.

Reviewed-by: Ryan Roberts <[email protected]>
Signed-off-by: Ard Biesheuvel <[email protected]>
---
 arch/arm64/include/asm/pgtable.h | 4 ++++
 arch/arm64/mm/mmu.c              | 6 ++++--
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index b3e58735c49b..dc007043d86b 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -187,6 +187,10 @@ static inline pteval_t __phys_to_pte_val(phys_addr_t phys)
  * Returns true if the pte is valid and has the contiguous bit set.
  */
 #define pte_valid_cont(pte)    (pte_valid(pte) && pte_cont(pte))
+/*
+ * Returns true if the pte is valid and has the contiguous bit cleared.
+ */
+#define pte_valid_noncont(pte) (pte_valid(pte) && !pte_cont(pte))
 /*
  * Could the pte be present in the TLB? We must check mm_tlb_flush_pending
  * so that we don't erroneously return false for pages that have been
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 9927b55022d8..7f7d63009440 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -230,7 +230,8 @@ static int alloc_init_cont_pte(pmd_t *pmdp, unsigned long 
addr,
 
                /* use a contiguous mapping if the range is suitably aligned */
                if ((((addr | next | phys) & ~CONT_PTE_MASK) == 0) &&
-                   (flags & NO_CONT_MAPPINGS) == 0)
+                   (flags & NO_CONT_MAPPINGS) == 0 &&
+                   !pte_valid_noncont(__ptep_get(ptep)))
                        __prot = __pgprot(pgprot_val(prot) | PTE_CONT);
 
                init_pte(ptep, addr, next, phys, __prot);
@@ -330,7 +331,8 @@ static int alloc_init_cont_pmd(pud_t *pudp, unsigned long 
addr,
 
                /* use a contiguous mapping if the range is suitably aligned */
                if ((((addr | next | phys) & ~CONT_PMD_MASK) == 0) &&
-                   (flags & NO_CONT_MAPPINGS) == 0)
+                   (flags & NO_CONT_MAPPINGS) == 0 &&
+                   !pte_valid_noncont(pmd_pte(READ_ONCE(*pmdp))))
                        __prot = __pgprot(pgprot_val(prot) | PTE_CONT);
 
                ret = init_pmd(pmdp, addr, next, phys, __prot, pgtable_alloc, 
flags);
-- 
2.53.0.959.g497ff81fa9-goog


Reply via email to