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