1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-only */
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * arch/arm/include/asm/pgalloc.h
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2000-2001 Russell King
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun #ifndef _ASMARM_PGALLOC_H
8*4882a593Smuzhiyun #define _ASMARM_PGALLOC_H
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/pagemap.h>
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <asm/domain.h>
13*4882a593Smuzhiyun #include <asm/pgtable-hwdef.h>
14*4882a593Smuzhiyun #include <asm/processor.h>
15*4882a593Smuzhiyun #include <asm/cacheflush.h>
16*4882a593Smuzhiyun #include <asm/tlbflush.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #ifdef CONFIG_MMU
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_USER))
21*4882a593Smuzhiyun #define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_KERNEL))
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #ifdef CONFIG_ARM_LPAE
24*4882a593Smuzhiyun
pud_populate(struct mm_struct * mm,pud_t * pud,pmd_t * pmd)25*4882a593Smuzhiyun static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE));
28*4882a593Smuzhiyun }
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #else /* !CONFIG_ARM_LPAE */
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /*
33*4882a593Smuzhiyun * Since we have only two-level page tables, these are trivial
34*4882a593Smuzhiyun */
35*4882a593Smuzhiyun #define pmd_alloc_one(mm,addr) ({ BUG(); ((pmd_t *)2); })
36*4882a593Smuzhiyun #define pmd_free(mm, pmd) do { } while (0)
37*4882a593Smuzhiyun #define pud_populate(mm,pmd,pte) BUG()
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #endif /* CONFIG_ARM_LPAE */
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun extern pgd_t *pgd_alloc(struct mm_struct *mm);
42*4882a593Smuzhiyun extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
43*4882a593Smuzhiyun
clean_pte_table(pte_t * pte)44*4882a593Smuzhiyun static inline void clean_pte_table(pte_t *pte)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun clean_dcache_area(pte + PTE_HWTABLE_PTRS, PTE_HWTABLE_SIZE);
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun /*
50*4882a593Smuzhiyun * Allocate one PTE table.
51*4882a593Smuzhiyun *
52*4882a593Smuzhiyun * This actually allocates two hardware PTE tables, but we wrap this up
53*4882a593Smuzhiyun * into one table thus:
54*4882a593Smuzhiyun *
55*4882a593Smuzhiyun * +------------+
56*4882a593Smuzhiyun * | Linux pt 0 |
57*4882a593Smuzhiyun * +------------+
58*4882a593Smuzhiyun * | Linux pt 1 |
59*4882a593Smuzhiyun * +------------+
60*4882a593Smuzhiyun * | h/w pt 0 |
61*4882a593Smuzhiyun * +------------+
62*4882a593Smuzhiyun * | h/w pt 1 |
63*4882a593Smuzhiyun * +------------+
64*4882a593Smuzhiyun */
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun #define __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL
67*4882a593Smuzhiyun #define __HAVE_ARCH_PTE_ALLOC_ONE
68*4882a593Smuzhiyun #define __HAVE_ARCH_PGD_FREE
69*4882a593Smuzhiyun #include <asm-generic/pgalloc.h>
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun static inline pte_t *
pte_alloc_one_kernel(struct mm_struct * mm)72*4882a593Smuzhiyun pte_alloc_one_kernel(struct mm_struct *mm)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun pte_t *pte = __pte_alloc_one_kernel(mm);
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun if (pte)
77*4882a593Smuzhiyun clean_pte_table(pte);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun return pte;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun #ifdef CONFIG_HIGHPTE
83*4882a593Smuzhiyun #define PGTABLE_HIGHMEM __GFP_HIGHMEM
84*4882a593Smuzhiyun #else
85*4882a593Smuzhiyun #define PGTABLE_HIGHMEM 0
86*4882a593Smuzhiyun #endif
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun static inline pgtable_t
pte_alloc_one(struct mm_struct * mm)89*4882a593Smuzhiyun pte_alloc_one(struct mm_struct *mm)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun struct page *pte;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun pte = __pte_alloc_one(mm, GFP_PGTABLE_USER | PGTABLE_HIGHMEM);
94*4882a593Smuzhiyun if (!pte)
95*4882a593Smuzhiyun return NULL;
96*4882a593Smuzhiyun if (!PageHighMem(pte))
97*4882a593Smuzhiyun clean_pte_table(page_address(pte));
98*4882a593Smuzhiyun return pte;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
__pmd_populate(pmd_t * pmdp,phys_addr_t pte,pmdval_t prot)101*4882a593Smuzhiyun static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte,
102*4882a593Smuzhiyun pmdval_t prot)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun pmdval_t pmdval = (pte + PTE_HWTABLE_OFF) | prot;
105*4882a593Smuzhiyun pmdp[0] = __pmd(pmdval);
106*4882a593Smuzhiyun #ifndef CONFIG_ARM_LPAE
107*4882a593Smuzhiyun pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
108*4882a593Smuzhiyun #endif
109*4882a593Smuzhiyun flush_pmd_entry(pmdp);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /*
113*4882a593Smuzhiyun * Populate the pmdp entry with a pointer to the pte. This pmd is part
114*4882a593Smuzhiyun * of the mm address space.
115*4882a593Smuzhiyun *
116*4882a593Smuzhiyun * Ensure that we always set both PMD entries.
117*4882a593Smuzhiyun */
118*4882a593Smuzhiyun static inline void
pmd_populate_kernel(struct mm_struct * mm,pmd_t * pmdp,pte_t * ptep)119*4882a593Smuzhiyun pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun /*
122*4882a593Smuzhiyun * The pmd must be loaded with the physical address of the PTE table
123*4882a593Smuzhiyun */
124*4882a593Smuzhiyun __pmd_populate(pmdp, __pa(ptep), _PAGE_KERNEL_TABLE);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun static inline void
pmd_populate(struct mm_struct * mm,pmd_t * pmdp,pgtable_t ptep)128*4882a593Smuzhiyun pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun extern pmdval_t user_pmd_table;
131*4882a593Smuzhiyun pmdval_t prot;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun if (__LINUX_ARM_ARCH__ >= 6 && !IS_ENABLED(CONFIG_ARM_LPAE))
134*4882a593Smuzhiyun prot = user_pmd_table;
135*4882a593Smuzhiyun else
136*4882a593Smuzhiyun prot = _PAGE_USER_TABLE;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun __pmd_populate(pmdp, page_to_phys(ptep), prot);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun #define pmd_pgtable(pmd) pmd_page(pmd)
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun #endif /* CONFIG_MMU */
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun #endif
145