1d2912cb1SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
24baa9922SRussell King /*
34baa9922SRussell King * arch/arm/include/asm/pgalloc.h
44baa9922SRussell King *
54baa9922SRussell King * Copyright (C) 2000-2001 Russell King
64baa9922SRussell King */
74baa9922SRussell King #ifndef _ASMARM_PGALLOC_H
84baa9922SRussell King #define _ASMARM_PGALLOC_H
94baa9922SRussell King
1097594b0fSUwe Kleine-König #include <linux/pagemap.h>
1197594b0fSUwe Kleine-König
124baa9922SRussell King #include <asm/domain.h>
134baa9922SRussell King #include <asm/pgtable-hwdef.h>
144baa9922SRussell King #include <asm/processor.h>
154baa9922SRussell King #include <asm/cacheflush.h>
164baa9922SRussell King #include <asm/tlbflush.h>
174baa9922SRussell King
184baa9922SRussell King #ifdef CONFIG_MMU
194baa9922SRussell King
204baa9922SRussell King #define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_USER))
214baa9922SRussell King #define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_KERNEL))
224baa9922SRussell King
23da028779SCatalin Marinas #ifdef CONFIG_ARM_LPAE
24*5615f69bSLinus Walleij #define PGD_SIZE (PTRS_PER_PGD * sizeof(pgd_t))
25da028779SCatalin Marinas
pud_populate(struct mm_struct * mm,pud_t * pud,pmd_t * pmd)26da028779SCatalin Marinas static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
27da028779SCatalin Marinas {
28da028779SCatalin Marinas set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE));
29da028779SCatalin Marinas }
30da028779SCatalin Marinas
31da028779SCatalin Marinas #else /* !CONFIG_ARM_LPAE */
32*5615f69bSLinus Walleij #define PGD_SIZE (PAGE_SIZE << 2)
33da028779SCatalin Marinas
344baa9922SRussell King /*
354baa9922SRussell King * Since we have only two-level page tables, these are trivial
364baa9922SRussell King */
374baa9922SRussell King #define pmd_alloc_one(mm,addr) ({ BUG(); ((pmd_t *)2); })
384baa9922SRussell King #define pmd_free(mm, pmd) do { } while (0)
39*5615f69bSLinus Walleij #ifdef CONFIG_KASAN
40*5615f69bSLinus Walleij /* The KASan core unconditionally calls pud_populate() on all architectures */
41*5615f69bSLinus Walleij #define pud_populate(mm,pmd,pte) do { } while (0)
42*5615f69bSLinus Walleij #else
43a32618d2SRussell King #define pud_populate(mm,pmd,pte) BUG()
44*5615f69bSLinus Walleij #endif
45da028779SCatalin Marinas #endif /* CONFIG_ARM_LPAE */
46da028779SCatalin Marinas
47b0d03745SRussell King extern pgd_t *pgd_alloc(struct mm_struct *mm);
48b0d03745SRussell King extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
494baa9922SRussell King
clean_pte_table(pte_t * pte)50d30e45eeSRussell King static inline void clean_pte_table(pte_t *pte)
51d30e45eeSRussell King {
52d30e45eeSRussell King clean_dcache_area(pte + PTE_HWTABLE_PTRS, PTE_HWTABLE_SIZE);
53d30e45eeSRussell King }
54d30e45eeSRussell King
554baa9922SRussell King /*
564baa9922SRussell King * Allocate one PTE table.
574baa9922SRussell King *
584baa9922SRussell King * This actually allocates two hardware PTE tables, but we wrap this up
594baa9922SRussell King * into one table thus:
604baa9922SRussell King *
614baa9922SRussell King * +------------+
624baa9922SRussell King * | Linux pt 0 |
634baa9922SRussell King * +------------+
644baa9922SRussell King * | Linux pt 1 |
654baa9922SRussell King * +------------+
66d30e45eeSRussell King * | h/w pt 0 |
67d30e45eeSRussell King * +------------+
68d30e45eeSRussell King * | h/w pt 1 |
69d30e45eeSRussell King * +------------+
704baa9922SRussell King */
7128bcf593SMike Rapoport
7228bcf593SMike Rapoport #define __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL
7328bcf593SMike Rapoport #define __HAVE_ARCH_PTE_ALLOC_ONE
74f9cb654cSMike Rapoport #define __HAVE_ARCH_PGD_FREE
7528bcf593SMike Rapoport #include <asm-generic/pgalloc.h>
7628bcf593SMike Rapoport
774baa9922SRussell King static inline pte_t *
pte_alloc_one_kernel(struct mm_struct * mm)784cf58924SJoel Fernandes (Google) pte_alloc_one_kernel(struct mm_struct *mm)
794baa9922SRussell King {
8028bcf593SMike Rapoport pte_t *pte = __pte_alloc_one_kernel(mm);
814baa9922SRussell King
82d30e45eeSRussell King if (pte)
83d30e45eeSRussell King clean_pte_table(pte);
844baa9922SRussell King
854baa9922SRussell King return pte;
864baa9922SRussell King }
874baa9922SRussell King
8828bcf593SMike Rapoport #ifdef CONFIG_HIGHPTE
8928bcf593SMike Rapoport #define PGTABLE_HIGHMEM __GFP_HIGHMEM
9028bcf593SMike Rapoport #else
9128bcf593SMike Rapoport #define PGTABLE_HIGHMEM 0
9228bcf593SMike Rapoport #endif
9328bcf593SMike Rapoport
944baa9922SRussell King static inline pgtable_t
pte_alloc_one(struct mm_struct * mm)954cf58924SJoel Fernandes (Google) pte_alloc_one(struct mm_struct *mm)
964baa9922SRussell King {
974baa9922SRussell King struct page *pte;
984baa9922SRussell King
9928bcf593SMike Rapoport pte = __pte_alloc_one(mm, GFP_PGTABLE_USER | PGTABLE_HIGHMEM);
100affce508SKirill A. Shutemov if (!pte)
101affce508SKirill A. Shutemov return NULL;
102d30e45eeSRussell King if (!PageHighMem(pte))
103d30e45eeSRussell King clean_pte_table(page_address(pte));
1044baa9922SRussell King return pte;
1054baa9922SRussell King }
1064baa9922SRussell King
__pmd_populate(pmd_t * pmdp,phys_addr_t pte,pmdval_t prot)10797092e0cSRussell King static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte,
108442e70c0SCatalin Marinas pmdval_t prot)
1094baa9922SRussell King {
110442e70c0SCatalin Marinas pmdval_t pmdval = (pte + PTE_HWTABLE_OFF) | prot;
1114baa9922SRussell King pmdp[0] = __pmd(pmdval);
112da028779SCatalin Marinas #ifndef CONFIG_ARM_LPAE
1134baa9922SRussell King pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
114da028779SCatalin Marinas #endif
1154baa9922SRussell King flush_pmd_entry(pmdp);
1164baa9922SRussell King }
1174baa9922SRussell King
1184baa9922SRussell King /*
1194baa9922SRussell King * Populate the pmdp entry with a pointer to the pte. This pmd is part
1204baa9922SRussell King * of the mm address space.
1214baa9922SRussell King *
1224baa9922SRussell King * Ensure that we always set both PMD entries.
1234baa9922SRussell King */
1244baa9922SRussell King static inline void
pmd_populate_kernel(struct mm_struct * mm,pmd_t * pmdp,pte_t * ptep)1254baa9922SRussell King pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
1264baa9922SRussell King {
1274baa9922SRussell King /*
128d30e45eeSRussell King * The pmd must be loaded with the physical address of the PTE table
1294baa9922SRussell King */
130d30e45eeSRussell King __pmd_populate(pmdp, __pa(ptep), _PAGE_KERNEL_TABLE);
1314baa9922SRussell King }
1324baa9922SRussell King
1334baa9922SRussell King static inline void
pmd_populate(struct mm_struct * mm,pmd_t * pmdp,pgtable_t ptep)1344baa9922SRussell King pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep)
1354baa9922SRussell King {
1361d4d3715SJungseung Lee extern pmdval_t user_pmd_table;
1371d4d3715SJungseung Lee pmdval_t prot;
1381d4d3715SJungseung Lee
1391d4d3715SJungseung Lee if (__LINUX_ARM_ARCH__ >= 6 && !IS_ENABLED(CONFIG_ARM_LPAE))
1401d4d3715SJungseung Lee prot = user_pmd_table;
1411d4d3715SJungseung Lee else
1421d4d3715SJungseung Lee prot = _PAGE_USER_TABLE;
1431d4d3715SJungseung Lee
1441d4d3715SJungseung Lee __pmd_populate(pmdp, page_to_phys(ptep), prot);
1454baa9922SRussell King }
1464baa9922SRussell King
1474baa9922SRussell King #endif /* CONFIG_MMU */
1484baa9922SRussell King
1494baa9922SRussell King #endif
150