162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_X86_PGTABLE_H
362306a36Sopenharmony_ci#define _ASM_X86_PGTABLE_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/mem_encrypt.h>
662306a36Sopenharmony_ci#include <asm/page.h>
762306a36Sopenharmony_ci#include <asm/pgtable_types.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/*
1062306a36Sopenharmony_ci * Macro to mark a page protection value as UC-
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci#define pgprot_noncached(prot)						\
1362306a36Sopenharmony_ci	((boot_cpu_data.x86 > 3)					\
1462306a36Sopenharmony_ci	 ? (__pgprot(pgprot_val(prot) |					\
1562306a36Sopenharmony_ci		     cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS)))	\
1662306a36Sopenharmony_ci	 : (prot))
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#ifndef __ASSEMBLY__
1962306a36Sopenharmony_ci#include <linux/spinlock.h>
2062306a36Sopenharmony_ci#include <asm/x86_init.h>
2162306a36Sopenharmony_ci#include <asm/pkru.h>
2262306a36Sopenharmony_ci#include <asm/fpu/api.h>
2362306a36Sopenharmony_ci#include <asm/coco.h>
2462306a36Sopenharmony_ci#include <asm-generic/pgtable_uffd.h>
2562306a36Sopenharmony_ci#include <linux/page_table_check.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciextern pgd_t early_top_pgt[PTRS_PER_PGD];
2862306a36Sopenharmony_cibool __init __early_make_pgtable(unsigned long address, pmdval_t pmd);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistruct seq_file;
3162306a36Sopenharmony_civoid ptdump_walk_pgd_level(struct seq_file *m, struct mm_struct *mm);
3262306a36Sopenharmony_civoid ptdump_walk_pgd_level_debugfs(struct seq_file *m, struct mm_struct *mm,
3362306a36Sopenharmony_ci				   bool user);
3462306a36Sopenharmony_civoid ptdump_walk_pgd_level_checkwx(void);
3562306a36Sopenharmony_civoid ptdump_walk_user_pgd_level_checkwx(void);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/*
3862306a36Sopenharmony_ci * Macros to add or remove encryption attribute
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ci#define pgprot_encrypted(prot)	__pgprot(cc_mkenc(pgprot_val(prot)))
4162306a36Sopenharmony_ci#define pgprot_decrypted(prot)	__pgprot(cc_mkdec(pgprot_val(prot)))
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_WX
4462306a36Sopenharmony_ci#define debug_checkwx()		ptdump_walk_pgd_level_checkwx()
4562306a36Sopenharmony_ci#define debug_checkwx_user()	ptdump_walk_user_pgd_level_checkwx()
4662306a36Sopenharmony_ci#else
4762306a36Sopenharmony_ci#define debug_checkwx()		do { } while (0)
4862306a36Sopenharmony_ci#define debug_checkwx_user()	do { } while (0)
4962306a36Sopenharmony_ci#endif
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/*
5262306a36Sopenharmony_ci * ZERO_PAGE is a global shared page that is always zero: used
5362306a36Sopenharmony_ci * for zero-mapped memory areas etc..
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_ciextern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]
5662306a36Sopenharmony_ci	__visible;
5762306a36Sopenharmony_ci#define ZERO_PAGE(vaddr) ((void)(vaddr),virt_to_page(empty_zero_page))
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ciextern spinlock_t pgd_lock;
6062306a36Sopenharmony_ciextern struct list_head pgd_list;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ciextern struct mm_struct *pgd_page_get_mm(struct page *page);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ciextern pmdval_t early_pmd_flags;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#ifdef CONFIG_PARAVIRT_XXL
6762306a36Sopenharmony_ci#include <asm/paravirt.h>
6862306a36Sopenharmony_ci#else  /* !CONFIG_PARAVIRT_XXL */
6962306a36Sopenharmony_ci#define set_pte(ptep, pte)		native_set_pte(ptep, pte)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define set_pte_atomic(ptep, pte)					\
7262306a36Sopenharmony_ci	native_set_pte_atomic(ptep, pte)
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#define set_pmd(pmdp, pmd)		native_set_pmd(pmdp, pmd)
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#ifndef __PAGETABLE_P4D_FOLDED
7762306a36Sopenharmony_ci#define set_pgd(pgdp, pgd)		native_set_pgd(pgdp, pgd)
7862306a36Sopenharmony_ci#define pgd_clear(pgd)			(pgtable_l5_enabled() ? native_pgd_clear(pgd) : 0)
7962306a36Sopenharmony_ci#endif
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#ifndef set_p4d
8262306a36Sopenharmony_ci# define set_p4d(p4dp, p4d)		native_set_p4d(p4dp, p4d)
8362306a36Sopenharmony_ci#endif
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#ifndef __PAGETABLE_PUD_FOLDED
8662306a36Sopenharmony_ci#define p4d_clear(p4d)			native_p4d_clear(p4d)
8762306a36Sopenharmony_ci#endif
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#ifndef set_pud
9062306a36Sopenharmony_ci# define set_pud(pudp, pud)		native_set_pud(pudp, pud)
9162306a36Sopenharmony_ci#endif
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci#ifndef __PAGETABLE_PUD_FOLDED
9462306a36Sopenharmony_ci#define pud_clear(pud)			native_pud_clear(pud)
9562306a36Sopenharmony_ci#endif
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define pte_clear(mm, addr, ptep)	native_pte_clear(mm, addr, ptep)
9862306a36Sopenharmony_ci#define pmd_clear(pmd)			native_pmd_clear(pmd)
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define pgd_val(x)	native_pgd_val(x)
10162306a36Sopenharmony_ci#define __pgd(x)	native_make_pgd(x)
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#ifndef __PAGETABLE_P4D_FOLDED
10462306a36Sopenharmony_ci#define p4d_val(x)	native_p4d_val(x)
10562306a36Sopenharmony_ci#define __p4d(x)	native_make_p4d(x)
10662306a36Sopenharmony_ci#endif
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#ifndef __PAGETABLE_PUD_FOLDED
10962306a36Sopenharmony_ci#define pud_val(x)	native_pud_val(x)
11062306a36Sopenharmony_ci#define __pud(x)	native_make_pud(x)
11162306a36Sopenharmony_ci#endif
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#ifndef __PAGETABLE_PMD_FOLDED
11462306a36Sopenharmony_ci#define pmd_val(x)	native_pmd_val(x)
11562306a36Sopenharmony_ci#define __pmd(x)	native_make_pmd(x)
11662306a36Sopenharmony_ci#endif
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#define pte_val(x)	native_pte_val(x)
11962306a36Sopenharmony_ci#define __pte(x)	native_make_pte(x)
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci#define arch_end_context_switch(prev)	do {} while(0)
12262306a36Sopenharmony_ci#endif	/* CONFIG_PARAVIRT_XXL */
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/*
12562306a36Sopenharmony_ci * The following only work if pte_present() is true.
12662306a36Sopenharmony_ci * Undefined behaviour if not..
12762306a36Sopenharmony_ci */
12862306a36Sopenharmony_cistatic inline bool pte_dirty(pte_t pte)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	return pte_flags(pte) & _PAGE_DIRTY_BITS;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic inline bool pte_shstk(pte_t pte)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	return cpu_feature_enabled(X86_FEATURE_SHSTK) &&
13662306a36Sopenharmony_ci	       (pte_flags(pte) & (_PAGE_RW | _PAGE_DIRTY)) == _PAGE_DIRTY;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic inline int pte_young(pte_t pte)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	return pte_flags(pte) & _PAGE_ACCESSED;
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic inline bool pmd_dirty(pmd_t pmd)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	return pmd_flags(pmd) & _PAGE_DIRTY_BITS;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic inline bool pmd_shstk(pmd_t pmd)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	return cpu_feature_enabled(X86_FEATURE_SHSTK) &&
15262306a36Sopenharmony_ci	       (pmd_flags(pmd) & (_PAGE_RW | _PAGE_DIRTY | _PAGE_PSE)) ==
15362306a36Sopenharmony_ci	       (_PAGE_DIRTY | _PAGE_PSE);
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci#define pmd_young pmd_young
15762306a36Sopenharmony_cistatic inline int pmd_young(pmd_t pmd)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	return pmd_flags(pmd) & _PAGE_ACCESSED;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic inline bool pud_dirty(pud_t pud)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	return pud_flags(pud) & _PAGE_DIRTY_BITS;
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic inline int pud_young(pud_t pud)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	return pud_flags(pud) & _PAGE_ACCESSED;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic inline int pte_write(pte_t pte)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	/*
17562306a36Sopenharmony_ci	 * Shadow stack pages are logically writable, but do not have
17662306a36Sopenharmony_ci	 * _PAGE_RW.  Check for them separately from _PAGE_RW itself.
17762306a36Sopenharmony_ci	 */
17862306a36Sopenharmony_ci	return (pte_flags(pte) & _PAGE_RW) || pte_shstk(pte);
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci#define pmd_write pmd_write
18262306a36Sopenharmony_cistatic inline int pmd_write(pmd_t pmd)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	/*
18562306a36Sopenharmony_ci	 * Shadow stack pages are logically writable, but do not have
18662306a36Sopenharmony_ci	 * _PAGE_RW.  Check for them separately from _PAGE_RW itself.
18762306a36Sopenharmony_ci	 */
18862306a36Sopenharmony_ci	return (pmd_flags(pmd) & _PAGE_RW) || pmd_shstk(pmd);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci#define pud_write pud_write
19262306a36Sopenharmony_cistatic inline int pud_write(pud_t pud)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	return pud_flags(pud) & _PAGE_RW;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic inline int pte_huge(pte_t pte)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	return pte_flags(pte) & _PAGE_PSE;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic inline int pte_global(pte_t pte)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	return pte_flags(pte) & _PAGE_GLOBAL;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic inline int pte_exec(pte_t pte)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	return !(pte_flags(pte) & _PAGE_NX);
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic inline int pte_special(pte_t pte)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	return pte_flags(pte) & _PAGE_SPECIAL;
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/* Entries that were set to PROT_NONE are inverted */
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic inline u64 protnone_mask(u64 val);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci#define PFN_PTE_SHIFT	PAGE_SHIFT
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic inline unsigned long pte_pfn(pte_t pte)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	phys_addr_t pfn = pte_val(pte);
22662306a36Sopenharmony_ci	pfn ^= protnone_mask(pfn);
22762306a36Sopenharmony_ci	return (pfn & PTE_PFN_MASK) >> PAGE_SHIFT;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic inline unsigned long pmd_pfn(pmd_t pmd)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	phys_addr_t pfn = pmd_val(pmd);
23362306a36Sopenharmony_ci	pfn ^= protnone_mask(pfn);
23462306a36Sopenharmony_ci	return (pfn & pmd_pfn_mask(pmd)) >> PAGE_SHIFT;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic inline unsigned long pud_pfn(pud_t pud)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	phys_addr_t pfn = pud_val(pud);
24062306a36Sopenharmony_ci	pfn ^= protnone_mask(pfn);
24162306a36Sopenharmony_ci	return (pfn & pud_pfn_mask(pud)) >> PAGE_SHIFT;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic inline unsigned long p4d_pfn(p4d_t p4d)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	return (p4d_val(p4d) & p4d_pfn_mask(p4d)) >> PAGE_SHIFT;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic inline unsigned long pgd_pfn(pgd_t pgd)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	return (pgd_val(pgd) & PTE_PFN_MASK) >> PAGE_SHIFT;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci#define p4d_leaf	p4d_large
25562306a36Sopenharmony_cistatic inline int p4d_large(p4d_t p4d)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	/* No 512 GiB pages yet */
25862306a36Sopenharmony_ci	return 0;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci#define pte_page(pte)	pfn_to_page(pte_pfn(pte))
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci#define pmd_leaf	pmd_large
26462306a36Sopenharmony_cistatic inline int pmd_large(pmd_t pte)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	return pmd_flags(pte) & _PAGE_PSE;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
27062306a36Sopenharmony_ci/* NOTE: when predicate huge page, consider also pmd_devmap, or use pmd_large */
27162306a36Sopenharmony_cistatic inline int pmd_trans_huge(pmd_t pmd)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	return (pmd_val(pmd) & (_PAGE_PSE|_PAGE_DEVMAP)) == _PAGE_PSE;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
27762306a36Sopenharmony_cistatic inline int pud_trans_huge(pud_t pud)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	return (pud_val(pud) & (_PAGE_PSE|_PAGE_DEVMAP)) == _PAGE_PSE;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci#endif
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci#define has_transparent_hugepage has_transparent_hugepage
28462306a36Sopenharmony_cistatic inline int has_transparent_hugepage(void)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	return boot_cpu_has(X86_FEATURE_PSE);
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci#ifdef CONFIG_ARCH_HAS_PTE_DEVMAP
29062306a36Sopenharmony_cistatic inline int pmd_devmap(pmd_t pmd)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	return !!(pmd_val(pmd) & _PAGE_DEVMAP);
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
29662306a36Sopenharmony_cistatic inline int pud_devmap(pud_t pud)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	return !!(pud_val(pud) & _PAGE_DEVMAP);
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci#else
30162306a36Sopenharmony_cistatic inline int pud_devmap(pud_t pud)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	return 0;
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci#endif
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic inline int pgd_devmap(pgd_t pgd)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	return 0;
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ci#endif
31262306a36Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic inline pte_t pte_set_flags(pte_t pte, pteval_t set)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	pteval_t v = native_pte_val(pte);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return native_make_pte(v | set);
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic inline pte_t pte_clear_flags(pte_t pte, pteval_t clear)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	pteval_t v = native_pte_val(pte);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	return native_make_pte(v & ~clear);
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci/*
32962306a36Sopenharmony_ci * Write protection operations can result in Dirty=1,Write=0 PTEs. But in the
33062306a36Sopenharmony_ci * case of X86_FEATURE_USER_SHSTK, these PTEs denote shadow stack memory. So
33162306a36Sopenharmony_ci * when creating dirty, write-protected memory, a software bit is used:
33262306a36Sopenharmony_ci * _PAGE_BIT_SAVED_DIRTY. The following functions take a PTE and transition the
33362306a36Sopenharmony_ci * Dirty bit to SavedDirty, and vice-vesra.
33462306a36Sopenharmony_ci *
33562306a36Sopenharmony_ci * This shifting is only done if needed. In the case of shifting
33662306a36Sopenharmony_ci * Dirty->SavedDirty, the condition is if the PTE is Write=0. In the case of
33762306a36Sopenharmony_ci * shifting SavedDirty->Dirty, the condition is Write=1.
33862306a36Sopenharmony_ci */
33962306a36Sopenharmony_cistatic inline pgprotval_t mksaveddirty_shift(pgprotval_t v)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	pgprotval_t cond = (~v >> _PAGE_BIT_RW) & 1;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	v |= ((v >> _PAGE_BIT_DIRTY) & cond) << _PAGE_BIT_SAVED_DIRTY;
34462306a36Sopenharmony_ci	v &= ~(cond << _PAGE_BIT_DIRTY);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return v;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic inline pgprotval_t clear_saveddirty_shift(pgprotval_t v)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	pgprotval_t cond = (v >> _PAGE_BIT_RW) & 1;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	v |= ((v >> _PAGE_BIT_SAVED_DIRTY) & cond) << _PAGE_BIT_DIRTY;
35462306a36Sopenharmony_ci	v &= ~(cond << _PAGE_BIT_SAVED_DIRTY);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	return v;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic inline pte_t pte_mksaveddirty(pte_t pte)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	pteval_t v = native_pte_val(pte);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	v = mksaveddirty_shift(v);
36462306a36Sopenharmony_ci	return native_make_pte(v);
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic inline pte_t pte_clear_saveddirty(pte_t pte)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	pteval_t v = native_pte_val(pte);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	v = clear_saveddirty_shift(v);
37262306a36Sopenharmony_ci	return native_make_pte(v);
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic inline pte_t pte_wrprotect(pte_t pte)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	pte = pte_clear_flags(pte, _PAGE_RW);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/*
38062306a36Sopenharmony_ci	 * Blindly clearing _PAGE_RW might accidentally create
38162306a36Sopenharmony_ci	 * a shadow stack PTE (Write=0,Dirty=1). Move the hardware
38262306a36Sopenharmony_ci	 * dirty value to the software bit, if present.
38362306a36Sopenharmony_ci	 */
38462306a36Sopenharmony_ci	return pte_mksaveddirty(pte);
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
38862306a36Sopenharmony_cistatic inline int pte_uffd_wp(pte_t pte)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	bool wp = pte_flags(pte) & _PAGE_UFFD_WP;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_VM
39362306a36Sopenharmony_ci	/*
39462306a36Sopenharmony_ci	 * Having write bit for wr-protect-marked present ptes is fatal,
39562306a36Sopenharmony_ci	 * because it means the uffd-wp bit will be ignored and write will
39662306a36Sopenharmony_ci	 * just go through.
39762306a36Sopenharmony_ci	 *
39862306a36Sopenharmony_ci	 * Use any chance of pgtable walking to verify this (e.g., when
39962306a36Sopenharmony_ci	 * page swapped out or being migrated for all purposes). It means
40062306a36Sopenharmony_ci	 * something is already wrong.  Tell the admin even before the
40162306a36Sopenharmony_ci	 * process crashes. We also nail it with wrong pgtable setup.
40262306a36Sopenharmony_ci	 */
40362306a36Sopenharmony_ci	WARN_ON_ONCE(wp && pte_write(pte));
40462306a36Sopenharmony_ci#endif
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	return wp;
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic inline pte_t pte_mkuffd_wp(pte_t pte)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	return pte_wrprotect(pte_set_flags(pte, _PAGE_UFFD_WP));
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic inline pte_t pte_clear_uffd_wp(pte_t pte)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	return pte_clear_flags(pte, _PAGE_UFFD_WP);
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic inline pte_t pte_mkclean(pte_t pte)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	return pte_clear_flags(pte, _PAGE_DIRTY_BITS);
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic inline pte_t pte_mkold(pte_t pte)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	return pte_clear_flags(pte, _PAGE_ACCESSED);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic inline pte_t pte_mkexec(pte_t pte)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	return pte_clear_flags(pte, _PAGE_NX);
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic inline pte_t pte_mkdirty(pte_t pte)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	pte = pte_set_flags(pte, _PAGE_DIRTY | _PAGE_SOFT_DIRTY);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	return pte_mksaveddirty(pte);
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic inline pte_t pte_mkwrite_shstk(pte_t pte)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	pte = pte_clear_flags(pte, _PAGE_RW);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	return pte_set_flags(pte, _PAGE_DIRTY);
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic inline pte_t pte_mkyoung(pte_t pte)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	return pte_set_flags(pte, _PAGE_ACCESSED);
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic inline pte_t pte_mkwrite_novma(pte_t pte)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	return pte_set_flags(pte, _PAGE_RW);
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_cistruct vm_area_struct;
46062306a36Sopenharmony_cipte_t pte_mkwrite(pte_t pte, struct vm_area_struct *vma);
46162306a36Sopenharmony_ci#define pte_mkwrite pte_mkwrite
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic inline pte_t pte_mkhuge(pte_t pte)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	return pte_set_flags(pte, _PAGE_PSE);
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic inline pte_t pte_clrhuge(pte_t pte)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	return pte_clear_flags(pte, _PAGE_PSE);
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic inline pte_t pte_mkglobal(pte_t pte)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	return pte_set_flags(pte, _PAGE_GLOBAL);
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic inline pte_t pte_clrglobal(pte_t pte)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	return pte_clear_flags(pte, _PAGE_GLOBAL);
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic inline pte_t pte_mkspecial(pte_t pte)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	return pte_set_flags(pte, _PAGE_SPECIAL);
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_cistatic inline pte_t pte_mkdevmap(pte_t pte)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	return pte_set_flags(pte, _PAGE_SPECIAL|_PAGE_DEVMAP);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic inline pmd_t pmd_set_flags(pmd_t pmd, pmdval_t set)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	pmdval_t v = native_pmd_val(pmd);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	return native_make_pmd(v | set);
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic inline pmd_t pmd_clear_flags(pmd_t pmd, pmdval_t clear)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	pmdval_t v = native_pmd_val(pmd);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	return native_make_pmd(v & ~clear);
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci/* See comments above mksaveddirty_shift() */
50862306a36Sopenharmony_cistatic inline pmd_t pmd_mksaveddirty(pmd_t pmd)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	pmdval_t v = native_pmd_val(pmd);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	v = mksaveddirty_shift(v);
51362306a36Sopenharmony_ci	return native_make_pmd(v);
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci/* See comments above mksaveddirty_shift() */
51762306a36Sopenharmony_cistatic inline pmd_t pmd_clear_saveddirty(pmd_t pmd)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	pmdval_t v = native_pmd_val(pmd);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	v = clear_saveddirty_shift(v);
52262306a36Sopenharmony_ci	return native_make_pmd(v);
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_cistatic inline pmd_t pmd_wrprotect(pmd_t pmd)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	pmd = pmd_clear_flags(pmd, _PAGE_RW);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	/*
53062306a36Sopenharmony_ci	 * Blindly clearing _PAGE_RW might accidentally create
53162306a36Sopenharmony_ci	 * a shadow stack PMD (RW=0, Dirty=1). Move the hardware
53262306a36Sopenharmony_ci	 * dirty value to the software bit.
53362306a36Sopenharmony_ci	 */
53462306a36Sopenharmony_ci	return pmd_mksaveddirty(pmd);
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
53862306a36Sopenharmony_cistatic inline int pmd_uffd_wp(pmd_t pmd)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	return pmd_flags(pmd) & _PAGE_UFFD_WP;
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic inline pmd_t pmd_mkuffd_wp(pmd_t pmd)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	return pmd_wrprotect(pmd_set_flags(pmd, _PAGE_UFFD_WP));
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistatic inline pmd_t pmd_clear_uffd_wp(pmd_t pmd)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	return pmd_clear_flags(pmd, _PAGE_UFFD_WP);
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic inline pmd_t pmd_mkold(pmd_t pmd)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	return pmd_clear_flags(pmd, _PAGE_ACCESSED);
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic inline pmd_t pmd_mkclean(pmd_t pmd)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	return pmd_clear_flags(pmd, _PAGE_DIRTY_BITS);
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic inline pmd_t pmd_mkdirty(pmd_t pmd)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	pmd = pmd_set_flags(pmd, _PAGE_DIRTY | _PAGE_SOFT_DIRTY);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	return pmd_mksaveddirty(pmd);
56962306a36Sopenharmony_ci}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_cistatic inline pmd_t pmd_mkwrite_shstk(pmd_t pmd)
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	pmd = pmd_clear_flags(pmd, _PAGE_RW);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	return pmd_set_flags(pmd, _PAGE_DIRTY);
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cistatic inline pmd_t pmd_mkdevmap(pmd_t pmd)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	return pmd_set_flags(pmd, _PAGE_DEVMAP);
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic inline pmd_t pmd_mkhuge(pmd_t pmd)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	return pmd_set_flags(pmd, _PAGE_PSE);
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cistatic inline pmd_t pmd_mkyoung(pmd_t pmd)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	return pmd_set_flags(pmd, _PAGE_ACCESSED);
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic inline pmd_t pmd_mkwrite_novma(pmd_t pmd)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	return pmd_set_flags(pmd, _PAGE_RW);
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cipmd_t pmd_mkwrite(pmd_t pmd, struct vm_area_struct *vma);
59962306a36Sopenharmony_ci#define pmd_mkwrite pmd_mkwrite
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cistatic inline pud_t pud_set_flags(pud_t pud, pudval_t set)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	pudval_t v = native_pud_val(pud);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	return native_make_pud(v | set);
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic inline pud_t pud_clear_flags(pud_t pud, pudval_t clear)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	pudval_t v = native_pud_val(pud);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	return native_make_pud(v & ~clear);
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci/* See comments above mksaveddirty_shift() */
61662306a36Sopenharmony_cistatic inline pud_t pud_mksaveddirty(pud_t pud)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	pudval_t v = native_pud_val(pud);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	v = mksaveddirty_shift(v);
62162306a36Sopenharmony_ci	return native_make_pud(v);
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci/* See comments above mksaveddirty_shift() */
62562306a36Sopenharmony_cistatic inline pud_t pud_clear_saveddirty(pud_t pud)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	pudval_t v = native_pud_val(pud);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	v = clear_saveddirty_shift(v);
63062306a36Sopenharmony_ci	return native_make_pud(v);
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic inline pud_t pud_mkold(pud_t pud)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	return pud_clear_flags(pud, _PAGE_ACCESSED);
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic inline pud_t pud_mkclean(pud_t pud)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	return pud_clear_flags(pud, _PAGE_DIRTY_BITS);
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_cistatic inline pud_t pud_wrprotect(pud_t pud)
64462306a36Sopenharmony_ci{
64562306a36Sopenharmony_ci	pud = pud_clear_flags(pud, _PAGE_RW);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	/*
64862306a36Sopenharmony_ci	 * Blindly clearing _PAGE_RW might accidentally create
64962306a36Sopenharmony_ci	 * a shadow stack PUD (RW=0, Dirty=1). Move the hardware
65062306a36Sopenharmony_ci	 * dirty value to the software bit.
65162306a36Sopenharmony_ci	 */
65262306a36Sopenharmony_ci	return pud_mksaveddirty(pud);
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cistatic inline pud_t pud_mkdirty(pud_t pud)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	pud = pud_set_flags(pud, _PAGE_DIRTY | _PAGE_SOFT_DIRTY);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	return pud_mksaveddirty(pud);
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistatic inline pud_t pud_mkdevmap(pud_t pud)
66362306a36Sopenharmony_ci{
66462306a36Sopenharmony_ci	return pud_set_flags(pud, _PAGE_DEVMAP);
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic inline pud_t pud_mkhuge(pud_t pud)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	return pud_set_flags(pud, _PAGE_PSE);
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cistatic inline pud_t pud_mkyoung(pud_t pud)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	return pud_set_flags(pud, _PAGE_ACCESSED);
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_cistatic inline pud_t pud_mkwrite(pud_t pud)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	pud = pud_set_flags(pud, _PAGE_RW);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	return pud_clear_saveddirty(pud);
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY
68562306a36Sopenharmony_cistatic inline int pte_soft_dirty(pte_t pte)
68662306a36Sopenharmony_ci{
68762306a36Sopenharmony_ci	return pte_flags(pte) & _PAGE_SOFT_DIRTY;
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_cistatic inline int pmd_soft_dirty(pmd_t pmd)
69162306a36Sopenharmony_ci{
69262306a36Sopenharmony_ci	return pmd_flags(pmd) & _PAGE_SOFT_DIRTY;
69362306a36Sopenharmony_ci}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_cistatic inline int pud_soft_dirty(pud_t pud)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	return pud_flags(pud) & _PAGE_SOFT_DIRTY;
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cistatic inline pte_t pte_mksoft_dirty(pte_t pte)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	return pte_set_flags(pte, _PAGE_SOFT_DIRTY);
70362306a36Sopenharmony_ci}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_cistatic inline pmd_t pmd_mksoft_dirty(pmd_t pmd)
70662306a36Sopenharmony_ci{
70762306a36Sopenharmony_ci	return pmd_set_flags(pmd, _PAGE_SOFT_DIRTY);
70862306a36Sopenharmony_ci}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_cistatic inline pud_t pud_mksoft_dirty(pud_t pud)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	return pud_set_flags(pud, _PAGE_SOFT_DIRTY);
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_cistatic inline pte_t pte_clear_soft_dirty(pte_t pte)
71662306a36Sopenharmony_ci{
71762306a36Sopenharmony_ci	return pte_clear_flags(pte, _PAGE_SOFT_DIRTY);
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic inline pmd_t pmd_clear_soft_dirty(pmd_t pmd)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	return pmd_clear_flags(pmd, _PAGE_SOFT_DIRTY);
72362306a36Sopenharmony_ci}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_cistatic inline pud_t pud_clear_soft_dirty(pud_t pud)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	return pud_clear_flags(pud, _PAGE_SOFT_DIRTY);
72862306a36Sopenharmony_ci}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci#endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci/*
73362306a36Sopenharmony_ci * Mask out unsupported bits in a present pgprot.  Non-present pgprots
73462306a36Sopenharmony_ci * can use those bits for other purposes, so leave them be.
73562306a36Sopenharmony_ci */
73662306a36Sopenharmony_cistatic inline pgprotval_t massage_pgprot(pgprot_t pgprot)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	pgprotval_t protval = pgprot_val(pgprot);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	if (protval & _PAGE_PRESENT)
74162306a36Sopenharmony_ci		protval &= __supported_pte_mask;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	return protval;
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic inline pgprotval_t check_pgprot(pgprot_t pgprot)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	pgprotval_t massaged_val = massage_pgprot(pgprot);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	/* mmdebug.h can not be included here because of dependencies */
75162306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_VM
75262306a36Sopenharmony_ci	WARN_ONCE(pgprot_val(pgprot) != massaged_val,
75362306a36Sopenharmony_ci		  "attempted to set unsupported pgprot: %016llx "
75462306a36Sopenharmony_ci		  "bits: %016llx supported: %016llx\n",
75562306a36Sopenharmony_ci		  (u64)pgprot_val(pgprot),
75662306a36Sopenharmony_ci		  (u64)pgprot_val(pgprot) ^ massaged_val,
75762306a36Sopenharmony_ci		  (u64)__supported_pte_mask);
75862306a36Sopenharmony_ci#endif
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	return massaged_val;
76162306a36Sopenharmony_ci}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_cistatic inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	phys_addr_t pfn = (phys_addr_t)page_nr << PAGE_SHIFT;
76662306a36Sopenharmony_ci	pfn ^= protnone_mask(pgprot_val(pgprot));
76762306a36Sopenharmony_ci	pfn &= PTE_PFN_MASK;
76862306a36Sopenharmony_ci	return __pte(pfn | check_pgprot(pgprot));
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_cistatic inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	phys_addr_t pfn = (phys_addr_t)page_nr << PAGE_SHIFT;
77462306a36Sopenharmony_ci	pfn ^= protnone_mask(pgprot_val(pgprot));
77562306a36Sopenharmony_ci	pfn &= PHYSICAL_PMD_PAGE_MASK;
77662306a36Sopenharmony_ci	return __pmd(pfn | check_pgprot(pgprot));
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic inline pud_t pfn_pud(unsigned long page_nr, pgprot_t pgprot)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci	phys_addr_t pfn = (phys_addr_t)page_nr << PAGE_SHIFT;
78262306a36Sopenharmony_ci	pfn ^= protnone_mask(pgprot_val(pgprot));
78362306a36Sopenharmony_ci	pfn &= PHYSICAL_PUD_PAGE_MASK;
78462306a36Sopenharmony_ci	return __pud(pfn | check_pgprot(pgprot));
78562306a36Sopenharmony_ci}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cistatic inline pmd_t pmd_mkinvalid(pmd_t pmd)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	return pfn_pmd(pmd_pfn(pmd),
79062306a36Sopenharmony_ci		      __pgprot(pmd_flags(pmd) & ~(_PAGE_PRESENT|_PAGE_PROTNONE)));
79162306a36Sopenharmony_ci}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_cistatic inline u64 flip_protnone_guard(u64 oldval, u64 val, u64 mask);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_cistatic inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
79662306a36Sopenharmony_ci{
79762306a36Sopenharmony_ci	pteval_t val = pte_val(pte), oldval = val;
79862306a36Sopenharmony_ci	pte_t pte_result;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	/*
80162306a36Sopenharmony_ci	 * Chop off the NX bit (if present), and add the NX portion of
80262306a36Sopenharmony_ci	 * the newprot (if present):
80362306a36Sopenharmony_ci	 */
80462306a36Sopenharmony_ci	val &= _PAGE_CHG_MASK;
80562306a36Sopenharmony_ci	val |= check_pgprot(newprot) & ~_PAGE_CHG_MASK;
80662306a36Sopenharmony_ci	val = flip_protnone_guard(oldval, val, PTE_PFN_MASK);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	pte_result = __pte(val);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	/*
81162306a36Sopenharmony_ci	 * To avoid creating Write=0,Dirty=1 PTEs, pte_modify() needs to avoid:
81262306a36Sopenharmony_ci	 *  1. Marking Write=0 PTEs Dirty=1
81362306a36Sopenharmony_ci	 *  2. Marking Dirty=1 PTEs Write=0
81462306a36Sopenharmony_ci	 *
81562306a36Sopenharmony_ci	 * The first case cannot happen because the _PAGE_CHG_MASK will filter
81662306a36Sopenharmony_ci	 * out any Dirty bit passed in newprot. Handle the second case by
81762306a36Sopenharmony_ci	 * going through the mksaveddirty exercise. Only do this if the old
81862306a36Sopenharmony_ci	 * value was Write=1 to avoid doing this on Shadow Stack PTEs.
81962306a36Sopenharmony_ci	 */
82062306a36Sopenharmony_ci	if (oldval & _PAGE_RW)
82162306a36Sopenharmony_ci		pte_result = pte_mksaveddirty(pte_result);
82262306a36Sopenharmony_ci	else
82362306a36Sopenharmony_ci		pte_result = pte_clear_saveddirty(pte_result);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	return pte_result;
82662306a36Sopenharmony_ci}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_cistatic inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
82962306a36Sopenharmony_ci{
83062306a36Sopenharmony_ci	pmdval_t val = pmd_val(pmd), oldval = val;
83162306a36Sopenharmony_ci	pmd_t pmd_result;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	val &= (_HPAGE_CHG_MASK & ~_PAGE_DIRTY);
83462306a36Sopenharmony_ci	val |= check_pgprot(newprot) & ~_HPAGE_CHG_MASK;
83562306a36Sopenharmony_ci	val = flip_protnone_guard(oldval, val, PHYSICAL_PMD_PAGE_MASK);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	pmd_result = __pmd(val);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	/*
84062306a36Sopenharmony_ci	 * To avoid creating Write=0,Dirty=1 PMDs, pte_modify() needs to avoid:
84162306a36Sopenharmony_ci	 *  1. Marking Write=0 PMDs Dirty=1
84262306a36Sopenharmony_ci	 *  2. Marking Dirty=1 PMDs Write=0
84362306a36Sopenharmony_ci	 *
84462306a36Sopenharmony_ci	 * The first case cannot happen because the _PAGE_CHG_MASK will filter
84562306a36Sopenharmony_ci	 * out any Dirty bit passed in newprot. Handle the second case by
84662306a36Sopenharmony_ci	 * going through the mksaveddirty exercise. Only do this if the old
84762306a36Sopenharmony_ci	 * value was Write=1 to avoid doing this on Shadow Stack PTEs.
84862306a36Sopenharmony_ci	 */
84962306a36Sopenharmony_ci	if (oldval & _PAGE_RW)
85062306a36Sopenharmony_ci		pmd_result = pmd_mksaveddirty(pmd_result);
85162306a36Sopenharmony_ci	else
85262306a36Sopenharmony_ci		pmd_result = pmd_clear_saveddirty(pmd_result);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	return pmd_result;
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci/*
85862306a36Sopenharmony_ci * mprotect needs to preserve PAT and encryption bits when updating
85962306a36Sopenharmony_ci * vm_page_prot
86062306a36Sopenharmony_ci */
86162306a36Sopenharmony_ci#define pgprot_modify pgprot_modify
86262306a36Sopenharmony_cistatic inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	pgprotval_t preservebits = pgprot_val(oldprot) & _PAGE_CHG_MASK;
86562306a36Sopenharmony_ci	pgprotval_t addbits = pgprot_val(newprot) & ~_PAGE_CHG_MASK;
86662306a36Sopenharmony_ci	return __pgprot(preservebits | addbits);
86762306a36Sopenharmony_ci}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci#define pte_pgprot(x) __pgprot(pte_flags(x))
87062306a36Sopenharmony_ci#define pmd_pgprot(x) __pgprot(pmd_flags(x))
87162306a36Sopenharmony_ci#define pud_pgprot(x) __pgprot(pud_flags(x))
87262306a36Sopenharmony_ci#define p4d_pgprot(x) __pgprot(p4d_flags(x))
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci#define canon_pgprot(p) __pgprot(massage_pgprot(p))
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_cistatic inline int is_new_memtype_allowed(u64 paddr, unsigned long size,
87762306a36Sopenharmony_ci					 enum page_cache_mode pcm,
87862306a36Sopenharmony_ci					 enum page_cache_mode new_pcm)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	/*
88162306a36Sopenharmony_ci	 * PAT type is always WB for untracked ranges, so no need to check.
88262306a36Sopenharmony_ci	 */
88362306a36Sopenharmony_ci	if (x86_platform.is_untracked_pat_range(paddr, paddr + size))
88462306a36Sopenharmony_ci		return 1;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	/*
88762306a36Sopenharmony_ci	 * Certain new memtypes are not allowed with certain
88862306a36Sopenharmony_ci	 * requested memtype:
88962306a36Sopenharmony_ci	 * - request is uncached, return cannot be write-back
89062306a36Sopenharmony_ci	 * - request is write-combine, return cannot be write-back
89162306a36Sopenharmony_ci	 * - request is write-through, return cannot be write-back
89262306a36Sopenharmony_ci	 * - request is write-through, return cannot be write-combine
89362306a36Sopenharmony_ci	 */
89462306a36Sopenharmony_ci	if ((pcm == _PAGE_CACHE_MODE_UC_MINUS &&
89562306a36Sopenharmony_ci	     new_pcm == _PAGE_CACHE_MODE_WB) ||
89662306a36Sopenharmony_ci	    (pcm == _PAGE_CACHE_MODE_WC &&
89762306a36Sopenharmony_ci	     new_pcm == _PAGE_CACHE_MODE_WB) ||
89862306a36Sopenharmony_ci	    (pcm == _PAGE_CACHE_MODE_WT &&
89962306a36Sopenharmony_ci	     new_pcm == _PAGE_CACHE_MODE_WB) ||
90062306a36Sopenharmony_ci	    (pcm == _PAGE_CACHE_MODE_WT &&
90162306a36Sopenharmony_ci	     new_pcm == _PAGE_CACHE_MODE_WC)) {
90262306a36Sopenharmony_ci		return 0;
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	return 1;
90662306a36Sopenharmony_ci}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_cipmd_t *populate_extra_pmd(unsigned long vaddr);
90962306a36Sopenharmony_cipte_t *populate_extra_pte(unsigned long vaddr);
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci#ifdef CONFIG_PAGE_TABLE_ISOLATION
91262306a36Sopenharmony_cipgd_t __pti_set_user_pgtbl(pgd_t *pgdp, pgd_t pgd);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci/*
91562306a36Sopenharmony_ci * Take a PGD location (pgdp) and a pgd value that needs to be set there.
91662306a36Sopenharmony_ci * Populates the user and returns the resulting PGD that must be set in
91762306a36Sopenharmony_ci * the kernel copy of the page tables.
91862306a36Sopenharmony_ci */
91962306a36Sopenharmony_cistatic inline pgd_t pti_set_user_pgtbl(pgd_t *pgdp, pgd_t pgd)
92062306a36Sopenharmony_ci{
92162306a36Sopenharmony_ci	if (!static_cpu_has(X86_FEATURE_PTI))
92262306a36Sopenharmony_ci		return pgd;
92362306a36Sopenharmony_ci	return __pti_set_user_pgtbl(pgdp, pgd);
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci#else   /* CONFIG_PAGE_TABLE_ISOLATION */
92662306a36Sopenharmony_cistatic inline pgd_t pti_set_user_pgtbl(pgd_t *pgdp, pgd_t pgd)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	return pgd;
92962306a36Sopenharmony_ci}
93062306a36Sopenharmony_ci#endif  /* CONFIG_PAGE_TABLE_ISOLATION */
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci#endif	/* __ASSEMBLY__ */
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci#ifdef CONFIG_X86_32
93662306a36Sopenharmony_ci# include <asm/pgtable_32.h>
93762306a36Sopenharmony_ci#else
93862306a36Sopenharmony_ci# include <asm/pgtable_64.h>
93962306a36Sopenharmony_ci#endif
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci#ifndef __ASSEMBLY__
94262306a36Sopenharmony_ci#include <linux/mm_types.h>
94362306a36Sopenharmony_ci#include <linux/mmdebug.h>
94462306a36Sopenharmony_ci#include <linux/log2.h>
94562306a36Sopenharmony_ci#include <asm/fixmap.h>
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_cistatic inline int pte_none(pte_t pte)
94862306a36Sopenharmony_ci{
94962306a36Sopenharmony_ci	return !(pte.pte & ~(_PAGE_KNL_ERRATUM_MASK));
95062306a36Sopenharmony_ci}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci#define __HAVE_ARCH_PTE_SAME
95362306a36Sopenharmony_cistatic inline int pte_same(pte_t a, pte_t b)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	return a.pte == b.pte;
95662306a36Sopenharmony_ci}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_cistatic inline pte_t pte_next_pfn(pte_t pte)
95962306a36Sopenharmony_ci{
96062306a36Sopenharmony_ci	if (__pte_needs_invert(pte_val(pte)))
96162306a36Sopenharmony_ci		return __pte(pte_val(pte) - (1UL << PFN_PTE_SHIFT));
96262306a36Sopenharmony_ci	return __pte(pte_val(pte) + (1UL << PFN_PTE_SHIFT));
96362306a36Sopenharmony_ci}
96462306a36Sopenharmony_ci#define pte_next_pfn	pte_next_pfn
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_cistatic inline int pte_present(pte_t a)
96762306a36Sopenharmony_ci{
96862306a36Sopenharmony_ci	return pte_flags(a) & (_PAGE_PRESENT | _PAGE_PROTNONE);
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci#ifdef CONFIG_ARCH_HAS_PTE_DEVMAP
97262306a36Sopenharmony_cistatic inline int pte_devmap(pte_t a)
97362306a36Sopenharmony_ci{
97462306a36Sopenharmony_ci	return (pte_flags(a) & _PAGE_DEVMAP) == _PAGE_DEVMAP;
97562306a36Sopenharmony_ci}
97662306a36Sopenharmony_ci#endif
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci#define pte_accessible pte_accessible
97962306a36Sopenharmony_cistatic inline bool pte_accessible(struct mm_struct *mm, pte_t a)
98062306a36Sopenharmony_ci{
98162306a36Sopenharmony_ci	if (pte_flags(a) & _PAGE_PRESENT)
98262306a36Sopenharmony_ci		return true;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	if ((pte_flags(a) & _PAGE_PROTNONE) &&
98562306a36Sopenharmony_ci			atomic_read(&mm->tlb_flush_pending))
98662306a36Sopenharmony_ci		return true;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	return false;
98962306a36Sopenharmony_ci}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_cistatic inline int pmd_present(pmd_t pmd)
99262306a36Sopenharmony_ci{
99362306a36Sopenharmony_ci	/*
99462306a36Sopenharmony_ci	 * Checking for _PAGE_PSE is needed too because
99562306a36Sopenharmony_ci	 * split_huge_page will temporarily clear the present bit (but
99662306a36Sopenharmony_ci	 * the _PAGE_PSE flag will remain set at all times while the
99762306a36Sopenharmony_ci	 * _PAGE_PRESENT bit is clear).
99862306a36Sopenharmony_ci	 */
99962306a36Sopenharmony_ci	return pmd_flags(pmd) & (_PAGE_PRESENT | _PAGE_PROTNONE | _PAGE_PSE);
100062306a36Sopenharmony_ci}
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci#ifdef CONFIG_NUMA_BALANCING
100362306a36Sopenharmony_ci/*
100462306a36Sopenharmony_ci * These work without NUMA balancing but the kernel does not care. See the
100562306a36Sopenharmony_ci * comment in include/linux/pgtable.h
100662306a36Sopenharmony_ci */
100762306a36Sopenharmony_cistatic inline int pte_protnone(pte_t pte)
100862306a36Sopenharmony_ci{
100962306a36Sopenharmony_ci	return (pte_flags(pte) & (_PAGE_PROTNONE | _PAGE_PRESENT))
101062306a36Sopenharmony_ci		== _PAGE_PROTNONE;
101162306a36Sopenharmony_ci}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_cistatic inline int pmd_protnone(pmd_t pmd)
101462306a36Sopenharmony_ci{
101562306a36Sopenharmony_ci	return (pmd_flags(pmd) & (_PAGE_PROTNONE | _PAGE_PRESENT))
101662306a36Sopenharmony_ci		== _PAGE_PROTNONE;
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci#endif /* CONFIG_NUMA_BALANCING */
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_cistatic inline int pmd_none(pmd_t pmd)
102162306a36Sopenharmony_ci{
102262306a36Sopenharmony_ci	/* Only check low word on 32-bit platforms, since it might be
102362306a36Sopenharmony_ci	   out of sync with upper half. */
102462306a36Sopenharmony_ci	unsigned long val = native_pmd_val(pmd);
102562306a36Sopenharmony_ci	return (val & ~_PAGE_KNL_ERRATUM_MASK) == 0;
102662306a36Sopenharmony_ci}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_cistatic inline unsigned long pmd_page_vaddr(pmd_t pmd)
102962306a36Sopenharmony_ci{
103062306a36Sopenharmony_ci	return (unsigned long)__va(pmd_val(pmd) & pmd_pfn_mask(pmd));
103162306a36Sopenharmony_ci}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci/*
103462306a36Sopenharmony_ci * Currently stuck as a macro due to indirect forward reference to
103562306a36Sopenharmony_ci * linux/mmzone.h's __section_mem_map_addr() definition:
103662306a36Sopenharmony_ci */
103762306a36Sopenharmony_ci#define pmd_page(pmd)	pfn_to_page(pmd_pfn(pmd))
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci/*
104062306a36Sopenharmony_ci * Conversion functions: convert a page and protection to a page entry,
104162306a36Sopenharmony_ci * and a page entry and page directory to the page they refer to.
104262306a36Sopenharmony_ci *
104362306a36Sopenharmony_ci * (Currently stuck as a macro because of indirect forward reference
104462306a36Sopenharmony_ci * to linux/mm.h:page_to_nid())
104562306a36Sopenharmony_ci */
104662306a36Sopenharmony_ci#define mk_pte(page, pgprot)						  \
104762306a36Sopenharmony_ci({									  \
104862306a36Sopenharmony_ci	pgprot_t __pgprot = pgprot;					  \
104962306a36Sopenharmony_ci									  \
105062306a36Sopenharmony_ci	WARN_ON_ONCE((pgprot_val(__pgprot) & (_PAGE_DIRTY | _PAGE_RW)) == \
105162306a36Sopenharmony_ci		    _PAGE_DIRTY);					  \
105262306a36Sopenharmony_ci	pfn_pte(page_to_pfn(page), __pgprot);				  \
105362306a36Sopenharmony_ci})
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_cistatic inline int pmd_bad(pmd_t pmd)
105662306a36Sopenharmony_ci{
105762306a36Sopenharmony_ci	return (pmd_flags(pmd) & ~(_PAGE_USER | _PAGE_ACCESSED)) !=
105862306a36Sopenharmony_ci	       (_KERNPG_TABLE & ~_PAGE_ACCESSED);
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_cistatic inline unsigned long pages_to_mb(unsigned long npg)
106262306a36Sopenharmony_ci{
106362306a36Sopenharmony_ci	return npg >> (20 - PAGE_SHIFT);
106462306a36Sopenharmony_ci}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 2
106762306a36Sopenharmony_cistatic inline int pud_none(pud_t pud)
106862306a36Sopenharmony_ci{
106962306a36Sopenharmony_ci	return (native_pud_val(pud) & ~(_PAGE_KNL_ERRATUM_MASK)) == 0;
107062306a36Sopenharmony_ci}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_cistatic inline int pud_present(pud_t pud)
107362306a36Sopenharmony_ci{
107462306a36Sopenharmony_ci	return pud_flags(pud) & _PAGE_PRESENT;
107562306a36Sopenharmony_ci}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_cistatic inline pmd_t *pud_pgtable(pud_t pud)
107862306a36Sopenharmony_ci{
107962306a36Sopenharmony_ci	return (pmd_t *)__va(pud_val(pud) & pud_pfn_mask(pud));
108062306a36Sopenharmony_ci}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci/*
108362306a36Sopenharmony_ci * Currently stuck as a macro due to indirect forward reference to
108462306a36Sopenharmony_ci * linux/mmzone.h's __section_mem_map_addr() definition:
108562306a36Sopenharmony_ci */
108662306a36Sopenharmony_ci#define pud_page(pud)	pfn_to_page(pud_pfn(pud))
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci#define pud_leaf	pud_large
108962306a36Sopenharmony_cistatic inline int pud_large(pud_t pud)
109062306a36Sopenharmony_ci{
109162306a36Sopenharmony_ci	return (pud_val(pud) & (_PAGE_PSE | _PAGE_PRESENT)) ==
109262306a36Sopenharmony_ci		(_PAGE_PSE | _PAGE_PRESENT);
109362306a36Sopenharmony_ci}
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_cistatic inline int pud_bad(pud_t pud)
109662306a36Sopenharmony_ci{
109762306a36Sopenharmony_ci	return (pud_flags(pud) & ~(_KERNPG_TABLE | _PAGE_USER)) != 0;
109862306a36Sopenharmony_ci}
109962306a36Sopenharmony_ci#else
110062306a36Sopenharmony_ci#define pud_leaf	pud_large
110162306a36Sopenharmony_cistatic inline int pud_large(pud_t pud)
110262306a36Sopenharmony_ci{
110362306a36Sopenharmony_ci	return 0;
110462306a36Sopenharmony_ci}
110562306a36Sopenharmony_ci#endif	/* CONFIG_PGTABLE_LEVELS > 2 */
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 3
110862306a36Sopenharmony_cistatic inline int p4d_none(p4d_t p4d)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci	return (native_p4d_val(p4d) & ~(_PAGE_KNL_ERRATUM_MASK)) == 0;
111162306a36Sopenharmony_ci}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_cistatic inline int p4d_present(p4d_t p4d)
111462306a36Sopenharmony_ci{
111562306a36Sopenharmony_ci	return p4d_flags(p4d) & _PAGE_PRESENT;
111662306a36Sopenharmony_ci}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_cistatic inline pud_t *p4d_pgtable(p4d_t p4d)
111962306a36Sopenharmony_ci{
112062306a36Sopenharmony_ci	return (pud_t *)__va(p4d_val(p4d) & p4d_pfn_mask(p4d));
112162306a36Sopenharmony_ci}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci/*
112462306a36Sopenharmony_ci * Currently stuck as a macro due to indirect forward reference to
112562306a36Sopenharmony_ci * linux/mmzone.h's __section_mem_map_addr() definition:
112662306a36Sopenharmony_ci */
112762306a36Sopenharmony_ci#define p4d_page(p4d)	pfn_to_page(p4d_pfn(p4d))
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_cistatic inline int p4d_bad(p4d_t p4d)
113062306a36Sopenharmony_ci{
113162306a36Sopenharmony_ci	unsigned long ignore_flags = _KERNPG_TABLE | _PAGE_USER;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION))
113462306a36Sopenharmony_ci		ignore_flags |= _PAGE_NX;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	return (p4d_flags(p4d) & ~ignore_flags) != 0;
113762306a36Sopenharmony_ci}
113862306a36Sopenharmony_ci#endif  /* CONFIG_PGTABLE_LEVELS > 3 */
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_cistatic inline unsigned long p4d_index(unsigned long address)
114162306a36Sopenharmony_ci{
114262306a36Sopenharmony_ci	return (address >> P4D_SHIFT) & (PTRS_PER_P4D - 1);
114362306a36Sopenharmony_ci}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 4
114662306a36Sopenharmony_cistatic inline int pgd_present(pgd_t pgd)
114762306a36Sopenharmony_ci{
114862306a36Sopenharmony_ci	if (!pgtable_l5_enabled())
114962306a36Sopenharmony_ci		return 1;
115062306a36Sopenharmony_ci	return pgd_flags(pgd) & _PAGE_PRESENT;
115162306a36Sopenharmony_ci}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_cistatic inline unsigned long pgd_page_vaddr(pgd_t pgd)
115462306a36Sopenharmony_ci{
115562306a36Sopenharmony_ci	return (unsigned long)__va((unsigned long)pgd_val(pgd) & PTE_PFN_MASK);
115662306a36Sopenharmony_ci}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci/*
115962306a36Sopenharmony_ci * Currently stuck as a macro due to indirect forward reference to
116062306a36Sopenharmony_ci * linux/mmzone.h's __section_mem_map_addr() definition:
116162306a36Sopenharmony_ci */
116262306a36Sopenharmony_ci#define pgd_page(pgd)	pfn_to_page(pgd_pfn(pgd))
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci/* to find an entry in a page-table-directory. */
116562306a36Sopenharmony_cistatic inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
116662306a36Sopenharmony_ci{
116762306a36Sopenharmony_ci	if (!pgtable_l5_enabled())
116862306a36Sopenharmony_ci		return (p4d_t *)pgd;
116962306a36Sopenharmony_ci	return (p4d_t *)pgd_page_vaddr(*pgd) + p4d_index(address);
117062306a36Sopenharmony_ci}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_cistatic inline int pgd_bad(pgd_t pgd)
117362306a36Sopenharmony_ci{
117462306a36Sopenharmony_ci	unsigned long ignore_flags = _PAGE_USER;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	if (!pgtable_l5_enabled())
117762306a36Sopenharmony_ci		return 0;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION))
118062306a36Sopenharmony_ci		ignore_flags |= _PAGE_NX;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	return (pgd_flags(pgd) & ~ignore_flags) != _KERNPG_TABLE;
118362306a36Sopenharmony_ci}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_cistatic inline int pgd_none(pgd_t pgd)
118662306a36Sopenharmony_ci{
118762306a36Sopenharmony_ci	if (!pgtable_l5_enabled())
118862306a36Sopenharmony_ci		return 0;
118962306a36Sopenharmony_ci	/*
119062306a36Sopenharmony_ci	 * There is no need to do a workaround for the KNL stray
119162306a36Sopenharmony_ci	 * A/D bit erratum here.  PGDs only point to page tables
119262306a36Sopenharmony_ci	 * except on 32-bit non-PAE which is not supported on
119362306a36Sopenharmony_ci	 * KNL.
119462306a36Sopenharmony_ci	 */
119562306a36Sopenharmony_ci	return !native_pgd_val(pgd);
119662306a36Sopenharmony_ci}
119762306a36Sopenharmony_ci#endif	/* CONFIG_PGTABLE_LEVELS > 4 */
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci#endif	/* __ASSEMBLY__ */
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci#define KERNEL_PGD_BOUNDARY	pgd_index(PAGE_OFFSET)
120262306a36Sopenharmony_ci#define KERNEL_PGD_PTRS		(PTRS_PER_PGD - KERNEL_PGD_BOUNDARY)
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci#ifndef __ASSEMBLY__
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ciextern int direct_gbpages;
120762306a36Sopenharmony_civoid init_mem_mapping(void);
120862306a36Sopenharmony_civoid early_alloc_pgt_buf(void);
120962306a36Sopenharmony_ciextern void memblock_find_dma_reserve(void);
121062306a36Sopenharmony_civoid __init poking_init(void);
121162306a36Sopenharmony_ciunsigned long init_memory_mapping(unsigned long start,
121262306a36Sopenharmony_ci				  unsigned long end, pgprot_t prot);
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci#ifdef CONFIG_X86_64
121562306a36Sopenharmony_ciextern pgd_t trampoline_pgd_entry;
121662306a36Sopenharmony_ci#endif
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci/* local pte updates need not use xchg for locking */
121962306a36Sopenharmony_cistatic inline pte_t native_local_ptep_get_and_clear(pte_t *ptep)
122062306a36Sopenharmony_ci{
122162306a36Sopenharmony_ci	pte_t res = *ptep;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	/* Pure native function needs no input for mm, addr */
122462306a36Sopenharmony_ci	native_pte_clear(NULL, 0, ptep);
122562306a36Sopenharmony_ci	return res;
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cistatic inline pmd_t native_local_pmdp_get_and_clear(pmd_t *pmdp)
122962306a36Sopenharmony_ci{
123062306a36Sopenharmony_ci	pmd_t res = *pmdp;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	native_pmd_clear(pmdp);
123362306a36Sopenharmony_ci	return res;
123462306a36Sopenharmony_ci}
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_cistatic inline pud_t native_local_pudp_get_and_clear(pud_t *pudp)
123762306a36Sopenharmony_ci{
123862306a36Sopenharmony_ci	pud_t res = *pudp;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	native_pud_clear(pudp);
124162306a36Sopenharmony_ci	return res;
124262306a36Sopenharmony_ci}
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_cistatic inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
124562306a36Sopenharmony_ci			      pmd_t *pmdp, pmd_t pmd)
124662306a36Sopenharmony_ci{
124762306a36Sopenharmony_ci	page_table_check_pmd_set(mm, pmdp, pmd);
124862306a36Sopenharmony_ci	set_pmd(pmdp, pmd);
124962306a36Sopenharmony_ci}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cistatic inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
125262306a36Sopenharmony_ci			      pud_t *pudp, pud_t pud)
125362306a36Sopenharmony_ci{
125462306a36Sopenharmony_ci	page_table_check_pud_set(mm, pudp, pud);
125562306a36Sopenharmony_ci	native_set_pud(pudp, pud);
125662306a36Sopenharmony_ci}
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci/*
125962306a36Sopenharmony_ci * We only update the dirty/accessed state if we set
126062306a36Sopenharmony_ci * the dirty bit by hand in the kernel, since the hardware
126162306a36Sopenharmony_ci * will do the accessed bit for us, and we don't want to
126262306a36Sopenharmony_ci * race with other CPU's that might be updating the dirty
126362306a36Sopenharmony_ci * bit at the same time.
126462306a36Sopenharmony_ci */
126562306a36Sopenharmony_cistruct vm_area_struct;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci#define  __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
126862306a36Sopenharmony_ciextern int ptep_set_access_flags(struct vm_area_struct *vma,
126962306a36Sopenharmony_ci				 unsigned long address, pte_t *ptep,
127062306a36Sopenharmony_ci				 pte_t entry, int dirty);
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
127362306a36Sopenharmony_ciextern int ptep_test_and_clear_young(struct vm_area_struct *vma,
127462306a36Sopenharmony_ci				     unsigned long addr, pte_t *ptep);
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
127762306a36Sopenharmony_ciextern int ptep_clear_flush_young(struct vm_area_struct *vma,
127862306a36Sopenharmony_ci				  unsigned long address, pte_t *ptep);
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
128162306a36Sopenharmony_cistatic inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
128262306a36Sopenharmony_ci				       pte_t *ptep)
128362306a36Sopenharmony_ci{
128462306a36Sopenharmony_ci	pte_t pte = native_ptep_get_and_clear(ptep);
128562306a36Sopenharmony_ci	page_table_check_pte_clear(mm, pte);
128662306a36Sopenharmony_ci	return pte;
128762306a36Sopenharmony_ci}
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
129062306a36Sopenharmony_cistatic inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
129162306a36Sopenharmony_ci					    unsigned long addr, pte_t *ptep,
129262306a36Sopenharmony_ci					    int full)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	pte_t pte;
129562306a36Sopenharmony_ci	if (full) {
129662306a36Sopenharmony_ci		/*
129762306a36Sopenharmony_ci		 * Full address destruction in progress; paravirt does not
129862306a36Sopenharmony_ci		 * care about updates and native needs no locking
129962306a36Sopenharmony_ci		 */
130062306a36Sopenharmony_ci		pte = native_local_ptep_get_and_clear(ptep);
130162306a36Sopenharmony_ci		page_table_check_pte_clear(mm, pte);
130262306a36Sopenharmony_ci	} else {
130362306a36Sopenharmony_ci		pte = ptep_get_and_clear(mm, addr, ptep);
130462306a36Sopenharmony_ci	}
130562306a36Sopenharmony_ci	return pte;
130662306a36Sopenharmony_ci}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_SET_WRPROTECT
130962306a36Sopenharmony_cistatic inline void ptep_set_wrprotect(struct mm_struct *mm,
131062306a36Sopenharmony_ci				      unsigned long addr, pte_t *ptep)
131162306a36Sopenharmony_ci{
131262306a36Sopenharmony_ci	/*
131362306a36Sopenharmony_ci	 * Avoid accidentally creating shadow stack PTEs
131462306a36Sopenharmony_ci	 * (Write=0,Dirty=1).  Use cmpxchg() to prevent races with
131562306a36Sopenharmony_ci	 * the hardware setting Dirty=1.
131662306a36Sopenharmony_ci	 */
131762306a36Sopenharmony_ci	pte_t old_pte, new_pte;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	old_pte = READ_ONCE(*ptep);
132062306a36Sopenharmony_ci	do {
132162306a36Sopenharmony_ci		new_pte = pte_wrprotect(old_pte);
132262306a36Sopenharmony_ci	} while (!try_cmpxchg((long *)&ptep->pte, (long *)&old_pte, *(long *)&new_pte));
132362306a36Sopenharmony_ci}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci#define flush_tlb_fix_spurious_fault(vma, address, ptep) do { } while (0)
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci#define mk_pmd(page, pgprot)   pfn_pmd(page_to_pfn(page), (pgprot))
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci#define  __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
133062306a36Sopenharmony_ciextern int pmdp_set_access_flags(struct vm_area_struct *vma,
133162306a36Sopenharmony_ci				 unsigned long address, pmd_t *pmdp,
133262306a36Sopenharmony_ci				 pmd_t entry, int dirty);
133362306a36Sopenharmony_ciextern int pudp_set_access_flags(struct vm_area_struct *vma,
133462306a36Sopenharmony_ci				 unsigned long address, pud_t *pudp,
133562306a36Sopenharmony_ci				 pud_t entry, int dirty);
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG
133862306a36Sopenharmony_ciextern int pmdp_test_and_clear_young(struct vm_area_struct *vma,
133962306a36Sopenharmony_ci				     unsigned long addr, pmd_t *pmdp);
134062306a36Sopenharmony_ciextern int pudp_test_and_clear_young(struct vm_area_struct *vma,
134162306a36Sopenharmony_ci				     unsigned long addr, pud_t *pudp);
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH
134462306a36Sopenharmony_ciextern int pmdp_clear_flush_young(struct vm_area_struct *vma,
134562306a36Sopenharmony_ci				  unsigned long address, pmd_t *pmdp);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR
134962306a36Sopenharmony_cistatic inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, unsigned long addr,
135062306a36Sopenharmony_ci				       pmd_t *pmdp)
135162306a36Sopenharmony_ci{
135262306a36Sopenharmony_ci	pmd_t pmd = native_pmdp_get_and_clear(pmdp);
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	page_table_check_pmd_clear(mm, pmd);
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	return pmd;
135762306a36Sopenharmony_ci}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci#define __HAVE_ARCH_PUDP_HUGE_GET_AND_CLEAR
136062306a36Sopenharmony_cistatic inline pud_t pudp_huge_get_and_clear(struct mm_struct *mm,
136162306a36Sopenharmony_ci					unsigned long addr, pud_t *pudp)
136262306a36Sopenharmony_ci{
136362306a36Sopenharmony_ci	pud_t pud = native_pudp_get_and_clear(pudp);
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	page_table_check_pud_clear(mm, pud);
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	return pud;
136862306a36Sopenharmony_ci}
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_SET_WRPROTECT
137162306a36Sopenharmony_cistatic inline void pmdp_set_wrprotect(struct mm_struct *mm,
137262306a36Sopenharmony_ci				      unsigned long addr, pmd_t *pmdp)
137362306a36Sopenharmony_ci{
137462306a36Sopenharmony_ci	/*
137562306a36Sopenharmony_ci	 * Avoid accidentally creating shadow stack PTEs
137662306a36Sopenharmony_ci	 * (Write=0,Dirty=1).  Use cmpxchg() to prevent races with
137762306a36Sopenharmony_ci	 * the hardware setting Dirty=1.
137862306a36Sopenharmony_ci	 */
137962306a36Sopenharmony_ci	pmd_t old_pmd, new_pmd;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	old_pmd = READ_ONCE(*pmdp);
138262306a36Sopenharmony_ci	do {
138362306a36Sopenharmony_ci		new_pmd = pmd_wrprotect(old_pmd);
138462306a36Sopenharmony_ci	} while (!try_cmpxchg((long *)pmdp, (long *)&old_pmd, *(long *)&new_pmd));
138562306a36Sopenharmony_ci}
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci#ifndef pmdp_establish
138862306a36Sopenharmony_ci#define pmdp_establish pmdp_establish
138962306a36Sopenharmony_cistatic inline pmd_t pmdp_establish(struct vm_area_struct *vma,
139062306a36Sopenharmony_ci		unsigned long address, pmd_t *pmdp, pmd_t pmd)
139162306a36Sopenharmony_ci{
139262306a36Sopenharmony_ci	page_table_check_pmd_set(vma->vm_mm, pmdp, pmd);
139362306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_SMP)) {
139462306a36Sopenharmony_ci		return xchg(pmdp, pmd);
139562306a36Sopenharmony_ci	} else {
139662306a36Sopenharmony_ci		pmd_t old = *pmdp;
139762306a36Sopenharmony_ci		WRITE_ONCE(*pmdp, pmd);
139862306a36Sopenharmony_ci		return old;
139962306a36Sopenharmony_ci	}
140062306a36Sopenharmony_ci}
140162306a36Sopenharmony_ci#endif
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_INVALIDATE_AD
140462306a36Sopenharmony_ciextern pmd_t pmdp_invalidate_ad(struct vm_area_struct *vma,
140562306a36Sopenharmony_ci				unsigned long address, pmd_t *pmdp);
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci/*
140862306a36Sopenharmony_ci * Page table pages are page-aligned.  The lower half of the top
140962306a36Sopenharmony_ci * level is used for userspace and the top half for the kernel.
141062306a36Sopenharmony_ci *
141162306a36Sopenharmony_ci * Returns true for parts of the PGD that map userspace and
141262306a36Sopenharmony_ci * false for the parts that map the kernel.
141362306a36Sopenharmony_ci */
141462306a36Sopenharmony_cistatic inline bool pgdp_maps_userspace(void *__ptr)
141562306a36Sopenharmony_ci{
141662306a36Sopenharmony_ci	unsigned long ptr = (unsigned long)__ptr;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	return (((ptr & ~PAGE_MASK) / sizeof(pgd_t)) < PGD_KERNEL_START);
141962306a36Sopenharmony_ci}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci#define pgd_leaf	pgd_large
142262306a36Sopenharmony_cistatic inline int pgd_large(pgd_t pgd) { return 0; }
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci#ifdef CONFIG_PAGE_TABLE_ISOLATION
142562306a36Sopenharmony_ci/*
142662306a36Sopenharmony_ci * All top-level PAGE_TABLE_ISOLATION page tables are order-1 pages
142762306a36Sopenharmony_ci * (8k-aligned and 8k in size).  The kernel one is at the beginning 4k and
142862306a36Sopenharmony_ci * the user one is in the last 4k.  To switch between them, you
142962306a36Sopenharmony_ci * just need to flip the 12th bit in their addresses.
143062306a36Sopenharmony_ci */
143162306a36Sopenharmony_ci#define PTI_PGTABLE_SWITCH_BIT	PAGE_SHIFT
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci/*
143462306a36Sopenharmony_ci * This generates better code than the inline assembly in
143562306a36Sopenharmony_ci * __set_bit().
143662306a36Sopenharmony_ci */
143762306a36Sopenharmony_cistatic inline void *ptr_set_bit(void *ptr, int bit)
143862306a36Sopenharmony_ci{
143962306a36Sopenharmony_ci	unsigned long __ptr = (unsigned long)ptr;
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	__ptr |= BIT(bit);
144262306a36Sopenharmony_ci	return (void *)__ptr;
144362306a36Sopenharmony_ci}
144462306a36Sopenharmony_cistatic inline void *ptr_clear_bit(void *ptr, int bit)
144562306a36Sopenharmony_ci{
144662306a36Sopenharmony_ci	unsigned long __ptr = (unsigned long)ptr;
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	__ptr &= ~BIT(bit);
144962306a36Sopenharmony_ci	return (void *)__ptr;
145062306a36Sopenharmony_ci}
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_cistatic inline pgd_t *kernel_to_user_pgdp(pgd_t *pgdp)
145362306a36Sopenharmony_ci{
145462306a36Sopenharmony_ci	return ptr_set_bit(pgdp, PTI_PGTABLE_SWITCH_BIT);
145562306a36Sopenharmony_ci}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_cistatic inline pgd_t *user_to_kernel_pgdp(pgd_t *pgdp)
145862306a36Sopenharmony_ci{
145962306a36Sopenharmony_ci	return ptr_clear_bit(pgdp, PTI_PGTABLE_SWITCH_BIT);
146062306a36Sopenharmony_ci}
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_cistatic inline p4d_t *kernel_to_user_p4dp(p4d_t *p4dp)
146362306a36Sopenharmony_ci{
146462306a36Sopenharmony_ci	return ptr_set_bit(p4dp, PTI_PGTABLE_SWITCH_BIT);
146562306a36Sopenharmony_ci}
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_cistatic inline p4d_t *user_to_kernel_p4dp(p4d_t *p4dp)
146862306a36Sopenharmony_ci{
146962306a36Sopenharmony_ci	return ptr_clear_bit(p4dp, PTI_PGTABLE_SWITCH_BIT);
147062306a36Sopenharmony_ci}
147162306a36Sopenharmony_ci#endif /* CONFIG_PAGE_TABLE_ISOLATION */
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci/*
147462306a36Sopenharmony_ci * clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
147562306a36Sopenharmony_ci *
147662306a36Sopenharmony_ci *  dst - pointer to pgd range anywhere on a pgd page
147762306a36Sopenharmony_ci *  src - ""
147862306a36Sopenharmony_ci *  count - the number of pgds to copy.
147962306a36Sopenharmony_ci *
148062306a36Sopenharmony_ci * dst and src can be on the same page, but the range must not overlap,
148162306a36Sopenharmony_ci * and must not cross a page boundary.
148262306a36Sopenharmony_ci */
148362306a36Sopenharmony_cistatic inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
148462306a36Sopenharmony_ci{
148562306a36Sopenharmony_ci	memcpy(dst, src, count * sizeof(pgd_t));
148662306a36Sopenharmony_ci#ifdef CONFIG_PAGE_TABLE_ISOLATION
148762306a36Sopenharmony_ci	if (!static_cpu_has(X86_FEATURE_PTI))
148862306a36Sopenharmony_ci		return;
148962306a36Sopenharmony_ci	/* Clone the user space pgd as well */
149062306a36Sopenharmony_ci	memcpy(kernel_to_user_pgdp(dst), kernel_to_user_pgdp(src),
149162306a36Sopenharmony_ci	       count * sizeof(pgd_t));
149262306a36Sopenharmony_ci#endif
149362306a36Sopenharmony_ci}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci#define PTE_SHIFT ilog2(PTRS_PER_PTE)
149662306a36Sopenharmony_cistatic inline int page_level_shift(enum pg_level level)
149762306a36Sopenharmony_ci{
149862306a36Sopenharmony_ci	return (PAGE_SHIFT - PTE_SHIFT) + level * PTE_SHIFT;
149962306a36Sopenharmony_ci}
150062306a36Sopenharmony_cistatic inline unsigned long page_level_size(enum pg_level level)
150162306a36Sopenharmony_ci{
150262306a36Sopenharmony_ci	return 1UL << page_level_shift(level);
150362306a36Sopenharmony_ci}
150462306a36Sopenharmony_cistatic inline unsigned long page_level_mask(enum pg_level level)
150562306a36Sopenharmony_ci{
150662306a36Sopenharmony_ci	return ~(page_level_size(level) - 1);
150762306a36Sopenharmony_ci}
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci/*
151062306a36Sopenharmony_ci * The x86 doesn't have any external MMU info: the kernel page
151162306a36Sopenharmony_ci * tables contain all the necessary information.
151262306a36Sopenharmony_ci */
151362306a36Sopenharmony_cistatic inline void update_mmu_cache(struct vm_area_struct *vma,
151462306a36Sopenharmony_ci		unsigned long addr, pte_t *ptep)
151562306a36Sopenharmony_ci{
151662306a36Sopenharmony_ci}
151762306a36Sopenharmony_cistatic inline void update_mmu_cache_range(struct vm_fault *vmf,
151862306a36Sopenharmony_ci		struct vm_area_struct *vma, unsigned long addr,
151962306a36Sopenharmony_ci		pte_t *ptep, unsigned int nr)
152062306a36Sopenharmony_ci{
152162306a36Sopenharmony_ci}
152262306a36Sopenharmony_cistatic inline void update_mmu_cache_pmd(struct vm_area_struct *vma,
152362306a36Sopenharmony_ci		unsigned long addr, pmd_t *pmd)
152462306a36Sopenharmony_ci{
152562306a36Sopenharmony_ci}
152662306a36Sopenharmony_cistatic inline void update_mmu_cache_pud(struct vm_area_struct *vma,
152762306a36Sopenharmony_ci		unsigned long addr, pud_t *pud)
152862306a36Sopenharmony_ci{
152962306a36Sopenharmony_ci}
153062306a36Sopenharmony_cistatic inline pte_t pte_swp_mkexclusive(pte_t pte)
153162306a36Sopenharmony_ci{
153262306a36Sopenharmony_ci	return pte_set_flags(pte, _PAGE_SWP_EXCLUSIVE);
153362306a36Sopenharmony_ci}
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_cistatic inline int pte_swp_exclusive(pte_t pte)
153662306a36Sopenharmony_ci{
153762306a36Sopenharmony_ci	return pte_flags(pte) & _PAGE_SWP_EXCLUSIVE;
153862306a36Sopenharmony_ci}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_cistatic inline pte_t pte_swp_clear_exclusive(pte_t pte)
154162306a36Sopenharmony_ci{
154262306a36Sopenharmony_ci	return pte_clear_flags(pte, _PAGE_SWP_EXCLUSIVE);
154362306a36Sopenharmony_ci}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY
154662306a36Sopenharmony_cistatic inline pte_t pte_swp_mksoft_dirty(pte_t pte)
154762306a36Sopenharmony_ci{
154862306a36Sopenharmony_ci	return pte_set_flags(pte, _PAGE_SWP_SOFT_DIRTY);
154962306a36Sopenharmony_ci}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_cistatic inline int pte_swp_soft_dirty(pte_t pte)
155262306a36Sopenharmony_ci{
155362306a36Sopenharmony_ci	return pte_flags(pte) & _PAGE_SWP_SOFT_DIRTY;
155462306a36Sopenharmony_ci}
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_cistatic inline pte_t pte_swp_clear_soft_dirty(pte_t pte)
155762306a36Sopenharmony_ci{
155862306a36Sopenharmony_ci	return pte_clear_flags(pte, _PAGE_SWP_SOFT_DIRTY);
155962306a36Sopenharmony_ci}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
156262306a36Sopenharmony_cistatic inline pmd_t pmd_swp_mksoft_dirty(pmd_t pmd)
156362306a36Sopenharmony_ci{
156462306a36Sopenharmony_ci	return pmd_set_flags(pmd, _PAGE_SWP_SOFT_DIRTY);
156562306a36Sopenharmony_ci}
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_cistatic inline int pmd_swp_soft_dirty(pmd_t pmd)
156862306a36Sopenharmony_ci{
156962306a36Sopenharmony_ci	return pmd_flags(pmd) & _PAGE_SWP_SOFT_DIRTY;
157062306a36Sopenharmony_ci}
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_cistatic inline pmd_t pmd_swp_clear_soft_dirty(pmd_t pmd)
157362306a36Sopenharmony_ci{
157462306a36Sopenharmony_ci	return pmd_clear_flags(pmd, _PAGE_SWP_SOFT_DIRTY);
157562306a36Sopenharmony_ci}
157662306a36Sopenharmony_ci#endif
157762306a36Sopenharmony_ci#endif
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
158062306a36Sopenharmony_cistatic inline pte_t pte_swp_mkuffd_wp(pte_t pte)
158162306a36Sopenharmony_ci{
158262306a36Sopenharmony_ci	return pte_set_flags(pte, _PAGE_SWP_UFFD_WP);
158362306a36Sopenharmony_ci}
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_cistatic inline int pte_swp_uffd_wp(pte_t pte)
158662306a36Sopenharmony_ci{
158762306a36Sopenharmony_ci	return pte_flags(pte) & _PAGE_SWP_UFFD_WP;
158862306a36Sopenharmony_ci}
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_cistatic inline pte_t pte_swp_clear_uffd_wp(pte_t pte)
159162306a36Sopenharmony_ci{
159262306a36Sopenharmony_ci	return pte_clear_flags(pte, _PAGE_SWP_UFFD_WP);
159362306a36Sopenharmony_ci}
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_cistatic inline pmd_t pmd_swp_mkuffd_wp(pmd_t pmd)
159662306a36Sopenharmony_ci{
159762306a36Sopenharmony_ci	return pmd_set_flags(pmd, _PAGE_SWP_UFFD_WP);
159862306a36Sopenharmony_ci}
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_cistatic inline int pmd_swp_uffd_wp(pmd_t pmd)
160162306a36Sopenharmony_ci{
160262306a36Sopenharmony_ci	return pmd_flags(pmd) & _PAGE_SWP_UFFD_WP;
160362306a36Sopenharmony_ci}
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_cistatic inline pmd_t pmd_swp_clear_uffd_wp(pmd_t pmd)
160662306a36Sopenharmony_ci{
160762306a36Sopenharmony_ci	return pmd_clear_flags(pmd, _PAGE_SWP_UFFD_WP);
160862306a36Sopenharmony_ci}
160962306a36Sopenharmony_ci#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_cistatic inline u16 pte_flags_pkey(unsigned long pte_flags)
161262306a36Sopenharmony_ci{
161362306a36Sopenharmony_ci#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
161462306a36Sopenharmony_ci	/* ifdef to avoid doing 59-bit shift on 32-bit values */
161562306a36Sopenharmony_ci	return (pte_flags & _PAGE_PKEY_MASK) >> _PAGE_BIT_PKEY_BIT0;
161662306a36Sopenharmony_ci#else
161762306a36Sopenharmony_ci	return 0;
161862306a36Sopenharmony_ci#endif
161962306a36Sopenharmony_ci}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_cistatic inline bool __pkru_allows_pkey(u16 pkey, bool write)
162262306a36Sopenharmony_ci{
162362306a36Sopenharmony_ci	u32 pkru = read_pkru();
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	if (!__pkru_allows_read(pkru, pkey))
162662306a36Sopenharmony_ci		return false;
162762306a36Sopenharmony_ci	if (write && !__pkru_allows_write(pkru, pkey))
162862306a36Sopenharmony_ci		return false;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	return true;
163162306a36Sopenharmony_ci}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci/*
163462306a36Sopenharmony_ci * 'pteval' can come from a PTE, PMD or PUD.  We only check
163562306a36Sopenharmony_ci * _PAGE_PRESENT, _PAGE_USER, and _PAGE_RW in here which are the
163662306a36Sopenharmony_ci * same value on all 3 types.
163762306a36Sopenharmony_ci */
163862306a36Sopenharmony_cistatic inline bool __pte_access_permitted(unsigned long pteval, bool write)
163962306a36Sopenharmony_ci{
164062306a36Sopenharmony_ci	unsigned long need_pte_bits = _PAGE_PRESENT|_PAGE_USER;
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	/*
164362306a36Sopenharmony_ci	 * Write=0,Dirty=1 PTEs are shadow stack, which the kernel
164462306a36Sopenharmony_ci	 * shouldn't generally allow access to, but since they
164562306a36Sopenharmony_ci	 * are already Write=0, the below logic covers both cases.
164662306a36Sopenharmony_ci	 */
164762306a36Sopenharmony_ci	if (write)
164862306a36Sopenharmony_ci		need_pte_bits |= _PAGE_RW;
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	if ((pteval & need_pte_bits) != need_pte_bits)
165162306a36Sopenharmony_ci		return 0;
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	return __pkru_allows_pkey(pte_flags_pkey(pteval), write);
165462306a36Sopenharmony_ci}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci#define pte_access_permitted pte_access_permitted
165762306a36Sopenharmony_cistatic inline bool pte_access_permitted(pte_t pte, bool write)
165862306a36Sopenharmony_ci{
165962306a36Sopenharmony_ci	return __pte_access_permitted(pte_val(pte), write);
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci#define pmd_access_permitted pmd_access_permitted
166362306a36Sopenharmony_cistatic inline bool pmd_access_permitted(pmd_t pmd, bool write)
166462306a36Sopenharmony_ci{
166562306a36Sopenharmony_ci	return __pte_access_permitted(pmd_val(pmd), write);
166662306a36Sopenharmony_ci}
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci#define pud_access_permitted pud_access_permitted
166962306a36Sopenharmony_cistatic inline bool pud_access_permitted(pud_t pud, bool write)
167062306a36Sopenharmony_ci{
167162306a36Sopenharmony_ci	return __pte_access_permitted(pud_val(pud), write);
167262306a36Sopenharmony_ci}
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci#define __HAVE_ARCH_PFN_MODIFY_ALLOWED 1
167562306a36Sopenharmony_ciextern bool pfn_modify_allowed(unsigned long pfn, pgprot_t prot);
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_cistatic inline bool arch_has_pfn_modify_check(void)
167862306a36Sopenharmony_ci{
167962306a36Sopenharmony_ci	return boot_cpu_has_bug(X86_BUG_L1TF);
168062306a36Sopenharmony_ci}
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci#define arch_has_hw_pte_young arch_has_hw_pte_young
168362306a36Sopenharmony_cistatic inline bool arch_has_hw_pte_young(void)
168462306a36Sopenharmony_ci{
168562306a36Sopenharmony_ci	return true;
168662306a36Sopenharmony_ci}
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci#define arch_check_zapped_pte arch_check_zapped_pte
168962306a36Sopenharmony_civoid arch_check_zapped_pte(struct vm_area_struct *vma, pte_t pte);
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci#define arch_check_zapped_pmd arch_check_zapped_pmd
169262306a36Sopenharmony_civoid arch_check_zapped_pmd(struct vm_area_struct *vma, pmd_t pmd);
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci#ifdef CONFIG_XEN_PV
169562306a36Sopenharmony_ci#define arch_has_hw_nonleaf_pmd_young arch_has_hw_nonleaf_pmd_young
169662306a36Sopenharmony_cistatic inline bool arch_has_hw_nonleaf_pmd_young(void)
169762306a36Sopenharmony_ci{
169862306a36Sopenharmony_ci	return !cpu_feature_enabled(X86_FEATURE_XENPV);
169962306a36Sopenharmony_ci}
170062306a36Sopenharmony_ci#endif
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci#ifdef CONFIG_PAGE_TABLE_CHECK
170362306a36Sopenharmony_cistatic inline bool pte_user_accessible_page(pte_t pte)
170462306a36Sopenharmony_ci{
170562306a36Sopenharmony_ci	return (pte_val(pte) & _PAGE_PRESENT) && (pte_val(pte) & _PAGE_USER);
170662306a36Sopenharmony_ci}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_cistatic inline bool pmd_user_accessible_page(pmd_t pmd)
170962306a36Sopenharmony_ci{
171062306a36Sopenharmony_ci	return pmd_leaf(pmd) && (pmd_val(pmd) & _PAGE_PRESENT) && (pmd_val(pmd) & _PAGE_USER);
171162306a36Sopenharmony_ci}
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_cistatic inline bool pud_user_accessible_page(pud_t pud)
171462306a36Sopenharmony_ci{
171562306a36Sopenharmony_ci	return pud_leaf(pud) && (pud_val(pud) & _PAGE_PRESENT) && (pud_val(pud) & _PAGE_USER);
171662306a36Sopenharmony_ci}
171762306a36Sopenharmony_ci#endif
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci#endif	/* __ASSEMBLY__ */
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci#endif /* _ASM_X86_PGTABLE_H */
1722