Skip to content

Commit

Permalink
powerpc: add support for folded p4d page tables
Browse files Browse the repository at this point in the history
Implement primitives necessary for the 4th level folding, add walks of p4d
level where appropriate and replace 5level-fixup.h with pgtable-nop4d.h.

[rppt@linux.ibm.com: powerpc/xmon: drop unused pgdir varialble in show_pte() function]
  Link: http://lkml.kernel.org/r/20200519181454.GI1059226@linux.ibm.com
[rppt@linux.ibm.com; build fix]
  Link: http://lkml.kernel.org/r/20200423141845.GI13521@linux.ibm.com
Signed-off-by: Mike Rapoport <rppt@linux.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Tested-by: Christophe Leroy <christophe.leroy@c-s.fr> # 8xx and 83xx
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: 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-9-rppt@kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Mike Rapoport authored and Linus Torvalds committed Jun 5, 2020
1 parent b187fb7 commit 2fb4706
Show file tree
Hide file tree
Showing 23 changed files with 200 additions and 145 deletions.
1 change: 0 additions & 1 deletion arch/powerpc/include/asm/book3s/32/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#ifndef _ASM_POWERPC_BOOK3S_32_PGTABLE_H
#define _ASM_POWERPC_BOOK3S_32_PGTABLE_H

#define __ARCH_USE_5LEVEL_HACK
#include <asm-generic/pgtable-nopmd.h>

#include <asm/book3s/32/hash.h>
Expand Down
4 changes: 2 additions & 2 deletions arch/powerpc/include/asm/book3s/64/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ static inline int get_region_id(unsigned long ea)

#define hash__pmd_bad(pmd) (pmd_val(pmd) & H_PMD_BAD_BITS)
#define hash__pud_bad(pud) (pud_val(pud) & H_PUD_BAD_BITS)
static inline int hash__pgd_bad(pgd_t pgd)
static inline int hash__p4d_bad(p4d_t p4d)
{
return (pgd_val(pgd) == 0);
return (p4d_val(p4d) == 0);
}
#ifdef CONFIG_STRICT_KERNEL_RWX
extern void hash__mark_rodata_ro(void);
Expand Down
4 changes: 2 additions & 2 deletions arch/powerpc/include/asm/book3s/64/pgalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
kmem_cache_free(PGT_CACHE(PGD_INDEX_SIZE), pgd);
}

static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
static inline void p4d_populate(struct mm_struct *mm, p4d_t *pgd, pud_t *pud)
{
*pgd = __pgd(__pgtable_ptr_val(pud) | PGD_VAL_BITS);
*pgd = __p4d(__pgtable_ptr_val(pud) | PGD_VAL_BITS);
}

static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
Expand Down
60 changes: 33 additions & 27 deletions arch/powerpc/include/asm/book3s/64/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#ifndef _ASM_POWERPC_BOOK3S_64_PGTABLE_H_
#define _ASM_POWERPC_BOOK3S_64_PGTABLE_H_

#include <asm-generic/5level-fixup.h>
#include <asm-generic/pgtable-nop4d.h>

#ifndef __ASSEMBLY__
#include <linux/mmdebug.h>
Expand Down Expand Up @@ -251,7 +251,7 @@ extern unsigned long __pmd_frag_size_shift;
/* Bits to mask out from a PUD to get to the PMD page */
#define PUD_MASKED_BITS 0xc0000000000000ffUL
/* Bits to mask out from a PGD to get to the PUD page */
#define PGD_MASKED_BITS 0xc0000000000000ffUL
#define P4D_MASKED_BITS 0xc0000000000000ffUL

