diff options
Diffstat (limited to 'arch/arm64/include/asm/pgtable.h')
| -rw-r--r-- | arch/arm64/include/asm/pgtable.h | 271 | 
1 files changed, 152 insertions, 119 deletions
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index f0bebc5e22c..e0ccceb317d 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -25,15 +25,16 @@   * Software defined PTE bits definition.   */  #define PTE_VALID		(_AT(pteval_t, 1) << 0) -#define PTE_PROT_NONE		(_AT(pteval_t, 1) << 2)	/* only when !PTE_VALID */ -#define PTE_FILE		(_AT(pteval_t, 1) << 3)	/* only when !pte_present() */ +#define PTE_FILE		(_AT(pteval_t, 1) << 2)	/* only when !pte_present() */  #define PTE_DIRTY		(_AT(pteval_t, 1) << 55)  #define PTE_SPECIAL		(_AT(pteval_t, 1) << 56) +#define PTE_WRITE		(_AT(pteval_t, 1) << 57) +#define PTE_PROT_NONE		(_AT(pteval_t, 1) << 58) /* only when !PTE_VALID */  /*   * VMALLOC and SPARSEMEM_VMEMMAP ranges.   */ -#define VMALLOC_START		UL(0xffffff8000000000) +#define VMALLOC_START		(UL(0xffffffffffffffff) << VA_BITS)  #define VMALLOC_END		(PAGE_OFFSET - UL(0x400000000) - SZ_64K)  #define vmemmap			((struct page *)(VMALLOC_END + SZ_64K)) @@ -51,66 +52,59 @@ extern void __pgd_error(const char *file, int line, unsigned long val);  #endif  #define pgd_ERROR(pgd)		__pgd_error(__FILE__, __LINE__, pgd_val(pgd)) -/* - * The pgprot_* and protection_map entries will be fixed up at runtime to - * include the cachable and bufferable bits based on memory policy, as well as - * any architecture dependent bits like global/ASID and SMP shared mapping - * bits. - */ -#define _PAGE_DEFAULT		PTE_TYPE_PAGE | PTE_AF +#ifdef CONFIG_SMP +#define PROT_DEFAULT		(PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) +#define PROT_SECT_DEFAULT	(PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) +#else +#define PROT_DEFAULT		(PTE_TYPE_PAGE | PTE_AF) +#define PROT_SECT_DEFAULT	(PMD_TYPE_SECT | PMD_SECT_AF) +#endif -extern pgprot_t pgprot_default; +#define PROT_DEVICE_nGnRE	(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRE)) +#define PROT_NORMAL_NC		(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL_NC)) +#define PROT_NORMAL		(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL)) -#define __pgprot_modify(prot,mask,bits) \ -	__pgprot((pgprot_val(prot) & ~(mask)) | (bits)) +#define PROT_SECT_DEVICE_nGnRE	(PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE)) +#define PROT_SECT_NORMAL	(PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL)) +#define PROT_SECT_NORMAL_EXEC	(PROT_SECT_DEFAULT | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL)) -#define _MOD_PROT(p, b)		__pgprot_modify(p, 0, b) +#define _PAGE_DEFAULT		(PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL)) -#define PAGE_NONE		__pgprot_modify(pgprot_default, PTE_TYPE_MASK, PTE_PROT_NONE | PTE_RDONLY | PTE_PXN | PTE_UXN) -#define PAGE_SHARED		_MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) -#define PAGE_SHARED_EXEC	_MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN) -#define PAGE_COPY		_MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) -#define PAGE_COPY_EXEC		_MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY) -#define PAGE_READONLY		_MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) -#define PAGE_READONLY_EXEC	_MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY) -#define PAGE_KERNEL		_MOD_PROT(pgprot_default, PTE_PXN | PTE_UXN | PTE_DIRTY) -#define PAGE_KERNEL_EXEC	_MOD_PROT(pgprot_default, PTE_UXN | PTE_DIRTY) +#define PAGE_KERNEL		__pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE) +#define PAGE_KERNEL_EXEC	__pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE) -#define PAGE_HYP		_MOD_PROT(pgprot_default, PTE_HYP) +#define PAGE_HYP		__pgprot(_PAGE_DEFAULT | PTE_HYP)  #define PAGE_HYP_DEVICE		__pgprot(PROT_DEVICE_nGnRE | PTE_HYP) -#define PAGE_S2			__pgprot_modify(pgprot_default, PTE_S2_MEMATTR_MASK, PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY) +#define PAGE_S2			__pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY)  #define PAGE_S2_DEVICE		__pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDWR | PTE_UXN) -#define __PAGE_NONE		__pgprot(((_PAGE_DEFAULT) & ~PTE_TYPE_MASK) | PTE_PROT_NONE | PTE_RDONLY | PTE_PXN | PTE_UXN) -#define __PAGE_SHARED		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) -#define __PAGE_SHARED_EXEC	__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN) -#define __PAGE_COPY		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) -#define __PAGE_COPY_EXEC	__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY) -#define __PAGE_READONLY		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) -#define __PAGE_READONLY_EXEC	__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY) - -#endif /* __ASSEMBLY__ */ - -#define __P000  __PAGE_NONE -#define __P001  __PAGE_READONLY -#define __P010  __PAGE_COPY -#define __P011  __PAGE_COPY -#define __P100  __PAGE_READONLY_EXEC -#define __P101  __PAGE_READONLY_EXEC -#define __P110  __PAGE_COPY_EXEC -#define __P111  __PAGE_COPY_EXEC - -#define __S000  __PAGE_NONE -#define __S001  __PAGE_READONLY -#define __S010  __PAGE_SHARED -#define __S011  __PAGE_SHARED -#define __S100  __PAGE_READONLY_EXEC -#define __S101  __PAGE_READONLY_EXEC -#define __S110  __PAGE_SHARED_EXEC -#define __S111  __PAGE_SHARED_EXEC +#define PAGE_NONE		__pgprot(((_PAGE_DEFAULT) & ~PTE_TYPE_MASK) | PTE_PROT_NONE | PTE_PXN | PTE_UXN) +#define PAGE_SHARED		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE) +#define PAGE_SHARED_EXEC	__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE) +#define PAGE_COPY		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) +#define PAGE_COPY_EXEC		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN) +#define PAGE_READONLY		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) +#define PAGE_READONLY_EXEC	__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN) + +#define __P000  PAGE_NONE +#define __P001  PAGE_READONLY +#define __P010  PAGE_COPY +#define __P011  PAGE_COPY +#define __P100  PAGE_READONLY_EXEC +#define __P101  PAGE_READONLY_EXEC +#define __P110  PAGE_COPY_EXEC +#define __P111  PAGE_COPY_EXEC + +#define __S000  PAGE_NONE +#define __S001  PAGE_READONLY +#define __S010  PAGE_SHARED +#define __S011  PAGE_SHARED +#define __S100  PAGE_READONLY_EXEC +#define __S101  PAGE_READONLY_EXEC +#define __S110  PAGE_SHARED_EXEC +#define __S111  PAGE_SHARED_EXEC -#ifndef __ASSEMBLY__  /*   * ZERO_PAGE is a global shared page that is always zero: used   * for zero-mapped memory areas etc.. @@ -135,26 +129,57 @@ extern struct page *empty_zero_page;  /*   * The following only work if pte_present(). Undefined behaviour otherwise.   */ -#define pte_present(pte)	(pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)) -#define pte_dirty(pte)		(pte_val(pte) & PTE_DIRTY) -#define pte_young(pte)		(pte_val(pte) & PTE_AF) -#define pte_special(pte)	(pte_val(pte) & PTE_SPECIAL) -#define pte_write(pte)		(!(pte_val(pte) & PTE_RDONLY)) +#define pte_present(pte)	(!!(pte_val(pte) & (PTE_VALID | PTE_PROT_NONE))) +#define pte_dirty(pte)		(!!(pte_val(pte) & PTE_DIRTY)) +#define pte_young(pte)		(!!(pte_val(pte) & PTE_AF)) +#define pte_special(pte)	(!!(pte_val(pte) & PTE_SPECIAL)) +#define pte_write(pte)		(!!(pte_val(pte) & PTE_WRITE))  #define pte_exec(pte)		(!(pte_val(pte) & PTE_UXN))  #define pte_valid_user(pte) \  	((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) -#define PTE_BIT_FUNC(fn,op) \ -static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } +static inline pte_t pte_wrprotect(pte_t pte) +{ +	pte_val(pte) &= ~PTE_WRITE; +	return pte; +} -PTE_BIT_FUNC(wrprotect, |= PTE_RDONLY); -PTE_BIT_FUNC(mkwrite,   &= ~PTE_RDONLY); -PTE_BIT_FUNC(mkclean,   &= ~PTE_DIRTY); -PTE_BIT_FUNC(mkdirty,   |= PTE_DIRTY); -PTE_BIT_FUNC(mkold,     &= ~PTE_AF); -PTE_BIT_FUNC(mkyoung,   |= PTE_AF); -PTE_BIT_FUNC(mkspecial, |= PTE_SPECIAL); +static inline pte_t pte_mkwrite(pte_t pte) +{ +	pte_val(pte) |= PTE_WRITE; +	return pte; +} + +static inline pte_t pte_mkclean(pte_t pte) +{ +	pte_val(pte) &= ~PTE_DIRTY; +	return pte; +} + +static inline pte_t pte_mkdirty(pte_t pte) +{ +	pte_val(pte) |= PTE_DIRTY; +	return pte; +} + +static inline pte_t pte_mkold(pte_t pte) +{ +	pte_val(pte) &= ~PTE_AF; +	return pte; +} + +static inline pte_t pte_mkyoung(pte_t pte) +{ +	pte_val(pte) |= PTE_AF; +	return pte; +} + +static inline pte_t pte_mkspecial(pte_t pte) +{ +	pte_val(pte) |= PTE_SPECIAL; +	return pte; +}  static inline void set_pte(pte_t *ptep, pte_t pte)  { @@ -167,10 +192,12 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,  			      pte_t *ptep, pte_t pte)  {  	if (pte_valid_user(pte)) { -		if (pte_exec(pte)) +		if (!pte_special(pte) && pte_exec(pte))  			__sync_icache_dcache(pte, addr); -		if (!pte_dirty(pte)) -			pte = pte_wrprotect(pte); +		if (pte_dirty(pte) && pte_write(pte)) +			pte_val(pte) &= ~PTE_RDONLY; +		else +			pte_val(pte) |= PTE_RDONLY;  	}  	set_pte(ptep, pte); @@ -193,36 +220,36 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,  #define __HAVE_ARCH_PTE_SPECIAL -/* - * Software PMD bits for THP - */ +static inline pte_t pmd_pte(pmd_t pmd) +{ +	return __pte(pmd_val(pmd)); +} -#define PMD_SECT_DIRTY		(_AT(pmdval_t, 1) << 55) -#define PMD_SECT_SPLITTING	(_AT(pmdval_t, 1) << 57) +static inline pmd_t pte_pmd(pte_t pte) +{ +	return __pmd(pte_val(pte)); +}  /*   * THP definitions.   */ -#define pmd_young(pmd)		(pmd_val(pmd) & PMD_SECT_AF) - -#define __HAVE_ARCH_PMD_WRITE -#define pmd_write(pmd)		(!(pmd_val(pmd) & PMD_SECT_RDONLY))  #ifdef CONFIG_TRANSPARENT_HUGEPAGE  #define pmd_trans_huge(pmd)	(pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT)) -#define pmd_trans_splitting(pmd) (pmd_val(pmd) & PMD_SECT_SPLITTING) +#define pmd_trans_splitting(pmd)	pte_special(pmd_pte(pmd))  #endif -#define PMD_BIT_FUNC(fn,op) \ -static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; } +#define pmd_young(pmd)		pte_young(pmd_pte(pmd)) +#define pmd_wrprotect(pmd)	pte_pmd(pte_wrprotect(pmd_pte(pmd))) +#define pmd_mksplitting(pmd)	pte_pmd(pte_mkspecial(pmd_pte(pmd))) +#define pmd_mkold(pmd)		pte_pmd(pte_mkold(pmd_pte(pmd))) +#define pmd_mkwrite(pmd)	pte_pmd(pte_mkwrite(pmd_pte(pmd))) +#define pmd_mkdirty(pmd)	pte_pmd(pte_mkdirty(pmd_pte(pmd))) +#define pmd_mkyoung(pmd)	pte_pmd(pte_mkyoung(pmd_pte(pmd))) +#define pmd_mknotpresent(pmd)	(__pmd(pmd_val(pmd) & ~PMD_TYPE_MASK)) -PMD_BIT_FUNC(wrprotect,	|= PMD_SECT_RDONLY); -PMD_BIT_FUNC(mkold,	&= ~PMD_SECT_AF); -PMD_BIT_FUNC(mksplitting, |= PMD_SECT_SPLITTING); -PMD_BIT_FUNC(mkwrite,   &= ~PMD_SECT_RDONLY); -PMD_BIT_FUNC(mkdirty,   |= PMD_SECT_DIRTY); -PMD_BIT_FUNC(mkyoung,   |= PMD_SECT_AF); -PMD_BIT_FUNC(mknotpresent, &= ~PMD_TYPE_MASK); +#define __HAVE_ARCH_PMD_WRITE +#define pmd_write(pmd)		pte_write(pmd_pte(pmd))  #define pmd_mkhuge(pmd)		(__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT)) @@ -231,32 +258,25 @@ PMD_BIT_FUNC(mknotpresent, &= ~PMD_TYPE_MASK);  #define mk_pmd(page,prot)	pfn_pmd(page_to_pfn(page),prot)  #define pmd_page(pmd)           pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK)) +#define pud_pfn(pud)		(((pud_val(pud) & PUD_MASK) & PHYS_MASK) >> PAGE_SHIFT) -static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) -{ -	const pmdval_t mask = PMD_SECT_USER | PMD_SECT_PXN | PMD_SECT_UXN | -			      PMD_SECT_RDONLY | PMD_SECT_PROT_NONE | -			      PMD_SECT_VALID; -	pmd_val(pmd) = (pmd_val(pmd) & ~mask) | (pgprot_val(newprot) & mask); -	return pmd; -} - -#define set_pmd_at(mm, addr, pmdp, pmd)	set_pmd(pmdp, pmd) +#define set_pmd_at(mm, addr, pmdp, pmd)	set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd))  static inline int has_transparent_hugepage(void)  {  	return 1;  } +#define __pgprot_modify(prot,mask,bits) \ +	__pgprot((pgprot_val(prot) & ~(mask)) | (bits)) +  /*   * Mark the prot value as uncacheable and unbufferable.   */  #define pgprot_noncached(prot) \ -	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE)) +	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE) | PTE_PXN | PTE_UXN)  #define pgprot_writecombine(prot) \ -	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_GRE)) -#define pgprot_dmacoherent(prot) \ -	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC)) +	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)  #define __HAVE_PHYS_MEM_ACCESS_PROT  struct file;  extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, @@ -272,11 +292,17 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,  #define pmd_sect(pmd)		((pmd_val(pmd) & PMD_TYPE_MASK) == \  				 PMD_TYPE_SECT) +#ifdef CONFIG_ARM64_64K_PAGES +#define pud_sect(pud)		(0) +#else +#define pud_sect(pud)		((pud_val(pud) & PUD_TYPE_MASK) == \ +				 PUD_TYPE_SECT) +#endif  static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)  {  	*pmdp = pmd; -	dsb(); +	dsb(ishst);  }  static inline void pmd_clear(pmd_t *pmdp) @@ -306,7 +332,7 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd)  static inline void set_pud(pud_t *pudp, pud_t pud)  {  	*pudp = pud; -	dsb(); +	dsb(ishst);  }  static inline void pud_clear(pud_t *pudp) @@ -344,11 +370,16 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)  static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)  {  	const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY | -			      PTE_PROT_NONE | PTE_VALID; +			      PTE_PROT_NONE | PTE_VALID | PTE_WRITE;  	pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);  	return pte;  } +static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) +{ +	return pte_pmd(pte_modify(pmd_pte(pmd), newprot)); +} +  extern pgd_t swapper_pg_dir[PTRS_PER_PGD];  extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; @@ -357,18 +388,20 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD];  /*   * Encode and decode a swap entry: - *	bits 0, 2:	present (must both be zero) - *	bit  3:		PTE_FILE - *	bits 4-8:	swap type - *	bits 9-63:	swap offset + *	bits 0-1:	present (must be zero) + *	bit  2:		PTE_FILE + *	bits 3-8:	swap type + *	bits 9-57:	swap offset   */ -#define __SWP_TYPE_SHIFT	4 +#define __SWP_TYPE_SHIFT	3  #define __SWP_TYPE_BITS		6 +#define __SWP_OFFSET_BITS	49  #define __SWP_TYPE_MASK		((1 << __SWP_TYPE_BITS) - 1)  #define __SWP_OFFSET_SHIFT	(__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) +#define __SWP_OFFSET_MASK	((1UL << __SWP_OFFSET_BITS) - 1)  #define __swp_type(x)		(((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK) -#define __swp_offset(x)		((x).val >> __SWP_OFFSET_SHIFT) +#define __swp_offset(x)		(((x).val >> __SWP_OFFSET_SHIFT) & __SWP_OFFSET_MASK)  #define __swp_entry(type,offset) ((swp_entry_t) { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) })  #define __pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) }) @@ -376,21 +409,21 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD];  /*   * Ensure that there are not more swap files than can be encoded in the kernel - * the PTEs. + * PTEs.   */  #define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS)  /*   * Encode and decode a file entry: - *	bits 0, 2:	present (must both be zero) - *	bit  3:		PTE_FILE - *	bits 4-63:	file offset / PAGE_SIZE + *	bits 0-1:	present (must be zero) + *	bit  2:		PTE_FILE + *	bits 3-57:	file offset / PAGE_SIZE   */  #define pte_file(pte)		(pte_val(pte) & PTE_FILE) -#define pte_to_pgoff(x)		(pte_val(x) >> 4) -#define pgoff_to_pte(x)		__pte(((x) << 4) | PTE_FILE) +#define pte_to_pgoff(x)		(pte_val(x) >> 3) +#define pgoff_to_pte(x)		__pte(((x) << 3) | PTE_FILE) -#define PTE_FILE_MAX_BITS	60 +#define PTE_FILE_MAX_BITS	55  extern int kern_addr_valid(unsigned long addr);  | 
