]> www.infradead.org Git - users/hch/configfs.git/commitdiff
LoongArch: Make KASAN work with 5-level page-tables
authorHuacai Chen <chenhuacai@loongson.cn>
Tue, 12 Nov 2024 08:35:39 +0000 (16:35 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Tue, 12 Nov 2024 08:35:39 +0000 (16:35 +0800)
Make KASAN work with 5-level page-tables, including:
1. Implement and use __pgd_none() and kasan_p4d_offset().
2. As done in kasan_pmd_populate() and kasan_pte_populate(), restrict
   the loop conditions of kasan_p4d_populate() and kasan_pud_populate()
   to avoid unnecessary population.

Cc: stable@vger.kernel.org
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
arch/loongarch/mm/kasan_init.c

index 427d6b1aec09e707837831888f55275165127c9b..4a0d1880dd7130cae252dedbe5abbe5dd7f1cf8d 100644 (file)
 
 static pgd_t kasan_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
 
+#ifdef __PAGETABLE_P4D_FOLDED
+#define __pgd_none(early, pgd) (0)
+#else
+#define __pgd_none(early, pgd) (early ? (pgd_val(pgd) == 0) : \
+(__pa(pgd_val(pgd)) == (unsigned long)__pa(kasan_early_shadow_p4d)))
+#endif
+
 #ifdef __PAGETABLE_PUD_FOLDED
 #define __p4d_none(early, p4d) (0)
 #else
@@ -142,6 +149,19 @@ static pud_t *__init kasan_pud_offset(p4d_t *p4dp, unsigned long addr, int node,
        return pud_offset(p4dp, addr);
 }
 
+static p4d_t *__init kasan_p4d_offset(pgd_t *pgdp, unsigned long addr, int node, bool early)
+{
+       if (__pgd_none(early, pgdp_get(pgdp))) {
+               phys_addr_t p4d_phys = early ?
+                       __pa_symbol(kasan_early_shadow_p4d) : kasan_alloc_zeroed_page(node);
+               if (!early)
+                       memcpy(__va(p4d_phys), kasan_early_shadow_p4d, sizeof(kasan_early_shadow_p4d));
+               pgd_populate(&init_mm, pgdp, (p4d_t *)__va(p4d_phys));
+       }
+
+       return p4d_offset(pgdp, addr);
+}
+
 static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr,
                                      unsigned long end, int node, bool early)
 {
@@ -178,19 +198,19 @@ static void __init kasan_pud_populate(p4d_t *p4dp, unsigned long addr,
        do {
                next = pud_addr_end(addr, end);
                kasan_pmd_populate(pudp, addr, next, node, early);
-       } while (pudp++, addr = next, addr != end);
+       } while (pudp++, addr = next, addr != end && __pud_none(early, READ_ONCE(*pudp)));
 }
 
 static void __init kasan_p4d_populate(pgd_t *pgdp, unsigned long addr,
                                            unsigned long end, int node, bool early)
 {
        unsigned long next;
-       p4d_t *p4dp = p4d_offset(pgdp, addr);
+       p4d_t *p4dp = kasan_p4d_offset(pgdp, addr, node, early);
 
        do {
                next = p4d_addr_end(addr, end);
                kasan_pud_populate(p4dp, addr, next, node, early);
-       } while (p4dp++, addr = next, addr != end);
+       } while (p4dp++, addr = next, addr != end && __p4d_none(early, READ_ONCE(*p4dp)));
 }
 
 static void __init kasan_pgd_populate(unsigned long addr, unsigned long end,