Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef __ASM_GENERIC_PGALLOC_H
0003 #define __ASM_GENERIC_PGALLOC_H
0004 
0005 #ifdef CONFIG_MMU
0006 
0007 #define GFP_PGTABLE_KERNEL  (GFP_KERNEL | __GFP_ZERO)
0008 #define GFP_PGTABLE_USER    (GFP_PGTABLE_KERNEL | __GFP_ACCOUNT)
0009 
0010 /**
0011  * __pte_alloc_one_kernel - allocate a page for PTE-level kernel page table
0012  * @mm: the mm_struct of the current context
0013  *
0014  * This function is intended for architectures that need
0015  * anything beyond simple page allocation.
0016  *
0017  * Return: pointer to the allocated memory or %NULL on error
0018  */
0019 static inline pte_t *__pte_alloc_one_kernel(struct mm_struct *mm)
0020 {
0021     return (pte_t *)__get_free_page(GFP_PGTABLE_KERNEL);
0022 }
0023 
0024 #ifndef __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL
0025 /**
0026  * pte_alloc_one_kernel - allocate a page for PTE-level kernel page table
0027  * @mm: the mm_struct of the current context
0028  *
0029  * Return: pointer to the allocated memory or %NULL on error
0030  */
0031 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
0032 {
0033     return __pte_alloc_one_kernel(mm);
0034 }
0035 #endif
0036 
0037 /**
0038  * pte_free_kernel - free PTE-level kernel page table page
0039  * @mm: the mm_struct of the current context
0040  * @pte: pointer to the memory containing the page table
0041  */
0042 static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
0043 {
0044     free_page((unsigned long)pte);
0045 }
0046 
0047 /**
0048  * __pte_alloc_one - allocate a page for PTE-level user page table
0049  * @mm: the mm_struct of the current context
0050  * @gfp: GFP flags to use for the allocation
0051  *
0052  * Allocates a page and runs the pgtable_pte_page_ctor().
0053  *
0054  * This function is intended for architectures that need
0055  * anything beyond simple page allocation or must have custom GFP flags.
0056  *
0057  * Return: `struct page` initialized as page table or %NULL on error
0058  */
0059 static inline pgtable_t __pte_alloc_one(struct mm_struct *mm, gfp_t gfp)
0060 {
0061     struct page *pte;
0062 
0063     pte = alloc_page(gfp);
0064     if (!pte)
0065         return NULL;
0066     if (!pgtable_pte_page_ctor(pte)) {
0067         __free_page(pte);
0068         return NULL;
0069     }
0070 
0071     return pte;
0072 }
0073 
0074 #ifndef __HAVE_ARCH_PTE_ALLOC_ONE
0075 /**
0076  * pte_alloc_one - allocate a page for PTE-level user page table
0077  * @mm: the mm_struct of the current context
0078  *
0079  * Allocates a page and runs the pgtable_pte_page_ctor().
0080  *
0081  * Return: `struct page` initialized as page table or %NULL on error
0082  */
0083 static inline pgtable_t pte_alloc_one(struct mm_struct *mm)
0084 {
0085     return __pte_alloc_one(mm, GFP_PGTABLE_USER);
0086 }
0087 #endif
0088 
0089 /*
0090  * Should really implement gc for free page table pages. This could be
0091  * done with a reference count in struct page.
0092  */
0093 
0094 /**
0095  * pte_free - free PTE-level user page table page
0096  * @mm: the mm_struct of the current context
0097  * @pte_page: the `struct page` representing the page table
0098  */
0099 static inline void pte_free(struct mm_struct *mm, struct page *pte_page)
0100 {
0101     pgtable_pte_page_dtor(pte_page);
0102     __free_page(pte_page);
0103 }
0104 
0105 
0106 #if CONFIG_PGTABLE_LEVELS > 2
0107 
0108 #ifndef __HAVE_ARCH_PMD_ALLOC_ONE
0109 /**
0110  * pmd_alloc_one - allocate a page for PMD-level page table
0111  * @mm: the mm_struct of the current context
0112  *
0113  * Allocates a page and runs the pgtable_pmd_page_ctor().
0114  * Allocations use %GFP_PGTABLE_USER in user context and
0115  * %GFP_PGTABLE_KERNEL in kernel context.
0116  *
0117  * Return: pointer to the allocated memory or %NULL on error
0118  */
0119 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
0120 {
0121     struct page *page;
0122     gfp_t gfp = GFP_PGTABLE_USER;
0123 
0124     if (mm == &init_mm)
0125         gfp = GFP_PGTABLE_KERNEL;
0126     page = alloc_pages(gfp, 0);
0127     if (!page)
0128         return NULL;
0129     if (!pgtable_pmd_page_ctor(page)) {
0130         __free_pages(page, 0);
0131         return NULL;
0132     }
0133     return (pmd_t *)page_address(page);
0134 }
0135 #endif
0136 
0137 #ifndef __HAVE_ARCH_PMD_FREE
0138 static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
0139 {
0140     BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
0141     pgtable_pmd_page_dtor(virt_to_page(pmd));
0142     free_page((unsigned long)pmd);
0143 }
0144 #endif
0145 
0146 #endif /* CONFIG_PGTABLE_LEVELS > 2 */
0147 
0148 #if CONFIG_PGTABLE_LEVELS > 3
0149 
0150 static inline pud_t *__pud_alloc_one(struct mm_struct *mm, unsigned long addr)
0151 {
0152     gfp_t gfp = GFP_PGTABLE_USER;
0153 
0154     if (mm == &init_mm)
0155         gfp = GFP_PGTABLE_KERNEL;
0156     return (pud_t *)get_zeroed_page(gfp);
0157 }
0158 
0159 #ifndef __HAVE_ARCH_PUD_ALLOC_ONE
0160 /**
0161  * pud_alloc_one - allocate a page for PUD-level page table
0162  * @mm: the mm_struct of the current context
0163  *
0164  * Allocates a page using %GFP_PGTABLE_USER for user context and
0165  * %GFP_PGTABLE_KERNEL for kernel context.
0166  *
0167  * Return: pointer to the allocated memory or %NULL on error
0168  */
0169 static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
0170 {
0171     return __pud_alloc_one(mm, addr);
0172 }
0173 #endif
0174 
0175 static inline void __pud_free(struct mm_struct *mm, pud_t *pud)
0176 {
0177     BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
0178     free_page((unsigned long)pud);
0179 }
0180 
0181 #ifndef __HAVE_ARCH_PUD_FREE
0182 static inline void pud_free(struct mm_struct *mm, pud_t *pud)
0183 {
0184     __pud_free(mm, pud);
0185 }
0186 #endif
0187 
0188 #endif /* CONFIG_PGTABLE_LEVELS > 3 */
0189 
0190 #ifndef __HAVE_ARCH_PGD_FREE
0191 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
0192 {
0193     free_page((unsigned long)pgd);
0194 }
0195 #endif
0196 
0197 #endif /* CONFIG_MMU */
0198 
0199 #endif /* __ASM_GENERIC_PGALLOC_H */