Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions arch/arm64/include/asm/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ static inline void __set_ptes(struct mm_struct *mm,
unsigned long __always_unused addr,
pte_t *ptep, pte_t pte, unsigned int nr)
{
page_table_check_ptes_set(mm, ptep, pte, nr);
page_table_check_ptes_set(mm, addr, ptep, pte, nr);
__sync_cache_and_tags(pte, nr);

for (;;) {
Expand Down Expand Up @@ -661,15 +661,15 @@ static inline void __set_pte_at(struct mm_struct *mm,
static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp, pmd_t pmd)
{
page_table_check_pmd_set(mm, pmdp, pmd);
page_table_check_pmd_set(mm, addr, pmdp, pmd);
return __set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd),
PMD_SIZE >> PAGE_SHIFT);
}

static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
pud_t *pudp, pud_t pud)
{
page_table_check_pud_set(mm, pudp, pud);
page_table_check_pud_set(mm, addr, pudp, pud);
return __set_pte_at(mm, addr, (pte_t *)pudp, pud_pte(pud),
PUD_SIZE >> PAGE_SHIFT);
}
Expand Down Expand Up @@ -1233,17 +1233,17 @@ static inline int pgd_devmap(pgd_t pgd)
#endif

#ifdef CONFIG_PAGE_TABLE_CHECK
static inline bool pte_user_accessible_page(pte_t pte)
static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
{
return pte_valid(pte) && (pte_user(pte) || pte_user_exec(pte));
}

static inline bool pmd_user_accessible_page(pmd_t pmd)
static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
{
return pmd_valid(pmd) && !pmd_table(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
}

static inline bool pud_user_accessible_page(pud_t pud)
static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
{
return pud_valid(pud) && !pud_table(pud) && (pud_user(pud) || pud_user_exec(pud));
}
Expand Down Expand Up @@ -1306,7 +1306,7 @@ static inline pte_t __ptep_get_and_clear(struct mm_struct *mm,
{
pte_t pte = __pte(xchg_relaxed(&pte_val(*ptep), 0));

page_table_check_pte_clear(mm, pte);
page_table_check_pte_clear(mm, address, pte);

return pte;
}
Expand Down Expand Up @@ -1349,7 +1349,7 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
{
pmd_t pmd = __pmd(xchg_relaxed(&pmd_val(*pmdp), 0));

page_table_check_pmd_clear(mm, pmd);
page_table_check_pmd_clear(mm, address, pmd);

return pmd;
}
Expand Down Expand Up @@ -1440,7 +1440,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
unsigned long address, pmd_t *pmdp, pmd_t pmd)
{
page_table_check_pmd_set(vma->vm_mm, pmdp, pmd);
page_table_check_pmd_set(vma->vm_mm, address, pmdp, pmd);
return __pmd(xchg_relaxed(&pmd_val(*pmdp), pmd_val(pmd)));
}
#endif
Expand Down
1 change: 1 addition & 0 deletions arch/powerpc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ config PPC
select ARCH_STACKWALK
select ARCH_SUPPORTS_ATOMIC_RMW
select ARCH_SUPPORTS_DEBUG_PAGEALLOC if PPC_BOOK3S || PPC_8xx
select ARCH_SUPPORTS_PAGE_TABLE_CHECK
select ARCH_USE_BUILTIN_BSWAP
select ARCH_USE_CMPXCHG_LOCKREF if PPC64
select ARCH_USE_MEMTEST
Expand Down
12 changes: 11 additions & 1 deletion arch/powerpc/include/asm/book3s/32/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ void unmap_kernel_page(unsigned long va);
#ifndef __ASSEMBLY__
#include <linux/sched.h>
#include <linux/threads.h>
#include <linux/page_table_check.h>

/* Bits to mask out from a PGD to get to the PUD page */
#define PGD_MASKED_BITS 0
Expand Down Expand Up @@ -315,7 +316,11 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
pte_t *ptep)
{
return __pte(pte_update(mm, addr, ptep, ~_PAGE_HASHPTE, 0, 0));
pte_t old_pte = __pte(pte_update(mm, addr, ptep, ~_PAGE_HASHPTE, 0, 0));

page_table_check_pte_clear(mm, addr, old_pte);

return old_pte;
}

#define __HAVE_ARCH_PTEP_SET_WRPROTECT
Expand Down Expand Up @@ -437,6 +442,11 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
return true;
}

static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
{
return pte_present(pte) && !is_kernel_addr(addr);
}

