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