162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * arch/arm/include/asm/pgalloc.h 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2000-2001 Russell King 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#ifndef _ASMARM_PGALLOC_H 862306a36Sopenharmony_ci#define _ASMARM_PGALLOC_H 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/pagemap.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <asm/domain.h> 1362306a36Sopenharmony_ci#include <asm/pgtable-hwdef.h> 1462306a36Sopenharmony_ci#include <asm/processor.h> 1562306a36Sopenharmony_ci#include <asm/cacheflush.h> 1662306a36Sopenharmony_ci#include <asm/tlbflush.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#ifdef CONFIG_MMU 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_USER)) 2162306a36Sopenharmony_ci#define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_KERNEL)) 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#ifdef CONFIG_ARM_LPAE 2462306a36Sopenharmony_ci#define PGD_SIZE (PTRS_PER_PGD * sizeof(pgd_t)) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE)); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#else /* !CONFIG_ARM_LPAE */ 3262306a36Sopenharmony_ci#define PGD_SIZE (PAGE_SIZE << 2) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * Since we have only two-level page tables, these are trivial 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci#define pmd_alloc_one(mm,addr) ({ BUG(); ((pmd_t *)2); }) 3862306a36Sopenharmony_ci#define pmd_free(mm, pmd) do { } while (0) 3962306a36Sopenharmony_ci#ifdef CONFIG_KASAN 4062306a36Sopenharmony_ci/* The KASan core unconditionally calls pud_populate() on all architectures */ 4162306a36Sopenharmony_ci#define pud_populate(mm,pmd,pte) do { } while (0) 4262306a36Sopenharmony_ci#else 4362306a36Sopenharmony_ci#define pud_populate(mm,pmd,pte) BUG() 4462306a36Sopenharmony_ci#endif 4562306a36Sopenharmony_ci#endif /* CONFIG_ARM_LPAE */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciextern pgd_t *pgd_alloc(struct mm_struct *mm); 4862306a36Sopenharmony_ciextern void pgd_free(struct mm_struct *mm, pgd_t *pgd); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic inline void clean_pte_table(pte_t *pte) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci clean_dcache_area(pte + PTE_HWTABLE_PTRS, PTE_HWTABLE_SIZE); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* 5662306a36Sopenharmony_ci * Allocate one PTE table. 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * This actually allocates two hardware PTE tables, but we wrap this up 5962306a36Sopenharmony_ci * into one table thus: 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * +------------+ 6262306a36Sopenharmony_ci * | Linux pt 0 | 6362306a36Sopenharmony_ci * +------------+ 6462306a36Sopenharmony_ci * | Linux pt 1 | 6562306a36Sopenharmony_ci * +------------+ 6662306a36Sopenharmony_ci * | h/w pt 0 | 6762306a36Sopenharmony_ci * +------------+ 6862306a36Sopenharmony_ci * | h/w pt 1 | 6962306a36Sopenharmony_ci * +------------+ 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL 7362306a36Sopenharmony_ci#define __HAVE_ARCH_PTE_ALLOC_ONE 7462306a36Sopenharmony_ci#define __HAVE_ARCH_PGD_FREE 7562306a36Sopenharmony_ci#include <asm-generic/pgalloc.h> 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic inline pte_t * 7862306a36Sopenharmony_cipte_alloc_one_kernel(struct mm_struct *mm) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci pte_t *pte = __pte_alloc_one_kernel(mm); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (pte) 8362306a36Sopenharmony_ci clean_pte_table(pte); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return pte; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#ifdef CONFIG_HIGHPTE 8962306a36Sopenharmony_ci#define PGTABLE_HIGHMEM __GFP_HIGHMEM 9062306a36Sopenharmony_ci#else 9162306a36Sopenharmony_ci#define PGTABLE_HIGHMEM 0 9262306a36Sopenharmony_ci#endif 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic inline pgtable_t 9562306a36Sopenharmony_cipte_alloc_one(struct mm_struct *mm) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct page *pte; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci pte = __pte_alloc_one(mm, GFP_PGTABLE_USER | PGTABLE_HIGHMEM); 10062306a36Sopenharmony_ci if (!pte) 10162306a36Sopenharmony_ci return NULL; 10262306a36Sopenharmony_ci if (!PageHighMem(pte)) 10362306a36Sopenharmony_ci clean_pte_table(page_address(pte)); 10462306a36Sopenharmony_ci return pte; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte, 10862306a36Sopenharmony_ci pmdval_t prot) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci pmdval_t pmdval = (pte + PTE_HWTABLE_OFF) | prot; 11162306a36Sopenharmony_ci pmdp[0] = __pmd(pmdval); 11262306a36Sopenharmony_ci#ifndef CONFIG_ARM_LPAE 11362306a36Sopenharmony_ci pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t)); 11462306a36Sopenharmony_ci#endif 11562306a36Sopenharmony_ci flush_pmd_entry(pmdp); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* 11962306a36Sopenharmony_ci * Populate the pmdp entry with a pointer to the pte. This pmd is part 12062306a36Sopenharmony_ci * of the mm address space. 12162306a36Sopenharmony_ci * 12262306a36Sopenharmony_ci * Ensure that we always set both PMD entries. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_cistatic inline void 12562306a36Sopenharmony_cipmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci /* 12862306a36Sopenharmony_ci * The pmd must be loaded with the physical address of the PTE table 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci __pmd_populate(pmdp, __pa(ptep), _PAGE_KERNEL_TABLE); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic inline void 13462306a36Sopenharmony_cipmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci extern pmdval_t user_pmd_table; 13762306a36Sopenharmony_ci pmdval_t prot; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (__LINUX_ARM_ARCH__ >= 6 && !IS_ENABLED(CONFIG_ARM_LPAE)) 14062306a36Sopenharmony_ci prot = user_pmd_table; 14162306a36Sopenharmony_ci else 14262306a36Sopenharmony_ci prot = _PAGE_USER_TABLE; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci __pmd_populate(pmdp, page_to_phys(ptep), prot); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci#endif /* CONFIG_MMU */ 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci#endif 150