162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2012 ARM Ltd.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#ifndef __ASM_PGTABLE_H
662306a36Sopenharmony_ci#define __ASM_PGTABLE_H
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <asm/bug.h>
962306a36Sopenharmony_ci#include <asm/proc-fns.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <asm/memory.h>
1262306a36Sopenharmony_ci#include <asm/mte.h>
1362306a36Sopenharmony_ci#include <asm/pgtable-hwdef.h>
1462306a36Sopenharmony_ci#include <asm/pgtable-prot.h>
1562306a36Sopenharmony_ci#include <asm/tlbflush.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * VMALLOC range.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * VMALLOC_START: beginning of the kernel vmalloc space
2162306a36Sopenharmony_ci * VMALLOC_END: extends to the available space below vmemmap, PCI I/O space
2262306a36Sopenharmony_ci *	and fixed mappings
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci#define VMALLOC_START		(MODULES_END)
2562306a36Sopenharmony_ci#define VMALLOC_END		(VMEMMAP_START - SZ_256M)
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define vmemmap			((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT))
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#ifndef __ASSEMBLY__
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include <asm/cmpxchg.h>
3262306a36Sopenharmony_ci#include <asm/fixmap.h>
3362306a36Sopenharmony_ci#include <linux/mmdebug.h>
3462306a36Sopenharmony_ci#include <linux/mm_types.h>
3562306a36Sopenharmony_ci#include <linux/sched.h>
3662306a36Sopenharmony_ci#include <linux/page_table_check.h>
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
3962306a36Sopenharmony_ci#define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/* Set stride and tlb_level in flush_*_tlb_range */
4262306a36Sopenharmony_ci#define flush_pmd_tlb_range(vma, addr, end)	\
4362306a36Sopenharmony_ci	__flush_tlb_range(vma, addr, end, PMD_SIZE, false, 2)
4462306a36Sopenharmony_ci#define flush_pud_tlb_range(vma, addr, end)	\
4562306a36Sopenharmony_ci	__flush_tlb_range(vma, addr, end, PUD_SIZE, false, 1)
4662306a36Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic inline bool arch_thp_swp_supported(void)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	return !system_supports_mte();
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci#define arch_thp_swp_supported arch_thp_swp_supported
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/*
5562306a36Sopenharmony_ci * Outside of a few very special situations (e.g. hibernation), we always
5662306a36Sopenharmony_ci * use broadcast TLB invalidation instructions, therefore a spurious page
5762306a36Sopenharmony_ci * fault on one CPU which has been handled concurrently by another CPU
5862306a36Sopenharmony_ci * does not need to perform additional invalidation.
5962306a36Sopenharmony_ci */
6062306a36Sopenharmony_ci#define flush_tlb_fix_spurious_fault(vma, address, ptep) do { } while (0)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/*
6362306a36Sopenharmony_ci * ZERO_PAGE is a global shared page that is always zero: used
6462306a36Sopenharmony_ci * for zero-mapped memory areas etc..
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_ciextern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
6762306a36Sopenharmony_ci#define ZERO_PAGE(vaddr)	phys_to_page(__pa_symbol(empty_zero_page))
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define pte_ERROR(e)	\
7062306a36Sopenharmony_ci	pr_err("%s:%d: bad pte %016llx.\n", __FILE__, __LINE__, pte_val(e))
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/*
7362306a36Sopenharmony_ci * Macros to convert between a physical address and its placement in a
7462306a36Sopenharmony_ci * page table entry, taking care of 52-bit addresses.
7562306a36Sopenharmony_ci */
7662306a36Sopenharmony_ci#ifdef CONFIG_ARM64_PA_BITS_52
7762306a36Sopenharmony_cistatic inline phys_addr_t __pte_to_phys(pte_t pte)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	return (pte_val(pte) & PTE_ADDR_LOW) |
8062306a36Sopenharmony_ci		((pte_val(pte) & PTE_ADDR_HIGH) << PTE_ADDR_HIGH_SHIFT);
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_cistatic inline pteval_t __phys_to_pte_val(phys_addr_t phys)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	return (phys | (phys >> PTE_ADDR_HIGH_SHIFT)) & PTE_ADDR_MASK;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci#else
8762306a36Sopenharmony_ci#define __pte_to_phys(pte)	(pte_val(pte) & PTE_ADDR_MASK)
8862306a36Sopenharmony_ci#define __phys_to_pte_val(phys)	(phys)
8962306a36Sopenharmony_ci#endif
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define pte_pfn(pte)		(__pte_to_phys(pte) >> PAGE_SHIFT)
9262306a36Sopenharmony_ci#define pfn_pte(pfn,prot)	\
9362306a36Sopenharmony_ci	__pte(__phys_to_pte_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define pte_none(pte)		(!pte_val(pte))
9662306a36Sopenharmony_ci#define pte_clear(mm,addr,ptep)	set_pte(ptep, __pte(0))
9762306a36Sopenharmony_ci#define pte_page(pte)		(pfn_to_page(pte_pfn(pte)))
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/*
10062306a36Sopenharmony_ci * The following only work if pte_present(). Undefined behaviour otherwise.
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_ci#define pte_present(pte)	(!!(pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)))
10362306a36Sopenharmony_ci#define pte_young(pte)		(!!(pte_val(pte) & PTE_AF))
10462306a36Sopenharmony_ci#define pte_special(pte)	(!!(pte_val(pte) & PTE_SPECIAL))
10562306a36Sopenharmony_ci#define pte_write(pte)		(!!(pte_val(pte) & PTE_WRITE))
10662306a36Sopenharmony_ci#define pte_rdonly(pte)		(!!(pte_val(pte) & PTE_RDONLY))
10762306a36Sopenharmony_ci#define pte_user(pte)		(!!(pte_val(pte) & PTE_USER))
10862306a36Sopenharmony_ci#define pte_user_exec(pte)	(!(pte_val(pte) & PTE_UXN))
10962306a36Sopenharmony_ci#define pte_cont(pte)		(!!(pte_val(pte) & PTE_CONT))
11062306a36Sopenharmony_ci#define pte_devmap(pte)		(!!(pte_val(pte) & PTE_DEVMAP))
11162306a36Sopenharmony_ci#define pte_tagged(pte)		((pte_val(pte) & PTE_ATTRINDX_MASK) == \
11262306a36Sopenharmony_ci				 PTE_ATTRINDX(MT_NORMAL_TAGGED))
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define pte_cont_addr_end(addr, end)						\
11562306a36Sopenharmony_ci({	unsigned long __boundary = ((addr) + CONT_PTE_SIZE) & CONT_PTE_MASK;	\
11662306a36Sopenharmony_ci	(__boundary - 1 < (end) - 1) ? __boundary : (end);			\
11762306a36Sopenharmony_ci})
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci#define pmd_cont_addr_end(addr, end)						\
12062306a36Sopenharmony_ci({	unsigned long __boundary = ((addr) + CONT_PMD_SIZE) & CONT_PMD_MASK;	\
12162306a36Sopenharmony_ci	(__boundary - 1 < (end) - 1) ? __boundary : (end);			\
12262306a36Sopenharmony_ci})
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#define pte_hw_dirty(pte)	(pte_write(pte) && !pte_rdonly(pte))
12562306a36Sopenharmony_ci#define pte_sw_dirty(pte)	(!!(pte_val(pte) & PTE_DIRTY))
12662306a36Sopenharmony_ci#define pte_dirty(pte)		(pte_sw_dirty(pte) || pte_hw_dirty(pte))
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#define pte_valid(pte)		(!!(pte_val(pte) & PTE_VALID))
12962306a36Sopenharmony_ci/*
13062306a36Sopenharmony_ci * Execute-only user mappings do not have the PTE_USER bit set. All valid
13162306a36Sopenharmony_ci * kernel mappings have the PTE_UXN bit set.
13262306a36Sopenharmony_ci */
13362306a36Sopenharmony_ci#define pte_valid_not_user(pte) \
13462306a36Sopenharmony_ci	((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == (PTE_VALID | PTE_UXN))
13562306a36Sopenharmony_ci/*
13662306a36Sopenharmony_ci * Could the pte be present in the TLB? We must check mm_tlb_flush_pending
13762306a36Sopenharmony_ci * so that we don't erroneously return false for pages that have been
13862306a36Sopenharmony_ci * remapped as PROT_NONE but are yet to be flushed from the TLB.
13962306a36Sopenharmony_ci * Note that we can't make any assumptions based on the state of the access
14062306a36Sopenharmony_ci * flag, since ptep_clear_flush_young() elides a DSB when invalidating the
14162306a36Sopenharmony_ci * TLB.
14262306a36Sopenharmony_ci */
14362306a36Sopenharmony_ci#define pte_accessible(mm, pte)	\
14462306a36Sopenharmony_ci	(mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid(pte))
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/*
14762306a36Sopenharmony_ci * p??_access_permitted() is true for valid user mappings (PTE_USER
14862306a36Sopenharmony_ci * bit set, subject to the write permission check). For execute-only
14962306a36Sopenharmony_ci * mappings, like PROT_EXEC with EPAN (both PTE_USER and PTE_UXN bits
15062306a36Sopenharmony_ci * not set) must return false. PROT_NONE mappings do not have the
15162306a36Sopenharmony_ci * PTE_VALID bit set.
15262306a36Sopenharmony_ci */
15362306a36Sopenharmony_ci#define pte_access_permitted(pte, write) \
15462306a36Sopenharmony_ci	(((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) && (!(write) || pte_write(pte)))
15562306a36Sopenharmony_ci#define pmd_access_permitted(pmd, write) \
15662306a36Sopenharmony_ci	(pte_access_permitted(pmd_pte(pmd), (write)))
15762306a36Sopenharmony_ci#define pud_access_permitted(pud, write) \
15862306a36Sopenharmony_ci	(pte_access_permitted(pud_pte(pud), (write)))
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	pte_val(pte) &= ~pgprot_val(prot);
16362306a36Sopenharmony_ci	return pte;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic inline pte_t set_pte_bit(pte_t pte, pgprot_t prot)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	pte_val(pte) |= pgprot_val(prot);
16962306a36Sopenharmony_ci	return pte;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic inline pmd_t clear_pmd_bit(pmd_t pmd, pgprot_t prot)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	pmd_val(pmd) &= ~pgprot_val(prot);
17562306a36Sopenharmony_ci	return pmd;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic inline pmd_t set_pmd_bit(pmd_t pmd, pgprot_t prot)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	pmd_val(pmd) |= pgprot_val(prot);
18162306a36Sopenharmony_ci	return pmd;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic inline pte_t pte_mkwrite_novma(pte_t pte)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	pte = set_pte_bit(pte, __pgprot(PTE_WRITE));
18762306a36Sopenharmony_ci	pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
18862306a36Sopenharmony_ci	return pte;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic inline pte_t pte_mkclean(pte_t pte)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	pte = clear_pte_bit(pte, __pgprot(PTE_DIRTY));
19462306a36Sopenharmony_ci	pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	return pte;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic inline pte_t pte_mkdirty(pte_t pte)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	pte = set_pte_bit(pte, __pgprot(PTE_DIRTY));
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (pte_write(pte))
20462306a36Sopenharmony_ci		pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	return pte;
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic inline pte_t pte_wrprotect(pte_t pte)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	/*
21262306a36Sopenharmony_ci	 * If hardware-dirty (PTE_WRITE/DBM bit set and PTE_RDONLY
21362306a36Sopenharmony_ci	 * clear), set the PTE_DIRTY bit.
21462306a36Sopenharmony_ci	 */
21562306a36Sopenharmony_ci	if (pte_hw_dirty(pte))
21662306a36Sopenharmony_ci		pte = set_pte_bit(pte, __pgprot(PTE_DIRTY));
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	pte = clear_pte_bit(pte, __pgprot(PTE_WRITE));
21962306a36Sopenharmony_ci	pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
22062306a36Sopenharmony_ci	return pte;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic inline pte_t pte_mkold(pte_t pte)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	return clear_pte_bit(pte, __pgprot(PTE_AF));
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic inline pte_t pte_mkyoung(pte_t pte)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	return set_pte_bit(pte, __pgprot(PTE_AF));
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic inline pte_t pte_mkspecial(pte_t pte)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	return set_pte_bit(pte, __pgprot(PTE_SPECIAL));
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic inline pte_t pte_mkcont(pte_t pte)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	pte = set_pte_bit(pte, __pgprot(PTE_CONT));
24162306a36Sopenharmony_ci	return set_pte_bit(pte, __pgprot(PTE_TYPE_PAGE));
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic inline pte_t pte_mknoncont(pte_t pte)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	return clear_pte_bit(pte, __pgprot(PTE_CONT));
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic inline pte_t pte_mkpresent(pte_t pte)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	return set_pte_bit(pte, __pgprot(PTE_VALID));
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic inline pmd_t pmd_mkcont(pmd_t pmd)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	return __pmd(pmd_val(pmd) | PMD_SECT_CONT);
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic inline pte_t pte_mkdevmap(pte_t pte)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	return set_pte_bit(pte, __pgprot(PTE_DEVMAP | PTE_SPECIAL));
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic inline void set_pte(pte_t *ptep, pte_t pte)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	WRITE_ONCE(*ptep, pte);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/*
26962306a36Sopenharmony_ci	 * Only if the new pte is valid and kernel, otherwise TLB maintenance
27062306a36Sopenharmony_ci	 * or update_mmu_cache() have the necessary barriers.
27162306a36Sopenharmony_ci	 */
27262306a36Sopenharmony_ci	if (pte_valid_not_user(pte)) {
27362306a36Sopenharmony_ci		dsb(ishst);
27462306a36Sopenharmony_ci		isb();
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ciextern void __sync_icache_dcache(pte_t pteval);
27962306a36Sopenharmony_cibool pgattr_change_is_safe(u64 old, u64 new);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci/*
28262306a36Sopenharmony_ci * PTE bits configuration in the presence of hardware Dirty Bit Management
28362306a36Sopenharmony_ci * (PTE_WRITE == PTE_DBM):
28462306a36Sopenharmony_ci *
28562306a36Sopenharmony_ci * Dirty  Writable | PTE_RDONLY  PTE_WRITE  PTE_DIRTY (sw)
28662306a36Sopenharmony_ci *   0      0      |   1           0          0
28762306a36Sopenharmony_ci *   0      1      |   1           1          0
28862306a36Sopenharmony_ci *   1      0      |   1           0          1
28962306a36Sopenharmony_ci *   1      1      |   0           1          x
29062306a36Sopenharmony_ci *
29162306a36Sopenharmony_ci * When hardware DBM is not present, the sofware PTE_DIRTY bit is updated via
29262306a36Sopenharmony_ci * the page fault mechanism. Checking the dirty status of a pte becomes:
29362306a36Sopenharmony_ci *
29462306a36Sopenharmony_ci *   PTE_DIRTY || (PTE_WRITE && !PTE_RDONLY)
29562306a36Sopenharmony_ci */
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic inline void __check_safe_pte_update(struct mm_struct *mm, pte_t *ptep,
29862306a36Sopenharmony_ci					   pte_t pte)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	pte_t old_pte;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_DEBUG_VM))
30362306a36Sopenharmony_ci		return;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	old_pte = READ_ONCE(*ptep);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	if (!pte_valid(old_pte) || !pte_valid(pte))
30862306a36Sopenharmony_ci		return;
30962306a36Sopenharmony_ci	if (mm != current->active_mm && atomic_read(&mm->mm_users) <= 1)
31062306a36Sopenharmony_ci		return;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	/*
31362306a36Sopenharmony_ci	 * Check for potential race with hardware updates of the pte
31462306a36Sopenharmony_ci	 * (ptep_set_access_flags safely changes valid ptes without going
31562306a36Sopenharmony_ci	 * through an invalid entry).
31662306a36Sopenharmony_ci	 */
31762306a36Sopenharmony_ci	VM_WARN_ONCE(!pte_young(pte),
31862306a36Sopenharmony_ci		     "%s: racy access flag clearing: 0x%016llx -> 0x%016llx",
31962306a36Sopenharmony_ci		     __func__, pte_val(old_pte), pte_val(pte));
32062306a36Sopenharmony_ci	VM_WARN_ONCE(pte_write(old_pte) && !pte_dirty(pte),
32162306a36Sopenharmony_ci		     "%s: racy dirty state clearing: 0x%016llx -> 0x%016llx",
32262306a36Sopenharmony_ci		     __func__, pte_val(old_pte), pte_val(pte));
32362306a36Sopenharmony_ci	VM_WARN_ONCE(!pgattr_change_is_safe(pte_val(old_pte), pte_val(pte)),
32462306a36Sopenharmony_ci		     "%s: unsafe attribute change: 0x%016llx -> 0x%016llx",
32562306a36Sopenharmony_ci		     __func__, pte_val(old_pte), pte_val(pte));
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
32962306a36Sopenharmony_ci				pte_t *ptep, pte_t pte)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	if (pte_present(pte) && pte_user_exec(pte) && !pte_special(pte))
33262306a36Sopenharmony_ci		__sync_icache_dcache(pte);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	/*
33562306a36Sopenharmony_ci	 * If the PTE would provide user space access to the tags associated
33662306a36Sopenharmony_ci	 * with it then ensure that the MTE tags are synchronised.  Although
33762306a36Sopenharmony_ci	 * pte_access_permitted() returns false for exec only mappings, they
33862306a36Sopenharmony_ci	 * don't expose tags (instruction fetches don't check tags).
33962306a36Sopenharmony_ci	 */
34062306a36Sopenharmony_ci	if (system_supports_mte() && pte_access_permitted(pte, false) &&
34162306a36Sopenharmony_ci	    !pte_special(pte) && pte_tagged(pte))
34262306a36Sopenharmony_ci		mte_sync_tags(pte);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	__check_safe_pte_update(mm, ptep, pte);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	set_pte(ptep, pte);
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic inline void set_ptes(struct mm_struct *mm, unsigned long addr,
35062306a36Sopenharmony_ci			      pte_t *ptep, pte_t pte, unsigned int nr)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	page_table_check_ptes_set(mm, ptep, pte, nr);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	for (;;) {
35562306a36Sopenharmony_ci		__set_pte_at(mm, addr, ptep, pte);
35662306a36Sopenharmony_ci		if (--nr == 0)
35762306a36Sopenharmony_ci			break;
35862306a36Sopenharmony_ci		ptep++;
35962306a36Sopenharmony_ci		addr += PAGE_SIZE;
36062306a36Sopenharmony_ci		pte_val(pte) += PAGE_SIZE;
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci#define set_ptes set_ptes
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci/*
36662306a36Sopenharmony_ci * Huge pte definitions.
36762306a36Sopenharmony_ci */
36862306a36Sopenharmony_ci#define pte_mkhuge(pte)		(__pte(pte_val(pte) & ~PTE_TABLE_BIT))
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci/*
37162306a36Sopenharmony_ci * Hugetlb definitions.
37262306a36Sopenharmony_ci */
37362306a36Sopenharmony_ci#define HUGE_MAX_HSTATE		4
37462306a36Sopenharmony_ci#define HPAGE_SHIFT		PMD_SHIFT
37562306a36Sopenharmony_ci#define HPAGE_SIZE		(_AC(1, UL) << HPAGE_SHIFT)
37662306a36Sopenharmony_ci#define HPAGE_MASK		(~(HPAGE_SIZE - 1))
37762306a36Sopenharmony_ci#define HUGETLB_PAGE_ORDER	(HPAGE_SHIFT - PAGE_SHIFT)
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic inline pte_t pgd_pte(pgd_t pgd)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	return __pte(pgd_val(pgd));
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic inline pte_t p4d_pte(p4d_t p4d)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	return __pte(p4d_val(p4d));
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic inline pte_t pud_pte(pud_t pud)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	return __pte(pud_val(pud));
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic inline pud_t pte_pud(pte_t pte)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	return __pud(pte_val(pte));
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic inline pmd_t pud_pmd(pud_t pud)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	return __pmd(pud_val(pud));
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic inline pte_t pmd_pte(pmd_t pmd)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	return __pte(pmd_val(pmd));
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic inline pmd_t pte_pmd(pte_t pte)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	return __pmd(pte_val(pte));
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic inline pgprot_t mk_pud_sect_prot(pgprot_t prot)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	return __pgprot((pgprot_val(prot) & ~PUD_TABLE_BIT) | PUD_TYPE_SECT);
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic inline pgprot_t mk_pmd_sect_prot(pgprot_t prot)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	return __pgprot((pgprot_val(prot) & ~PMD_TABLE_BIT) | PMD_TYPE_SECT);
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic inline pte_t pte_swp_mkexclusive(pte_t pte)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	return set_pte_bit(pte, __pgprot(PTE_SWP_EXCLUSIVE));
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic inline int pte_swp_exclusive(pte_t pte)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	return pte_val(pte) & PTE_SWP_EXCLUSIVE;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic inline pte_t pte_swp_clear_exclusive(pte_t pte)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	return clear_pte_bit(pte, __pgprot(PTE_SWP_EXCLUSIVE));
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci/*
44062306a36Sopenharmony_ci * Select all bits except the pfn
44162306a36Sopenharmony_ci */
44262306a36Sopenharmony_cistatic inline pgprot_t pte_pgprot(pte_t pte)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	unsigned long pfn = pte_pfn(pte);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	return __pgprot(pte_val(pfn_pte(pfn, __pgprot(0))) ^ pte_val(pte));
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci#ifdef CONFIG_NUMA_BALANCING
45062306a36Sopenharmony_ci/*
45162306a36Sopenharmony_ci * See the comment in include/linux/pgtable.h
45262306a36Sopenharmony_ci */
45362306a36Sopenharmony_cistatic inline int pte_protnone(pte_t pte)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	return (pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)) == PTE_PROT_NONE;
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic inline int pmd_protnone(pmd_t pmd)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	return pte_protnone(pmd_pte(pmd));
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci#endif
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci#define pmd_present_invalid(pmd)     (!!(pmd_val(pmd) & PMD_PRESENT_INVALID))
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic inline int pmd_present(pmd_t pmd)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	return pte_present(pmd_pte(pmd)) || pmd_present_invalid(pmd);
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci/*
47262306a36Sopenharmony_ci * THP definitions.
47362306a36Sopenharmony_ci */
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
47662306a36Sopenharmony_cistatic inline int pmd_trans_huge(pmd_t pmd)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	return pmd_val(pmd) && pmd_present(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT);
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci#define pmd_dirty(pmd)		pte_dirty(pmd_pte(pmd))
48362306a36Sopenharmony_ci#define pmd_young(pmd)		pte_young(pmd_pte(pmd))
48462306a36Sopenharmony_ci#define pmd_valid(pmd)		pte_valid(pmd_pte(pmd))
48562306a36Sopenharmony_ci#define pmd_user(pmd)		pte_user(pmd_pte(pmd))
48662306a36Sopenharmony_ci#define pmd_user_exec(pmd)	pte_user_exec(pmd_pte(pmd))
48762306a36Sopenharmony_ci#define pmd_cont(pmd)		pte_cont(pmd_pte(pmd))
48862306a36Sopenharmony_ci#define pmd_wrprotect(pmd)	pte_pmd(pte_wrprotect(pmd_pte(pmd)))
48962306a36Sopenharmony_ci#define pmd_mkold(pmd)		pte_pmd(pte_mkold(pmd_pte(pmd)))
49062306a36Sopenharmony_ci#define pmd_mkwrite_novma(pmd)	pte_pmd(pte_mkwrite_novma(pmd_pte(pmd)))
49162306a36Sopenharmony_ci#define pmd_mkclean(pmd)	pte_pmd(pte_mkclean(pmd_pte(pmd)))
49262306a36Sopenharmony_ci#define pmd_mkdirty(pmd)	pte_pmd(pte_mkdirty(pmd_pte(pmd)))
49362306a36Sopenharmony_ci#define pmd_mkyoung(pmd)	pte_pmd(pte_mkyoung(pmd_pte(pmd)))
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic inline pmd_t pmd_mkinvalid(pmd_t pmd)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	pmd = set_pmd_bit(pmd, __pgprot(PMD_PRESENT_INVALID));
49862306a36Sopenharmony_ci	pmd = clear_pmd_bit(pmd, __pgprot(PMD_SECT_VALID));
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	return pmd;
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci#define pmd_thp_or_huge(pmd)	(pmd_huge(pmd) || pmd_trans_huge(pmd))
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci#define pmd_write(pmd)		pte_write(pmd_pte(pmd))
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci#define pmd_mkhuge(pmd)		(__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
51062306a36Sopenharmony_ci#define pmd_devmap(pmd)		pte_devmap(pmd_pte(pmd))
51162306a36Sopenharmony_ci#endif
51262306a36Sopenharmony_cistatic inline pmd_t pmd_mkdevmap(pmd_t pmd)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	return pte_pmd(set_pte_bit(pmd_pte(pmd), __pgprot(PTE_DEVMAP)));
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci#define __pmd_to_phys(pmd)	__pte_to_phys(pmd_pte(pmd))
51862306a36Sopenharmony_ci#define __phys_to_pmd_val(phys)	__phys_to_pte_val(phys)
51962306a36Sopenharmony_ci#define pmd_pfn(pmd)		((__pmd_to_phys(pmd) & PMD_MASK) >> PAGE_SHIFT)
52062306a36Sopenharmony_ci#define pfn_pmd(pfn,prot)	__pmd(__phys_to_pmd_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
52162306a36Sopenharmony_ci#define mk_pmd(page,prot)	pfn_pmd(page_to_pfn(page),prot)
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci#define pud_young(pud)		pte_young(pud_pte(pud))
52462306a36Sopenharmony_ci#define pud_mkyoung(pud)	pte_pud(pte_mkyoung(pud_pte(pud)))
52562306a36Sopenharmony_ci#define pud_write(pud)		pte_write(pud_pte(pud))
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci#define pud_mkhuge(pud)		(__pud(pud_val(pud) & ~PUD_TABLE_BIT))
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci#define __pud_to_phys(pud)	__pte_to_phys(pud_pte(pud))
53062306a36Sopenharmony_ci#define __phys_to_pud_val(phys)	__phys_to_pte_val(phys)
53162306a36Sopenharmony_ci#define pud_pfn(pud)		((__pud_to_phys(pud) & PUD_MASK) >> PAGE_SHIFT)
53262306a36Sopenharmony_ci#define pfn_pud(pfn,prot)	__pud(__phys_to_pud_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_cistatic inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
53562306a36Sopenharmony_ci			      pmd_t *pmdp, pmd_t pmd)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	page_table_check_pmd_set(mm, pmdp, pmd);
53862306a36Sopenharmony_ci	return __set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd));
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
54262306a36Sopenharmony_ci			      pud_t *pudp, pud_t pud)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	page_table_check_pud_set(mm, pudp, pud);
54562306a36Sopenharmony_ci	return __set_pte_at(mm, addr, (pte_t *)pudp, pud_pte(pud));
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci#define __p4d_to_phys(p4d)	__pte_to_phys(p4d_pte(p4d))
54962306a36Sopenharmony_ci#define __phys_to_p4d_val(phys)	__phys_to_pte_val(phys)
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci#define __pgd_to_phys(pgd)	__pte_to_phys(pgd_pte(pgd))
55262306a36Sopenharmony_ci#define __phys_to_pgd_val(phys)	__phys_to_pte_val(phys)
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci#define __pgprot_modify(prot,mask,bits) \
55562306a36Sopenharmony_ci	__pgprot((pgprot_val(prot) & ~(mask)) | (bits))
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci#define pgprot_nx(prot) \
55862306a36Sopenharmony_ci	__pgprot_modify(prot, PTE_MAYBE_GP, PTE_PXN)
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci/*
56162306a36Sopenharmony_ci * Mark the prot value as uncacheable and unbufferable.
56262306a36Sopenharmony_ci */
56362306a36Sopenharmony_ci#define pgprot_noncached(prot) \
56462306a36Sopenharmony_ci	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE) | PTE_PXN | PTE_UXN)
56562306a36Sopenharmony_ci#define pgprot_writecombine(prot) \
56662306a36Sopenharmony_ci	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
56762306a36Sopenharmony_ci#define pgprot_device(prot) \
56862306a36Sopenharmony_ci	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN)
56962306a36Sopenharmony_ci#define pgprot_tagged(prot) \
57062306a36Sopenharmony_ci	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_TAGGED))
57162306a36Sopenharmony_ci#define pgprot_mhp	pgprot_tagged
57262306a36Sopenharmony_ci/*
57362306a36Sopenharmony_ci * DMA allocations for non-coherent devices use what the Arm architecture calls
57462306a36Sopenharmony_ci * "Normal non-cacheable" memory, which permits speculation, unaligned accesses
57562306a36Sopenharmony_ci * and merging of writes.  This is different from "Device-nGnR[nE]" memory which
57662306a36Sopenharmony_ci * is intended for MMIO and thus forbids speculation, preserves access size,
57762306a36Sopenharmony_ci * requires strict alignment and can also force write responses to come from the
57862306a36Sopenharmony_ci * endpoint.
57962306a36Sopenharmony_ci */
58062306a36Sopenharmony_ci#define pgprot_dmacoherent(prot) \
58162306a36Sopenharmony_ci	__pgprot_modify(prot, PTE_ATTRINDX_MASK, \
58262306a36Sopenharmony_ci			PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci#define __HAVE_PHYS_MEM_ACCESS_PROT
58562306a36Sopenharmony_cistruct file;
58662306a36Sopenharmony_ciextern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
58762306a36Sopenharmony_ci				     unsigned long size, pgprot_t vma_prot);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci#define pmd_none(pmd)		(!pmd_val(pmd))
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci#define pmd_table(pmd)		((pmd_val(pmd) & PMD_TYPE_MASK) == \
59262306a36Sopenharmony_ci				 PMD_TYPE_TABLE)
59362306a36Sopenharmony_ci#define pmd_sect(pmd)		((pmd_val(pmd) & PMD_TYPE_MASK) == \
59462306a36Sopenharmony_ci				 PMD_TYPE_SECT)
59562306a36Sopenharmony_ci#define pmd_leaf(pmd)		(pmd_present(pmd) && !pmd_table(pmd))
59662306a36Sopenharmony_ci#define pmd_bad(pmd)		(!pmd_table(pmd))
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci#define pmd_leaf_size(pmd)	(pmd_cont(pmd) ? CONT_PMD_SIZE : PMD_SIZE)
59962306a36Sopenharmony_ci#define pte_leaf_size(pte)	(pte_cont(pte) ? CONT_PTE_SIZE : PAGE_SIZE)
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci#if defined(CONFIG_ARM64_64K_PAGES) || CONFIG_PGTABLE_LEVELS < 3
60262306a36Sopenharmony_cistatic inline bool pud_sect(pud_t pud) { return false; }
60362306a36Sopenharmony_cistatic inline bool pud_table(pud_t pud) { return true; }
60462306a36Sopenharmony_ci#else
60562306a36Sopenharmony_ci#define pud_sect(pud)		((pud_val(pud) & PUD_TYPE_MASK) == \
60662306a36Sopenharmony_ci				 PUD_TYPE_SECT)
60762306a36Sopenharmony_ci#define pud_table(pud)		((pud_val(pud) & PUD_TYPE_MASK) == \
60862306a36Sopenharmony_ci				 PUD_TYPE_TABLE)
60962306a36Sopenharmony_ci#endif
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ciextern pgd_t init_pg_dir[PTRS_PER_PGD];
61262306a36Sopenharmony_ciextern pgd_t init_pg_end[];
61362306a36Sopenharmony_ciextern pgd_t swapper_pg_dir[PTRS_PER_PGD];
61462306a36Sopenharmony_ciextern pgd_t idmap_pg_dir[PTRS_PER_PGD];
61562306a36Sopenharmony_ciextern pgd_t tramp_pg_dir[PTRS_PER_PGD];
61662306a36Sopenharmony_ciextern pgd_t reserved_pg_dir[PTRS_PER_PGD];
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ciextern void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_cistatic inline bool in_swapper_pgdir(void *addr)
62162306a36Sopenharmony_ci{
62262306a36Sopenharmony_ci	return ((unsigned long)addr & PAGE_MASK) ==
62362306a36Sopenharmony_ci	        ((unsigned long)swapper_pg_dir & PAGE_MASK);
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cistatic inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci#ifdef __PAGETABLE_PMD_FOLDED
62962306a36Sopenharmony_ci	if (in_swapper_pgdir(pmdp)) {
63062306a36Sopenharmony_ci		set_swapper_pgd((pgd_t *)pmdp, __pgd(pmd_val(pmd)));
63162306a36Sopenharmony_ci		return;
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci#endif /* __PAGETABLE_PMD_FOLDED */
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	WRITE_ONCE(*pmdp, pmd);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	if (pmd_valid(pmd)) {
63862306a36Sopenharmony_ci		dsb(ishst);
63962306a36Sopenharmony_ci		isb();
64062306a36Sopenharmony_ci	}
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_cistatic inline void pmd_clear(pmd_t *pmdp)
64462306a36Sopenharmony_ci{
64562306a36Sopenharmony_ci	set_pmd(pmdp, __pmd(0));
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic inline phys_addr_t pmd_page_paddr(pmd_t pmd)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	return __pmd_to_phys(pmd);
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cistatic inline unsigned long pmd_page_vaddr(pmd_t pmd)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	return (unsigned long)__va(pmd_page_paddr(pmd));
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci/* Find an entry in the third-level page table. */
65962306a36Sopenharmony_ci#define pte_offset_phys(dir,addr)	(pmd_page_paddr(READ_ONCE(*(dir))) + pte_index(addr) * sizeof(pte_t))
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci#define pte_set_fixmap(addr)		((pte_t *)set_fixmap_offset(FIX_PTE, addr))
66262306a36Sopenharmony_ci#define pte_set_fixmap_offset(pmd, addr)	pte_set_fixmap(pte_offset_phys(pmd, addr))
66362306a36Sopenharmony_ci#define pte_clear_fixmap()		clear_fixmap(FIX_PTE)
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci#define pmd_page(pmd)			phys_to_page(__pmd_to_phys(pmd))
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci/* use ONLY for statically allocated translation tables */
66862306a36Sopenharmony_ci#define pte_offset_kimg(dir,addr)	((pte_t *)__phys_to_kimg(pte_offset_phys((dir), (addr))))
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci/*
67162306a36Sopenharmony_ci * Conversion functions: convert a page and protection to a page entry,
67262306a36Sopenharmony_ci * and a page entry and page directory to the page they refer to.
67362306a36Sopenharmony_ci */
67462306a36Sopenharmony_ci#define mk_pte(page,prot)	pfn_pte(page_to_pfn(page),prot)
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 2
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci#define pmd_ERROR(e)	\
67962306a36Sopenharmony_ci	pr_err("%s:%d: bad pmd %016llx.\n", __FILE__, __LINE__, pmd_val(e))
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci#define pud_none(pud)		(!pud_val(pud))
68262306a36Sopenharmony_ci#define pud_bad(pud)		(!pud_table(pud))
68362306a36Sopenharmony_ci#define pud_present(pud)	pte_present(pud_pte(pud))
68462306a36Sopenharmony_ci#define pud_leaf(pud)		(pud_present(pud) && !pud_table(pud))
68562306a36Sopenharmony_ci#define pud_valid(pud)		pte_valid(pud_pte(pud))
68662306a36Sopenharmony_ci#define pud_user(pud)		pte_user(pud_pte(pud))
68762306a36Sopenharmony_ci#define pud_user_exec(pud)	pte_user_exec(pud_pte(pud))
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_cistatic inline void set_pud(pud_t *pudp, pud_t pud)
69062306a36Sopenharmony_ci{
69162306a36Sopenharmony_ci#ifdef __PAGETABLE_PUD_FOLDED
69262306a36Sopenharmony_ci	if (in_swapper_pgdir(pudp)) {
69362306a36Sopenharmony_ci		set_swapper_pgd((pgd_t *)pudp, __pgd(pud_val(pud)));
69462306a36Sopenharmony_ci		return;
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci#endif /* __PAGETABLE_PUD_FOLDED */
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	WRITE_ONCE(*pudp, pud);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	if (pud_valid(pud)) {
70162306a36Sopenharmony_ci		dsb(ishst);
70262306a36Sopenharmony_ci		isb();
70362306a36Sopenharmony_ci	}
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic inline void pud_clear(pud_t *pudp)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	set_pud(pudp, __pud(0));
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic inline phys_addr_t pud_page_paddr(pud_t pud)
71262306a36Sopenharmony_ci{
71362306a36Sopenharmony_ci	return __pud_to_phys(pud);
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic inline pmd_t *pud_pgtable(pud_t pud)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	return (pmd_t *)__va(pud_page_paddr(pud));
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci/* Find an entry in the second-level page table. */
72262306a36Sopenharmony_ci#define pmd_offset_phys(dir, addr)	(pud_page_paddr(READ_ONCE(*(dir))) + pmd_index(addr) * sizeof(pmd_t))
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci#define pmd_set_fixmap(addr)		((pmd_t *)set_fixmap_offset(FIX_PMD, addr))
72562306a36Sopenharmony_ci#define pmd_set_fixmap_offset(pud, addr)	pmd_set_fixmap(pmd_offset_phys(pud, addr))
72662306a36Sopenharmony_ci#define pmd_clear_fixmap()		clear_fixmap(FIX_PMD)
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci#define pud_page(pud)			phys_to_page(__pud_to_phys(pud))
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci/* use ONLY for statically allocated translation tables */
73162306a36Sopenharmony_ci#define pmd_offset_kimg(dir,addr)	((pmd_t *)__phys_to_kimg(pmd_offset_phys((dir), (addr))))
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci#else
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci#define pud_page_paddr(pud)	({ BUILD_BUG(); 0; })
73662306a36Sopenharmony_ci#define pud_user_exec(pud)	pud_user(pud) /* Always 0 with folding */
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci/* Match pmd_offset folding in <asm/generic/pgtable-nopmd.h> */
73962306a36Sopenharmony_ci#define pmd_set_fixmap(addr)		NULL
74062306a36Sopenharmony_ci#define pmd_set_fixmap_offset(pudp, addr)	((pmd_t *)pudp)
74162306a36Sopenharmony_ci#define pmd_clear_fixmap()
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci#define pmd_offset_kimg(dir,addr)	((pmd_t *)dir)
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci#endif	/* CONFIG_PGTABLE_LEVELS > 2 */
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 3
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci#define pud_ERROR(e)	\
75062306a36Sopenharmony_ci	pr_err("%s:%d: bad pud %016llx.\n", __FILE__, __LINE__, pud_val(e))
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci#define p4d_none(p4d)		(!p4d_val(p4d))
75362306a36Sopenharmony_ci#define p4d_bad(p4d)		(!(p4d_val(p4d) & 2))
75462306a36Sopenharmony_ci#define p4d_present(p4d)	(p4d_val(p4d))
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_cistatic inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	if (in_swapper_pgdir(p4dp)) {
75962306a36Sopenharmony_ci		set_swapper_pgd((pgd_t *)p4dp, __pgd(p4d_val(p4d)));
76062306a36Sopenharmony_ci		return;
76162306a36Sopenharmony_ci	}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	WRITE_ONCE(*p4dp, p4d);
76462306a36Sopenharmony_ci	dsb(ishst);
76562306a36Sopenharmony_ci	isb();
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistatic inline void p4d_clear(p4d_t *p4dp)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	set_p4d(p4dp, __p4d(0));
77162306a36Sopenharmony_ci}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_cistatic inline phys_addr_t p4d_page_paddr(p4d_t p4d)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	return __p4d_to_phys(p4d);
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_cistatic inline pud_t *p4d_pgtable(p4d_t p4d)
77962306a36Sopenharmony_ci{
78062306a36Sopenharmony_ci	return (pud_t *)__va(p4d_page_paddr(p4d));
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci/* Find an entry in the first-level page table. */
78462306a36Sopenharmony_ci#define pud_offset_phys(dir, addr)	(p4d_page_paddr(READ_ONCE(*(dir))) + pud_index(addr) * sizeof(pud_t))
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci#define pud_set_fixmap(addr)		((pud_t *)set_fixmap_offset(FIX_PUD, addr))
78762306a36Sopenharmony_ci#define pud_set_fixmap_offset(p4d, addr)	pud_set_fixmap(pud_offset_phys(p4d, addr))
78862306a36Sopenharmony_ci#define pud_clear_fixmap()		clear_fixmap(FIX_PUD)
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci#define p4d_page(p4d)		pfn_to_page(__phys_to_pfn(__p4d_to_phys(p4d)))
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci/* use ONLY for statically allocated translation tables */
79362306a36Sopenharmony_ci#define pud_offset_kimg(dir,addr)	((pud_t *)__phys_to_kimg(pud_offset_phys((dir), (addr))))
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci#else
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci#define p4d_page_paddr(p4d)	({ BUILD_BUG(); 0;})
79862306a36Sopenharmony_ci#define pgd_page_paddr(pgd)	({ BUILD_BUG(); 0;})
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci/* Match pud_offset folding in <asm/generic/pgtable-nopud.h> */
80162306a36Sopenharmony_ci#define pud_set_fixmap(addr)		NULL
80262306a36Sopenharmony_ci#define pud_set_fixmap_offset(pgdp, addr)	((pud_t *)pgdp)
80362306a36Sopenharmony_ci#define pud_clear_fixmap()
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci#define pud_offset_kimg(dir,addr)	((pud_t *)dir)
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci#endif  /* CONFIG_PGTABLE_LEVELS > 3 */
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci#define pgd_ERROR(e)	\
81062306a36Sopenharmony_ci	pr_err("%s:%d: bad pgd %016llx.\n", __FILE__, __LINE__, pgd_val(e))
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci#define pgd_set_fixmap(addr)	((pgd_t *)set_fixmap_offset(FIX_PGD, addr))
81362306a36Sopenharmony_ci#define pgd_clear_fixmap()	clear_fixmap(FIX_PGD)
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_cistatic inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	/*
81862306a36Sopenharmony_ci	 * Normal and Normal-Tagged are two different memory types and indices
81962306a36Sopenharmony_ci	 * in MAIR_EL1. The mask below has to include PTE_ATTRINDX_MASK.
82062306a36Sopenharmony_ci	 */
82162306a36Sopenharmony_ci	const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
82262306a36Sopenharmony_ci			      PTE_PROT_NONE | PTE_VALID | PTE_WRITE | PTE_GP |
82362306a36Sopenharmony_ci			      PTE_ATTRINDX_MASK;
82462306a36Sopenharmony_ci	/* preserve the hardware dirty information */
82562306a36Sopenharmony_ci	if (pte_hw_dirty(pte))
82662306a36Sopenharmony_ci		pte = set_pte_bit(pte, __pgprot(PTE_DIRTY));
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
82962306a36Sopenharmony_ci	/*
83062306a36Sopenharmony_ci	 * If we end up clearing hw dirtiness for a sw-dirty PTE, set hardware
83162306a36Sopenharmony_ci	 * dirtiness again.
83262306a36Sopenharmony_ci	 */
83362306a36Sopenharmony_ci	if (pte_sw_dirty(pte))
83462306a36Sopenharmony_ci		pte = pte_mkdirty(pte);
83562306a36Sopenharmony_ci	return pte;
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_cistatic inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	return pte_pmd(pte_modify(pmd_pte(pmd), newprot));
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
84462306a36Sopenharmony_ciextern int ptep_set_access_flags(struct vm_area_struct *vma,
84562306a36Sopenharmony_ci				 unsigned long address, pte_t *ptep,
84662306a36Sopenharmony_ci				 pte_t entry, int dirty);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
84962306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
85062306a36Sopenharmony_cistatic inline int pmdp_set_access_flags(struct vm_area_struct *vma,
85162306a36Sopenharmony_ci					unsigned long address, pmd_t *pmdp,
85262306a36Sopenharmony_ci					pmd_t entry, int dirty)
85362306a36Sopenharmony_ci{
85462306a36Sopenharmony_ci	return ptep_set_access_flags(vma, address, (pte_t *)pmdp, pmd_pte(entry), dirty);
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_cistatic inline int pud_devmap(pud_t pud)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	return 0;
86062306a36Sopenharmony_ci}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_cistatic inline int pgd_devmap(pgd_t pgd)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	return 0;
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ci#endif
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci#ifdef CONFIG_PAGE_TABLE_CHECK
86962306a36Sopenharmony_cistatic inline bool pte_user_accessible_page(pte_t pte)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci	return pte_present(pte) && (pte_user(pte) || pte_user_exec(pte));
87262306a36Sopenharmony_ci}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_cistatic inline bool pmd_user_accessible_page(pmd_t pmd)
87562306a36Sopenharmony_ci{
87662306a36Sopenharmony_ci	return pmd_leaf(pmd) && !pmd_present_invalid(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
87762306a36Sopenharmony_ci}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_cistatic inline bool pud_user_accessible_page(pud_t pud)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	return pud_leaf(pud) && (pud_user(pud) || pud_user_exec(pud));
88262306a36Sopenharmony_ci}
88362306a36Sopenharmony_ci#endif
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci/*
88662306a36Sopenharmony_ci * Atomic pte/pmd modifications.
88762306a36Sopenharmony_ci */
88862306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
88962306a36Sopenharmony_cistatic inline int __ptep_test_and_clear_young(pte_t *ptep)
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci	pte_t old_pte, pte;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	pte = READ_ONCE(*ptep);
89462306a36Sopenharmony_ci	do {
89562306a36Sopenharmony_ci		old_pte = pte;
89662306a36Sopenharmony_ci		pte = pte_mkold(pte);
89762306a36Sopenharmony_ci		pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
89862306a36Sopenharmony_ci					       pte_val(old_pte), pte_val(pte));
89962306a36Sopenharmony_ci	} while (pte_val(pte) != pte_val(old_pte));
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	return pte_young(pte);
90262306a36Sopenharmony_ci}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_cistatic inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
90562306a36Sopenharmony_ci					    unsigned long address,
90662306a36Sopenharmony_ci					    pte_t *ptep)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	return __ptep_test_and_clear_young(ptep);
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
91262306a36Sopenharmony_cistatic inline int ptep_clear_flush_young(struct vm_area_struct *vma,
91362306a36Sopenharmony_ci					 unsigned long address, pte_t *ptep)
91462306a36Sopenharmony_ci{
91562306a36Sopenharmony_ci	int young = ptep_test_and_clear_young(vma, address, ptep);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	if (young) {
91862306a36Sopenharmony_ci		/*
91962306a36Sopenharmony_ci		 * We can elide the trailing DSB here since the worst that can
92062306a36Sopenharmony_ci		 * happen is that a CPU continues to use the young entry in its
92162306a36Sopenharmony_ci		 * TLB and we mistakenly reclaim the associated page. The
92262306a36Sopenharmony_ci		 * window for such an event is bounded by the next
92362306a36Sopenharmony_ci		 * context-switch, which provides a DSB to complete the TLB
92462306a36Sopenharmony_ci		 * invalidation.
92562306a36Sopenharmony_ci		 */
92662306a36Sopenharmony_ci		flush_tlb_page_nosync(vma, address);
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	return young;
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
93362306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG
93462306a36Sopenharmony_cistatic inline int pmdp_test_and_clear_young(struct vm_area_struct *vma,
93562306a36Sopenharmony_ci					    unsigned long address,
93662306a36Sopenharmony_ci					    pmd_t *pmdp)
93762306a36Sopenharmony_ci{
93862306a36Sopenharmony_ci	return ptep_test_and_clear_young(vma, address, (pte_t *)pmdp);
93962306a36Sopenharmony_ci}
94062306a36Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
94362306a36Sopenharmony_cistatic inline pte_t ptep_get_and_clear(struct mm_struct *mm,
94462306a36Sopenharmony_ci				       unsigned long address, pte_t *ptep)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	pte_t pte = __pte(xchg_relaxed(&pte_val(*ptep), 0));
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	page_table_check_pte_clear(mm, pte);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	return pte;
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
95462306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR
95562306a36Sopenharmony_cistatic inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
95662306a36Sopenharmony_ci					    unsigned long address, pmd_t *pmdp)
95762306a36Sopenharmony_ci{
95862306a36Sopenharmony_ci	pmd_t pmd = __pmd(xchg_relaxed(&pmd_val(*pmdp), 0));
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	page_table_check_pmd_clear(mm, pmd);
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	return pmd;
96362306a36Sopenharmony_ci}
96462306a36Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci/*
96762306a36Sopenharmony_ci * ptep_set_wrprotect - mark read-only while trasferring potential hardware
96862306a36Sopenharmony_ci * dirty status (PTE_DBM && !PTE_RDONLY) to the software PTE_DIRTY bit.
96962306a36Sopenharmony_ci */
97062306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_SET_WRPROTECT
97162306a36Sopenharmony_cistatic inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep)
97262306a36Sopenharmony_ci{
97362306a36Sopenharmony_ci	pte_t old_pte, pte;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	pte = READ_ONCE(*ptep);
97662306a36Sopenharmony_ci	do {
97762306a36Sopenharmony_ci		old_pte = pte;
97862306a36Sopenharmony_ci		pte = pte_wrprotect(pte);
97962306a36Sopenharmony_ci		pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
98062306a36Sopenharmony_ci					       pte_val(old_pte), pte_val(pte));
98162306a36Sopenharmony_ci	} while (pte_val(pte) != pte_val(old_pte));
98262306a36Sopenharmony_ci}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
98562306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_SET_WRPROTECT
98662306a36Sopenharmony_cistatic inline void pmdp_set_wrprotect(struct mm_struct *mm,
98762306a36Sopenharmony_ci				      unsigned long address, pmd_t *pmdp)
98862306a36Sopenharmony_ci{
98962306a36Sopenharmony_ci	ptep_set_wrprotect(mm, address, (pte_t *)pmdp);
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci#define pmdp_establish pmdp_establish
99362306a36Sopenharmony_cistatic inline pmd_t pmdp_establish(struct vm_area_struct *vma,
99462306a36Sopenharmony_ci		unsigned long address, pmd_t *pmdp, pmd_t pmd)
99562306a36Sopenharmony_ci{
99662306a36Sopenharmony_ci	page_table_check_pmd_set(vma->vm_mm, pmdp, pmd);
99762306a36Sopenharmony_ci	return __pmd(xchg_relaxed(&pmd_val(*pmdp), pmd_val(pmd)));
99862306a36Sopenharmony_ci}
99962306a36Sopenharmony_ci#endif
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci/*
100262306a36Sopenharmony_ci * Encode and decode a swap entry:
100362306a36Sopenharmony_ci *	bits 0-1:	present (must be zero)
100462306a36Sopenharmony_ci *	bits 2:		remember PG_anon_exclusive
100562306a36Sopenharmony_ci *	bits 3-7:	swap type
100662306a36Sopenharmony_ci *	bits 8-57:	swap offset
100762306a36Sopenharmony_ci *	bit  58:	PTE_PROT_NONE (must be zero)
100862306a36Sopenharmony_ci */
100962306a36Sopenharmony_ci#define __SWP_TYPE_SHIFT	3
101062306a36Sopenharmony_ci#define __SWP_TYPE_BITS		5
101162306a36Sopenharmony_ci#define __SWP_OFFSET_BITS	50
101262306a36Sopenharmony_ci#define __SWP_TYPE_MASK		((1 << __SWP_TYPE_BITS) - 1)
101362306a36Sopenharmony_ci#define __SWP_OFFSET_SHIFT	(__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
101462306a36Sopenharmony_ci#define __SWP_OFFSET_MASK	((1UL << __SWP_OFFSET_BITS) - 1)
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci#define __swp_type(x)		(((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK)
101762306a36Sopenharmony_ci#define __swp_offset(x)		(((x).val >> __SWP_OFFSET_SHIFT) & __SWP_OFFSET_MASK)
101862306a36Sopenharmony_ci#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) })
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci#define __pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) })
102162306a36Sopenharmony_ci#define __swp_entry_to_pte(swp)	((pte_t) { (swp).val })
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
102462306a36Sopenharmony_ci#define __pmd_to_swp_entry(pmd)		((swp_entry_t) { pmd_val(pmd) })
102562306a36Sopenharmony_ci#define __swp_entry_to_pmd(swp)		__pmd((swp).val)
102662306a36Sopenharmony_ci#endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci/*
102962306a36Sopenharmony_ci * Ensure that there are not more swap files than can be encoded in the kernel
103062306a36Sopenharmony_ci * PTEs.
103162306a36Sopenharmony_ci */
103262306a36Sopenharmony_ci#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS)
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci#ifdef CONFIG_ARM64_MTE
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci#define __HAVE_ARCH_PREPARE_TO_SWAP
103762306a36Sopenharmony_cistatic inline int arch_prepare_to_swap(struct page *page)
103862306a36Sopenharmony_ci{
103962306a36Sopenharmony_ci	if (system_supports_mte())
104062306a36Sopenharmony_ci		return mte_save_tags(page);
104162306a36Sopenharmony_ci	return 0;
104262306a36Sopenharmony_ci}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci#define __HAVE_ARCH_SWAP_INVALIDATE
104562306a36Sopenharmony_cistatic inline void arch_swap_invalidate_page(int type, pgoff_t offset)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci	if (system_supports_mte())
104862306a36Sopenharmony_ci		mte_invalidate_tags(type, offset);
104962306a36Sopenharmony_ci}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_cistatic inline void arch_swap_invalidate_area(int type)
105262306a36Sopenharmony_ci{
105362306a36Sopenharmony_ci	if (system_supports_mte())
105462306a36Sopenharmony_ci		mte_invalidate_tags_area(type);
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci#define __HAVE_ARCH_SWAP_RESTORE
105862306a36Sopenharmony_cistatic inline void arch_swap_restore(swp_entry_t entry, struct folio *folio)
105962306a36Sopenharmony_ci{
106062306a36Sopenharmony_ci	if (system_supports_mte())
106162306a36Sopenharmony_ci		mte_restore_tags(entry, &folio->page);
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci#endif /* CONFIG_ARM64_MTE */
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci/*
106762306a36Sopenharmony_ci * On AArch64, the cache coherency is handled via the set_pte_at() function.
106862306a36Sopenharmony_ci */
106962306a36Sopenharmony_cistatic inline void update_mmu_cache_range(struct vm_fault *vmf,
107062306a36Sopenharmony_ci		struct vm_area_struct *vma, unsigned long addr, pte_t *ptep,
107162306a36Sopenharmony_ci		unsigned int nr)
107262306a36Sopenharmony_ci{
107362306a36Sopenharmony_ci	/*
107462306a36Sopenharmony_ci	 * We don't do anything here, so there's a very small chance of
107562306a36Sopenharmony_ci	 * us retaking a user fault which we just fixed up. The alternative
107662306a36Sopenharmony_ci	 * is doing a dsb(ishst), but that penalises the fastpath.
107762306a36Sopenharmony_ci	 */
107862306a36Sopenharmony_ci}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci#define update_mmu_cache(vma, addr, ptep) \
108162306a36Sopenharmony_ci	update_mmu_cache_range(NULL, vma, addr, ptep, 1)
108262306a36Sopenharmony_ci#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci#ifdef CONFIG_ARM64_PA_BITS_52
108562306a36Sopenharmony_ci#define phys_to_ttbr(addr)	(((addr) | ((addr) >> 46)) & TTBR_BADDR_MASK_52)
108662306a36Sopenharmony_ci#else
108762306a36Sopenharmony_ci#define phys_to_ttbr(addr)	(addr)
108862306a36Sopenharmony_ci#endif
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci/*
109162306a36Sopenharmony_ci * On arm64 without hardware Access Flag, copying from user will fail because
109262306a36Sopenharmony_ci * the pte is old and cannot be marked young. So we always end up with zeroed
109362306a36Sopenharmony_ci * page after fork() + CoW for pfn mappings. We don't always have a
109462306a36Sopenharmony_ci * hardware-managed access flag on arm64.
109562306a36Sopenharmony_ci */
109662306a36Sopenharmony_ci#define arch_has_hw_pte_young		cpu_has_hw_af
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci/*
109962306a36Sopenharmony_ci * Experimentally, it's cheap to set the access flag in hardware and we
110062306a36Sopenharmony_ci * benefit from prefaulting mappings as 'old' to start with.
110162306a36Sopenharmony_ci */
110262306a36Sopenharmony_ci#define arch_wants_old_prefaulted_pte	cpu_has_hw_af
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_cistatic inline bool pud_sect_supported(void)
110562306a36Sopenharmony_ci{
110662306a36Sopenharmony_ci	return PAGE_SIZE == SZ_4K;
110762306a36Sopenharmony_ci}
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
111162306a36Sopenharmony_ci#define ptep_modify_prot_start ptep_modify_prot_start
111262306a36Sopenharmony_ciextern pte_t ptep_modify_prot_start(struct vm_area_struct *vma,
111362306a36Sopenharmony_ci				    unsigned long addr, pte_t *ptep);
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci#define ptep_modify_prot_commit ptep_modify_prot_commit
111662306a36Sopenharmony_ciextern void ptep_modify_prot_commit(struct vm_area_struct *vma,
111762306a36Sopenharmony_ci				    unsigned long addr, pte_t *ptep,
111862306a36Sopenharmony_ci				    pte_t old_pte, pte_t new_pte);
111962306a36Sopenharmony_ci#endif /* !__ASSEMBLY__ */
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci#endif /* __ASM_PGTABLE_H */
1122