Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-only */
0002 /*
0003  *  arch/arm/include/asm/pgalloc.h
0004  *
0005  *  Copyright (C) 2000-2001 Russell King
0006  */
0007 #ifndef _ASMARM_PGALLOC_H
0008 #define _ASMARM_PGALLOC_H
0009 
0010 #include <linux/pagemap.h>
0011 
0012 #include <asm/domain.h>
0013 #include <asm/pgtable-hwdef.h>
0014 #include <asm/processor.h>
0015 #include <asm/cacheflush.h>
0016 #include <asm/tlbflush.h>
0017 
0018 #ifdef CONFIG_MMU
0019 
0020 #define _PAGE_USER_TABLE    (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_USER))
0021 #define _PAGE_KERNEL_TABLE  (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_KERNEL))
0022 
0023 #ifdef CONFIG_ARM_LPAE
0024 #define PGD_SIZE        (PTRS_PER_PGD * sizeof(pgd_t))
0025 
0026 static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
0027 {
0028     set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE));
0029 }
0030 
0031 #else   /* !CONFIG_ARM_LPAE */
0032 #define PGD_SIZE        (PAGE_SIZE << 2)
0033 
0034 /*
0035  * Since we have only two-level page tables, these are trivial
0036  */
0037 #define pmd_alloc_one(mm,addr)      ({ BUG(); ((pmd_t *)2); })
0038 #define pmd_free(mm, pmd)       do { } while (0)
0039 #ifdef CONFIG_KASAN
0040 /* The KASan core unconditionally calls pud_populate() on all architectures */
0041 #define pud_populate(mm,pmd,pte)    do { } while (0)
0042 #else
0043 #define pud_populate(mm,pmd,pte)    BUG()
0044 #endif
0045 #endif  /* CONFIG_ARM_LPAE */
0046 
0047 extern pgd_t *pgd_alloc(struct mm_struct *mm);
0048 extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
0049 
0050 static inline void clean_pte_table(pte_t *pte)
0051 {
0052     clean_dcache_area(pte + PTE_HWTABLE_PTRS, PTE_HWTABLE_SIZE);
0053 }
0054 
0055 /*
0056  * Allocate one PTE table.
0057  *
0058  * This actually allocates two hardware PTE tables, but we wrap this up
0059  * into one table thus:
0060  *
0061  *  +------------+
0062  *  | Linux pt 0 |
0063  *  +------------+
0064  *  | Linux pt 1 |
0065  *  +------------+
0066  *  |  h/w pt 0  |
0067  *  +------------+
0068  *  |  h/w pt 1  |
0069  *  +------------+
0070  */
0071 
0072 #define __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL
0073 #define __HAVE_ARCH_PTE_ALLOC_ONE
0074 #define __HAVE_ARCH_PGD_FREE
0075 #include <asm-generic/pgalloc.h>
0076 
0077 static inline pte_t *
0078 pte_alloc_one_kernel(struct mm_struct *mm)
0079 {
0080     pte_t *pte = __pte_alloc_one_kernel(mm);
0081 
0082     if (pte)
0083         clean_pte_table(pte);
0084 
0085     return pte;
0086 }
0087 
0088 #ifdef CONFIG_HIGHPTE
0089 #define PGTABLE_HIGHMEM __GFP_HIGHMEM
0090 #else
0091 #define PGTABLE_HIGHMEM 0
0092 #endif
0093 
0094 static inline pgtable_t
0095 pte_alloc_one(struct mm_struct *mm)
0096 {
0097     struct page *pte;
0098 
0099     pte = __pte_alloc_one(mm, GFP_PGTABLE_USER | PGTABLE_HIGHMEM);
0100     if (!pte)
0101         return NULL;
0102     if (!PageHighMem(pte))
0103         clean_pte_table(page_address(pte));
0104     return pte;
0105 }
0106 
0107 static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte,
0108                   pmdval_t prot)
0109 {
0110     pmdval_t pmdval = (pte + PTE_HWTABLE_OFF) | prot;
0111     pmdp[0] = __pmd(pmdval);
0112 #ifndef CONFIG_ARM_LPAE
0113     pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
0114 #endif
0115     flush_pmd_entry(pmdp);
0116 }
0117 
0118 /*
0119  * Populate the pmdp entry with a pointer to the pte.  This pmd is part
0120  * of the mm address space.
0121  *
0122  * Ensure that we always set both PMD entries.
0123  */
0124 static inline void
0125 pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
0126 {
0127     /*
0128      * The pmd must be loaded with the physical address of the PTE table
0129      */
0130     __pmd_populate(pmdp, __pa(ptep), _PAGE_KERNEL_TABLE);
0131 }
0132 
0133 static inline void
0134 pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep)
0135 {
0136     extern pmdval_t user_pmd_table;
0137     pmdval_t prot;
0138 
0139     if (__LINUX_ARM_ARCH__ >= 6 && !IS_ENABLED(CONFIG_ARM_LPAE))
0140         prot = user_pmd_table;
0141     else
0142         prot = _PAGE_USER_TABLE;
0143 
0144     __pmd_populate(pmdp, page_to_phys(ptep), prot);
0145 }
0146 
0147 #endif /* CONFIG_MMU */
0148 
0149 #endif