/*
* Used as an indicator for rcu callback functions
Expand Down Expand Up @@ -949,54 +949,60 @@ static inline bool pud_access_permitted(pud_t pud, bool write)
return pte_access_permitted(pud_pte(pud), write);
}

#define pgd_write(pgd) pte_write(pgd_pte(pgd))
#define __p4d_raw(x) ((p4d_t) { __pgd_raw(x) })
static inline __be64 p4d_raw(p4d_t x)
{
return pgd_raw(x.pgd);
}

#define p4d_write(p4d) pte_write(p4d_pte(p4d))

static inline void pgd_clear(pgd_t *pgdp)
static inline void p4d_clear(p4d_t *p4dp)
{
*pgdp = __pgd(0);
*p4dp = __p4d(0);
}

static inline int pgd_none(pgd_t pgd)
static inline int p4d_none(p4d_t p4d)
{
return !pgd_raw(pgd);
return !p4d_raw(p4d);
}

static inline int pgd_present(pgd_t pgd)
static inline int p4d_present(p4d_t p4d)
{
return !!(pgd_raw(pgd) & cpu_to_be64(_PAGE_PRESENT));
return !!(p4d_raw(p4d) & cpu_to_be64(_PAGE_PRESENT));
}

static inline pte_t pgd_pte(pgd_t pgd)
static inline pte_t p4d_pte(p4d_t p4d)
{
return __pte_raw(pgd_raw(pgd));
return __pte_raw(p4d_raw(p4d));
}

static inline pgd_t pte_pgd(pte_t pte)
static inline p4d_t pte_p4d(pte_t pte)
{
return __pgd_raw(pte_raw(pte));
return __p4d_raw(pte_raw(pte));
}

static inline int pgd_bad(pgd_t pgd)
static inline int p4d_bad(p4d_t p4d)
{
if (radix_enabled())
return radix__pgd_bad(pgd);
return hash__pgd_bad(pgd);
return radix__p4d_bad(p4d);
return hash__p4d_bad(p4d);
}

#define pgd_access_permitted pgd_access_permitted
static inline bool pgd_access_permitted(pgd_t pgd, bool write)
#define p4d_access_permitted p4d_access_permitted
static inline bool p4d_access_permitted(p4d_t p4d, bool write)
{
return pte_access_permitted(pgd_pte(pgd), write);
return pte_access_permitted(p4d_pte(p4d), write);
}

extern struct page *pgd_page(pgd_t pgd);
extern struct page *p4d_page(p4d_t p4d);

/* Pointers in the page table tree are physical addresses */
#define __pgtable_ptr_val(ptr) __pa(ptr)

#define pmd_page_vaddr(pmd) __va(pmd_val(pmd) & ~PMD_MASKED_BITS)
#define pud_page_vaddr(pud) __va(pud_val(pud) & ~PUD_MASKED_BITS)
#define pgd_page_vaddr(pgd) __va(pgd_val(pgd) & ~PGD_MASKED_BITS)
#define p4d_page_vaddr(p4d) __va(p4d_val(p4d) & ~P4D_MASKED_BITS)

#define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & (PTRS_PER_PGD - 1))
#define pud_index(address) (((address) >> (PUD_SHIFT)) & (PTRS_PER_PUD - 1))
Expand All @@ -1010,8 +1016,8 @@ extern struct page *pgd_page(pgd_t pgd);

#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))

#define pud_offset(pgdp, addr) \
(((pud_t *) pgd_page_vaddr(*(pgdp))) + pud_index(addr))
#define pud_offset(p4dp, addr) \
(((pud_t *) p4d_page_vaddr(*(p4dp))) + pud_index(addr))
#define pmd_offset(pudp,addr) \
(((pmd_t *) pud_page_vaddr(*(pudp))) + pmd_index(addr))
#define pte_offset_kernel(dir,addr) \
Expand Down Expand Up @@ -1366,11 +1372,11 @@ static inline bool pud_is_leaf(pud_t pud)
return !!(pud_raw(pud) & cpu_to_be64(_PAGE_PTE));
}

#define pgd_is_leaf pgd_is_leaf
#define pgd_leaf pgd_is_leaf
static inline bool pgd_is_leaf(pgd_t pgd)
#define p4d_is_leaf p4d_is_leaf
#define p4d_leaf p4d_is_leaf
static inline bool p4d_is_leaf(p4d_t p4d)
{
return !!(pgd_raw(pgd) & cpu_to_be64(_PAGE_PTE));
return !!(p4d_raw(p4d) & cpu_to_be64(_PAGE_PTE));
}

#endif /* __ASSEMBLY__ */
Expand Down
6 changes: 3 additions & 3 deletions arch/powerpc/include/asm/book3s/64/radix.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
/* Don't have anything in the reserved bits and leaf bits */
#define RADIX_PMD_BAD_BITS 0x60000000000000e0UL
#define RADIX_PUD_BAD_BITS 0x60000000000000e0UL
#define RADIX_PGD_BAD_BITS 0x60000000000000e0UL
#define RADIX_P4D_BAD_BITS 0x60000000000000e0UL

#define RADIX_PMD_SHIFT (PAGE_SHIFT + RADIX_PTE_INDEX_SIZE)
#define RADIX_PUD_SHIFT (RADIX_PMD_SHIFT + RADIX_PMD_INDEX_SIZE)
Expand Down Expand Up @@ -227,9 +227,9 @@ static inline int radix__pud_bad(pud_t pud)
}


static inline int radix__pgd_bad(pgd_t pgd)
static inline int radix__p4d_bad(p4d_t p4d)
{
return !!(pgd_val(pgd) & RADIX_PGD_BAD_BITS);
return !!(p4d_val(p4d) & RADIX_P4D_BAD_BITS);
}

