18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2012 ARM Ltd.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci#ifndef __ASM_PGTABLE_H
68c2ecf20Sopenharmony_ci#define __ASM_PGTABLE_H
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <asm/bug.h>
98c2ecf20Sopenharmony_ci#include <asm/proc-fns.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <asm/memory.h>
128c2ecf20Sopenharmony_ci#include <asm/mte.h>
138c2ecf20Sopenharmony_ci#include <asm/pgtable-hwdef.h>
148c2ecf20Sopenharmony_ci#include <asm/pgtable-prot.h>
158c2ecf20Sopenharmony_ci#include <asm/tlbflush.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/*
188c2ecf20Sopenharmony_ci * VMALLOC range.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * VMALLOC_START: beginning of the kernel vmalloc space
218c2ecf20Sopenharmony_ci * VMALLOC_END: extends to the available space below vmemmap, PCI I/O space
228c2ecf20Sopenharmony_ci *	and fixed mappings
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_ci#define VMALLOC_START		(MODULES_END)
258c2ecf20Sopenharmony_ci#define VMALLOC_END		(- PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define vmemmap			((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT))
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define FIRST_USER_ADDRESS	0UL
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h>
348c2ecf20Sopenharmony_ci#include <asm/fixmap.h>
358c2ecf20Sopenharmony_ci#include <linux/mmdebug.h>
368c2ecf20Sopenharmony_ci#include <linux/mm_types.h>
378c2ecf20Sopenharmony_ci#include <linux/sched.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
408c2ecf20Sopenharmony_ci#define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/* Set stride and tlb_level in flush_*_tlb_range */
438c2ecf20Sopenharmony_ci#define flush_pmd_tlb_range(vma, addr, end)	\
448c2ecf20Sopenharmony_ci	__flush_tlb_range(vma, addr, end, PMD_SIZE, false, 2)
458c2ecf20Sopenharmony_ci#define flush_pud_tlb_range(vma, addr, end)	\
468c2ecf20Sopenharmony_ci	__flush_tlb_range(vma, addr, end, PUD_SIZE, false, 1)
478c2ecf20Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/*
508c2ecf20Sopenharmony_ci * Outside of a few very special situations (e.g. hibernation), we always
518c2ecf20Sopenharmony_ci * use broadcast TLB invalidation instructions, therefore a spurious page
528c2ecf20Sopenharmony_ci * fault on one CPU which has been handled concurrently by another CPU
538c2ecf20Sopenharmony_ci * does not need to perform additional invalidation.
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_ci#define flush_tlb_fix_spurious_fault(vma, address) do { } while (0)
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/*
588c2ecf20Sopenharmony_ci * ZERO_PAGE is a global shared page that is always zero: used
598c2ecf20Sopenharmony_ci * for zero-mapped memory areas etc..
608c2ecf20Sopenharmony_ci */
618c2ecf20Sopenharmony_ciextern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
628c2ecf20Sopenharmony_ci#define ZERO_PAGE(vaddr)	phys_to_page(__pa_symbol(empty_zero_page))
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci#define pte_ERROR(e)	\
658c2ecf20Sopenharmony_ci	pr_err("%s:%d: bad pte %016llx.\n", __FILE__, __LINE__, pte_val(e))
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci/*
688c2ecf20Sopenharmony_ci * Macros to convert between a physical address and its placement in a
698c2ecf20Sopenharmony_ci * page table entry, taking care of 52-bit addresses.
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM64_PA_BITS_52
728c2ecf20Sopenharmony_cistatic inline phys_addr_t __pte_to_phys(pte_t pte)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	return (pte_val(pte) & PTE_ADDR_LOW) |
758c2ecf20Sopenharmony_ci		((pte_val(pte) & PTE_ADDR_HIGH) << 36);
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_cistatic inline pteval_t __phys_to_pte_val(phys_addr_t phys)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	return (phys | (phys >> 36)) & PTE_ADDR_MASK;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci#else
828c2ecf20Sopenharmony_ci#define __pte_to_phys(pte)	(pte_val(pte) & PTE_ADDR_MASK)
838c2ecf20Sopenharmony_ci#define __phys_to_pte_val(phys)	(phys)
848c2ecf20Sopenharmony_ci#endif
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#define pte_pfn(pte)		(__pte_to_phys(pte) >> PAGE_SHIFT)
878c2ecf20Sopenharmony_ci#define pfn_pte(pfn,prot)	\
888c2ecf20Sopenharmony_ci	__pte(__phys_to_pte_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci#define pte_none(pte)		(!pte_val(pte))
918c2ecf20Sopenharmony_ci#define pte_clear(mm,addr,ptep)	set_pte(ptep, __pte(0))
928c2ecf20Sopenharmony_ci#define pte_page(pte)		(pfn_to_page(pte_pfn(pte)))
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci/*
958c2ecf20Sopenharmony_ci * The following only work if pte_present(). Undefined behaviour otherwise.
968c2ecf20Sopenharmony_ci */
978c2ecf20Sopenharmony_ci#define pte_present(pte)	(!!(pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)))
988c2ecf20Sopenharmony_ci#define pte_young(pte)		(!!(pte_val(pte) & PTE_AF))
998c2ecf20Sopenharmony_ci#define pte_special(pte)	(!!(pte_val(pte) & PTE_SPECIAL))
1008c2ecf20Sopenharmony_ci#define pte_write(pte)		(!!(pte_val(pte) & PTE_WRITE))
1018c2ecf20Sopenharmony_ci#define pte_user_exec(pte)	(!(pte_val(pte) & PTE_UXN))
1028c2ecf20Sopenharmony_ci#define pte_cont(pte)		(!!(pte_val(pte) & PTE_CONT))
1038c2ecf20Sopenharmony_ci#define pte_devmap(pte)		(!!(pte_val(pte) & PTE_DEVMAP))
1048c2ecf20Sopenharmony_ci#define pte_tagged(pte)		((pte_val(pte) & PTE_ATTRINDX_MASK) == \
1058c2ecf20Sopenharmony_ci				 PTE_ATTRINDX(MT_NORMAL_TAGGED))
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci#define pte_cont_addr_end(addr, end)						\
1088c2ecf20Sopenharmony_ci({	unsigned long __boundary = ((addr) + CONT_PTE_SIZE) & CONT_PTE_MASK;	\
1098c2ecf20Sopenharmony_ci	(__boundary - 1 < (end) - 1) ? __boundary : (end);			\
1108c2ecf20Sopenharmony_ci})
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci#define pmd_cont_addr_end(addr, end)						\
1138c2ecf20Sopenharmony_ci({	unsigned long __boundary = ((addr) + CONT_PMD_SIZE) & CONT_PMD_MASK;	\
1148c2ecf20Sopenharmony_ci	(__boundary - 1 < (end) - 1) ? __boundary : (end);			\
1158c2ecf20Sopenharmony_ci})
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#define pte_hw_dirty(pte)	(pte_write(pte) && !(pte_val(pte) & PTE_RDONLY))
1188c2ecf20Sopenharmony_ci#define pte_sw_dirty(pte)	(!!(pte_val(pte) & PTE_DIRTY))
1198c2ecf20Sopenharmony_ci#define pte_dirty(pte)		(pte_sw_dirty(pte) || pte_hw_dirty(pte))
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci#define pte_valid(pte)		(!!(pte_val(pte) & PTE_VALID))
1228c2ecf20Sopenharmony_ci#define pte_valid_not_user(pte) \
1238c2ecf20Sopenharmony_ci	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
1248c2ecf20Sopenharmony_ci#define pte_valid_user(pte) \
1258c2ecf20Sopenharmony_ci	((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER))
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/*
1288c2ecf20Sopenharmony_ci * Could the pte be present in the TLB? We must check mm_tlb_flush_pending
1298c2ecf20Sopenharmony_ci * so that we don't erroneously return false for pages that have been
1308c2ecf20Sopenharmony_ci * remapped as PROT_NONE but are yet to be flushed from the TLB.
1318c2ecf20Sopenharmony_ci * Note that we can't make any assumptions based on the state of the access
1328c2ecf20Sopenharmony_ci * flag, since ptep_clear_flush_young() elides a DSB when invalidating the
1338c2ecf20Sopenharmony_ci * TLB.
1348c2ecf20Sopenharmony_ci */
1358c2ecf20Sopenharmony_ci#define pte_accessible(mm, pte)	\
1368c2ecf20Sopenharmony_ci	(mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid(pte))
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/*
1398c2ecf20Sopenharmony_ci * p??_access_permitted() is true for valid user mappings (subject to the
1408c2ecf20Sopenharmony_ci * write permission check). PROT_NONE mappings do not have the PTE_VALID bit
1418c2ecf20Sopenharmony_ci * set.
1428c2ecf20Sopenharmony_ci */
1438c2ecf20Sopenharmony_ci#define pte_access_permitted(pte, write) \
1448c2ecf20Sopenharmony_ci	(pte_valid_user(pte) && (!(write) || pte_write(pte)))
1458c2ecf20Sopenharmony_ci#define pmd_access_permitted(pmd, write) \
1468c2ecf20Sopenharmony_ci	(pte_access_permitted(pmd_pte(pmd), (write)))
1478c2ecf20Sopenharmony_ci#define pud_access_permitted(pud, write) \
1488c2ecf20Sopenharmony_ci	(pte_access_permitted(pud_pte(pud), (write)))
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	pte_val(pte) &= ~pgprot_val(prot);
1538c2ecf20Sopenharmony_ci	return pte;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic inline pte_t set_pte_bit(pte_t pte, pgprot_t prot)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	pte_val(pte) |= pgprot_val(prot);
1598c2ecf20Sopenharmony_ci	return pte;
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic inline pmd_t clear_pmd_bit(pmd_t pmd, pgprot_t prot)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	pmd_val(pmd) &= ~pgprot_val(prot);
1658c2ecf20Sopenharmony_ci	return pmd;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic inline pmd_t set_pmd_bit(pmd_t pmd, pgprot_t prot)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	pmd_val(pmd) |= pgprot_val(prot);
1718c2ecf20Sopenharmony_ci	return pmd;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic inline pte_t pte_mkwrite(pte_t pte)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	pte = set_pte_bit(pte, __pgprot(PTE_WRITE));
1778c2ecf20Sopenharmony_ci	pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
1788c2ecf20Sopenharmony_ci	return pte;
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic inline pte_t pte_mkclean(pte_t pte)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	pte = clear_pte_bit(pte, __pgprot(PTE_DIRTY));
1848c2ecf20Sopenharmony_ci	pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	return pte;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic inline pte_t pte_mkdirty(pte_t pte)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	pte = set_pte_bit(pte, __pgprot(PTE_DIRTY));
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	if (pte_write(pte))
1948c2ecf20Sopenharmony_ci		pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	return pte;
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic inline pte_t pte_wrprotect(pte_t pte)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	/*
2028c2ecf20Sopenharmony_ci	 * If hardware-dirty (PTE_WRITE/DBM bit set and PTE_RDONLY
2038c2ecf20Sopenharmony_ci	 * clear), set the PTE_DIRTY bit.
2048c2ecf20Sopenharmony_ci	 */
2058c2ecf20Sopenharmony_ci	if (pte_hw_dirty(pte))
2068c2ecf20Sopenharmony_ci		pte = pte_mkdirty(pte);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	pte = clear_pte_bit(pte, __pgprot(PTE_WRITE));
2098c2ecf20Sopenharmony_ci	pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
2108c2ecf20Sopenharmony_ci	return pte;
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic inline pte_t pte_mkold(pte_t pte)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	return clear_pte_bit(pte, __pgprot(PTE_AF));
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistatic inline pte_t pte_mkyoung(pte_t pte)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	return set_pte_bit(pte, __pgprot(PTE_AF));
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic inline pte_t pte_mkspecial(pte_t pte)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	return set_pte_bit(pte, __pgprot(PTE_SPECIAL));
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic inline pte_t pte_mkcont(pte_t pte)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	pte = set_pte_bit(pte, __pgprot(PTE_CONT));
2318c2ecf20Sopenharmony_ci	return set_pte_bit(pte, __pgprot(PTE_TYPE_PAGE));
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic inline pte_t pte_mknoncont(pte_t pte)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	return clear_pte_bit(pte, __pgprot(PTE_CONT));
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic inline pte_t pte_mkpresent(pte_t pte)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	return set_pte_bit(pte, __pgprot(PTE_VALID));
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic inline pmd_t pmd_mkcont(pmd_t pmd)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	return __pmd(pmd_val(pmd) | PMD_SECT_CONT);
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic inline pte_t pte_mkdevmap(pte_t pte)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	return set_pte_bit(pte, __pgprot(PTE_DEVMAP | PTE_SPECIAL));
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic inline void set_pte(pte_t *ptep, pte_t pte)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	WRITE_ONCE(*ptep, pte);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	/*
2598c2ecf20Sopenharmony_ci	 * Only if the new pte is valid and kernel, otherwise TLB maintenance
2608c2ecf20Sopenharmony_ci	 * or update_mmu_cache() have the necessary barriers.
2618c2ecf20Sopenharmony_ci	 */
2628c2ecf20Sopenharmony_ci	if (pte_valid_not_user(pte)) {
2638c2ecf20Sopenharmony_ci		dsb(ishst);
2648c2ecf20Sopenharmony_ci		isb();
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ciextern void __sync_icache_dcache(pte_t pteval);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci/*
2718c2ecf20Sopenharmony_ci * PTE bits configuration in the presence of hardware Dirty Bit Management
2728c2ecf20Sopenharmony_ci * (PTE_WRITE == PTE_DBM):
2738c2ecf20Sopenharmony_ci *
2748c2ecf20Sopenharmony_ci * Dirty  Writable | PTE_RDONLY  PTE_WRITE  PTE_DIRTY (sw)
2758c2ecf20Sopenharmony_ci *   0      0      |   1           0          0
2768c2ecf20Sopenharmony_ci *   0      1      |   1           1          0
2778c2ecf20Sopenharmony_ci *   1      0      |   1           0          1
2788c2ecf20Sopenharmony_ci *   1      1      |   0           1          x
2798c2ecf20Sopenharmony_ci *
2808c2ecf20Sopenharmony_ci * When hardware DBM is not present, the sofware PTE_DIRTY bit is updated via
2818c2ecf20Sopenharmony_ci * the page fault mechanism. Checking the dirty status of a pte becomes:
2828c2ecf20Sopenharmony_ci *
2838c2ecf20Sopenharmony_ci *   PTE_DIRTY || (PTE_WRITE && !PTE_RDONLY)
2848c2ecf20Sopenharmony_ci */
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic inline void __check_racy_pte_update(struct mm_struct *mm, pte_t *ptep,
2878c2ecf20Sopenharmony_ci					   pte_t pte)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	pte_t old_pte;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_DEBUG_VM))
2928c2ecf20Sopenharmony_ci		return;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	old_pte = READ_ONCE(*ptep);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (!pte_valid(old_pte) || !pte_valid(pte))
2978c2ecf20Sopenharmony_ci		return;
2988c2ecf20Sopenharmony_ci	if (mm != current->active_mm && atomic_read(&mm->mm_users) <= 1)
2998c2ecf20Sopenharmony_ci		return;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/*
3028c2ecf20Sopenharmony_ci	 * Check for potential race with hardware updates of the pte
3038c2ecf20Sopenharmony_ci	 * (ptep_set_access_flags safely changes valid ptes without going
3048c2ecf20Sopenharmony_ci	 * through an invalid entry).
3058c2ecf20Sopenharmony_ci	 */
3068c2ecf20Sopenharmony_ci	VM_WARN_ONCE(!pte_young(pte),
3078c2ecf20Sopenharmony_ci		     "%s: racy access flag clearing: 0x%016llx -> 0x%016llx",
3088c2ecf20Sopenharmony_ci		     __func__, pte_val(old_pte), pte_val(pte));
3098c2ecf20Sopenharmony_ci	VM_WARN_ONCE(pte_write(old_pte) && !pte_dirty(pte),
3108c2ecf20Sopenharmony_ci		     "%s: racy dirty state clearing: 0x%016llx -> 0x%016llx",
3118c2ecf20Sopenharmony_ci		     __func__, pte_val(old_pte), pte_val(pte));
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
3158c2ecf20Sopenharmony_ci			      pte_t *ptep, pte_t pte)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	if (pte_present(pte) && pte_user_exec(pte) && !pte_special(pte))
3188c2ecf20Sopenharmony_ci		__sync_icache_dcache(pte);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (system_supports_mte() &&
3218c2ecf20Sopenharmony_ci	    pte_present(pte) && pte_tagged(pte) && !pte_special(pte))
3228c2ecf20Sopenharmony_ci		mte_sync_tags(ptep, pte);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	__check_racy_pte_update(mm, ptep, pte);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	set_pte(ptep, pte);
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci/*
3308c2ecf20Sopenharmony_ci * Huge pte definitions.
3318c2ecf20Sopenharmony_ci */
3328c2ecf20Sopenharmony_ci#define pte_mkhuge(pte)		(__pte(pte_val(pte) & ~PTE_TABLE_BIT))
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci/*
3358c2ecf20Sopenharmony_ci * Hugetlb definitions.
3368c2ecf20Sopenharmony_ci */
3378c2ecf20Sopenharmony_ci#define HUGE_MAX_HSTATE		4
3388c2ecf20Sopenharmony_ci#define HPAGE_SHIFT		PMD_SHIFT
3398c2ecf20Sopenharmony_ci#define HPAGE_SIZE		(_AC(1, UL) << HPAGE_SHIFT)
3408c2ecf20Sopenharmony_ci#define HPAGE_MASK		(~(HPAGE_SIZE - 1))
3418c2ecf20Sopenharmony_ci#define HUGETLB_PAGE_ORDER	(HPAGE_SHIFT - PAGE_SHIFT)
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic inline pte_t pgd_pte(pgd_t pgd)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	return __pte(pgd_val(pgd));
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic inline pte_t p4d_pte(p4d_t p4d)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	return __pte(p4d_val(p4d));
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic inline pte_t pud_pte(pud_t pud)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	return __pte(pud_val(pud));
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic inline pud_t pte_pud(pte_t pte)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	return __pud(pte_val(pte));
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cistatic inline pmd_t pud_pmd(pud_t pud)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	return __pmd(pud_val(pud));
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic inline pte_t pmd_pte(pmd_t pmd)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	return __pte(pmd_val(pmd));
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic inline pmd_t pte_pmd(pte_t pte)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	return __pmd(pte_val(pte));
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic inline pgprot_t mk_pud_sect_prot(pgprot_t prot)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	return __pgprot((pgprot_val(prot) & ~PUD_TABLE_BIT) | PUD_TYPE_SECT);
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic inline pgprot_t mk_pmd_sect_prot(pgprot_t prot)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	return __pgprot((pgprot_val(prot) & ~PMD_TABLE_BIT) | PMD_TYPE_SECT);
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA_BALANCING
3898c2ecf20Sopenharmony_ci/*
3908c2ecf20Sopenharmony_ci * See the comment in include/linux/pgtable.h
3918c2ecf20Sopenharmony_ci */
3928c2ecf20Sopenharmony_cistatic inline int pte_protnone(pte_t pte)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	return (pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)) == PTE_PROT_NONE;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic inline int pmd_protnone(pmd_t pmd)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	return pte_protnone(pmd_pte(pmd));
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci#endif
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci#define pmd_present_invalid(pmd)     (!!(pmd_val(pmd) & PMD_PRESENT_INVALID))
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic inline int pmd_present(pmd_t pmd)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	return pte_present(pmd_pte(pmd)) || pmd_present_invalid(pmd);
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci/*
4118c2ecf20Sopenharmony_ci * THP definitions.
4128c2ecf20Sopenharmony_ci */
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
4158c2ecf20Sopenharmony_cistatic inline int pmd_trans_huge(pmd_t pmd)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	return pmd_val(pmd) && pmd_present(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT);
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci#define pmd_dirty(pmd)		pte_dirty(pmd_pte(pmd))
4228c2ecf20Sopenharmony_ci#define pmd_young(pmd)		pte_young(pmd_pte(pmd))
4238c2ecf20Sopenharmony_ci#define pmd_valid(pmd)		pte_valid(pmd_pte(pmd))
4248c2ecf20Sopenharmony_ci#define pmd_wrprotect(pmd)	pte_pmd(pte_wrprotect(pmd_pte(pmd)))
4258c2ecf20Sopenharmony_ci#define pmd_mkold(pmd)		pte_pmd(pte_mkold(pmd_pte(pmd)))
4268c2ecf20Sopenharmony_ci#define pmd_mkwrite(pmd)	pte_pmd(pte_mkwrite(pmd_pte(pmd)))
4278c2ecf20Sopenharmony_ci#define pmd_mkclean(pmd)	pte_pmd(pte_mkclean(pmd_pte(pmd)))
4288c2ecf20Sopenharmony_ci#define pmd_mkdirty(pmd)	pte_pmd(pte_mkdirty(pmd_pte(pmd)))
4298c2ecf20Sopenharmony_ci#define pmd_mkyoung(pmd)	pte_pmd(pte_mkyoung(pmd_pte(pmd)))
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_cistatic inline pmd_t pmd_mkinvalid(pmd_t pmd)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	pmd = set_pmd_bit(pmd, __pgprot(PMD_PRESENT_INVALID));
4348c2ecf20Sopenharmony_ci	pmd = clear_pmd_bit(pmd, __pgprot(PMD_SECT_VALID));
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	return pmd;
4378c2ecf20Sopenharmony_ci}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci#define pmd_thp_or_huge(pmd)	(pmd_huge(pmd) || pmd_trans_huge(pmd))
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci#define pmd_write(pmd)		pte_write(pmd_pte(pmd))
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci#define pmd_mkhuge(pmd)		(__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
4468c2ecf20Sopenharmony_ci#define pmd_devmap(pmd)		pte_devmap(pmd_pte(pmd))
4478c2ecf20Sopenharmony_ci#endif
4488c2ecf20Sopenharmony_cistatic inline pmd_t pmd_mkdevmap(pmd_t pmd)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	return pte_pmd(set_pte_bit(pmd_pte(pmd), __pgprot(PTE_DEVMAP)));
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci#define __pmd_to_phys(pmd)	__pte_to_phys(pmd_pte(pmd))
4548c2ecf20Sopenharmony_ci#define __phys_to_pmd_val(phys)	__phys_to_pte_val(phys)
4558c2ecf20Sopenharmony_ci#define pmd_pfn(pmd)		((__pmd_to_phys(pmd) & PMD_MASK) >> PAGE_SHIFT)
4568c2ecf20Sopenharmony_ci#define pfn_pmd(pfn,prot)	__pmd(__phys_to_pmd_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
4578c2ecf20Sopenharmony_ci#define mk_pmd(page,prot)	pfn_pmd(page_to_pfn(page),prot)
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci#define pud_young(pud)		pte_young(pud_pte(pud))
4608c2ecf20Sopenharmony_ci#define pud_mkyoung(pud)	pte_pud(pte_mkyoung(pud_pte(pud)))
4618c2ecf20Sopenharmony_ci#define pud_write(pud)		pte_write(pud_pte(pud))
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci#define pud_mkhuge(pud)		(__pud(pud_val(pud) & ~PUD_TABLE_BIT))
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci#define __pud_to_phys(pud)	__pte_to_phys(pud_pte(pud))
4668c2ecf20Sopenharmony_ci#define __phys_to_pud_val(phys)	__phys_to_pte_val(phys)
4678c2ecf20Sopenharmony_ci#define pud_pfn(pud)		((__pud_to_phys(pud) & PUD_MASK) >> PAGE_SHIFT)
4688c2ecf20Sopenharmony_ci#define pfn_pud(pfn,prot)	__pud(__phys_to_pud_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci#define set_pmd_at(mm, addr, pmdp, pmd)	set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd))
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci#define __p4d_to_phys(p4d)	__pte_to_phys(p4d_pte(p4d))
4738c2ecf20Sopenharmony_ci#define __phys_to_p4d_val(phys)	__phys_to_pte_val(phys)
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci#define __pgd_to_phys(pgd)	__pte_to_phys(pgd_pte(pgd))
4768c2ecf20Sopenharmony_ci#define __phys_to_pgd_val(phys)	__phys_to_pte_val(phys)
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci#define __pgprot_modify(prot,mask,bits) \
4798c2ecf20Sopenharmony_ci	__pgprot((pgprot_val(prot) & ~(mask)) | (bits))
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci#define pgprot_nx(prot) \
4828c2ecf20Sopenharmony_ci	__pgprot_modify(prot, PTE_MAYBE_GP, PTE_PXN)
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci/*
4858c2ecf20Sopenharmony_ci * Mark the prot value as uncacheable and unbufferable.
4868c2ecf20Sopenharmony_ci */
4878c2ecf20Sopenharmony_ci#define pgprot_noncached(prot) \
4888c2ecf20Sopenharmony_ci	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE) | PTE_PXN | PTE_UXN)
4898c2ecf20Sopenharmony_ci#define pgprot_writecombine(prot) \
4908c2ecf20Sopenharmony_ci	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
4918c2ecf20Sopenharmony_ci#define pgprot_device(prot) \
4928c2ecf20Sopenharmony_ci	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN)
4938c2ecf20Sopenharmony_ci#define pgprot_tagged(prot) \
4948c2ecf20Sopenharmony_ci	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_TAGGED))
4958c2ecf20Sopenharmony_ci#define pgprot_mhp	pgprot_tagged
4968c2ecf20Sopenharmony_ci/*
4978c2ecf20Sopenharmony_ci * DMA allocations for non-coherent devices use what the Arm architecture calls
4988c2ecf20Sopenharmony_ci * "Normal non-cacheable" memory, which permits speculation, unaligned accesses
4998c2ecf20Sopenharmony_ci * and merging of writes.  This is different from "Device-nGnR[nE]" memory which
5008c2ecf20Sopenharmony_ci * is intended for MMIO and thus forbids speculation, preserves access size,
5018c2ecf20Sopenharmony_ci * requires strict alignment and can also force write responses to come from the
5028c2ecf20Sopenharmony_ci * endpoint.
5038c2ecf20Sopenharmony_ci */
5048c2ecf20Sopenharmony_ci#define pgprot_dmacoherent(prot) \
5058c2ecf20Sopenharmony_ci	__pgprot_modify(prot, PTE_ATTRINDX_MASK, \
5068c2ecf20Sopenharmony_ci			PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci#define __HAVE_PHYS_MEM_ACCESS_PROT
5098c2ecf20Sopenharmony_cistruct file;
5108c2ecf20Sopenharmony_ciextern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
5118c2ecf20Sopenharmony_ci				     unsigned long size, pgprot_t vma_prot);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci#define pmd_none(pmd)		(!pmd_val(pmd))
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci#define pmd_table(pmd)		((pmd_val(pmd) & PMD_TYPE_MASK) == \
5168c2ecf20Sopenharmony_ci				 PMD_TYPE_TABLE)
5178c2ecf20Sopenharmony_ci#define pmd_sect(pmd)		((pmd_val(pmd) & PMD_TYPE_MASK) == \
5188c2ecf20Sopenharmony_ci				 PMD_TYPE_SECT)
5198c2ecf20Sopenharmony_ci#define pmd_leaf(pmd)		(pmd_present(pmd) && !pmd_table(pmd))
5208c2ecf20Sopenharmony_ci#define pmd_bad(pmd)		(!pmd_table(pmd))
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci#if defined(CONFIG_ARM64_64K_PAGES) || CONFIG_PGTABLE_LEVELS < 3
5238c2ecf20Sopenharmony_cistatic inline bool pud_sect(pud_t pud) { return false; }
5248c2ecf20Sopenharmony_cistatic inline bool pud_table(pud_t pud) { return true; }
5258c2ecf20Sopenharmony_ci#else
5268c2ecf20Sopenharmony_ci#define pud_sect(pud)		((pud_val(pud) & PUD_TYPE_MASK) == \
5278c2ecf20Sopenharmony_ci				 PUD_TYPE_SECT)
5288c2ecf20Sopenharmony_ci#define pud_table(pud)		((pud_val(pud) & PUD_TYPE_MASK) == \
5298c2ecf20Sopenharmony_ci				 PUD_TYPE_TABLE)
5308c2ecf20Sopenharmony_ci#endif
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ciextern pgd_t init_pg_dir[PTRS_PER_PGD];
5338c2ecf20Sopenharmony_ciextern pgd_t init_pg_end[];
5348c2ecf20Sopenharmony_ciextern pgd_t swapper_pg_dir[PTRS_PER_PGD];
5358c2ecf20Sopenharmony_ciextern pgd_t idmap_pg_dir[PTRS_PER_PGD];
5368c2ecf20Sopenharmony_ciextern pgd_t idmap_pg_end[];
5378c2ecf20Sopenharmony_ciextern pgd_t tramp_pg_dir[PTRS_PER_PGD];
5388c2ecf20Sopenharmony_ciextern pgd_t reserved_pg_dir[PTRS_PER_PGD];
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ciextern void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd);
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic inline bool in_swapper_pgdir(void *addr)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	return ((unsigned long)addr & PAGE_MASK) ==
5458c2ecf20Sopenharmony_ci	        ((unsigned long)swapper_pg_dir & PAGE_MASK);
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
5498c2ecf20Sopenharmony_ci{
5508c2ecf20Sopenharmony_ci#ifdef __PAGETABLE_PMD_FOLDED
5518c2ecf20Sopenharmony_ci	if (in_swapper_pgdir(pmdp)) {
5528c2ecf20Sopenharmony_ci		set_swapper_pgd((pgd_t *)pmdp, __pgd(pmd_val(pmd)));
5538c2ecf20Sopenharmony_ci		return;
5548c2ecf20Sopenharmony_ci	}
5558c2ecf20Sopenharmony_ci#endif /* __PAGETABLE_PMD_FOLDED */
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	WRITE_ONCE(*pmdp, pmd);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	if (pmd_valid(pmd)) {
5608c2ecf20Sopenharmony_ci		dsb(ishst);
5618c2ecf20Sopenharmony_ci		isb();
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_cistatic inline void pmd_clear(pmd_t *pmdp)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	set_pmd(pmdp, __pmd(0));
5688c2ecf20Sopenharmony_ci}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_cistatic inline phys_addr_t pmd_page_paddr(pmd_t pmd)
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	return __pmd_to_phys(pmd);
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_cistatic inline unsigned long pmd_page_vaddr(pmd_t pmd)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	return (unsigned long)__va(pmd_page_paddr(pmd));
5788c2ecf20Sopenharmony_ci}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci/* Find an entry in the third-level page table. */
5818c2ecf20Sopenharmony_ci#define pte_offset_phys(dir,addr)	(pmd_page_paddr(READ_ONCE(*(dir))) + pte_index(addr) * sizeof(pte_t))
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci#define pte_set_fixmap(addr)		((pte_t *)set_fixmap_offset(FIX_PTE, addr))
5848c2ecf20Sopenharmony_ci#define pte_set_fixmap_offset(pmd, addr)	pte_set_fixmap(pte_offset_phys(pmd, addr))
5858c2ecf20Sopenharmony_ci#define pte_clear_fixmap()		clear_fixmap(FIX_PTE)
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci#define pmd_page(pmd)			phys_to_page(__pmd_to_phys(pmd))
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci/* use ONLY for statically allocated translation tables */
5908c2ecf20Sopenharmony_ci#define pte_offset_kimg(dir,addr)	((pte_t *)__phys_to_kimg(pte_offset_phys((dir), (addr))))
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci/*
5938c2ecf20Sopenharmony_ci * Conversion functions: convert a page and protection to a page entry,
5948c2ecf20Sopenharmony_ci * and a page entry and page directory to the page they refer to.
5958c2ecf20Sopenharmony_ci */
5968c2ecf20Sopenharmony_ci#define mk_pte(page,prot)	pfn_pte(page_to_pfn(page),prot)
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 2
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci#define pmd_ERROR(e)	\
6018c2ecf20Sopenharmony_ci	pr_err("%s:%d: bad pmd %016llx.\n", __FILE__, __LINE__, pmd_val(e))
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci#define pud_none(pud)		(!pud_val(pud))
6048c2ecf20Sopenharmony_ci#define pud_bad(pud)		(!pud_table(pud))
6058c2ecf20Sopenharmony_ci#define pud_present(pud)	pte_present(pud_pte(pud))
6068c2ecf20Sopenharmony_ci#define pud_leaf(pud)		(pud_present(pud) && !pud_table(pud))
6078c2ecf20Sopenharmony_ci#define pud_valid(pud)		pte_valid(pud_pte(pud))
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_cistatic inline void set_pud(pud_t *pudp, pud_t pud)
6108c2ecf20Sopenharmony_ci{
6118c2ecf20Sopenharmony_ci#ifdef __PAGETABLE_PUD_FOLDED
6128c2ecf20Sopenharmony_ci	if (in_swapper_pgdir(pudp)) {
6138c2ecf20Sopenharmony_ci		set_swapper_pgd((pgd_t *)pudp, __pgd(pud_val(pud)));
6148c2ecf20Sopenharmony_ci		return;
6158c2ecf20Sopenharmony_ci	}
6168c2ecf20Sopenharmony_ci#endif /* __PAGETABLE_PUD_FOLDED */
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	WRITE_ONCE(*pudp, pud);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	if (pud_valid(pud)) {
6218c2ecf20Sopenharmony_ci		dsb(ishst);
6228c2ecf20Sopenharmony_ci		isb();
6238c2ecf20Sopenharmony_ci	}
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_cistatic inline void pud_clear(pud_t *pudp)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	set_pud(pudp, __pud(0));
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_cistatic inline phys_addr_t pud_page_paddr(pud_t pud)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	return __pud_to_phys(pud);
6348c2ecf20Sopenharmony_ci}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_cistatic inline pmd_t *pud_pgtable(pud_t pud)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	return (pmd_t *)__va(pud_page_paddr(pud));
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci/* Find an entry in the second-level page table. */
6428c2ecf20Sopenharmony_ci#define pmd_offset_phys(dir, addr)	(pud_page_paddr(READ_ONCE(*(dir))) + pmd_index(addr) * sizeof(pmd_t))
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci#define pmd_set_fixmap(addr)		((pmd_t *)set_fixmap_offset(FIX_PMD, addr))
6458c2ecf20Sopenharmony_ci#define pmd_set_fixmap_offset(pud, addr)	pmd_set_fixmap(pmd_offset_phys(pud, addr))
6468c2ecf20Sopenharmony_ci#define pmd_clear_fixmap()		clear_fixmap(FIX_PMD)
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci#define pud_page(pud)			phys_to_page(__pud_to_phys(pud))
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci/* use ONLY for statically allocated translation tables */
6518c2ecf20Sopenharmony_ci#define pmd_offset_kimg(dir,addr)	((pmd_t *)__phys_to_kimg(pmd_offset_phys((dir), (addr))))
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci#else
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci#define pud_page_paddr(pud)	({ BUILD_BUG(); 0; })
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci/* Match pmd_offset folding in <asm/generic/pgtable-nopmd.h> */
6588c2ecf20Sopenharmony_ci#define pmd_set_fixmap(addr)		NULL
6598c2ecf20Sopenharmony_ci#define pmd_set_fixmap_offset(pudp, addr)	((pmd_t *)pudp)
6608c2ecf20Sopenharmony_ci#define pmd_clear_fixmap()
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci#define pmd_offset_kimg(dir,addr)	((pmd_t *)dir)
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci#endif	/* CONFIG_PGTABLE_LEVELS > 2 */
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 3
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci#define pud_ERROR(e)	\
6698c2ecf20Sopenharmony_ci	pr_err("%s:%d: bad pud %016llx.\n", __FILE__, __LINE__, pud_val(e))
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci#define p4d_none(p4d)		(!p4d_val(p4d))
6728c2ecf20Sopenharmony_ci#define p4d_bad(p4d)		(!(p4d_val(p4d) & 2))
6738c2ecf20Sopenharmony_ci#define p4d_present(p4d)	(p4d_val(p4d))
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_cistatic inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
6768c2ecf20Sopenharmony_ci{
6778c2ecf20Sopenharmony_ci	if (in_swapper_pgdir(p4dp)) {
6788c2ecf20Sopenharmony_ci		set_swapper_pgd((pgd_t *)p4dp, __pgd(p4d_val(p4d)));
6798c2ecf20Sopenharmony_ci		return;
6808c2ecf20Sopenharmony_ci	}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	WRITE_ONCE(*p4dp, p4d);
6838c2ecf20Sopenharmony_ci	dsb(ishst);
6848c2ecf20Sopenharmony_ci	isb();
6858c2ecf20Sopenharmony_ci}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_cistatic inline void p4d_clear(p4d_t *p4dp)
6888c2ecf20Sopenharmony_ci{
6898c2ecf20Sopenharmony_ci	set_p4d(p4dp, __p4d(0));
6908c2ecf20Sopenharmony_ci}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_cistatic inline phys_addr_t p4d_page_paddr(p4d_t p4d)
6938c2ecf20Sopenharmony_ci{
6948c2ecf20Sopenharmony_ci	return __p4d_to_phys(p4d);
6958c2ecf20Sopenharmony_ci}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_cistatic inline pud_t *p4d_pgtable(p4d_t p4d)
6988c2ecf20Sopenharmony_ci{
6998c2ecf20Sopenharmony_ci	return (pud_t *)__va(p4d_page_paddr(p4d));
7008c2ecf20Sopenharmony_ci}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci/* Find an entry in the frst-level page table. */
7038c2ecf20Sopenharmony_ci#define pud_offset_phys(dir, addr)	(p4d_page_paddr(READ_ONCE(*(dir))) + pud_index(addr) * sizeof(pud_t))
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci#define pud_set_fixmap(addr)		((pud_t *)set_fixmap_offset(FIX_PUD, addr))
7068c2ecf20Sopenharmony_ci#define pud_set_fixmap_offset(p4d, addr)	pud_set_fixmap(pud_offset_phys(p4d, addr))
7078c2ecf20Sopenharmony_ci#define pud_clear_fixmap()		clear_fixmap(FIX_PUD)
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci#define p4d_page(p4d)		pfn_to_page(__phys_to_pfn(__p4d_to_phys(p4d)))
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci/* use ONLY for statically allocated translation tables */
7128c2ecf20Sopenharmony_ci#define pud_offset_kimg(dir,addr)	((pud_t *)__phys_to_kimg(pud_offset_phys((dir), (addr))))
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci#else
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci#define p4d_page_paddr(p4d)	({ BUILD_BUG(); 0;})
7178c2ecf20Sopenharmony_ci#define pgd_page_paddr(pgd)	({ BUILD_BUG(); 0;})
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci/* Match pud_offset folding in <asm/generic/pgtable-nopud.h> */
7208c2ecf20Sopenharmony_ci#define pud_set_fixmap(addr)		NULL
7218c2ecf20Sopenharmony_ci#define pud_set_fixmap_offset(pgdp, addr)	((pud_t *)pgdp)
7228c2ecf20Sopenharmony_ci#define pud_clear_fixmap()
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci#define pud_offset_kimg(dir,addr)	((pud_t *)dir)
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci#endif  /* CONFIG_PGTABLE_LEVELS > 3 */
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci#define pgd_ERROR(e)	\
7298c2ecf20Sopenharmony_ci	pr_err("%s:%d: bad pgd %016llx.\n", __FILE__, __LINE__, pgd_val(e))
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci#define pgd_set_fixmap(addr)	((pgd_t *)set_fixmap_offset(FIX_PGD, addr))
7328c2ecf20Sopenharmony_ci#define pgd_clear_fixmap()	clear_fixmap(FIX_PGD)
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_cistatic inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
7358c2ecf20Sopenharmony_ci{
7368c2ecf20Sopenharmony_ci	/*
7378c2ecf20Sopenharmony_ci	 * Normal and Normal-Tagged are two different memory types and indices
7388c2ecf20Sopenharmony_ci	 * in MAIR_EL1. The mask below has to include PTE_ATTRINDX_MASK.
7398c2ecf20Sopenharmony_ci	 */
7408c2ecf20Sopenharmony_ci	const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
7418c2ecf20Sopenharmony_ci			      PTE_PROT_NONE | PTE_VALID | PTE_WRITE | PTE_GP |
7428c2ecf20Sopenharmony_ci			      PTE_ATTRINDX_MASK;
7438c2ecf20Sopenharmony_ci	/* preserve the hardware dirty information */
7448c2ecf20Sopenharmony_ci	if (pte_hw_dirty(pte))
7458c2ecf20Sopenharmony_ci		pte = pte_mkdirty(pte);
7468c2ecf20Sopenharmony_ci	pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
7478c2ecf20Sopenharmony_ci	/*
7488c2ecf20Sopenharmony_ci	 * If we end up clearing hw dirtiness for a sw-dirty PTE, set hardware
7498c2ecf20Sopenharmony_ci	 * dirtiness again.
7508c2ecf20Sopenharmony_ci	 */
7518c2ecf20Sopenharmony_ci	if (pte_sw_dirty(pte))
7528c2ecf20Sopenharmony_ci		pte = pte_mkdirty(pte);
7538c2ecf20Sopenharmony_ci	return pte;
7548c2ecf20Sopenharmony_ci}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_cistatic inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	return pte_pmd(pte_modify(pmd_pte(pmd), newprot));
7598c2ecf20Sopenharmony_ci}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
7628c2ecf20Sopenharmony_ciextern int ptep_set_access_flags(struct vm_area_struct *vma,
7638c2ecf20Sopenharmony_ci				 unsigned long address, pte_t *ptep,
7648c2ecf20Sopenharmony_ci				 pte_t entry, int dirty);
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
7678c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
7688c2ecf20Sopenharmony_cistatic inline int pmdp_set_access_flags(struct vm_area_struct *vma,
7698c2ecf20Sopenharmony_ci					unsigned long address, pmd_t *pmdp,
7708c2ecf20Sopenharmony_ci					pmd_t entry, int dirty)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	return ptep_set_access_flags(vma, address, (pte_t *)pmdp, pmd_pte(entry), dirty);
7738c2ecf20Sopenharmony_ci}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_cistatic inline int pud_devmap(pud_t pud)
7768c2ecf20Sopenharmony_ci{
7778c2ecf20Sopenharmony_ci	return 0;
7788c2ecf20Sopenharmony_ci}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_cistatic inline int pgd_devmap(pgd_t pgd)
7818c2ecf20Sopenharmony_ci{
7828c2ecf20Sopenharmony_ci	return 0;
7838c2ecf20Sopenharmony_ci}
7848c2ecf20Sopenharmony_ci#endif
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci/*
7878c2ecf20Sopenharmony_ci * Atomic pte/pmd modifications.
7888c2ecf20Sopenharmony_ci */
7898c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
7908c2ecf20Sopenharmony_cistatic inline int __ptep_test_and_clear_young(pte_t *ptep)
7918c2ecf20Sopenharmony_ci{
7928c2ecf20Sopenharmony_ci	pte_t old_pte, pte;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	pte = READ_ONCE(*ptep);
7958c2ecf20Sopenharmony_ci	do {
7968c2ecf20Sopenharmony_ci		old_pte = pte;
7978c2ecf20Sopenharmony_ci		pte = pte_mkold(pte);
7988c2ecf20Sopenharmony_ci		pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
7998c2ecf20Sopenharmony_ci					       pte_val(old_pte), pte_val(pte));
8008c2ecf20Sopenharmony_ci	} while (pte_val(pte) != pte_val(old_pte));
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	return pte_young(pte);
8038c2ecf20Sopenharmony_ci}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_cistatic inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
8068c2ecf20Sopenharmony_ci					    unsigned long address,
8078c2ecf20Sopenharmony_ci					    pte_t *ptep)
8088c2ecf20Sopenharmony_ci{
8098c2ecf20Sopenharmony_ci	return __ptep_test_and_clear_young(ptep);
8108c2ecf20Sopenharmony_ci}
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
8138c2ecf20Sopenharmony_cistatic inline int ptep_clear_flush_young(struct vm_area_struct *vma,
8148c2ecf20Sopenharmony_ci					 unsigned long address, pte_t *ptep)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	int young = ptep_test_and_clear_young(vma, address, ptep);
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	if (young) {
8198c2ecf20Sopenharmony_ci		/*
8208c2ecf20Sopenharmony_ci		 * We can elide the trailing DSB here since the worst that can
8218c2ecf20Sopenharmony_ci		 * happen is that a CPU continues to use the young entry in its
8228c2ecf20Sopenharmony_ci		 * TLB and we mistakenly reclaim the associated page. The
8238c2ecf20Sopenharmony_ci		 * window for such an event is bounded by the next
8248c2ecf20Sopenharmony_ci		 * context-switch, which provides a DSB to complete the TLB
8258c2ecf20Sopenharmony_ci		 * invalidation.
8268c2ecf20Sopenharmony_ci		 */
8278c2ecf20Sopenharmony_ci		flush_tlb_page_nosync(vma, address);
8288c2ecf20Sopenharmony_ci	}
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	return young;
8318c2ecf20Sopenharmony_ci}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
8348c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG
8358c2ecf20Sopenharmony_cistatic inline int pmdp_test_and_clear_young(struct vm_area_struct *vma,
8368c2ecf20Sopenharmony_ci					    unsigned long address,
8378c2ecf20Sopenharmony_ci					    pmd_t *pmdp)
8388c2ecf20Sopenharmony_ci{
8398c2ecf20Sopenharmony_ci	return ptep_test_and_clear_young(vma, address, (pte_t *)pmdp);
8408c2ecf20Sopenharmony_ci}
8418c2ecf20Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
8448c2ecf20Sopenharmony_cistatic inline pte_t ptep_get_and_clear(struct mm_struct *mm,
8458c2ecf20Sopenharmony_ci				       unsigned long address, pte_t *ptep)
8468c2ecf20Sopenharmony_ci{
8478c2ecf20Sopenharmony_ci	return __pte(xchg_relaxed(&pte_val(*ptep), 0));
8488c2ecf20Sopenharmony_ci}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
8518c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR
8528c2ecf20Sopenharmony_cistatic inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
8538c2ecf20Sopenharmony_ci					    unsigned long address, pmd_t *pmdp)
8548c2ecf20Sopenharmony_ci{
8558c2ecf20Sopenharmony_ci	return pte_pmd(ptep_get_and_clear(mm, address, (pte_t *)pmdp));
8568c2ecf20Sopenharmony_ci}
8578c2ecf20Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci/*
8608c2ecf20Sopenharmony_ci * ptep_set_wrprotect - mark read-only while trasferring potential hardware
8618c2ecf20Sopenharmony_ci * dirty status (PTE_DBM && !PTE_RDONLY) to the software PTE_DIRTY bit.
8628c2ecf20Sopenharmony_ci */
8638c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PTEP_SET_WRPROTECT
8648c2ecf20Sopenharmony_cistatic inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep)
8658c2ecf20Sopenharmony_ci{
8668c2ecf20Sopenharmony_ci	pte_t old_pte, pte;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	pte = READ_ONCE(*ptep);
8698c2ecf20Sopenharmony_ci	do {
8708c2ecf20Sopenharmony_ci		old_pte = pte;
8718c2ecf20Sopenharmony_ci		pte = pte_wrprotect(pte);
8728c2ecf20Sopenharmony_ci		pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
8738c2ecf20Sopenharmony_ci					       pte_val(old_pte), pte_val(pte));
8748c2ecf20Sopenharmony_ci	} while (pte_val(pte) != pte_val(old_pte));
8758c2ecf20Sopenharmony_ci}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
8788c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PMDP_SET_WRPROTECT
8798c2ecf20Sopenharmony_cistatic inline void pmdp_set_wrprotect(struct mm_struct *mm,
8808c2ecf20Sopenharmony_ci				      unsigned long address, pmd_t *pmdp)
8818c2ecf20Sopenharmony_ci{
8828c2ecf20Sopenharmony_ci	ptep_set_wrprotect(mm, address, (pte_t *)pmdp);
8838c2ecf20Sopenharmony_ci}
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci#define pmdp_establish pmdp_establish
8868c2ecf20Sopenharmony_cistatic inline pmd_t pmdp_establish(struct vm_area_struct *vma,
8878c2ecf20Sopenharmony_ci		unsigned long address, pmd_t *pmdp, pmd_t pmd)
8888c2ecf20Sopenharmony_ci{
8898c2ecf20Sopenharmony_ci	return __pmd(xchg_relaxed(&pmd_val(*pmdp), pmd_val(pmd)));
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci#endif
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci/*
8948c2ecf20Sopenharmony_ci * Encode and decode a swap entry:
8958c2ecf20Sopenharmony_ci *	bits 0-1:	present (must be zero)
8968c2ecf20Sopenharmony_ci *	bits 2-7:	swap type
8978c2ecf20Sopenharmony_ci *	bits 8-57:	swap offset
8988c2ecf20Sopenharmony_ci *	bit  58:	PTE_PROT_NONE (must be zero)
8998c2ecf20Sopenharmony_ci */
9008c2ecf20Sopenharmony_ci#define __SWP_TYPE_SHIFT	2
9018c2ecf20Sopenharmony_ci#define __SWP_TYPE_BITS		6
9028c2ecf20Sopenharmony_ci#define __SWP_OFFSET_BITS	50
9038c2ecf20Sopenharmony_ci#define __SWP_TYPE_MASK		((1 << __SWP_TYPE_BITS) - 1)
9048c2ecf20Sopenharmony_ci#define __SWP_OFFSET_SHIFT	(__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
9058c2ecf20Sopenharmony_ci#define __SWP_OFFSET_MASK	((1UL << __SWP_OFFSET_BITS) - 1)
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci#define __swp_type(x)		(((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK)
9088c2ecf20Sopenharmony_ci#define __swp_offset(x)		(((x).val >> __SWP_OFFSET_SHIFT) & __SWP_OFFSET_MASK)
9098c2ecf20Sopenharmony_ci#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) })
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci#define __pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) })
9128c2ecf20Sopenharmony_ci#define __swp_entry_to_pte(swp)	((pte_t) { (swp).val })
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
9158c2ecf20Sopenharmony_ci#define __pmd_to_swp_entry(pmd)		((swp_entry_t) { pmd_val(pmd) })
9168c2ecf20Sopenharmony_ci#define __swp_entry_to_pmd(swp)		__pmd((swp).val)
9178c2ecf20Sopenharmony_ci#endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci/*
9208c2ecf20Sopenharmony_ci * Ensure that there are not more swap files than can be encoded in the kernel
9218c2ecf20Sopenharmony_ci * PTEs.
9228c2ecf20Sopenharmony_ci */
9238c2ecf20Sopenharmony_ci#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS)
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ciextern int kern_addr_valid(unsigned long addr);
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM64_MTE
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PREPARE_TO_SWAP
9308c2ecf20Sopenharmony_cistatic inline int arch_prepare_to_swap(struct page *page)
9318c2ecf20Sopenharmony_ci{
9328c2ecf20Sopenharmony_ci	if (system_supports_mte())
9338c2ecf20Sopenharmony_ci		return mte_save_tags(page);
9348c2ecf20Sopenharmony_ci	return 0;
9358c2ecf20Sopenharmony_ci}
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci#define __HAVE_ARCH_SWAP_INVALIDATE
9388c2ecf20Sopenharmony_cistatic inline void arch_swap_invalidate_page(int type, pgoff_t offset)
9398c2ecf20Sopenharmony_ci{
9408c2ecf20Sopenharmony_ci	if (system_supports_mte())
9418c2ecf20Sopenharmony_ci		mte_invalidate_tags(type, offset);
9428c2ecf20Sopenharmony_ci}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_cistatic inline void arch_swap_invalidate_area(int type)
9458c2ecf20Sopenharmony_ci{
9468c2ecf20Sopenharmony_ci	if (system_supports_mte())
9478c2ecf20Sopenharmony_ci		mte_invalidate_tags_area(type);
9488c2ecf20Sopenharmony_ci}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci#define __HAVE_ARCH_SWAP_RESTORE
9518c2ecf20Sopenharmony_cistatic inline void arch_swap_restore(swp_entry_t entry, struct page *page)
9528c2ecf20Sopenharmony_ci{
9538c2ecf20Sopenharmony_ci	if (system_supports_mte() && mte_restore_tags(entry, page))
9548c2ecf20Sopenharmony_ci		set_bit(PG_mte_tagged, &page->flags);
9558c2ecf20Sopenharmony_ci}
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci#endif /* CONFIG_ARM64_MTE */
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci/*
9608c2ecf20Sopenharmony_ci * On AArch64, the cache coherency is handled via the set_pte_at() function.
9618c2ecf20Sopenharmony_ci */
9628c2ecf20Sopenharmony_cistatic inline void update_mmu_cache(struct vm_area_struct *vma,
9638c2ecf20Sopenharmony_ci				    unsigned long addr, pte_t *ptep)
9648c2ecf20Sopenharmony_ci{
9658c2ecf20Sopenharmony_ci	/*
9668c2ecf20Sopenharmony_ci	 * We don't do anything here, so there's a very small chance of
9678c2ecf20Sopenharmony_ci	 * us retaking a user fault which we just fixed up. The alternative
9688c2ecf20Sopenharmony_ci	 * is doing a dsb(ishst), but that penalises the fastpath.
9698c2ecf20Sopenharmony_ci	 */
9708c2ecf20Sopenharmony_ci}
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM64_PA_BITS_52
9758c2ecf20Sopenharmony_ci#define phys_to_ttbr(addr)	(((addr) | ((addr) >> 46)) & TTBR_BADDR_MASK_52)
9768c2ecf20Sopenharmony_ci#else
9778c2ecf20Sopenharmony_ci#define phys_to_ttbr(addr)	(addr)
9788c2ecf20Sopenharmony_ci#endif
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci/*
9818c2ecf20Sopenharmony_ci * On arm64 without hardware Access Flag, copying from user will fail because
9828c2ecf20Sopenharmony_ci * the pte is old and cannot be marked young. So we always end up with zeroed
9838c2ecf20Sopenharmony_ci * page after fork() + CoW for pfn mappings. We don't always have a
9848c2ecf20Sopenharmony_ci * hardware-managed access flag on arm64.
9858c2ecf20Sopenharmony_ci */
9868c2ecf20Sopenharmony_cistatic inline bool arch_faults_on_old_pte(void)
9878c2ecf20Sopenharmony_ci{
9888c2ecf20Sopenharmony_ci	WARN_ON(preemptible());
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	return !cpu_has_hw_af();
9918c2ecf20Sopenharmony_ci}
9928c2ecf20Sopenharmony_ci#define arch_faults_on_old_pte arch_faults_on_old_pte
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci#endif /* !__ASSEMBLY__ */
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci#endif /* __ASM_PGTABLE_H */
997