1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <linux/kernel.h>
25#include <linux/gfp.h>
26#include <linux/mm.h>
27#include <linux/init.h>
28#include <linux/percpu.h>
29#include <linux/hardirq.h>
30#include <asm/pgalloc.h>
31#include <asm/tlbflush.h>
32#include <asm/tlb.h>
33
34#include "mmu_decl.h"
35
36DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
37
38#ifdef CONFIG_SMP
39
40
41
42
43
44
45
46static DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
47static unsigned long pte_freelist_forced_free;
48
49struct pte_freelist_batch
50{
51 struct rcu_head rcu;
52 unsigned int index;
53 unsigned long tables[0];
54};
55
56#define PTE_FREELIST_SIZE \
57 ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \
58 / sizeof(unsigned long))
59
60static void pte_free_smp_sync(void *arg)
61{
62
63}
64
65
66
67
68static void pgtable_free_now(void *table, unsigned shift)
69{
70 pte_freelist_forced_free++;
71
72 smp_call_function(pte_free_smp_sync, NULL, 1);
73
74 pgtable_free(table, shift);
75}
76
77static void pte_free_rcu_callback(struct rcu_head *head)
78{
79 struct pte_freelist_batch *batch =
80 container_of(head, struct pte_freelist_batch, rcu);
81 unsigned int i;
82
83 for (i = 0; i < batch->index; i++) {
84 void *table = (void *)(batch->tables[i] & ~MAX_PGTABLE_INDEX_SIZE);
85 unsigned shift = batch->tables[i] & MAX_PGTABLE_INDEX_SIZE;
86
87 pgtable_free(table, shift);
88 }
89
90 free_page((unsigned long)batch);
91}
92
93static void pte_free_submit(struct pte_freelist_batch *batch)
94{
95 call_rcu_sched(&batch->rcu, pte_free_rcu_callback);
96}
97
98void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift)
99{
100
101 struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
102 unsigned long pgf;
103
104 if (atomic_read(&tlb->mm->mm_users) < 2 ||
105 cpumask_equal(mm_cpumask(tlb->mm), cpumask_of(smp_processor_id()))){
106 pgtable_free(table, shift);
107 return;
108 }
109
110 if (*batchp == NULL) {
111 *batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC);
112 if (*batchp == NULL) {
113 pgtable_free_now(table, shift);
114 return;
115 }
116 (*batchp)->index = 0;
117 }
118 BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
119 pgf = (unsigned long)table | shift;
120 (*batchp)->tables[(*batchp)->index++] = pgf;
121 if ((*batchp)->index == PTE_FREELIST_SIZE) {
122 pte_free_submit(*batchp);
123 *batchp = NULL;
124 }
125}
126
127void pte_free_finish(void)
128{
129
130 struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
131
132 if (*batchp == NULL)
133 return;
134 pte_free_submit(*batchp);
135 *batchp = NULL;
136}
137
138#endif
139
140static inline int is_exec_fault(void)
141{
142 return current->thread.regs && TRAP(current->thread.regs) == 0x400;
143}
144
145
146
147
148
149
150static inline int pte_looks_normal(pte_t pte)
151{
152 return (pte_val(pte) &
153 (_PAGE_PRESENT | _PAGE_SPECIAL | _PAGE_NO_CACHE | _PAGE_USER)) ==
154 (_PAGE_PRESENT | _PAGE_USER);
155}
156
157struct page * maybe_pte_to_page(pte_t pte)
158{
159 unsigned long pfn = pte_pfn(pte);
160 struct page *page;
161
162 if (unlikely(!pfn_valid(pfn)))
163 return NULL;
164 page = pfn_to_page(pfn);
165 if (PageReserved(page))
166 return NULL;
167 return page;
168}
169
170#if defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0
171
172
173
174
175
176
177
178static pte_t set_pte_filter(pte_t pte, unsigned long addr)
179{
180 pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
181 if (pte_looks_normal(pte) && !(cpu_has_feature(CPU_FTR_COHERENT_ICACHE) ||
182 cpu_has_feature(CPU_FTR_NOEXECUTE))) {
183 struct page *pg = maybe_pte_to_page(pte);
184 if (!pg)
185 return pte;
186 if (!test_bit(PG_arch_1, &pg->flags)) {
187#ifdef CONFIG_8xx
188
189
190
191
192
193
194
195
196 _tlbil_va(addr, 0, 0, 0);
197#endif
198 flush_dcache_icache_page(pg);
199 set_bit(PG_arch_1, &pg->flags);
200 }
201 }
202 return pte;
203}
204
205static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma,
206 int dirty)
207{
208 return pte;
209}
210
211#else
212
213
214
215
216
217static pte_t set_pte_filter(pte_t pte, unsigned long addr)
218{
219 struct page *pg;
220
221
222 if (!(pte_val(pte) & _PAGE_EXEC) || !pte_looks_normal(pte))
223 return pte;
224
225
226 pg = maybe_pte_to_page(pte);
227 if (unlikely(!pg))
228 return pte;
229
230
231 if (test_bit(PG_arch_1, &pg->flags))
232 return pte;
233
234
235 if (is_exec_fault()) {
236 flush_dcache_icache_page(pg);
237 set_bit(PG_arch_1, &pg->flags);
238 return pte;
239 }
240
241
242 return __pte(pte_val(pte) & ~_PAGE_EXEC);
243}
244
245static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma,
246 int dirty)
247{
248 struct page *pg;
249
250
251
252
253
254
255 if (dirty || (pte_val(pte) & _PAGE_EXEC) || !is_exec_fault())
256 return pte;
257
258#ifdef CONFIG_DEBUG_VM
259
260
261
262
263 if (WARN_ON(!(vma->vm_flags & VM_EXEC)))
264 return pte;
265#endif
266
267
268 pg = maybe_pte_to_page(pte);
269 if (unlikely(!pg))
270 goto bail;
271
272
273 if (test_bit(PG_arch_1, &pg->flags))
274 goto bail;
275
276
277 flush_dcache_icache_page(pg);
278 set_bit(PG_arch_1, &pg->flags);
279
280 bail:
281 return __pte(pte_val(pte) | _PAGE_EXEC);
282}
283
284#endif
285
286
287
288
289void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
290 pte_t pte)
291{
292#ifdef CONFIG_DEBUG_VM
293 WARN_ON(pte_present(*ptep));
294#endif
295
296
297
298
299 pte = set_pte_filter(pte, addr);
300
301
302 __set_pte_at(mm, addr, ptep, pte, 0);
303}
304
305
306
307
308
309
310
311
312int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
313 pte_t *ptep, pte_t entry, int dirty)
314{
315 int changed;
316 entry = set_access_flags_filter(entry, vma, dirty);
317 changed = !pte_same(*(ptep), entry);
318 if (changed) {
319 if (!(vma->vm_flags & VM_HUGETLB))
320 assert_pte_locked(vma->vm_mm, address);
321 __ptep_set_access_flags(ptep, entry);
322 flush_tlb_page_nohash(vma, address);
323 }
324 return changed;
325}
326
327#ifdef CONFIG_DEBUG_VM
328void assert_pte_locked(struct mm_struct *mm, unsigned long addr)
329{
330 pgd_t *pgd;
331 pud_t *pud;
332 pmd_t *pmd;
333
334 if (mm == &init_mm)
335 return;
336 pgd = mm->pgd + pgd_index(addr);
337 BUG_ON(pgd_none(*pgd));
338 pud = pud_offset(pgd, addr);
339 BUG_ON(pud_none(*pud));
340 pmd = pmd_offset(pud, addr);
341 BUG_ON(!pmd_present(*pmd));
342 assert_spin_locked(pte_lockptr(mm, pmd));
343}
344#endif
345
346