/* Conversion functions: convert a page and protection to a page entry,
* and a page entry and page directory to the page they refer to.
*
Expand Down
62 changes: 52 additions & 10 deletions arch/powerpc/include/asm/book3s/64/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@
#define PAGE_KERNEL_ROX __pgprot(_PAGE_BASE | _PAGE_KERNEL_ROX)

#ifndef __ASSEMBLY__
#include <linux/page_table_check.h>

/*
* page table defines
*/
Expand Down Expand Up @@ -417,8 +419,11 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
{
unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0, 0);
return __pte(old);
pte_t old_pte = __pte(pte_update(mm, addr, ptep, ~0UL, 0, 0));

page_table_check_pte_clear(mm, addr, old_pte);

return old_pte;
}

#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
Expand All @@ -427,11 +432,16 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
pte_t *ptep, int full)
{
if (full && radix_enabled()) {
pte_t old_pte;

/*
* We know that this is a full mm pte clear and
* hence can be sure there is no parallel set_pte.
*/
return radix__ptep_get_and_clear_full(mm, addr, ptep, full);
old_pte = radix__ptep_get_and_clear_full(mm, addr, ptep, full);
page_table_check_pte_clear(mm, addr, old_pte);

return old_pte;
}
return ptep_get_and_clear(mm, addr, ptep);
}
Expand Down Expand Up @@ -540,6 +550,11 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
return arch_pte_access_permitted(pte_val(pte), write, 0);
}

static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
{
return pte_present(pte) && pte_user(pte);
}

/*
* Conversion functions: convert a page and protection to a page entry,
* and a page entry and page directory to the page they refer to.
Expand Down Expand Up @@ -1304,19 +1319,34 @@ extern int pudp_test_and_clear_young(struct vm_area_struct *vma,
static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
unsigned long addr, pmd_t *pmdp)
{
if (radix_enabled())
return radix__pmdp_huge_get_and_clear(mm, addr, pmdp);
return hash__pmdp_huge_get_and_clear(mm, addr, pmdp);
pmd_t old_pmd;

if (radix_enabled()) {
old_pmd = radix__pmdp_huge_get_and_clear(mm, addr, pmdp);
} else {
old_pmd = hash__pmdp_huge_get_and_clear(mm, addr, pmdp);
}

page_table_check_pmd_clear(mm, addr, old_pmd);

return old_pmd;
}

#define __HAVE_ARCH_PUDP_HUGE_GET_AND_CLEAR
static inline pud_t pudp_huge_get_and_clear(struct mm_struct *mm,
unsigned long addr, pud_t *pudp)
{
if (radix_enabled())
return radix__pudp_huge_get_and_clear(mm, addr, pudp);
BUG();
return *pudp;
pud_t old_pud;

if (radix_enabled()) {
old_pud = radix__pudp_huge_get_and_clear(mm, addr, pudp);
} else {
BUG();
}

page_table_check_pud_clear(mm, addr, old_pud);

return old_pud;
}

static inline pmd_t pmdp_collapse_flush(struct vm_area_struct *vma,
Expand Down Expand Up @@ -1431,5 +1461,17 @@ static inline bool is_pte_rw_upgrade(unsigned long old_val, unsigned long new_va
return false;
}

#define pmd_user_accessible_page pmd_user_accessible_page
static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
{
return pmd_leaf(pmd) && pte_user_accessible_page(pmd_pte(pmd), addr);
}

#define pud_user_accessible_page pud_user_accessible_page
static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
{
return pud_leaf(pud) && pte_user_accessible_page(pud_pte(pud), addr);
}

#endif /* __ASSEMBLY__ */
#endif /* _ASM_POWERPC_BOOK3S_64_PGTABLE_H_ */
13 changes: 12 additions & 1 deletion arch/powerpc/include/asm/nohash/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, p

#ifndef __ASSEMBLY__

#include <linux/page_table_check.h>

extern int icache_44x_need_flush;

#ifndef pte_huge_size
Expand Down Expand Up @@ -122,7 +124,11 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
pte_t *ptep)
{
return __pte(pte_update(mm, addr, ptep, ~0UL, 0, 0));
pte_t old_pte = __pte(pte_update(mm, addr, ptep, ~0UL, 0, 0));

page_table_check_pte_clear(mm, addr, old_pte);

return old_pte;
}
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR

Expand Down Expand Up @@ -243,6 +249,11 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
return true;
}

static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
{
return pte_present(pte) && !is_kernel_addr(addr);
}

