Commit e9f63768 authored by Mike Rapoport's avatar Mike Rapoport Committed by Linus Torvalds

arm64: add support for folded p4d page tables

Implement primitives necessary for the 4th level folding, add walks of p4d
level where appropriate, replace 5level-fixup.h with pgtable-nop4d.h and
remove __ARCH_USE_5LEVEL_HACK.

[arnd@arndb.de: fix gcc-10 shift warning]
  Link: http://lkml.kernel.org/r/20200429185657.4085975-1-arnd@arndb.deSigned-off-by: default avatarMike Rapoport <rppt@linux.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Brian Cain <bcain@codeaurora.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Christophe Leroy <christophe.leroy@c-s.fr>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Guan Xuetao <gxt@pku.edu.cn>
Cc: James Morse <james.morse@arm.com>
Cc: Jonas Bonn <jonas@southpole.se>
Cc: Julien Thierry <julien.thierry.kdev@gmail.com>
Cc: Ley Foon Tan <ley.foon.tan@intel.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Rich Felker <dalias@libc.org>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Stafford Horne <shorne@gmail.com>
Cc: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Will Deacon <will@kernel.org>
Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
Link: http://lkml.kernel.org/r/20200414153455.21744-4-rppt@kernel.orgSigned-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 84e6ffb2
...@@ -172,8 +172,8 @@ void kvm_clear_hyp_idmap(void); ...@@ -172,8 +172,8 @@ void kvm_clear_hyp_idmap(void);
__pmd(__phys_to_pmd_val(__pa(ptep)) | PMD_TYPE_TABLE) __pmd(__phys_to_pmd_val(__pa(ptep)) | PMD_TYPE_TABLE)
#define kvm_mk_pud(pmdp) \ #define kvm_mk_pud(pmdp) \
__pud(__phys_to_pud_val(__pa(pmdp)) | PMD_TYPE_TABLE) __pud(__phys_to_pud_val(__pa(pmdp)) | PMD_TYPE_TABLE)
#define kvm_mk_pgd(pudp) \ #define kvm_mk_p4d(pmdp) \
__pgd(__phys_to_pgd_val(__pa(pudp)) | PUD_TYPE_TABLE) __p4d(__phys_to_p4d_val(__pa(pmdp)) | PUD_TYPE_TABLE)
#define kvm_set_pud(pudp, pud) set_pud(pudp, pud) #define kvm_set_pud(pudp, pud) set_pud(pudp, pud)
...@@ -299,6 +299,12 @@ static inline bool kvm_s2pud_young(pud_t pud) ...@@ -299,6 +299,12 @@ static inline bool kvm_s2pud_young(pud_t pud)
#define hyp_pud_table_empty(pudp) kvm_page_empty(pudp) #define hyp_pud_table_empty(pudp) kvm_page_empty(pudp)
#endif #endif
#ifdef __PAGETABLE_P4D_FOLDED
#define hyp_p4d_table_empty(p4dp) (0)
#else
#define hyp_p4d_table_empty(p4dp) kvm_page_empty(p4dp)
#endif
struct kvm; struct kvm;
#define kvm_flush_dcache_to_poc(a,l) __flush_dcache_area((a), (l)) #define kvm_flush_dcache_to_poc(a,l) __flush_dcache_area((a), (l))
......
...@@ -73,17 +73,17 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pudp) ...@@ -73,17 +73,17 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pudp)
free_page((unsigned long)pudp); free_page((unsigned long)pudp);
} }
static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pudp, pgdval_t prot) static inline void __p4d_populate(p4d_t *p4dp, phys_addr_t pudp, p4dval_t prot)
{ {
set_pgd(pgdp, __pgd(__phys_to_pgd_val(pudp) | prot)); set_p4d(p4dp, __p4d(__phys_to_p4d_val(pudp) | prot));
} }
static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgdp, pud_t *pudp) static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4dp, pud_t *pudp)
{ {
__pgd_populate(pgdp, __pa(pudp), PUD_TYPE_TABLE); __p4d_populate(p4dp, __pa(pudp), PUD_TYPE_TABLE);
} }
#else #else
static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pudp, pgdval_t prot) static inline void __p4d_populate(p4d_t *p4dp, phys_addr_t pudp, p4dval_t prot)
{ {
BUILD_BUG(); BUILD_BUG();
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
typedef u64 pteval_t; typedef u64 pteval_t;
typedef u64 pmdval_t; typedef u64 pmdval_t;
typedef u64 pudval_t; typedef u64 pudval_t;
typedef u64 p4dval_t;
typedef u64 pgdval_t; typedef u64 pgdval_t;
/* /*
...@@ -44,13 +45,11 @@ typedef struct { pteval_t pgprot; } pgprot_t; ...@@ -44,13 +45,11 @@ typedef struct { pteval_t pgprot; } pgprot_t;
#define __pgprot(x) ((pgprot_t) { (x) } ) #define __pgprot(x) ((pgprot_t) { (x) } )
#if CONFIG_PGTABLE_LEVELS == 2 #if CONFIG_PGTABLE_LEVELS == 2
#define __ARCH_USE_5LEVEL_HACK
#include <asm-generic/pgtable-nopmd.h> #include <asm-generic/pgtable-nopmd.h>
#elif CONFIG_PGTABLE_LEVELS == 3 #elif CONFIG_PGTABLE_LEVELS == 3
#define __ARCH_USE_5LEVEL_HACK
#include <asm-generic/pgtable-nopud.h> #include <asm-generic/pgtable-nopud.h>
#elif CONFIG_PGTABLE_LEVELS == 4 #elif CONFIG_PGTABLE_LEVELS == 4
#include <asm-generic/5level-fixup.h> #include <asm-generic/pgtable-nop4d.h>
#endif #endif
#endif /* __ASM_PGTABLE_TYPES_H */ #endif /* __ASM_PGTABLE_TYPES_H */
...@@ -298,6 +298,11 @@ static inline pte_t pgd_pte(pgd_t pgd) ...@@ -298,6 +298,11 @@ static inline pte_t pgd_pte(pgd_t pgd)
return __pte(pgd_val(pgd)); return __pte(pgd_val(pgd));
} }
static inline pte_t p4d_pte(p4d_t p4d)
{
return __pte(p4d_val(p4d));
}
static inline pte_t pud_pte(pud_t pud) static inline pte_t pud_pte(pud_t pud)
{ {
return __pte(pud_val(pud)); return __pte(pud_val(pud));
...@@ -401,6 +406,9 @@ static inline pmd_t pmd_mkdevmap(pmd_t pmd) ...@@ -401,6 +406,9 @@ static inline pmd_t pmd_mkdevmap(pmd_t pmd)
#define set_pmd_at(mm, addr, pmdp, pmd) set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd)) #define set_pmd_at(mm, addr, pmdp, pmd) set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd))
#define __p4d_to_phys(p4d) __pte_to_phys(p4d_pte(p4d))
#define __phys_to_p4d_val(phys) __phys_to_pte_val(phys)
#define __pgd_to_phys(pgd) __pte_to_phys(pgd_pte(pgd)) #define __pgd_to_phys(pgd) __pte_to_phys(pgd_pte(pgd))
#define __phys_to_pgd_val(phys) __phys_to_pte_val(phys) #define __phys_to_pgd_val(phys) __phys_to_pte_val(phys)
...@@ -592,49 +600,50 @@ static inline phys_addr_t pud_page_paddr(pud_t pud) ...@@ -592,49 +600,50 @@ static inline phys_addr_t pud_page_paddr(pud_t pud)
#define pud_ERROR(pud) __pud_error(__FILE__, __LINE__, pud_val(pud)) #define pud_ERROR(pud) __pud_error(__FILE__, __LINE__, pud_val(pud))
#define pgd_none(pgd) (!pgd_val(pgd)) #define p4d_none(p4d) (!p4d_val(p4d))
#define pgd_bad(pgd) (!(pgd_val(pgd) & 2)) #define p4d_bad(p4d) (!(p4d_val(p4d) & 2))
#define pgd_present(pgd) (pgd_val(pgd)) #define p4d_present(p4d) (p4d_val(p4d))
static inline void set_pgd(pgd_t *pgdp, pgd_t pgd) static inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
{ {
if (in_swapper_pgdir(pgdp)) { if (in_swapper_pgdir(p4dp)) {
set_swapper_pgd(pgdp, pgd); set_swapper_pgd((pgd_t *)p4dp, __pgd(p4d_val(p4d)));
return; return;
} }
WRITE_ONCE(*pgdp, pgd); WRITE_ONCE(*p4dp, p4d);
dsb(ishst); dsb(ishst);
isb(); isb();
} }
static inline void pgd_clear(pgd_t *pgdp) static inline void p4d_clear(p4d_t *p4dp)
{ {
set_pgd(pgdp, __pgd(0)); set_p4d(p4dp, __p4d(0));
} }
static inline phys_addr_t pgd_page_paddr(pgd_t pgd) static inline phys_addr_t p4d_page_paddr(p4d_t p4d)
{ {
return __pgd_to_phys(pgd); return __p4d_to_phys(p4d);
} }
/* Find an entry in the frst-level page table. */ /* Find an entry in the frst-level page table. */
#define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) #define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
#define pud_offset_phys(dir, addr) (pgd_page_paddr(READ_ONCE(*(dir))) + pud_index(addr) * sizeof(pud_t)) #define pud_offset_phys(dir, addr) (p4d_page_paddr(READ_ONCE(*(dir))) + pud_index(addr) * sizeof(pud_t))
#define pud_offset(dir, addr) ((pud_t *)__va(pud_offset_phys((dir), (addr)))) #define pud_offset(dir, addr) ((pud_t *)__va(pud_offset_phys((dir), (addr))))
#define pud_set_fixmap(addr) ((pud_t *)set_fixmap_offset(FIX_PUD, addr)) #define pud_set_fixmap(addr) ((pud_t *)set_fixmap_offset(FIX_PUD, addr))
#define pud_set_fixmap_offset(pgd, addr) pud_set_fixmap(pud_offset_phys(pgd, addr)) #define pud_set_fixmap_offset(p4d, addr) pud_set_fixmap(pud_offset_phys(p4d, addr))
#define pud_clear_fixmap() clear_fixmap(FIX_PUD) #define pud_clear_fixmap() clear_fixmap(FIX_PUD)
#define pgd_page(pgd) phys_to_page(__pgd_to_phys(pgd)) #define p4d_page(p4d) pfn_to_page(__phys_to_pfn(__p4d_to_phys(p4d)))
/* use ONLY for statically allocated translation tables */ /* use ONLY for statically allocated translation tables */
#define pud_offset_kimg(dir,addr) ((pud_t *)__phys_to_kimg(pud_offset_phys((dir), (addr)))) #define pud_offset_kimg(dir,addr) ((pud_t *)__phys_to_kimg(pud_offset_phys((dir), (addr))))
#else #else
#define p4d_page_paddr(p4d) ({ BUILD_BUG(); 0;})
#define pgd_page_paddr(pgd) ({ BUILD_BUG(); 0;}) #define pgd_page_paddr(pgd) ({ BUILD_BUG(); 0;})
/* Match pud_offset folding in <asm/generic/pgtable-nopud.h> */ /* Match pud_offset folding in <asm/generic/pgtable-nopud.h> */
......
...@@ -68,41 +68,67 @@ static inline bool kvm_stage2_has_pud(struct kvm *kvm) ...@@ -68,41 +68,67 @@ static inline bool kvm_stage2_has_pud(struct kvm *kvm)
#define S2_PUD_SIZE (1UL << S2_PUD_SHIFT) #define S2_PUD_SIZE (1UL << S2_PUD_SHIFT)
#define S2_PUD_MASK (~(S2_PUD_SIZE - 1)) #define S2_PUD_MASK (~(S2_PUD_SIZE - 1))
static inline bool stage2_pgd_none(struct kvm *kvm, pgd_t pgd) #define stage2_pgd_none(kvm, pgd) pgd_none(pgd)
#define stage2_pgd_clear(kvm, pgd) pgd_clear(pgd)
#define stage2_pgd_present(kvm, pgd) pgd_present(pgd)
#define stage2_pgd_populate(kvm, pgd, p4d) pgd_populate(NULL, pgd, p4d)
static inline p4d_t *stage2_p4d_offset(struct kvm *kvm,
pgd_t *pgd, unsigned long address)
{
return p4d_offset(pgd, address);
}
static inline void stage2_p4d_free(struct kvm *kvm, p4d_t *p4d)
{
}
static inline bool stage2_p4d_table_empty(struct kvm *kvm, p4d_t *p4dp)
{
return false;
}
static inline phys_addr_t stage2_p4d_addr_end(struct kvm *kvm,
phys_addr_t addr, phys_addr_t end)
{
return end;
}
static inline bool stage2_p4d_none(struct kvm *kvm, p4d_t p4d)
{ {
if (kvm_stage2_has_pud(kvm)) if (kvm_stage2_has_pud(kvm))
return pgd_none(pgd); return p4d_none(p4d);
else else
return 0; return 0;
} }
static inline void stage2_pgd_clear(struct kvm *kvm, pgd_t *pgdp) static inline void stage2_p4d_clear(struct kvm *kvm, p4d_t *p4dp)
{ {
if (kvm_stage2_has_pud(kvm)) if (kvm_stage2_has_pud(kvm))
pgd_clear(pgdp); p4d_clear(p4dp);
} }
static inline bool stage2_pgd_present(struct kvm *kvm, pgd_t pgd) static inline bool stage2_p4d_present(struct kvm *kvm, p4d_t p4d)
{ {
if (kvm_stage2_has_pud(kvm)) if (kvm_stage2_has_pud(kvm))
return pgd_present(pgd); return p4d_present(p4d);
else else
return 1; return 1;
} }
static inline void stage2_pgd_populate(struct kvm *kvm, pgd_t *pgd, pud_t *pud) static inline void stage2_p4d_populate(struct kvm *kvm, p4d_t *p4d, pud_t *pud)
{ {
if (kvm_stage2_has_pud(kvm)) if (kvm_stage2_has_pud(kvm))
pgd_populate(NULL, pgd, pud); p4d_populate(NULL, p4d, pud);
} }
static inline pud_t *stage2_pud_offset(struct kvm *kvm, static inline pud_t *stage2_pud_offset(struct kvm *kvm,
pgd_t *pgd, unsigned long address) p4d_t *p4d, unsigned long address)
{ {
if (kvm_stage2_has_pud(kvm)) if (kvm_stage2_has_pud(kvm))
return pud_offset(pgd, address); return pud_offset(p4d, address);
else else
return (pud_t *)pgd; return (pud_t *)p4d;
} }
static inline void stage2_pud_free(struct kvm *kvm, pud_t *pud) static inline void stage2_pud_free(struct kvm *kvm, pud_t *pud)
......
...@@ -184,6 +184,7 @@ static int trans_pgd_map_page(pgd_t *trans_pgd, void *page, ...@@ -184,6 +184,7 @@ static int trans_pgd_map_page(pgd_t *trans_pgd, void *page,
pgprot_t pgprot) pgprot_t pgprot)
{ {
pgd_t *pgdp; pgd_t *pgdp;
p4d_t *p4dp;
pud_t *pudp; pud_t *pudp;
pmd_t *pmdp; pmd_t *pmdp;
pte_t *ptep; pte_t *ptep;
...@@ -196,7 +197,15 @@ static int trans_pgd_map_page(pgd_t *trans_pgd, void *page, ...@@ -196,7 +197,15 @@ static int trans_pgd_map_page(pgd_t *trans_pgd, void *page,
pgd_populate(&init_mm, pgdp, pudp); pgd_populate(&init_mm, pgdp, pudp);
} }
pudp = pud_offset(pgdp, dst_addr); p4dp = p4d_offset(pgdp, dst_addr);
if (p4d_none(READ_ONCE(*p4dp))) {
pudp = (void *)get_safe_page(GFP_ATOMIC);
if (!pudp)
return -ENOMEM;
p4d_populate(&init_mm, p4dp, pudp);
}
pudp = pud_offset(p4dp, dst_addr);
if (pud_none(READ_ONCE(*pudp))) { if (pud_none(READ_ONCE(*pudp))) {
pmdp = (void *)get_safe_page(GFP_ATOMIC); pmdp = (void *)get_safe_page(GFP_ATOMIC);
if (!pmdp) if (!pmdp)
...@@ -419,7 +428,7 @@ static int copy_pmd(pud_t *dst_pudp, pud_t *src_pudp, unsigned long start, ...@@ -419,7 +428,7 @@ static int copy_pmd(pud_t *dst_pudp, pud_t *src_pudp, unsigned long start,
return 0; return 0;
} }
static int copy_pud(pgd_t *dst_pgdp, pgd_t *src_pgdp, unsigned long start, static int copy_pud(p4d_t *dst_p4dp, p4d_t *src_p4dp, unsigned long start,
unsigned long end) unsigned long end)
{ {
pud_t *dst_pudp; pud_t *dst_pudp;
...@@ -427,15 +436,15 @@ static int copy_pud(pgd_t *dst_pgdp, pgd_t *src_pgdp, unsigned long start, ...@@ -427,15 +436,15 @@ static int copy_pud(pgd_t *dst_pgdp, pgd_t *src_pgdp, unsigned long start,
unsigned long next; unsigned long next;
unsigned long addr = start; unsigned long addr = start;
if (pgd_none(READ_ONCE(*dst_pgdp))) { if (p4d_none(READ_ONCE(*dst_p4dp))) {
dst_pudp = (pud_t *)get_safe_page(GFP_ATOMIC); dst_pudp = (pud_t *)get_safe_page(GFP_ATOMIC);
if (!dst_pudp) if (!dst_pudp)
return -ENOMEM; return -ENOMEM;
pgd_populate(&init_mm, dst_pgdp, dst_pudp); p4d_populate(&init_mm, dst_p4dp, dst_pudp);
} }
dst_pudp = pud_offset(dst_pgdp, start); dst_pudp = pud_offset(dst_p4dp, start);
src_pudp = pud_offset(src_pgdp, start); src_pudp = pud_offset(src_p4dp, start);
do { do {
pud_t pud = READ_ONCE(*src_pudp); pud_t pud = READ_ONCE(*src_pudp);
...@@ -454,6 +463,27 @@ static int copy_pud(pgd_t *dst_pgdp, pgd_t *src_pgdp, unsigned long start, ...@@ -454,6 +463,27 @@ static int copy_pud(pgd_t *dst_pgdp, pgd_t *src_pgdp, unsigned long start,
return 0; return 0;
} }
static int copy_p4d(pgd_t *dst_pgdp, pgd_t *src_pgdp, unsigned long start,
unsigned long end)
{
p4d_t *dst_p4dp;
p4d_t *src_p4dp;
unsigned long next;
unsigned long addr = start;
dst_p4dp = p4d_offset(dst_pgdp, start);
src_p4dp = p4d_offset(src_pgdp, start);
do {
next = p4d_addr_end(addr, end);
if (p4d_none(READ_ONCE(*src_p4dp)))
continue;
if (copy_pud(dst_p4dp, src_p4dp, addr, next))
return -ENOMEM;
} while (dst_p4dp++, src_p4dp++, addr = next, addr != end);
return 0;
}
static int copy_page_tables(pgd_t *dst_pgdp, unsigned long start, static int copy_page_tables(pgd_t *dst_pgdp, unsigned long start,
unsigned long end) unsigned long end)
{ {
...@@ -466,7 +496,7 @@ static int copy_page_tables(pgd_t *dst_pgdp, unsigned long start, ...@@ -466,7 +496,7 @@ static int copy_page_tables(pgd_t *dst_pgdp, unsigned long start,
next = pgd_addr_end(addr, end); next = pgd_addr_end(addr, end);
if (pgd_none(READ_ONCE(*src_pgdp))) if (pgd_none(READ_ONCE(*src_pgdp)))
continue; continue;
if (copy_pud(dst_pgdp, src_pgdp, addr, next)) if (copy_p4d(dst_pgdp, src_pgdp, addr, next))
return -ENOMEM; return -ENOMEM;
} while (dst_pgdp++, src_pgdp++, addr = next, addr != end); } while (dst_pgdp++, src_pgdp++, addr = next, addr != end);
......
This diff is collapsed.
...@@ -145,6 +145,7 @@ static void show_pte(unsigned long addr) ...@@ -145,6 +145,7 @@ static void show_pte(unsigned long addr)
pr_alert("[%016lx] pgd=%016llx", addr, pgd_val(pgd)); pr_alert("[%016lx] pgd=%016llx", addr, pgd_val(pgd));
do { do {
p4d_t *p4dp, p4d;
pud_t *pudp, pud; pud_t *pudp, pud;
pmd_t *pmdp, pmd; pmd_t *pmdp, pmd;
pte_t *ptep, pte; pte_t *ptep, pte;
...@@ -152,7 +153,13 @@ static void show_pte(unsigned long addr) ...@@ -152,7 +153,13 @@ static void show_pte(unsigned long addr)
if (pgd_none(pgd) || pgd_bad(pgd)) if (pgd_none(pgd) || pgd_bad(pgd))
break; break;
pudp = pud_offset(pgdp, addr); p4dp = p4d_offset(pgdp, addr);
p4d = READ_ONCE(*p4dp);
pr_cont(", p4d=%016llx", p4d_val(p4d));
if (p4d_none(p4d) || p4d_bad(p4d))
break;
pudp = pud_offset(p4dp, addr);
pud = READ_ONCE(*pudp); pud = READ_ONCE(*pudp);
pr_cont(", pud=%016llx", pud_val(pud)); pr_cont(", pud=%016llx", pud_val(pud));
if (pud_none(pud) || pud_bad(pud)) if (pud_none(pud) || pud_bad(pud))
......
...@@ -67,11 +67,13 @@ static int find_num_contig(struct mm_struct *mm, unsigned long addr, ...@@ -67,11 +67,13 @@ static int find_num_contig(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, size_t *pgsize) pte_t *ptep, size_t *pgsize)
{ {
pgd_t *pgdp = pgd_offset(mm, addr); pgd_t *pgdp = pgd_offset(mm, addr);
p4d_t *p4dp;
pud_t *pudp; pud_t *pudp;
pmd_t *pmdp; pmd_t *pmdp;
*pgsize = PAGE_SIZE; *pgsize = PAGE_SIZE;
pudp = pud_offset(pgdp, addr); p4dp = p4d_offset(pgdp, addr);
pudp = pud_offset(p4dp, addr);
pmdp = pmd_offset(pudp, addr); pmdp = pmd_offset(pudp, addr);
if ((pte_t *)pmdp == ptep) { if ((pte_t *)pmdp == ptep) {
*pgsize = PMD_SIZE; *pgsize = PMD_SIZE;
...@@ -217,12 +219,14 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, ...@@ -217,12 +219,14 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,
unsigned long addr, unsigned long sz) unsigned long addr, unsigned long sz)
{ {
pgd_t *pgdp; pgd_t *pgdp;
p4d_t *p4dp;
pud_t *pudp; pud_t *pudp;
pmd_t *pmdp; pmd_t *pmdp;
pte_t *ptep = NULL; pte_t *ptep = NULL;
pgdp = pgd_offset(mm, addr); pgdp = pgd_offset(mm, addr);
pudp = pud_alloc(mm, pgdp, addr); p4dp = p4d_offset(pgdp, addr);
pudp = pud_alloc(mm, p4dp, addr);
if (!pudp) if (!pudp)
return NULL; return NULL;
...@@ -261,6 +265,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm, ...@@ -261,6 +265,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm,
unsigned long addr, unsigned long sz) unsigned long addr, unsigned long sz)
{ {
pgd_t *pgdp; pgd_t *pgdp;
p4d_t *p4dp;
pud_t *pudp, pud; pud_t *pudp, pud;
pmd_t *pmdp, pmd; pmd_t *pmdp, pmd;
...@@ -268,7 +273,11 @@ pte_t *huge_pte_offset(struct mm_struct *mm, ...@@ -268,7 +273,11 @@ pte_t *huge_pte_offset(struct mm_struct *mm,
if (!pgd_present(READ_ONCE(*pgdp))) if (!pgd_present(READ_ONCE(*pgdp)))
return NULL; return NULL;
pudp = pud_offset(pgdp, addr); p4dp = p4d_offset(pgdp, addr);
if (!p4d_present(READ_ONCE(*p4dp)))
return NULL;
pudp = pud_offset(p4dp, addr);
pud = READ_ONCE(*pudp); pud = READ_ONCE(*pudp);
if (sz != PUD_SIZE && pud_none(pud)) if (sz != PUD_SIZE && pud_none(pud))
return NULL; return NULL;
......
...@@ -84,17 +84,17 @@ static pmd_t *__init kasan_pmd_offset(pud_t *pudp, unsigned long addr, int node, ...@@ -84,17 +84,17 @@ static pmd_t *__init kasan_pmd_offset(pud_t *pudp, unsigned long addr, int node,
return early ? pmd_offset_kimg(pudp, addr) : pmd_offset(pudp, addr); return early ? pmd_offset_kimg(pudp, addr) : pmd_offset(pudp, addr);
} }
static pud_t *__init kasan_pud_offset(pgd_t *pgdp, unsigned long addr, int node, static pud_t *__init kasan_pud_offset(p4d_t *p4dp, unsigned long addr, int node,
bool early) bool early)
{ {
if (pgd_none(READ_ONCE(*pgdp))) { if (p4d_none(READ_ONCE(*p4dp))) {
phys_addr_t pud_phys = early ? phys_addr_t pud_phys = early ?
__pa_symbol(kasan_early_shadow_pud) __pa_symbol(kasan_early_shadow_pud)
: kasan_alloc_zeroed_page(node); : kasan_alloc_zeroed_page(node);
__pgd_populate(pgdp, pud_phys, PMD_TYPE_TABLE); __p4d_populate(p4dp, pud_phys, PMD_TYPE_TABLE);
} }
return early ? pud_offset_kimg(pgdp, addr) : pud_offset(pgdp, addr); return early ? pud_offset_kimg(p4dp, addr) : pud_offset(p4dp, addr);
} }
static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr, static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr,
...@@ -126,11 +126,11 @@ static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr, ...@@ -126,11 +126,11 @@ static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr,
} while (pmdp++, addr = next, addr != end && pmd_none(READ_ONCE(*pmdp))); } while (pmdp++, addr = next, addr != end && pmd_none(READ_ONCE(*pmdp)));
} }
static void __init kasan_pud_populate(pgd_t *pgdp, unsigned long addr, static void __init kasan_pud_populate(p4d_t *p4dp, unsigned long addr,
unsigned long end, int node, bool early) unsigned long end, int node, bool early)
{ {
unsigned long next; unsigned long next;
pud_t *pudp = kasan_pud_offset(pgdp, addr, node, early); pud_t *pudp = kasan_pud_offset(p4dp, addr, node, early);
do { do {
next = pud_addr_end(addr, end); next = pud_addr_end(addr, end);
...@@ -138,6 +138,18 @@ static void __init kasan_pud_populate(pgd_t *pgdp, unsigned long addr, ...@@ -138,6 +138,18 @@ static void __init kasan_pud_populate(pgd_t *pgdp, unsigned long addr,
} while (pudp++, addr = next, addr != end && pud_none(READ_ONCE(*pudp))); } while (pudp++, addr = next, addr != end && pud_none(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);
do {
next = p4d_addr_end(addr, end);
kasan_pud_populate(p4dp, addr, next, node, early);
} while (p4dp++, addr = next, addr != end);
}
static void __init kasan_pgd_populate(unsigned long addr, unsigned long end, static void __init kasan_pgd_populate(unsigned long addr, unsigned long end,
int node, bool early) int node, bool early)
{ {
...@@ -147,7 +159,7 @@ static void __init kasan_pgd_populate(unsigned long addr, unsigned long end, ...@@ -147,7 +159,7 @@ static void __init kasan_pgd_populate(unsigned long addr, unsigned long end,
pgdp = pgd_offset_k(addr); pgdp = pgd_offset_k(addr);
do { do {
next = pgd_addr_end(addr, end); next = pgd_addr_end(addr, end);
kasan_pud_populate(pgdp, addr, next, node, early); kasan_p4d_populate(pgdp, addr, next, node, early);
} while (pgdp++, addr = next, addr != end); } while (pgdp++, addr = next, addr != end);
} }
......
...@@ -290,18 +290,19 @@ static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end, ...@@ -290,18 +290,19 @@ static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end,
{ {
unsigned long next; unsigned long next;
pud_t *pudp; pud_t *pudp;
pgd_t pgd = READ_ONCE(*pgdp); p4d_t *p4dp = p4d_offset(pgdp, addr);
p4d_t p4d = READ_ONCE(*p4dp);
if (pgd_none(pgd)) { if (p4d_none(p4d)) {
phys_addr_t pud_phys; phys_addr_t pud_phys;
BUG_ON(!pgtable_alloc); BUG_ON(!pgtable_alloc);
pud_phys = pgtable_alloc(PUD_SHIFT); pud_phys = pgtable_alloc(PUD_SHIFT);
__pgd_populate(pgdp, pud_phys, PUD_TYPE_TABLE); __p4d_populate(p4dp, pud_phys, PUD_TYPE_TABLE);
pgd = READ_ONCE(*pgdp); p4d = READ_ONCE(*p4dp);
} }
BUG_ON(pgd_bad(pgd)); BUG_ON(p4d_bad(p4d));
pudp = pud_set_fixmap_offset(pgdp, addr); pudp = pud_set_fixmap_offset(p4dp, addr);
do { do {
pud_t old_pud = READ_ONCE(*pudp); pud_t old_pud = READ_ONCE(*pudp);
...@@ -672,6 +673,7 @@ static void __init map_kernel(pgd_t *pgdp) ...@@ -672,6 +673,7 @@ static void __init map_kernel(pgd_t *pgdp)
READ_ONCE(*pgd_offset_k(FIXADDR_START))); READ_ONCE(*pgd_offset_k(FIXADDR_START)));
} else if (CONFIG_PGTABLE_LEVELS > 3) { } else if (CONFIG_PGTABLE_LEVELS > 3) {
pgd_t *bm_pgdp; pgd_t *bm_pgdp;
p4d_t *bm_p4dp;
pud_t *bm_pudp; pud_t *bm_pudp;
/* /*
* The fixmap shares its top level pgd entry with the kernel * The fixmap shares its top level pgd entry with the kernel
...@@ -681,7 +683,8 @@ static void __init map_kernel(pgd_t *pgdp) ...@@ -681,7 +683,8 @@ static void __init map_kernel(pgd_t *pgdp)
*/ */
BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES)); BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
bm_pgdp = pgd_offset_raw(pgdp, FIXADDR_START); bm_pgdp = pgd_offset_raw(pgdp, FIXADDR_START);
bm_pudp = pud_set_fixmap_offset(bm_pgdp, FIXADDR_START); bm_p4dp = p4d_offset(bm_pgdp, FIXADDR_START);
bm_pudp = pud_set_fixmap_offset(bm_p4dp, FIXADDR_START);
pud_populate(&init_mm, bm_pudp, lm_alias(bm_pmd)); pud_populate(&init_mm, bm_pudp, lm_alias(bm_pmd));
pud_clear_fixmap(); pud_clear_fixmap();
} else { } else {
...@@ -715,6 +718,7 @@ void __init paging_init(void) ...@@ -715,6 +718,7 @@ void __init paging_init(void)
int kern_addr_valid(unsigned long addr) int kern_addr_valid(unsigned long addr)
{ {
pgd_t *pgdp; pgd_t *pgdp;
p4d_t *p4dp;
pud_t *pudp, pud; pud_t *pudp, pud;
pmd_t *pmdp, pmd; pmd_t *pmdp, pmd;
pte_t *ptep, pte; pte_t *ptep, pte;
...@@ -726,7 +730,11 @@ int kern_addr_valid(unsigned long addr) ...@@ -726,7 +730,11 @@ int kern_addr_valid(unsigned long addr)
if (pgd_none(READ_ONCE(*pgdp))) if (pgd_none(READ_ONCE(*pgdp)))
return 0; return 0;
pudp = pud_offset(pgdp, addr); p4dp = p4d_offset(pgdp, addr);
if (p4d_none(READ_ONCE(*p4dp)))
return 0;
pudp = pud_offset(p4dp, addr);
pud = READ_ONCE(*pudp); pud = READ_ONCE(*pudp);
if (pud_none(pud)) if (pud_none(pud))
return 0; return 0;
...@@ -1069,6 +1077,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node, ...@@ -1069,6 +1077,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
unsigned long addr = start; unsigned long addr = start;
unsigned long next; unsigned long next;
pgd_t *pgdp; pgd_t *pgdp;
p4d_t *p4dp;
pud_t *pudp; pud_t *pudp;
pmd_t *pmdp; pmd_t *pmdp;
...@@ -1079,7 +1088,11 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node, ...@@ -1079,7 +1088,11 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
if (!pgdp) if (!pgdp)
return -ENOMEM; return -ENOMEM;
pudp = vmemmap_pud_populate(pgdp, addr, node); p4dp = vmemmap_p4d_populate(pgdp, addr, node);
if (!p4dp)
return -ENOMEM;
pudp = vmemmap_pud_populate(p4dp, addr, node);
if (!pudp) if (!pudp)
return -ENOMEM; return -ENOMEM;
...@@ -1114,11 +1127,12 @@ void vmemmap_free(unsigned long start, unsigned long end, ...@@ -1114,11 +1127,12 @@ void vmemmap_free(unsigned long start, unsigned long end,
static inline pud_t * fixmap_pud(unsigned long addr) static inline pud_t * fixmap_pud(unsigned long addr)
{ {
pgd_t *pgdp = pgd_offset_k(addr); pgd_t *pgdp = pgd_offset_k(addr);
pgd_t pgd = READ_ONCE(*pgdp); p4d_t *p4dp = p4d_offset(pgdp, addr);
p4d_t p4d = READ_ONCE(*p4dp);
BUG_ON(pgd_none(pgd) || pgd_bad(pgd)); BUG_ON(p4d_none(p4d) || p4d_bad(p4d));
return pud_offset_kimg(pgdp, addr); return pud_offset_kimg(p4dp, addr);
} }
static inline pmd_t * fixmap_pmd(unsigned long addr) static inline pmd_t * fixmap_pmd(unsigned long addr)
...@@ -1144,25 +1158,27 @@ static inline pte_t * fixmap_pte(unsigned long addr) ...@@ -1144,25 +1158,27 @@ static inline pte_t * fixmap_pte(unsigned long addr)
*/ */
void __init early_fixmap_init(void) void __init early_fixmap_init(void)
{ {
pgd_t *pgdp, pgd; pgd_t *pgdp;
p4d_t *p4dp, p4d;
pud_t *pudp; pud_t *pudp;
pmd_t *pmdp; pmd_t *pmdp;
unsigned long addr = FIXADDR_START; unsigned long addr = FIXADDR_START;
pgdp = pgd_offset_k(addr); pgdp = pgd_offset_k(addr);
pgd = READ_ONCE(*pgdp); p4dp = p4d_offset(pgdp, addr);
p4d = READ_ONCE(*p4dp);
if (CONFIG_PGTABLE_LEVELS > 3 && if (CONFIG_PGTABLE_LEVELS > 3 &&
!(pgd_none(pgd) || pgd_page_paddr(pgd) == __pa_symbol(bm_pud))) { !(p4d_none(p4d) || p4d_page_paddr(p4d) == __pa_symbol(bm_pud))) {
/* /*
* We only end up here if the kernel mapping and the fixmap * We only end up here if the kernel mapping and the fixmap
* share the top level pgd entry, which should only happen on * share the top level pgd entry, which should only happen on
* 16k/4 levels configurations. * 16k/4 levels configurations.
*/ */
BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES)); BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
pudp = pud_offset_kimg(pgdp, addr); pudp = pud_offset_kimg(p4dp, addr);
} else { } else {
if (pgd_none(pgd)) if (p4d_none(p4d))
__pgd_populate(pgdp, __pa_symbol(bm_pud), PUD_TYPE_TABLE); __p4d_populate(p4dp, __pa_symbol(bm_pud), PUD_TYPE_TABLE);
pudp = fixmap_pud(addr); pudp = fixmap_pud(addr);
} }
if (pud_none(READ_ONCE(*pudp))) if (pud_none(READ_ONCE(*pudp)))
......
...@@ -198,6 +198,7 @@ void __kernel_map_pages(struct page *page, int numpages, int enable) ...@@ -198,6 +198,7 @@ void __kernel_map_pages(struct page *page, int numpages, int enable)
bool kernel_page_present(struct page *page) bool kernel_page_present(struct page *page)
{ {
pgd_t *pgdp; pgd_t *pgdp;
p4d_t *p4dp;
pud_t *pudp, pud; pud_t *pudp, pud;
pmd_t *pmdp, pmd; pmd_t *pmdp, pmd;
pte_t *ptep; pte_t *ptep;
...@@ -210,7 +211,11 @@ bool kernel_page_present(struct page *page) ...@@ -210,7 +211,11 @@ bool kernel_page_present(struct page *page)
if (pgd_none(READ_ONCE(*pgdp))) if (pgd_none(READ_ONCE(*pgdp)))
return false; return false;
pudp = pud_offset(pgdp, addr); p4dp = p4d_offset(pgdp, addr);
if (p4d_none(READ_ONCE(*p4dp)))
return false;
pudp = pud_offset(p4dp, addr);
pud = READ_ONCE(*pudp); pud = READ_ONCE(*pudp);
if (pud_none(pud)) if (pud_none(pud))
return false; return false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment