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