/* Conversion functions: convert a page and protection to a page entry,
* and a page entry and page directory to the page they refer to.
*
Expand Down
19 changes: 19 additions & 0 deletions arch/powerpc/include/asm/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ struct mm_struct;
void set_ptes(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
pte_t pte, unsigned int nr);
#define set_ptes set_ptes
void set_pte_at_unchecked(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte);
#define update_mmu_cache(vma, addr, ptep) \
update_mmu_cache_range(NULL, vma, addr, ptep, 1)

Expand Down Expand Up @@ -215,6 +217,23 @@ static inline bool arch_supports_memmap_on_memory(unsigned long vmemmap_size)

#endif /* CONFIG_PPC64 */

#ifndef pud_pfn
#define pud_pfn pud_pfn
static inline int pud_pfn(pud_t pud)
{
BUILD_BUG();
return 0;
}
#endif

#ifndef pmd_user_accessible_page
#define pmd_user_accessible_page(pmd, addr) false
#endif

#ifndef pud_user_accessible_page
#define pud_user_accessible_page(pud, addr) false
#endif

#endif /* __ASSEMBLY__ */

#endif /* _ASM_POWERPC_PGTABLE_H */
4 changes: 4 additions & 0 deletions arch/powerpc/mm/book3s64/hash_pgtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <linux/sched.h>
#include <linux/mm_types.h>
#include <linux/mm.h>
#include <linux/page_table_check.h>
#include <linux/stop_machine.h>

#include <asm/sections.h>
Expand Down Expand Up @@ -231,6 +232,9 @@ pmd_t hash__pmdp_collapse_flush(struct vm_area_struct *vma, unsigned long addres

pmd = *pmdp;
pmd_clear(pmdp);

page_table_check_pmd_clear(vma->vm_mm, address, pmd);

/*
* Wait for all pending hash_page to finish. This is needed
* in case of subpage collapse. When we collapse normal pages
Expand Down
17 changes: 11 additions & 6 deletions arch/powerpc/mm/book3s64/pgtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <linux/pkeys.h>
#include <linux/debugfs.h>
#include <linux/proc_fs.h>
#include <linux/page_table_check.h>

#include <asm/pgalloc.h>
#include <asm/tlb.h>
Expand Down Expand Up @@ -128,7 +129,8 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
WARN_ON(!(pmd_leaf(pmd)));
#endif
trace_hugepage_set_pmd(addr, pmd_val(pmd));
return set_pte_at(mm, addr, pmdp_ptep(pmdp), pmd_pte(pmd));
page_table_check_pmd_set(mm, addr, pmdp, pmd);
return set_pte_at_unchecked(mm, addr, pmdp_ptep(pmdp), pmd_pte(pmd));
}

void set_pud_at(struct mm_struct *mm, unsigned long addr,
Expand All @@ -145,7 +147,8 @@ void set_pud_at(struct mm_struct *mm, unsigned long addr,
WARN_ON(!(pud_leaf(pud)));
#endif
trace_hugepage_set_pud(addr, pud_val(pud));
return set_pte_at(mm, addr, pudp_ptep(pudp), pud_pte(pud));
page_table_check_pud_set(mm, addr, pudp, pud);
return set_pte_at_unchecked(mm, addr, pudp_ptep(pudp), pud_pte(pud));
}

static void do_serialize(void *arg)
Expand Down Expand Up @@ -180,12 +183,14 @@ void serialize_against_pte_lookup(struct mm_struct *mm)
pmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
pmd_t *pmdp)
{
unsigned long old_pmd;
pmd_t old_pmd;

VM_WARN_ON_ONCE(!pmd_present(*pmdp));
old_pmd = pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, _PAGE_INVALID);
old_pmd = __pmd(pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, _PAGE_INVALID));
flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
return __pmd(old_pmd);
page_table_check_pmd_clear(vma->vm_mm, address, old_pmd);

return old_pmd;
}

pud_t pudp_invalidate(struct vm_area_struct *vma, unsigned long address,
Expand Down Expand Up @@ -556,7 +561,7 @@ void ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr,
if (radix_enabled())
return radix__ptep_modify_prot_commit(vma, addr,
ptep, old_pte, pte);
set_pte_at(vma->vm_mm, addr, ptep, pte);
set_pte_at_unchecked(vma->vm_mm, addr, ptep, pte);
}

#ifdef CONFIG_TRANSPARENT_HUGEPAGE
Expand Down
Loading
Loading