#ifdef CONFIG_TRANSPARENT_HUGEPAGE
Expand Down
1 change: 0 additions & 1 deletion arch/powerpc/include/asm/nohash/32/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#ifndef _ASM_POWERPC_NOHASH_32_PGTABLE_H
#define _ASM_POWERPC_NOHASH_32_PGTABLE_H

#define __ARCH_USE_5LEVEL_HACK
#include <asm-generic/pgtable-nopmd.h>

#ifndef __ASSEMBLY__
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/include/asm/nohash/64/pgalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct vmemmap_backing {
};
extern struct vmemmap_backing *vmemmap_list;

#define pgd_populate(MM, PGD, PUD) pgd_set(PGD, (unsigned long)PUD)
#define p4d_populate(MM, P4D, PUD) p4d_set(P4D, (unsigned long)PUD)

static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
{
Expand Down
32 changes: 16 additions & 16 deletions arch/powerpc/include/asm/nohash/64/pgtable-4k.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#ifndef _ASM_POWERPC_NOHASH_64_PGTABLE_4K_H
#define _ASM_POWERPC_NOHASH_64_PGTABLE_4K_H

#include <asm-generic/5level-fixup.h>
#include <asm-generic/pgtable-nop4d.h>

/*
* Entries per page directory level. The PTE level must use a 64b record
Expand Down Expand Up @@ -45,41 +45,41 @@
#define PMD_MASKED_BITS 0
/* Bits to mask out from a PUD to get to the PMD page */
#define PUD_MASKED_BITS 0
/* Bits to mask out from a PGD to get to the PUD page */
#define PGD_MASKED_BITS 0
/* Bits to mask out from a P4D to get to the PUD page */
#define P4D_MASKED_BITS 0


/*
* 4-level page tables related bits
*/

#define pgd_none(pgd) (!pgd_val(pgd))
#define pgd_bad(pgd) (pgd_val(pgd) == 0)
#define pgd_present(pgd) (pgd_val(pgd) != 0)
#define pgd_page_vaddr(pgd) (pgd_val(pgd) & ~PGD_MASKED_BITS)
#define p4d_none(p4d) (!p4d_val(p4d))
#define p4d_bad(p4d) (p4d_val(p4d) == 0)
#define p4d_present(p4d) (p4d_val(p4d) != 0)
#define p4d_page_vaddr(p4d) (p4d_val(p4d) & ~P4D_MASKED_BITS)

#ifndef __ASSEMBLY__

static inline void pgd_clear(pgd_t *pgdp)
static inline void p4d_clear(p4d_t *p4dp)
{
*pgdp = __pgd(0);
*p4dp = __p4d(0);
}

static inline pte_t pgd_pte(pgd_t pgd)
static inline pte_t p4d_pte(p4d_t p4d)
{
return __pte(pgd_val(pgd));
return __pte(p4d_val(p4d));
}

static inline pgd_t pte_pgd(pte_t pte)
static inline p4d_t pte_p4d(pte_t pte)
{
return __pgd(pte_val(pte));
return __p4d(pte_val(pte));
}
extern struct page *pgd_page(pgd_t pgd);
extern struct page *p4d_page(p4d_t p4d);

#endif /* !__ASSEMBLY__ */

#define pud_offset(pgdp, addr) \
(((pud_t *) pgd_page_vaddr(*(pgdp))) + \
#define pud_offset(p4dp, addr) \
(((pud_t *) p4d_page_vaddr(*(p4dp))) + \
(((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)))

#define pud_ERROR(e) \
Expand Down
6 changes: 3 additions & 3 deletions arch/powerpc/include/asm/nohash/64/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,11 @@ static inline pud_t pte_pud(pte_t pte)
return __pud(pte_val(pte));
}
#define pud_write(pud) pte_write(pud_pte(pud))
#define pgd_write(pgd) pte_write(pgd_pte(pgd))
#define p4d_write(pgd) pte_write(p4d_pte(p4d))

static inline void pgd_set(pgd_t *pgdp, unsigned long val)
static inline void p4d_set(p4d_t *p4dp, unsigned long val)
{
*pgdp = __pgd(val);
*p4dp = __p4d(val);
}

/*
Expand Down
10 changes: 5 additions & 5 deletions arch/powerpc/include/asm/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ struct mm_struct;
#ifdef CONFIG_PPC32
static inline pmd_t *pmd_ptr(struct mm_struct *mm, unsigned long va)
{
return pmd_offset(pud_offset(pgd_offset(mm, va), va), va);
return pmd_offset(pud_offset(p4d_offset(pgd_offset(mm, va), va), va), va);
}

static inline pmd_t *pmd_ptr_k(unsigned long va)
{
return pmd_offset(pud_offset(pgd_offset_k(va), va), va);
return pmd_offset(pud_offset(p4d_offset(pgd_offset_k(va), va), va), va);
}

static inline pte_t *virt_to_kpte(unsigned long vaddr)
Expand Down Expand Up @@ -158,9 +158,9 @@ static inline bool pud_is_leaf(pud_t pud)
}
#endif

#ifndef pgd_is_leaf
#define pgd_is_leaf pgd_is_leaf
static inline bool pgd_is_leaf(pgd_t pgd)
#ifndef p4d_is_leaf
#define p4d_is_leaf p4d_is_leaf
static inline bool p4d_is_leaf(p4d_t p4d)
{
return false;
}
Expand Down
32 changes: 19 additions & 13 deletions arch/powerpc/kvm/book3s_64_mmu_radix.c
Original file line number Diff line number Diff line change
Expand Up @@ -499,13 +499,14 @@ void kvmppc_free_pgtable_radix(struct kvm *kvm, pgd_t *pgd, unsigned int lpid)
unsigned long ig;

for (ig = 0; ig < PTRS_PER_PGD; ++ig, ++pgd) {
p4d_t *p4d = p4d_offset(pgd, 0);
pud_t *pud;

if (!pgd_present(*pgd))
if (!p4d_present(*p4d))
continue;
pud = pud_offset(pgd, 0);
pud = pud_offset(p4d, 0);
kvmppc_unmap_free_pud(kvm, pud, lpid);
pgd_clear(pgd);
p4d_clear(p4d);
}
}

Expand Down Expand Up @@ -566,16 +567,19 @@ int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte,
unsigned long *rmapp, struct rmap_nested **n_rmap)
{
pgd_t *pgd;
p4d_t *p4d;
pud_t *pud, *new_pud = NULL;
pmd_t *pmd, *new_pmd = NULL;
pte_t *ptep, *new_ptep = NULL;
int ret;

/* Traverse the guest's 2nd-level tree, allocate new levels needed */
pgd = pgtable + pgd_index(gpa);
p4d = p4d_offset(pgd, gpa);

pud = NULL;
if (pgd_present(*pgd))
pud = pud_offset(pgd, gpa);
if (p4d_present(*p4d))
pud = pud_offset(p4d, gpa);
else
new_pud = pud_alloc_one(kvm->mm, gpa);

Expand All @@ -596,13 +600,13 @@ int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte,

/* Now traverse again under the lock and change the tree */
ret = -ENOMEM;
if (pgd_none(*pgd)) {
if (p4d_none(*p4d)) {
if (!new_pud)
goto out_unlock;
pgd_populate(kvm->mm, pgd, new_pud);
p4d_populate(kvm->mm, p4d, new_pud);
new_pud = NULL;
}
pud = pud_offset(pgd, gpa);
pud = pud_offset(p4d, gpa);
if (pud_is_leaf(*pud)) {
unsigned long hgpa = gpa & PUD_MASK;

Expand Down Expand Up @@ -1220,7 +1224,8 @@ static ssize_t debugfs_radix_read(struct file *file, char __user *buf,
unsigned long gpa;
pgd_t *pgt;
struct kvm_nested_guest *nested;
pgd_t pgd, *pgdp;
pgd_t *pgdp;
p4d_t p4d, *p4dp;
pud_t pud, *pudp;
pmd_t pmd, *pmdp;
pte_t *ptep;
Expand Down Expand Up @@ -1293,13 +1298,14 @@ static ssize_t debugfs_radix_read(struct file *file, char __user *buf,
}

pgdp = pgt + pgd_index(gpa);
pgd = READ_ONCE(*pgdp);
if (!(pgd_val(pgd) & _PAGE_PRESENT)) {
gpa = (gpa & PGDIR_MASK) + PGDIR_SIZE;
p4dp = p4d_offset(pgdp, gpa);
p4d = READ_ONCE(*p4dp);
if (!(p4d_val(p4d) & _PAGE_PRESENT)) {
gpa = (gpa & P4D_MASK) + P4D_SIZE;
continue;
}

pudp = pud_offset(&pgd, gpa);
pudp = pud_offset(&p4d, gpa);
pud = READ_ONCE(*pudp);
if (!(pud_val(pud) & _PAGE_PRESENT)) {
gpa = (gpa & PUD_MASK) + PUD_SIZE;
Expand Down
Loading

0 comments on commit 2fb4706

Please sign in to comment.