xref: /linux/arch/arm64/include/asm/pgtable.h (revision cac4b8cdf5a20a11d1725b832350c044d9e13d29)
14f04d8f0SCatalin Marinas /*
24f04d8f0SCatalin Marinas  * Copyright (C) 2012 ARM Ltd.
34f04d8f0SCatalin Marinas  *
44f04d8f0SCatalin Marinas  * This program is free software; you can redistribute it and/or modify
54f04d8f0SCatalin Marinas  * it under the terms of the GNU General Public License version 2 as
64f04d8f0SCatalin Marinas  * published by the Free Software Foundation.
74f04d8f0SCatalin Marinas  *
84f04d8f0SCatalin Marinas  * This program is distributed in the hope that it will be useful,
94f04d8f0SCatalin Marinas  * but WITHOUT ANY WARRANTY; without even the implied warranty of
104f04d8f0SCatalin Marinas  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
114f04d8f0SCatalin Marinas  * GNU General Public License for more details.
124f04d8f0SCatalin Marinas  *
134f04d8f0SCatalin Marinas  * You should have received a copy of the GNU General Public License
144f04d8f0SCatalin Marinas  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
154f04d8f0SCatalin Marinas  */
164f04d8f0SCatalin Marinas #ifndef __ASM_PGTABLE_H
174f04d8f0SCatalin Marinas #define __ASM_PGTABLE_H
184f04d8f0SCatalin Marinas 
192f4b829cSCatalin Marinas #include <asm/bug.h>
204f04d8f0SCatalin Marinas #include <asm/proc-fns.h>
214f04d8f0SCatalin Marinas 
224f04d8f0SCatalin Marinas #include <asm/memory.h>
234f04d8f0SCatalin Marinas #include <asm/pgtable-hwdef.h>
244f04d8f0SCatalin Marinas 
254f04d8f0SCatalin Marinas /*
264f04d8f0SCatalin Marinas  * Software defined PTE bits definition.
274f04d8f0SCatalin Marinas  */
28a6fadf7eSWill Deacon #define PTE_VALID		(_AT(pteval_t, 1) << 0)
29bf950040SWill Deacon #define PTE_WRITE		(PTE_DBM)		 /* same as DBM (51) */
304f04d8f0SCatalin Marinas #define PTE_DIRTY		(_AT(pteval_t, 1) << 55)
314f04d8f0SCatalin Marinas #define PTE_SPECIAL		(_AT(pteval_t, 1) << 56)
323676f9efSCatalin Marinas #define PTE_PROT_NONE		(_AT(pteval_t, 1) << 58) /* only when !PTE_VALID */
334f04d8f0SCatalin Marinas 
344f04d8f0SCatalin Marinas /*
354f04d8f0SCatalin Marinas  * VMALLOC and SPARSEMEM_VMEMMAP ranges.
3608375198SCatalin Marinas  *
3708375198SCatalin Marinas  * VMEMAP_SIZE: allows the whole VA space to be covered by a struct page array
3808375198SCatalin Marinas  *	(rounded up to PUD_SIZE).
39f9040773SArd Biesheuvel  * VMALLOC_START: beginning of the kernel vmalloc space
4008375198SCatalin Marinas  * VMALLOC_END: extends to the available space below vmmemmap, PCI I/O space,
4108375198SCatalin Marinas  *	fixed mappings and modules
424f04d8f0SCatalin Marinas  */
4308375198SCatalin Marinas #define VMEMMAP_SIZE		ALIGN((1UL << (VA_BITS - PAGE_SHIFT)) * sizeof(struct page), PUD_SIZE)
4439d114ddSAndrey Ryabinin 
45f9040773SArd Biesheuvel #define VMALLOC_START		(MODULES_END)
4608375198SCatalin Marinas #define VMALLOC_END		(PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
474f04d8f0SCatalin Marinas 
484f04d8f0SCatalin Marinas #define vmemmap			((struct page *)(VMALLOC_END + SZ_64K))
494f04d8f0SCatalin Marinas 
50d016bf7eSKirill A. Shutemov #define FIRST_USER_ADDRESS	0UL
514f04d8f0SCatalin Marinas 
524f04d8f0SCatalin Marinas #ifndef __ASSEMBLY__
532f4b829cSCatalin Marinas 
54961faac1SMark Rutland #include <asm/fixmap.h>
552f4b829cSCatalin Marinas #include <linux/mmdebug.h>
562f4b829cSCatalin Marinas 
574f04d8f0SCatalin Marinas extern void __pte_error(const char *file, int line, unsigned long val);
584f04d8f0SCatalin Marinas extern void __pmd_error(const char *file, int line, unsigned long val);
59c79b954bSJungseok Lee extern void __pud_error(const char *file, int line, unsigned long val);
604f04d8f0SCatalin Marinas extern void __pgd_error(const char *file, int line, unsigned long val);
614f04d8f0SCatalin Marinas 
62a501e324SCatalin Marinas #define PROT_DEFAULT		(PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
63a501e324SCatalin Marinas #define PROT_SECT_DEFAULT	(PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
644f04d8f0SCatalin Marinas 
65ac15bd63SCatalin Marinas #define PROT_DEVICE_nGnRnE	(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRnE))
66ac15bd63SCatalin Marinas #define PROT_DEVICE_nGnRE	(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRE))
67ac15bd63SCatalin Marinas #define PROT_NORMAL_NC		(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_NC))
68ac15bd63SCatalin Marinas #define PROT_NORMAL_WT		(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_WT))
69ac15bd63SCatalin Marinas #define PROT_NORMAL		(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL))
704f04d8f0SCatalin Marinas 
71a501e324SCatalin Marinas #define PROT_SECT_DEVICE_nGnRE	(PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE))
72a501e324SCatalin Marinas #define PROT_SECT_NORMAL	(PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
73a501e324SCatalin Marinas #define PROT_SECT_NORMAL_EXEC	(PROT_SECT_DEFAULT | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
744f04d8f0SCatalin Marinas 
75a501e324SCatalin Marinas #define _PAGE_DEFAULT		(PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
76a6fadf7eSWill Deacon 
77a501e324SCatalin Marinas #define PAGE_KERNEL		__pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE)
78fb226c3dSArd Biesheuvel #define PAGE_KERNEL_RO		__pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
790b2aa5b8SLaura Abbott #define PAGE_KERNEL_ROX		__pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
80a501e324SCatalin Marinas #define PAGE_KERNEL_EXEC	__pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE)
8106f90d25SJeremy Linton #define PAGE_KERNEL_EXEC_CONT	__pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_CONT)
824f04d8f0SCatalin Marinas 
83a501e324SCatalin Marinas #define PAGE_HYP		__pgprot(_PAGE_DEFAULT | PTE_HYP)
8436311607SMarc Zyngier #define PAGE_HYP_DEVICE		__pgprot(PROT_DEVICE_nGnRE | PTE_HYP)
8536311607SMarc Zyngier 
86a501e324SCatalin Marinas #define PAGE_S2			__pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY)
874a513fb0SArd Biesheuvel #define PAGE_S2_DEVICE		__pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_UXN)
8836311607SMarc Zyngier 
891a541b4eSSteve Capper #define PAGE_NONE		__pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_PXN | PTE_UXN)
90a501e324SCatalin Marinas #define PAGE_SHARED		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE)
91a501e324SCatalin Marinas #define PAGE_SHARED_EXEC	__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE)
92a501e324SCatalin Marinas #define PAGE_COPY		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
93a501e324SCatalin Marinas #define PAGE_COPY_EXEC		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN)
94a501e324SCatalin Marinas #define PAGE_READONLY		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
95a501e324SCatalin Marinas #define PAGE_READONLY_EXEC	__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN)
964f04d8f0SCatalin Marinas 
97a501e324SCatalin Marinas #define __P000  PAGE_NONE
98a501e324SCatalin Marinas #define __P001  PAGE_READONLY
99a501e324SCatalin Marinas #define __P010  PAGE_COPY
100a501e324SCatalin Marinas #define __P011  PAGE_COPY
1015a0fdfadSCatalin Marinas #define __P100  PAGE_READONLY_EXEC
102a501e324SCatalin Marinas #define __P101  PAGE_READONLY_EXEC
103a501e324SCatalin Marinas #define __P110  PAGE_COPY_EXEC
104a501e324SCatalin Marinas #define __P111  PAGE_COPY_EXEC
1054f04d8f0SCatalin Marinas 
106a501e324SCatalin Marinas #define __S000  PAGE_NONE
107a501e324SCatalin Marinas #define __S001  PAGE_READONLY
108a501e324SCatalin Marinas #define __S010  PAGE_SHARED
109a501e324SCatalin Marinas #define __S011  PAGE_SHARED
1105a0fdfadSCatalin Marinas #define __S100  PAGE_READONLY_EXEC
111a501e324SCatalin Marinas #define __S101  PAGE_READONLY_EXEC
112a501e324SCatalin Marinas #define __S110  PAGE_SHARED_EXEC
113a501e324SCatalin Marinas #define __S111  PAGE_SHARED_EXEC
1144f04d8f0SCatalin Marinas 
1154f04d8f0SCatalin Marinas /*
1164f04d8f0SCatalin Marinas  * ZERO_PAGE is a global shared page that is always zero: used
1174f04d8f0SCatalin Marinas  * for zero-mapped memory areas etc..
1184f04d8f0SCatalin Marinas  */
1195227cfa7SMark Rutland extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
1205227cfa7SMark Rutland #define ZERO_PAGE(vaddr)	virt_to_page(empty_zero_page)
1214f04d8f0SCatalin Marinas 
1227078db46SCatalin Marinas #define pte_ERROR(pte)		__pte_error(__FILE__, __LINE__, pte_val(pte))
1237078db46SCatalin Marinas 
1244f04d8f0SCatalin Marinas #define pte_pfn(pte)		((pte_val(pte) & PHYS_MASK) >> PAGE_SHIFT)
1254f04d8f0SCatalin Marinas 
1264f04d8f0SCatalin Marinas #define pfn_pte(pfn,prot)	(__pte(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
1274f04d8f0SCatalin Marinas 
1284f04d8f0SCatalin Marinas #define pte_none(pte)		(!pte_val(pte))
1294f04d8f0SCatalin Marinas #define pte_clear(mm,addr,ptep)	set_pte(ptep, __pte(0))
1304f04d8f0SCatalin Marinas #define pte_page(pte)		(pfn_to_page(pte_pfn(pte)))
1317078db46SCatalin Marinas 
1324f04d8f0SCatalin Marinas /*
1334f04d8f0SCatalin Marinas  * The following only work if pte_present(). Undefined behaviour otherwise.
1344f04d8f0SCatalin Marinas  */
13584fe6826SSteve Capper #define pte_present(pte)	(!!(pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)))
13684fe6826SSteve Capper #define pte_young(pte)		(!!(pte_val(pte) & PTE_AF))
13784fe6826SSteve Capper #define pte_special(pte)	(!!(pte_val(pte) & PTE_SPECIAL))
13884fe6826SSteve Capper #define pte_write(pte)		(!!(pte_val(pte) & PTE_WRITE))
1398e620b04SCatalin Marinas #define pte_exec(pte)		(!(pte_val(pte) & PTE_UXN))
14093ef666aSJeremy Linton #define pte_cont(pte)		(!!(pte_val(pte) & PTE_CONT))
141ac15bd63SCatalin Marinas #define pte_user(pte)		(!!(pte_val(pte) & PTE_USER))
1424f04d8f0SCatalin Marinas 
1432f4b829cSCatalin Marinas #ifdef CONFIG_ARM64_HW_AFDBM
144b847415cSCatalin Marinas #define pte_hw_dirty(pte)	(pte_write(pte) && !(pte_val(pte) & PTE_RDONLY))
1452f4b829cSCatalin Marinas #else
1462f4b829cSCatalin Marinas #define pte_hw_dirty(pte)	(0)
1472f4b829cSCatalin Marinas #endif
1482f4b829cSCatalin Marinas #define pte_sw_dirty(pte)	(!!(pte_val(pte) & PTE_DIRTY))
1492f4b829cSCatalin Marinas #define pte_dirty(pte)		(pte_sw_dirty(pte) || pte_hw_dirty(pte))
1502f4b829cSCatalin Marinas 
151766ffb69SWill Deacon #define pte_valid(pte)		(!!(pte_val(pte) & PTE_VALID))
1527f0b1bf0SCatalin Marinas #define pte_valid_not_user(pte) \
1537f0b1bf0SCatalin Marinas 	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
15476c714beSWill Deacon #define pte_valid_young(pte) \
15576c714beSWill Deacon 	((pte_val(pte) & (PTE_VALID | PTE_AF)) == (PTE_VALID | PTE_AF))
15676c714beSWill Deacon 
15776c714beSWill Deacon /*
15876c714beSWill Deacon  * Could the pte be present in the TLB? We must check mm_tlb_flush_pending
15976c714beSWill Deacon  * so that we don't erroneously return false for pages that have been
16076c714beSWill Deacon  * remapped as PROT_NONE but are yet to be flushed from the TLB.
16176c714beSWill Deacon  */
16276c714beSWill Deacon #define pte_accessible(mm, pte)	\
16376c714beSWill Deacon 	(mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid_young(pte))
1644f04d8f0SCatalin Marinas 
165b6d4f280SLaura Abbott static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
166b6d4f280SLaura Abbott {
167b6d4f280SLaura Abbott 	pte_val(pte) &= ~pgprot_val(prot);
168b6d4f280SLaura Abbott 	return pte;
169b6d4f280SLaura Abbott }
170b6d4f280SLaura Abbott 
171b6d4f280SLaura Abbott static inline pte_t set_pte_bit(pte_t pte, pgprot_t prot)
172b6d4f280SLaura Abbott {
173b6d4f280SLaura Abbott 	pte_val(pte) |= pgprot_val(prot);
174b6d4f280SLaura Abbott 	return pte;
175b6d4f280SLaura Abbott }
176b6d4f280SLaura Abbott 
17744b6dfc5SSteve Capper static inline pte_t pte_wrprotect(pte_t pte)
17844b6dfc5SSteve Capper {
179b6d4f280SLaura Abbott 	return clear_pte_bit(pte, __pgprot(PTE_WRITE));
18044b6dfc5SSteve Capper }
1814f04d8f0SCatalin Marinas 
18244b6dfc5SSteve Capper static inline pte_t pte_mkwrite(pte_t pte)
18344b6dfc5SSteve Capper {
184b6d4f280SLaura Abbott 	return set_pte_bit(pte, __pgprot(PTE_WRITE));
18544b6dfc5SSteve Capper }
18644b6dfc5SSteve Capper 
18744b6dfc5SSteve Capper static inline pte_t pte_mkclean(pte_t pte)
18844b6dfc5SSteve Capper {
189b6d4f280SLaura Abbott 	return clear_pte_bit(pte, __pgprot(PTE_DIRTY));
19044b6dfc5SSteve Capper }
19144b6dfc5SSteve Capper 
19244b6dfc5SSteve Capper static inline pte_t pte_mkdirty(pte_t pte)
19344b6dfc5SSteve Capper {
194b6d4f280SLaura Abbott 	return set_pte_bit(pte, __pgprot(PTE_DIRTY));
19544b6dfc5SSteve Capper }
19644b6dfc5SSteve Capper 
19744b6dfc5SSteve Capper static inline pte_t pte_mkold(pte_t pte)
19844b6dfc5SSteve Capper {
199b6d4f280SLaura Abbott 	return clear_pte_bit(pte, __pgprot(PTE_AF));
20044b6dfc5SSteve Capper }
20144b6dfc5SSteve Capper 
20244b6dfc5SSteve Capper static inline pte_t pte_mkyoung(pte_t pte)
20344b6dfc5SSteve Capper {
204b6d4f280SLaura Abbott 	return set_pte_bit(pte, __pgprot(PTE_AF));
20544b6dfc5SSteve Capper }
20644b6dfc5SSteve Capper 
20744b6dfc5SSteve Capper static inline pte_t pte_mkspecial(pte_t pte)
20844b6dfc5SSteve Capper {
209b6d4f280SLaura Abbott 	return set_pte_bit(pte, __pgprot(PTE_SPECIAL));
21044b6dfc5SSteve Capper }
2114f04d8f0SCatalin Marinas 
21293ef666aSJeremy Linton static inline pte_t pte_mkcont(pte_t pte)
21393ef666aSJeremy Linton {
21466b3923aSDavid Woods 	pte = set_pte_bit(pte, __pgprot(PTE_CONT));
21566b3923aSDavid Woods 	return set_pte_bit(pte, __pgprot(PTE_TYPE_PAGE));
21693ef666aSJeremy Linton }
21793ef666aSJeremy Linton 
21893ef666aSJeremy Linton static inline pte_t pte_mknoncont(pte_t pte)
21993ef666aSJeremy Linton {
22093ef666aSJeremy Linton 	return clear_pte_bit(pte, __pgprot(PTE_CONT));
22193ef666aSJeremy Linton }
22293ef666aSJeremy Linton 
22366b3923aSDavid Woods static inline pmd_t pmd_mkcont(pmd_t pmd)
22466b3923aSDavid Woods {
22566b3923aSDavid Woods 	return __pmd(pmd_val(pmd) | PMD_SECT_CONT);
22666b3923aSDavid Woods }
22766b3923aSDavid Woods 
2284f04d8f0SCatalin Marinas static inline void set_pte(pte_t *ptep, pte_t pte)
2294f04d8f0SCatalin Marinas {
2304f04d8f0SCatalin Marinas 	*ptep = pte;
2317f0b1bf0SCatalin Marinas 
2327f0b1bf0SCatalin Marinas 	/*
2337f0b1bf0SCatalin Marinas 	 * Only if the new pte is valid and kernel, otherwise TLB maintenance
2347f0b1bf0SCatalin Marinas 	 * or update_mmu_cache() have the necessary barriers.
2357f0b1bf0SCatalin Marinas 	 */
2367f0b1bf0SCatalin Marinas 	if (pte_valid_not_user(pte)) {
2377f0b1bf0SCatalin Marinas 		dsb(ishst);
2387f0b1bf0SCatalin Marinas 		isb();
2397f0b1bf0SCatalin Marinas 	}
2404f04d8f0SCatalin Marinas }
2414f04d8f0SCatalin Marinas 
2422f4b829cSCatalin Marinas struct mm_struct;
2432f4b829cSCatalin Marinas struct vm_area_struct;
2442f4b829cSCatalin Marinas 
2454f04d8f0SCatalin Marinas extern void __sync_icache_dcache(pte_t pteval, unsigned long addr);
2464f04d8f0SCatalin Marinas 
2472f4b829cSCatalin Marinas /*
2482f4b829cSCatalin Marinas  * PTE bits configuration in the presence of hardware Dirty Bit Management
2492f4b829cSCatalin Marinas  * (PTE_WRITE == PTE_DBM):
2502f4b829cSCatalin Marinas  *
2512f4b829cSCatalin Marinas  * Dirty  Writable | PTE_RDONLY  PTE_WRITE  PTE_DIRTY (sw)
2522f4b829cSCatalin Marinas  *   0      0      |   1           0          0
2532f4b829cSCatalin Marinas  *   0      1      |   1           1          0
2542f4b829cSCatalin Marinas  *   1      0      |   1           0          1
2552f4b829cSCatalin Marinas  *   1      1      |   0           1          x
2562f4b829cSCatalin Marinas  *
2572f4b829cSCatalin Marinas  * When hardware DBM is not present, the sofware PTE_DIRTY bit is updated via
2582f4b829cSCatalin Marinas  * the page fault mechanism. Checking the dirty status of a pte becomes:
2592f4b829cSCatalin Marinas  *
260b847415cSCatalin Marinas  *   PTE_DIRTY || (PTE_WRITE && !PTE_RDONLY)
2612f4b829cSCatalin Marinas  */
2624f04d8f0SCatalin Marinas static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
2634f04d8f0SCatalin Marinas 			      pte_t *ptep, pte_t pte)
2644f04d8f0SCatalin Marinas {
265ac15bd63SCatalin Marinas 	if (pte_valid(pte)) {
2662f4b829cSCatalin Marinas 		if (pte_sw_dirty(pte) && pte_write(pte))
267c2c93e5bSSteve Capper 			pte_val(pte) &= ~PTE_RDONLY;
268c2c93e5bSSteve Capper 		else
269c2c93e5bSSteve Capper 			pte_val(pte) |= PTE_RDONLY;
270ac15bd63SCatalin Marinas 		if (pte_user(pte) && pte_exec(pte) && !pte_special(pte))
271ac15bd63SCatalin Marinas 			__sync_icache_dcache(pte, addr);
27202522463SWill Deacon 	}
27302522463SWill Deacon 
2742f4b829cSCatalin Marinas 	/*
2752f4b829cSCatalin Marinas 	 * If the existing pte is valid, check for potential race with
2762f4b829cSCatalin Marinas 	 * hardware updates of the pte (ptep_set_access_flags safely changes
2772f4b829cSCatalin Marinas 	 * valid ptes without going through an invalid entry).
2782f4b829cSCatalin Marinas 	 */
27982d34008SCatalin Marinas 	if (IS_ENABLED(CONFIG_ARM64_HW_AFDBM) &&
28082d34008SCatalin Marinas 	    pte_valid(*ptep) && pte_valid(pte)) {
28182d34008SCatalin Marinas 		VM_WARN_ONCE(!pte_young(pte),
28282d34008SCatalin Marinas 			     "%s: racy access flag clearing: 0x%016llx -> 0x%016llx",
28382d34008SCatalin Marinas 			     __func__, pte_val(*ptep), pte_val(pte));
28482d34008SCatalin Marinas 		VM_WARN_ONCE(pte_write(*ptep) && !pte_dirty(pte),
28582d34008SCatalin Marinas 			     "%s: racy dirty state clearing: 0x%016llx -> 0x%016llx",
28682d34008SCatalin Marinas 			     __func__, pte_val(*ptep), pte_val(pte));
2872f4b829cSCatalin Marinas 	}
2882f4b829cSCatalin Marinas 
2894f04d8f0SCatalin Marinas 	set_pte(ptep, pte);
2904f04d8f0SCatalin Marinas }
2914f04d8f0SCatalin Marinas 
2924f04d8f0SCatalin Marinas /*
2934f04d8f0SCatalin Marinas  * Huge pte definitions.
2944f04d8f0SCatalin Marinas  */
295084bd298SSteve Capper #define pte_huge(pte)		(!(pte_val(pte) & PTE_TABLE_BIT))
296084bd298SSteve Capper #define pte_mkhuge(pte)		(__pte(pte_val(pte) & ~PTE_TABLE_BIT))
297084bd298SSteve Capper 
298084bd298SSteve Capper /*
299084bd298SSteve Capper  * Hugetlb definitions.
300084bd298SSteve Capper  */
30166b3923aSDavid Woods #define HUGE_MAX_HSTATE		4
302084bd298SSteve Capper #define HPAGE_SHIFT		PMD_SHIFT
303084bd298SSteve Capper #define HPAGE_SIZE		(_AC(1, UL) << HPAGE_SHIFT)
304084bd298SSteve Capper #define HPAGE_MASK		(~(HPAGE_SIZE - 1))
305084bd298SSteve Capper #define HUGETLB_PAGE_ORDER	(HPAGE_SHIFT - PAGE_SHIFT)
3064f04d8f0SCatalin Marinas 
3074f04d8f0SCatalin Marinas #define __HAVE_ARCH_PTE_SPECIAL
3084f04d8f0SCatalin Marinas 
30929e56940SSteve Capper static inline pte_t pud_pte(pud_t pud)
31029e56940SSteve Capper {
31129e56940SSteve Capper 	return __pte(pud_val(pud));
31229e56940SSteve Capper }
31329e56940SSteve Capper 
31429e56940SSteve Capper static inline pmd_t pud_pmd(pud_t pud)
31529e56940SSteve Capper {
31629e56940SSteve Capper 	return __pmd(pud_val(pud));
31729e56940SSteve Capper }
31829e56940SSteve Capper 
3199c7e535fSSteve Capper static inline pte_t pmd_pte(pmd_t pmd)
3209c7e535fSSteve Capper {
3219c7e535fSSteve Capper 	return __pte(pmd_val(pmd));
3229c7e535fSSteve Capper }
323af074848SSteve Capper 
3249c7e535fSSteve Capper static inline pmd_t pte_pmd(pte_t pte)
3259c7e535fSSteve Capper {
3269c7e535fSSteve Capper 	return __pmd(pte_val(pte));
3279c7e535fSSteve Capper }
328af074848SSteve Capper 
3298ce837ceSArd Biesheuvel static inline pgprot_t mk_sect_prot(pgprot_t prot)
3308ce837ceSArd Biesheuvel {
3318ce837ceSArd Biesheuvel 	return __pgprot(pgprot_val(prot) & ~PTE_TABLE_BIT);
3328ce837ceSArd Biesheuvel }
3338ce837ceSArd Biesheuvel 
334af074848SSteve Capper /*
335af074848SSteve Capper  * THP definitions.
336af074848SSteve Capper  */
337af074848SSteve Capper 
338af074848SSteve Capper #ifdef CONFIG_TRANSPARENT_HUGEPAGE
339af074848SSteve Capper #define pmd_trans_huge(pmd)	(pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
34029e56940SSteve Capper #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
341af074848SSteve Capper 
342c164e038SKirill A. Shutemov #define pmd_dirty(pmd)		pte_dirty(pmd_pte(pmd))
3439c7e535fSSteve Capper #define pmd_young(pmd)		pte_young(pmd_pte(pmd))
3449c7e535fSSteve Capper #define pmd_wrprotect(pmd)	pte_pmd(pte_wrprotect(pmd_pte(pmd)))
3459c7e535fSSteve Capper #define pmd_mkold(pmd)		pte_pmd(pte_mkold(pmd_pte(pmd)))
3469c7e535fSSteve Capper #define pmd_mkwrite(pmd)	pte_pmd(pte_mkwrite(pmd_pte(pmd)))
34705ee26d9SMinchan Kim #define pmd_mkclean(pmd)       pte_pmd(pte_mkclean(pmd_pte(pmd)))
3489c7e535fSSteve Capper #define pmd_mkdirty(pmd)	pte_pmd(pte_mkdirty(pmd_pte(pmd)))
3499c7e535fSSteve Capper #define pmd_mkyoung(pmd)	pte_pmd(pte_mkyoung(pmd_pte(pmd)))
350e3a920afSWill Deacon #define pmd_mknotpresent(pmd)	(__pmd(pmd_val(pmd) & ~PMD_TYPE_MASK))
351af074848SSteve Capper 
3529c7e535fSSteve Capper #define __HAVE_ARCH_PMD_WRITE
3539c7e535fSSteve Capper #define pmd_write(pmd)		pte_write(pmd_pte(pmd))
354af074848SSteve Capper 
355af074848SSteve Capper #define pmd_mkhuge(pmd)		(__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
356af074848SSteve Capper 
357af074848SSteve Capper #define pmd_pfn(pmd)		(((pmd_val(pmd) & PMD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
358af074848SSteve Capper #define pfn_pmd(pfn,prot)	(__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
359af074848SSteve Capper #define mk_pmd(page,prot)	pfn_pmd(page_to_pfn(page),prot)
360af074848SSteve Capper 
36129e56940SSteve Capper #define pud_write(pud)		pte_write(pud_pte(pud))
362206a2a73SSteve Capper #define pud_pfn(pud)		(((pud_val(pud) & PUD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
363af074848SSteve Capper 
364ceb21835SWill Deacon #define set_pmd_at(mm, addr, pmdp, pmd)	set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd))
365af074848SSteve Capper 
366af074848SSteve Capper static inline int has_transparent_hugepage(void)
367af074848SSteve Capper {
368af074848SSteve Capper 	return 1;
369af074848SSteve Capper }
370af074848SSteve Capper 
371a501e324SCatalin Marinas #define __pgprot_modify(prot,mask,bits) \
372a501e324SCatalin Marinas 	__pgprot((pgprot_val(prot) & ~(mask)) | (bits))
373a501e324SCatalin Marinas 
374af074848SSteve Capper /*
3754f04d8f0SCatalin Marinas  * Mark the prot value as uncacheable and unbufferable.
3764f04d8f0SCatalin Marinas  */
3774f04d8f0SCatalin Marinas #define pgprot_noncached(prot) \
378de2db743SCatalin Marinas 	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE) | PTE_PXN | PTE_UXN)
3794f04d8f0SCatalin Marinas #define pgprot_writecombine(prot) \
380de2db743SCatalin Marinas 	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
381d1e6dc91SLiviu Dudau #define pgprot_device(prot) \
382d1e6dc91SLiviu Dudau 	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN)
3834f04d8f0SCatalin Marinas #define __HAVE_PHYS_MEM_ACCESS_PROT
3844f04d8f0SCatalin Marinas struct file;
3854f04d8f0SCatalin Marinas extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
3864f04d8f0SCatalin Marinas 				     unsigned long size, pgprot_t vma_prot);
3874f04d8f0SCatalin Marinas 
3884f04d8f0SCatalin Marinas #define pmd_none(pmd)		(!pmd_val(pmd))
3894f04d8f0SCatalin Marinas #define pmd_present(pmd)	(pmd_val(pmd))
3904f04d8f0SCatalin Marinas 
3914f04d8f0SCatalin Marinas #define pmd_bad(pmd)		(!(pmd_val(pmd) & 2))
3924f04d8f0SCatalin Marinas 
39336311607SMarc Zyngier #define pmd_table(pmd)		((pmd_val(pmd) & PMD_TYPE_MASK) == \
39436311607SMarc Zyngier 				 PMD_TYPE_TABLE)
39536311607SMarc Zyngier #define pmd_sect(pmd)		((pmd_val(pmd) & PMD_TYPE_MASK) == \
39636311607SMarc Zyngier 				 PMD_TYPE_SECT)
39736311607SMarc Zyngier 
398*cac4b8cdSCatalin Marinas #if defined(CONFIG_ARM64_64K_PAGES) || CONFIG_PGTABLE_LEVELS < 3
399206a2a73SSteve Capper #define pud_sect(pud)		(0)
400523d6e9fSzhichang.yuan #define pud_table(pud)		(1)
401206a2a73SSteve Capper #else
402206a2a73SSteve Capper #define pud_sect(pud)		((pud_val(pud) & PUD_TYPE_MASK) == \
403206a2a73SSteve Capper 				 PUD_TYPE_SECT)
404523d6e9fSzhichang.yuan #define pud_table(pud)		((pud_val(pud) & PUD_TYPE_MASK) == \
405523d6e9fSzhichang.yuan 				 PUD_TYPE_TABLE)
406206a2a73SSteve Capper #endif
40736311607SMarc Zyngier 
4084f04d8f0SCatalin Marinas static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
4094f04d8f0SCatalin Marinas {
4104f04d8f0SCatalin Marinas 	*pmdp = pmd;
41198f7685eSWill Deacon 	dsb(ishst);
4127f0b1bf0SCatalin Marinas 	isb();
4134f04d8f0SCatalin Marinas }
4144f04d8f0SCatalin Marinas 
4154f04d8f0SCatalin Marinas static inline void pmd_clear(pmd_t *pmdp)
4164f04d8f0SCatalin Marinas {
4174f04d8f0SCatalin Marinas 	set_pmd(pmdp, __pmd(0));
4184f04d8f0SCatalin Marinas }
4194f04d8f0SCatalin Marinas 
420dca56dcaSMark Rutland static inline phys_addr_t pmd_page_paddr(pmd_t pmd)
4214f04d8f0SCatalin Marinas {
422dca56dcaSMark Rutland 	return pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK;
4234f04d8f0SCatalin Marinas }
4244f04d8f0SCatalin Marinas 
425053520f7SMark Rutland /* Find an entry in the third-level page table. */
426053520f7SMark Rutland #define pte_index(addr)		(((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
427053520f7SMark Rutland 
428dca56dcaSMark Rutland #define pte_offset_phys(dir,addr)	(pmd_page_paddr(*(dir)) + pte_index(addr) * sizeof(pte_t))
429dca56dcaSMark Rutland #define pte_offset_kernel(dir,addr)	((pte_t *)__va(pte_offset_phys((dir), (addr))))
430053520f7SMark Rutland 
431053520f7SMark Rutland #define pte_offset_map(dir,addr)	pte_offset_kernel((dir), (addr))
432053520f7SMark Rutland #define pte_offset_map_nested(dir,addr)	pte_offset_kernel((dir), (addr))
433053520f7SMark Rutland #define pte_unmap(pte)			do { } while (0)
434053520f7SMark Rutland #define pte_unmap_nested(pte)		do { } while (0)
435053520f7SMark Rutland 
436961faac1SMark Rutland #define pte_set_fixmap(addr)		((pte_t *)set_fixmap_offset(FIX_PTE, addr))
437961faac1SMark Rutland #define pte_set_fixmap_offset(pmd, addr)	pte_set_fixmap(pte_offset_phys(pmd, addr))
438961faac1SMark Rutland #define pte_clear_fixmap()		clear_fixmap(FIX_PTE)
439961faac1SMark Rutland 
4404f04d8f0SCatalin Marinas #define pmd_page(pmd)		pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
4414f04d8f0SCatalin Marinas 
4426533945aSArd Biesheuvel /* use ONLY for statically allocated translation tables */
4436533945aSArd Biesheuvel #define pte_offset_kimg(dir,addr)	((pte_t *)__phys_to_kimg(pte_offset_phys((dir), (addr))))
4446533945aSArd Biesheuvel 
4454f04d8f0SCatalin Marinas /*
4464f04d8f0SCatalin Marinas  * Conversion functions: convert a page and protection to a page entry,
4474f04d8f0SCatalin Marinas  * and a page entry and page directory to the page they refer to.
4484f04d8f0SCatalin Marinas  */
4494f04d8f0SCatalin Marinas #define mk_pte(page,prot)	pfn_pte(page_to_pfn(page),prot)
4504f04d8f0SCatalin Marinas 
4519f25e6adSKirill A. Shutemov #if CONFIG_PGTABLE_LEVELS > 2
4524f04d8f0SCatalin Marinas 
4537078db46SCatalin Marinas #define pmd_ERROR(pmd)		__pmd_error(__FILE__, __LINE__, pmd_val(pmd))
4547078db46SCatalin Marinas 
4554f04d8f0SCatalin Marinas #define pud_none(pud)		(!pud_val(pud))
4564f04d8f0SCatalin Marinas #define pud_bad(pud)		(!(pud_val(pud) & 2))
4574f04d8f0SCatalin Marinas #define pud_present(pud)	(pud_val(pud))
4584f04d8f0SCatalin Marinas 
4594f04d8f0SCatalin Marinas static inline void set_pud(pud_t *pudp, pud_t pud)
4604f04d8f0SCatalin Marinas {
4614f04d8f0SCatalin Marinas 	*pudp = pud;
46298f7685eSWill Deacon 	dsb(ishst);
4637f0b1bf0SCatalin Marinas 	isb();
4644f04d8f0SCatalin Marinas }
4654f04d8f0SCatalin Marinas 
4664f04d8f0SCatalin Marinas static inline void pud_clear(pud_t *pudp)
4674f04d8f0SCatalin Marinas {
4684f04d8f0SCatalin Marinas 	set_pud(pudp, __pud(0));
4694f04d8f0SCatalin Marinas }
4704f04d8f0SCatalin Marinas 
471dca56dcaSMark Rutland static inline phys_addr_t pud_page_paddr(pud_t pud)
4724f04d8f0SCatalin Marinas {
473dca56dcaSMark Rutland 	return pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK;
4744f04d8f0SCatalin Marinas }
4754f04d8f0SCatalin Marinas 
4767078db46SCatalin Marinas /* Find an entry in the second-level page table. */
4777078db46SCatalin Marinas #define pmd_index(addr)		(((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
4787078db46SCatalin Marinas 
479dca56dcaSMark Rutland #define pmd_offset_phys(dir, addr)	(pud_page_paddr(*(dir)) + pmd_index(addr) * sizeof(pmd_t))
480dca56dcaSMark Rutland #define pmd_offset(dir, addr)		((pmd_t *)__va(pmd_offset_phys((dir), (addr))))
4817078db46SCatalin Marinas 
482961faac1SMark Rutland #define pmd_set_fixmap(addr)		((pmd_t *)set_fixmap_offset(FIX_PMD, addr))
483961faac1SMark Rutland #define pmd_set_fixmap_offset(pud, addr)	pmd_set_fixmap(pmd_offset_phys(pud, addr))
484961faac1SMark Rutland #define pmd_clear_fixmap()		clear_fixmap(FIX_PMD)
485961faac1SMark Rutland 
4865d96e0cbSJungseok Lee #define pud_page(pud)		pfn_to_page(__phys_to_pfn(pud_val(pud) & PHYS_MASK))
48729e56940SSteve Capper 
4886533945aSArd Biesheuvel /* use ONLY for statically allocated translation tables */
4896533945aSArd Biesheuvel #define pmd_offset_kimg(dir,addr)	((pmd_t *)__phys_to_kimg(pmd_offset_phys((dir), (addr))))
4906533945aSArd Biesheuvel 
491dca56dcaSMark Rutland #else
492dca56dcaSMark Rutland 
493dca56dcaSMark Rutland #define pud_page_paddr(pud)	({ BUILD_BUG(); 0; })
494dca56dcaSMark Rutland 
495961faac1SMark Rutland /* Match pmd_offset folding in <asm/generic/pgtable-nopmd.h> */
496961faac1SMark Rutland #define pmd_set_fixmap(addr)		NULL
497961faac1SMark Rutland #define pmd_set_fixmap_offset(pudp, addr)	((pmd_t *)pudp)
498961faac1SMark Rutland #define pmd_clear_fixmap()
499961faac1SMark Rutland 
5006533945aSArd Biesheuvel #define pmd_offset_kimg(dir,addr)	((pmd_t *)dir)
5016533945aSArd Biesheuvel 
5029f25e6adSKirill A. Shutemov #endif	/* CONFIG_PGTABLE_LEVELS > 2 */
5034f04d8f0SCatalin Marinas 
5049f25e6adSKirill A. Shutemov #if CONFIG_PGTABLE_LEVELS > 3
505c79b954bSJungseok Lee 
5067078db46SCatalin Marinas #define pud_ERROR(pud)		__pud_error(__FILE__, __LINE__, pud_val(pud))
5077078db46SCatalin Marinas 
508c79b954bSJungseok Lee #define pgd_none(pgd)		(!pgd_val(pgd))
509c79b954bSJungseok Lee #define pgd_bad(pgd)		(!(pgd_val(pgd) & 2))
510c79b954bSJungseok Lee #define pgd_present(pgd)	(pgd_val(pgd))
511c79b954bSJungseok Lee 
512c79b954bSJungseok Lee static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
513c79b954bSJungseok Lee {
514c79b954bSJungseok Lee 	*pgdp = pgd;
515c79b954bSJungseok Lee 	dsb(ishst);
516c79b954bSJungseok Lee }
517c79b954bSJungseok Lee 
518c79b954bSJungseok Lee static inline void pgd_clear(pgd_t *pgdp)
519c79b954bSJungseok Lee {
520c79b954bSJungseok Lee 	set_pgd(pgdp, __pgd(0));
521c79b954bSJungseok Lee }
522c79b954bSJungseok Lee 
523dca56dcaSMark Rutland static inline phys_addr_t pgd_page_paddr(pgd_t pgd)
524c79b954bSJungseok Lee {
525dca56dcaSMark Rutland 	return pgd_val(pgd) & PHYS_MASK & (s32)PAGE_MASK;
526c79b954bSJungseok Lee }
527c79b954bSJungseok Lee 
5287078db46SCatalin Marinas /* Find an entry in the frst-level page table. */
5297078db46SCatalin Marinas #define pud_index(addr)		(((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
5307078db46SCatalin Marinas 
531dca56dcaSMark Rutland #define pud_offset_phys(dir, addr)	(pgd_page_paddr(*(dir)) + pud_index(addr) * sizeof(pud_t))
532dca56dcaSMark Rutland #define pud_offset(dir, addr)		((pud_t *)__va(pud_offset_phys((dir), (addr))))
5337078db46SCatalin Marinas 
534961faac1SMark Rutland #define pud_set_fixmap(addr)		((pud_t *)set_fixmap_offset(FIX_PUD, addr))
535961faac1SMark Rutland #define pud_set_fixmap_offset(pgd, addr)	pud_set_fixmap(pud_offset_phys(pgd, addr))
536961faac1SMark Rutland #define pud_clear_fixmap()		clear_fixmap(FIX_PUD)
537961faac1SMark Rutland 
5385d96e0cbSJungseok Lee #define pgd_page(pgd)		pfn_to_page(__phys_to_pfn(pgd_val(pgd) & PHYS_MASK))
5395d96e0cbSJungseok Lee 
5406533945aSArd Biesheuvel /* use ONLY for statically allocated translation tables */
5416533945aSArd Biesheuvel #define pud_offset_kimg(dir,addr)	((pud_t *)__phys_to_kimg(pud_offset_phys((dir), (addr))))
5426533945aSArd Biesheuvel 
543dca56dcaSMark Rutland #else
544dca56dcaSMark Rutland 
545dca56dcaSMark Rutland #define pgd_page_paddr(pgd)	({ BUILD_BUG(); 0;})
546dca56dcaSMark Rutland 
547961faac1SMark Rutland /* Match pud_offset folding in <asm/generic/pgtable-nopud.h> */
548961faac1SMark Rutland #define pud_set_fixmap(addr)		NULL
549961faac1SMark Rutland #define pud_set_fixmap_offset(pgdp, addr)	((pud_t *)pgdp)
550961faac1SMark Rutland #define pud_clear_fixmap()
551961faac1SMark Rutland 
5526533945aSArd Biesheuvel #define pud_offset_kimg(dir,addr)	((pud_t *)dir)
5536533945aSArd Biesheuvel 
5549f25e6adSKirill A. Shutemov #endif  /* CONFIG_PGTABLE_LEVELS > 3 */
555c79b954bSJungseok Lee 
5567078db46SCatalin Marinas #define pgd_ERROR(pgd)		__pgd_error(__FILE__, __LINE__, pgd_val(pgd))
5577078db46SCatalin Marinas 
5584f04d8f0SCatalin Marinas /* to find an entry in a page-table-directory */
5594f04d8f0SCatalin Marinas #define pgd_index(addr)		(((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
5604f04d8f0SCatalin Marinas 
561dca56dcaSMark Rutland #define pgd_offset_raw(pgd, addr)	((pgd) + pgd_index(addr))
562dca56dcaSMark Rutland 
563dca56dcaSMark Rutland #define pgd_offset(mm, addr)	(pgd_offset_raw((mm)->pgd, (addr)))
5644f04d8f0SCatalin Marinas 
5654f04d8f0SCatalin Marinas /* to find an entry in a kernel page-table-directory */
5664f04d8f0SCatalin Marinas #define pgd_offset_k(addr)	pgd_offset(&init_mm, addr)
5674f04d8f0SCatalin Marinas 
568961faac1SMark Rutland #define pgd_set_fixmap(addr)	((pgd_t *)set_fixmap_offset(FIX_PGD, addr))
569961faac1SMark Rutland #define pgd_clear_fixmap()	clear_fixmap(FIX_PGD)
570961faac1SMark Rutland 
5714f04d8f0SCatalin Marinas static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
5724f04d8f0SCatalin Marinas {
573a6fadf7eSWill Deacon 	const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
5741a541b4eSSteve Capper 			      PTE_PROT_NONE | PTE_VALID | PTE_WRITE;
5752f4b829cSCatalin Marinas 	/* preserve the hardware dirty information */
5762f4b829cSCatalin Marinas 	if (pte_hw_dirty(pte))
57762d96c71SCatalin Marinas 		pte = pte_mkdirty(pte);
5784f04d8f0SCatalin Marinas 	pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
5794f04d8f0SCatalin Marinas 	return pte;
5804f04d8f0SCatalin Marinas }
5814f04d8f0SCatalin Marinas 
5829c7e535fSSteve Capper static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
5839c7e535fSSteve Capper {
5849c7e535fSSteve Capper 	return pte_pmd(pte_modify(pmd_pte(pmd), newprot));
5859c7e535fSSteve Capper }
5869c7e535fSSteve Capper 
5872f4b829cSCatalin Marinas #ifdef CONFIG_ARM64_HW_AFDBM
5882f4b829cSCatalin Marinas /*
5892f4b829cSCatalin Marinas  * Atomic pte/pmd modifications.
5902f4b829cSCatalin Marinas  */
5912f4b829cSCatalin Marinas #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
5922f4b829cSCatalin Marinas static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
5932f4b829cSCatalin Marinas 					    unsigned long address,
5942f4b829cSCatalin Marinas 					    pte_t *ptep)
5952f4b829cSCatalin Marinas {
5962f4b829cSCatalin Marinas 	pteval_t pteval;
5972f4b829cSCatalin Marinas 	unsigned int tmp, res;
5982f4b829cSCatalin Marinas 
5992f4b829cSCatalin Marinas 	asm volatile("//	ptep_test_and_clear_young\n"
6002f4b829cSCatalin Marinas 	"	prfm	pstl1strm, %2\n"
6012f4b829cSCatalin Marinas 	"1:	ldxr	%0, %2\n"
6022f4b829cSCatalin Marinas 	"	ubfx	%w3, %w0, %5, #1	// extract PTE_AF (young)\n"
6032f4b829cSCatalin Marinas 	"	and	%0, %0, %4		// clear PTE_AF\n"
6042f4b829cSCatalin Marinas 	"	stxr	%w1, %0, %2\n"
6052f4b829cSCatalin Marinas 	"	cbnz	%w1, 1b\n"
6062f4b829cSCatalin Marinas 	: "=&r" (pteval), "=&r" (tmp), "+Q" (pte_val(*ptep)), "=&r" (res)
6072f4b829cSCatalin Marinas 	: "L" (~PTE_AF), "I" (ilog2(PTE_AF)));
6082f4b829cSCatalin Marinas 
6092f4b829cSCatalin Marinas 	return res;
6102f4b829cSCatalin Marinas }
6112f4b829cSCatalin Marinas 
6122f4b829cSCatalin Marinas #ifdef CONFIG_TRANSPARENT_HUGEPAGE
6132f4b829cSCatalin Marinas #define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG
6142f4b829cSCatalin Marinas static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma,
6152f4b829cSCatalin Marinas 					    unsigned long address,
6162f4b829cSCatalin Marinas 					    pmd_t *pmdp)
6172f4b829cSCatalin Marinas {
6182f4b829cSCatalin Marinas 	return ptep_test_and_clear_young(vma, address, (pte_t *)pmdp);
6192f4b829cSCatalin Marinas }
6202f4b829cSCatalin Marinas #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
6212f4b829cSCatalin Marinas 
6222f4b829cSCatalin Marinas #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
6232f4b829cSCatalin Marinas static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
6242f4b829cSCatalin Marinas 				       unsigned long address, pte_t *ptep)
6252f4b829cSCatalin Marinas {
6262f4b829cSCatalin Marinas 	pteval_t old_pteval;
6272f4b829cSCatalin Marinas 	unsigned int tmp;
6282f4b829cSCatalin Marinas 
6292f4b829cSCatalin Marinas 	asm volatile("//	ptep_get_and_clear\n"
6302f4b829cSCatalin Marinas 	"	prfm	pstl1strm, %2\n"
6312f4b829cSCatalin Marinas 	"1:	ldxr	%0, %2\n"
6322f4b829cSCatalin Marinas 	"	stxr	%w1, xzr, %2\n"
6332f4b829cSCatalin Marinas 	"	cbnz	%w1, 1b\n"
6342f4b829cSCatalin Marinas 	: "=&r" (old_pteval), "=&r" (tmp), "+Q" (pte_val(*ptep)));
6352f4b829cSCatalin Marinas 
6362f4b829cSCatalin Marinas 	return __pte(old_pteval);
6372f4b829cSCatalin Marinas }
6382f4b829cSCatalin Marinas 
6392f4b829cSCatalin Marinas #ifdef CONFIG_TRANSPARENT_HUGEPAGE
6402f4b829cSCatalin Marinas #define __HAVE_ARCH_PMDP_GET_AND_CLEAR
6412f4b829cSCatalin Marinas static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm,
6422f4b829cSCatalin Marinas 				       unsigned long address, pmd_t *pmdp)
6432f4b829cSCatalin Marinas {
6442f4b829cSCatalin Marinas 	return pte_pmd(ptep_get_and_clear(mm, address, (pte_t *)pmdp));
6452f4b829cSCatalin Marinas }
6462f4b829cSCatalin Marinas #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
6472f4b829cSCatalin Marinas 
6482f4b829cSCatalin Marinas /*
6492f4b829cSCatalin Marinas  * ptep_set_wrprotect - mark read-only while trasferring potential hardware
6502f4b829cSCatalin Marinas  * dirty status (PTE_DBM && !PTE_RDONLY) to the software PTE_DIRTY bit.
6512f4b829cSCatalin Marinas  */
6522f4b829cSCatalin Marinas #define __HAVE_ARCH_PTEP_SET_WRPROTECT
6532f4b829cSCatalin Marinas static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep)
6542f4b829cSCatalin Marinas {
6552f4b829cSCatalin Marinas 	pteval_t pteval;
6562f4b829cSCatalin Marinas 	unsigned long tmp;
6572f4b829cSCatalin Marinas 
6582f4b829cSCatalin Marinas 	asm volatile("//	ptep_set_wrprotect\n"
6592f4b829cSCatalin Marinas 	"	prfm	pstl1strm, %2\n"
6602f4b829cSCatalin Marinas 	"1:	ldxr	%0, %2\n"
6612f4b829cSCatalin Marinas 	"	tst	%0, %4			// check for hw dirty (!PTE_RDONLY)\n"
6622f4b829cSCatalin Marinas 	"	csel	%1, %3, xzr, eq		// set PTE_DIRTY|PTE_RDONLY if dirty\n"
6632f4b829cSCatalin Marinas 	"	orr	%0, %0, %1		// if !dirty, PTE_RDONLY is already set\n"
6642f4b829cSCatalin Marinas 	"	and	%0, %0, %5		// clear PTE_WRITE/PTE_DBM\n"
6652f4b829cSCatalin Marinas 	"	stxr	%w1, %0, %2\n"
6662f4b829cSCatalin Marinas 	"	cbnz	%w1, 1b\n"
6672f4b829cSCatalin Marinas 	: "=&r" (pteval), "=&r" (tmp), "+Q" (pte_val(*ptep))
6682f4b829cSCatalin Marinas 	: "r" (PTE_DIRTY|PTE_RDONLY), "L" (PTE_RDONLY), "L" (~PTE_WRITE)
6692f4b829cSCatalin Marinas 	: "cc");
6702f4b829cSCatalin Marinas }
6712f4b829cSCatalin Marinas 
6722f4b829cSCatalin Marinas #ifdef CONFIG_TRANSPARENT_HUGEPAGE
6732f4b829cSCatalin Marinas #define __HAVE_ARCH_PMDP_SET_WRPROTECT
6742f4b829cSCatalin Marinas static inline void pmdp_set_wrprotect(struct mm_struct *mm,
6752f4b829cSCatalin Marinas 				      unsigned long address, pmd_t *pmdp)
6762f4b829cSCatalin Marinas {
6772f4b829cSCatalin Marinas 	ptep_set_wrprotect(mm, address, (pte_t *)pmdp);
6782f4b829cSCatalin Marinas }
6792f4b829cSCatalin Marinas #endif
6802f4b829cSCatalin Marinas #endif	/* CONFIG_ARM64_HW_AFDBM */
6812f4b829cSCatalin Marinas 
6824f04d8f0SCatalin Marinas extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
6834f04d8f0SCatalin Marinas extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
6844f04d8f0SCatalin Marinas 
6854f04d8f0SCatalin Marinas /*
6864f04d8f0SCatalin Marinas  * Encode and decode a swap entry:
6873676f9efSCatalin Marinas  *	bits 0-1:	present (must be zero)
6889b3e661eSKirill A. Shutemov  *	bits 2-7:	swap type
6899b3e661eSKirill A. Shutemov  *	bits 8-57:	swap offset
6904f04d8f0SCatalin Marinas  */
6919b3e661eSKirill A. Shutemov #define __SWP_TYPE_SHIFT	2
6924f04d8f0SCatalin Marinas #define __SWP_TYPE_BITS		6
6939b3e661eSKirill A. Shutemov #define __SWP_OFFSET_BITS	50
6944f04d8f0SCatalin Marinas #define __SWP_TYPE_MASK		((1 << __SWP_TYPE_BITS) - 1)
6954f04d8f0SCatalin Marinas #define __SWP_OFFSET_SHIFT	(__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
6963676f9efSCatalin Marinas #define __SWP_OFFSET_MASK	((1UL << __SWP_OFFSET_BITS) - 1)
6974f04d8f0SCatalin Marinas 
6984f04d8f0SCatalin Marinas #define __swp_type(x)		(((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK)
6993676f9efSCatalin Marinas #define __swp_offset(x)		(((x).val >> __SWP_OFFSET_SHIFT) & __SWP_OFFSET_MASK)
7004f04d8f0SCatalin Marinas #define __swp_entry(type,offset) ((swp_entry_t) { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) })
7014f04d8f0SCatalin Marinas 
7024f04d8f0SCatalin Marinas #define __pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) })
7034f04d8f0SCatalin Marinas #define __swp_entry_to_pte(swp)	((pte_t) { (swp).val })
7044f04d8f0SCatalin Marinas 
7054f04d8f0SCatalin Marinas /*
7064f04d8f0SCatalin Marinas  * Ensure that there are not more swap files than can be encoded in the kernel
707aad9061bSGeert Uytterhoeven  * PTEs.
7084f04d8f0SCatalin Marinas  */
7094f04d8f0SCatalin Marinas #define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS)
7104f04d8f0SCatalin Marinas 
7114f04d8f0SCatalin Marinas extern int kern_addr_valid(unsigned long addr);
7124f04d8f0SCatalin Marinas 
7134f04d8f0SCatalin Marinas #include <asm-generic/pgtable.h>
7144f04d8f0SCatalin Marinas 
71539b5be9bSWill Deacon void pgd_cache_init(void);
71639b5be9bSWill Deacon #define pgtable_cache_init	pgd_cache_init
7174f04d8f0SCatalin Marinas 
718cba3574fSWill Deacon /*
719cba3574fSWill Deacon  * On AArch64, the cache coherency is handled via the set_pte_at() function.
720cba3574fSWill Deacon  */
721cba3574fSWill Deacon static inline void update_mmu_cache(struct vm_area_struct *vma,
722cba3574fSWill Deacon 				    unsigned long addr, pte_t *ptep)
723cba3574fSWill Deacon {
724cba3574fSWill Deacon 	/*
725120798d2SWill Deacon 	 * We don't do anything here, so there's a very small chance of
726120798d2SWill Deacon 	 * us retaking a user fault which we just fixed up. The alternative
727120798d2SWill Deacon 	 * is doing a dsb(ishst), but that penalises the fastpath.
728cba3574fSWill Deacon 	 */
729cba3574fSWill Deacon }
730cba3574fSWill Deacon 
731cba3574fSWill Deacon #define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
732cba3574fSWill Deacon 
73303875ad5Syalin wang #define kc_vaddr_to_offset(v)	((v) & ~VA_START)
73403875ad5Syalin wang #define kc_offset_to_vaddr(o)	((o) | VA_START)
7357db743c6SCatalin Marinas 
7364f04d8f0SCatalin Marinas #endif /* !__ASSEMBLY__ */
7374f04d8f0SCatalin Marinas 
7384f04d8f0SCatalin Marinas #endif /* __ASM_PGTABLE_H */
739