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
46 changes: 23 additions & 23 deletions arch/arm64/include/asm/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -712,22 +712,24 @@ static inline pgprot_t pud_pgprot(pud_t pud)
return __pgprot(pud_val(pfn_pud(pfn, __pgprot(0))) ^ pud_val(pud));
}

static inline void __set_ptes_anysz(struct mm_struct *mm, pte_t *ptep,
pte_t pte, unsigned int nr,
static inline void __set_ptes_anysz(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte, unsigned int nr,
unsigned long pgsize)
{
unsigned long stride = pgsize >> PAGE_SHIFT;

switch (pgsize) {
case PAGE_SIZE:
page_table_check_ptes_set(mm, ptep, pte, nr);
page_table_check_ptes_set(mm, addr, ptep, pte, nr);
break;
case PMD_SIZE:
page_table_check_pmds_set(mm, (pmd_t *)ptep, pte_pmd(pte), nr);
page_table_check_pmds_set(mm, addr, (pmd_t *)ptep,
pte_pmd(pte), nr);
break;
#ifndef __PAGETABLE_PMD_FOLDED
case PUD_SIZE:
page_table_check_puds_set(mm, (pud_t *)ptep, pte_pud(pte), nr);
page_table_check_puds_set(mm, addr, (pud_t *)ptep,
pte_pud(pte), nr);
break;
#endif
default:
Expand All @@ -748,26 +750,23 @@ static inline void __set_ptes_anysz(struct mm_struct *mm, pte_t *ptep,
__set_pte_complete(pte);
}

static inline void __set_ptes(struct mm_struct *mm,
unsigned long __always_unused addr,
static inline void __set_ptes(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte, unsigned int nr)
{
__set_ptes_anysz(mm, ptep, pte, nr, PAGE_SIZE);
__set_ptes_anysz(mm, addr, ptep, pte, nr, PAGE_SIZE);
}

static inline void __set_pmds(struct mm_struct *mm,
unsigned long __always_unused addr,
static inline void __set_pmds(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp, pmd_t pmd, unsigned int nr)
{
__set_ptes_anysz(mm, (pte_t *)pmdp, pmd_pte(pmd), nr, PMD_SIZE);
__set_ptes_anysz(mm, addr, (pte_t *)pmdp, pmd_pte(pmd), nr, PMD_SIZE);
}
#define set_pmd_at(mm, addr, pmdp, pmd) __set_pmds(mm, addr, pmdp, pmd, 1)

static inline void __set_puds(struct mm_struct *mm,
unsigned long __always_unused addr,
static inline void __set_puds(struct mm_struct *mm, unsigned long addr,
pud_t *pudp, pud_t pud, unsigned int nr)
{
__set_ptes_anysz(mm, (pte_t *)pudp, pud_pte(pud), nr, PUD_SIZE);
__set_ptes_anysz(mm, addr, (pte_t *)pudp, pud_pte(pud), nr, PUD_SIZE);
}
#define set_pud_at(mm, addr, pudp, pud) __set_puds(mm, addr, pudp, pud, 1)

Expand Down Expand Up @@ -1315,17 +1314,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 @@ -1384,21 +1383,22 @@ static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma,
#endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG */

static inline pte_t __ptep_get_and_clear_anysz(struct mm_struct *mm,
unsigned long address,
pte_t *ptep,
unsigned long pgsize)
{
pte_t pte = __pte(xchg_relaxed(&pte_val(*ptep), 0));

switch (pgsize) {
case PAGE_SIZE:
page_table_check_pte_clear(mm, pte);
page_table_check_pte_clear(mm, address, pte);
break;
case PMD_SIZE:
page_table_check_pmd_clear(mm, pte_pmd(pte));
page_table_check_pmd_clear(mm, address, pte_pmd(pte));
break;
#ifndef __PAGETABLE_PMD_FOLDED
case PUD_SIZE:
page_table_check_pud_clear(mm, pte_pud(pte));
page_table_check_pud_clear(mm, address, pte_pud(pte));
break;
#endif
default:
Expand All @@ -1411,7 +1411,7 @@ static inline pte_t __ptep_get_and_clear_anysz(struct mm_struct *mm,
static inline pte_t __ptep_get_and_clear(struct mm_struct *mm,
unsigned long address, pte_t *ptep)
{
return __ptep_get_and_clear_anysz(mm, ptep, PAGE_SIZE);
return __ptep_get_and_clear_anysz(mm, address, ptep, PAGE_SIZE);
}

static inline void __clear_full_ptes(struct mm_struct *mm, unsigned long addr,
Expand Down Expand Up @@ -1450,7 +1450,7 @@ static inline pte_t __get_and_clear_full_ptes(struct mm_struct *mm,
static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
unsigned long address, pmd_t *pmdp)
{
return pte_pmd(__ptep_get_and_clear_anysz(mm, (pte_t *)pmdp, PMD_SIZE));
return pte_pmd(__ptep_get_and_clear_anysz(mm, address, (pte_t *)pmdp, PMD_SIZE));
}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */

Expand Down Expand Up @@ -1539,7 +1539,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
15 changes: 8 additions & 7 deletions arch/arm64/mm/hugetlbpage.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,12 @@ static pte_t get_clear_contig(struct mm_struct *mm,
pte_t pte, tmp_pte;
bool present;

pte = __ptep_get_and_clear_anysz(mm, ptep, pgsize);
pte = __ptep_get_and_clear_anysz(mm, addr, ptep, pgsize);
present = pte_present(pte);
while (--ncontig) {
ptep++;
tmp_pte = __ptep_get_and_clear_anysz(mm, ptep, pgsize);
addr += pgsize;
tmp_pte = __ptep_get_and_clear_anysz(mm, addr, ptep, pgsize);
if (present) {
if (pte_dirty(tmp_pte))
pte = pte_mkdirty(pte);
Expand Down Expand Up @@ -207,7 +208,7 @@ static void clear_flush(struct mm_struct *mm,
unsigned long i, saddr = addr;

for (i = 0; i < ncontig; i++, addr += pgsize, ptep++)
__ptep_get_and_clear_anysz(mm, ptep, pgsize);
__ptep_get_and_clear_anysz(mm, addr, ptep, pgsize);

if (mm == &init_mm)
flush_tlb_kernel_range(saddr, addr);
Expand All @@ -226,15 +227,15 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,

if (!pte_present(pte)) {
for (i = 0; i < ncontig; i++, ptep++, addr += pgsize)
__set_ptes_anysz(mm, ptep, pte, 1, pgsize);
__set_ptes_anysz(mm, addr, ptep, pte, 1, pgsize);
return;
}

/* Only need to "break" if transitioning valid -> valid. */
if (pte_cont(pte) && pte_valid(__ptep_get(ptep)))
clear_flush(mm, addr, ptep, pgsize, ncontig);

__set_ptes_anysz(mm, ptep, pte, ncontig, pgsize);
__set_ptes_anysz(mm, addr, ptep, pte, ncontig, pgsize);
}

pte_t *huge_pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma,
Expand Down Expand Up @@ -449,7 +450,7 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma,
if (pte_young(orig_pte))
pte = pte_mkyoung(pte);

__set_ptes_anysz(mm, ptep, pte, ncontig, pgsize);
__set_ptes_anysz(mm, addr, ptep, pte, ncontig, pgsize);
return 1;
}

Expand All @@ -473,7 +474,7 @@ void huge_ptep_set_wrprotect(struct mm_struct *mm,
pte = get_clear_contig_flush(mm, addr, ptep, pgsize, ncontig);
pte = pte_wrprotect(pte);

__set_ptes_anysz(mm, ptep, pte, ncontig, pgsize);
__set_ptes_anysz(mm, addr, ptep, pte, ncontig, pgsize);
}

pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
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 @@ -1303,19 +1318,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 @@ -1430,5 +1460,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
Loading
Loading