]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/include/pmap_var.h
arm unwind: Reject unaligned stack pointers
[FreeBSD/FreeBSD.git] / sys / arm / include / pmap_var.h
1 /*-
2  * Copyright 2014 Svatopluk Kraus <onwahe@gmail.com>
3  * Copyright 2014 Michal Meloun <meloun@miracle.cz>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #ifndef _MACHINE_PMAP_VAR_H_
29 #define _MACHINE_PMAP_VAR_H_
30
31 #include <machine/pte.h>
32
33 /*
34  *  Various PMAP defines, exports, and inline functions
35  *  definitions also usable in other MD code.
36  */
37
38 /*  A number of pages in L1 page table. */
39 #define NPG_IN_PT1      (NB_IN_PT1 / PAGE_SIZE)
40
41 /*  A number of L2 page tables in a page. */
42 #define NPT2_IN_PG      (PAGE_SIZE / NB_IN_PT2)
43
44 /*  A number of L2 page table entries in a page. */
45 #define NPTE2_IN_PG     (NPT2_IN_PG * NPTE2_IN_PT2)
46
47 #ifdef _KERNEL
48
49 /*
50  *  A L2 page tables page contains NPT2_IN_PG L2 page tables. Masking of
51  *  pte1_idx by PT2PG_MASK gives us an index to associated L2 page table
52  *  in a page. The PT2PG_SHIFT definition depends on NPT2_IN_PG strictly.
53  *  I.e., (1 << PT2PG_SHIFT) == NPT2_IN_PG must be fulfilled.
54  */
55 #define PT2PG_SHIFT     2
56 #define PT2PG_MASK      ((1 << PT2PG_SHIFT) - 1)
57
58 /*
59  *  A PT2TAB holds all allocated L2 page table pages in a pmap.
60  *  Right shifting of virtual address by PT2TAB_SHIFT gives us an index
61  *  to L2 page table page in PT2TAB which holds the address mapping.
62  */
63 #define PT2TAB_ENTRIES  (NPTE1_IN_PT1 / NPT2_IN_PG)
64 #define PT2TAB_SHIFT    (PTE1_SHIFT + PT2PG_SHIFT)
65
66 /*
67  *  All allocated L2 page table pages in a pmap are mapped into PT2MAP space.
68  *  An virtual address right shifting by PT2MAP_SHIFT gives us an index to PTE2
69  *  which maps the address.
70  */
71 #define PT2MAP_SIZE     (NPTE1_IN_PT1 * NB_IN_PT2)
72 #define PT2MAP_SHIFT    PTE2_SHIFT
73
74 extern pt1_entry_t *kern_pt1;
75 extern pt2_entry_t *kern_pt2tab;
76 extern pt2_entry_t *PT2MAP;
77
78 /*
79  *  Virtual interface for L1 page table management.
80  */
81
82 static __inline u_int
83 pte1_index(vm_offset_t va)
84 {
85
86         return (va >> PTE1_SHIFT);
87 }
88
89 static __inline pt1_entry_t *
90 pte1_ptr(pt1_entry_t *pt1, vm_offset_t va)
91 {
92
93         return (pt1 + pte1_index(va));
94 }
95
96 static __inline vm_offset_t
97 pte1_trunc(vm_offset_t va)
98 {
99
100         return (va & PTE1_FRAME);
101 }
102
103 static __inline vm_offset_t
104 pte1_roundup(vm_offset_t va)
105 {
106
107         return ((va + PTE1_OFFSET) & PTE1_FRAME);
108 }
109
110 /*
111  *  Virtual interface for L1 page table entries management.
112  *
113  *  XXX: Some of the following functions now with a synchronization barrier
114  *  are called in a loop, so it could be useful to have two versions of them.
115  *  One with the barrier and one without the barrier. In this case, pure
116  *  barrier pte1_sync() should be implemented as well.
117  */
118 static __inline void
119 pte1_sync(pt1_entry_t *pte1p)
120 {
121
122         dsb();
123 #ifndef PMAP_PTE_NOCACHE
124         if (!cpuinfo.coherent_walk)
125                 dcache_wb_pou((vm_offset_t)pte1p, sizeof(*pte1p));
126 #endif
127 }
128
129 static __inline void
130 pte1_sync_range(pt1_entry_t *pte1p, vm_size_t size)
131 {
132
133         dsb();
134 #ifndef PMAP_PTE_NOCACHE
135         if (!cpuinfo.coherent_walk)
136                 dcache_wb_pou((vm_offset_t)pte1p, size);
137 #endif
138 }
139
140 static __inline void
141 pte1_store(pt1_entry_t *pte1p, pt1_entry_t pte1)
142 {
143
144         dmb();
145         *pte1p = pte1;
146         pte1_sync(pte1p);
147 }
148
149 static __inline void
150 pte1_clear(pt1_entry_t *pte1p)
151 {
152
153         pte1_store(pte1p, 0);
154 }
155
156 static __inline void
157 pte1_clear_bit(pt1_entry_t *pte1p, uint32_t bit)
158 {
159
160         *pte1p &= ~bit;
161         pte1_sync(pte1p);
162 }
163
164 static __inline boolean_t
165 pte1_is_link(pt1_entry_t pte1)
166 {
167
168         return ((pte1 & L1_TYPE_MASK) == L1_TYPE_C);
169 }
170
171 static __inline int
172 pte1_is_section(pt1_entry_t pte1)
173 {
174
175         return ((pte1 & L1_TYPE_MASK) == L1_TYPE_S);
176 }
177
178 static __inline boolean_t
179 pte1_is_dirty(pt1_entry_t pte1)
180 {
181
182         return ((pte1 & (PTE1_NM | PTE1_RO)) == 0);
183 }
184
185 static __inline boolean_t
186 pte1_is_global(pt1_entry_t pte1)
187 {
188
189         return ((pte1 & PTE1_NG) == 0);
190 }
191
192 static __inline boolean_t
193 pte1_is_valid(pt1_entry_t pte1)
194 {
195         int l1_type;
196
197         l1_type = pte1 & L1_TYPE_MASK;
198         return ((l1_type == L1_TYPE_C) || (l1_type == L1_TYPE_S));
199 }
200
201 static __inline boolean_t
202 pte1_is_wired(pt1_entry_t pte1)
203 {
204
205         return (pte1 & PTE1_W);
206 }
207
208 static __inline pt1_entry_t
209 pte1_load(pt1_entry_t *pte1p)
210 {
211         pt1_entry_t pte1;
212
213         pte1 = *pte1p;
214         return (pte1);
215 }
216
217 static __inline pt1_entry_t
218 pte1_load_clear(pt1_entry_t *pte1p)
219 {
220         pt1_entry_t opte1;
221
222         opte1 = *pte1p;
223         *pte1p = 0;
224         pte1_sync(pte1p);
225         return (opte1);
226 }
227
228 static __inline void
229 pte1_set_bit(pt1_entry_t *pte1p, uint32_t bit)
230 {
231
232         *pte1p |= bit;
233         pte1_sync(pte1p);
234 }
235
236 static __inline vm_paddr_t
237 pte1_pa(pt1_entry_t pte1)
238 {
239
240         return ((vm_paddr_t)(pte1 & PTE1_FRAME));
241 }
242
243 static __inline vm_paddr_t
244 pte1_link_pa(pt1_entry_t pte1)
245 {
246
247         return ((vm_paddr_t)(pte1 & L1_C_ADDR_MASK));
248 }
249
250 /*
251  *  Virtual interface for L2 page table entries management.
252  *
253  *  XXX: Some of the following functions now with a synchronization barrier
254  *  are called in a loop, so it could be useful to have two versions of them.
255  *  One with the barrier and one without the barrier.
256  */
257
258 static __inline void
259 pte2_sync(pt2_entry_t *pte2p)
260 {
261
262         dsb();
263 #ifndef PMAP_PTE_NOCACHE
264         if (!cpuinfo.coherent_walk)
265                 dcache_wb_pou((vm_offset_t)pte2p, sizeof(*pte2p));
266 #endif
267 }
268
269 static __inline void
270 pte2_sync_range(pt2_entry_t *pte2p, vm_size_t size)
271 {
272
273         dsb();
274 #ifndef PMAP_PTE_NOCACHE
275         if (!cpuinfo.coherent_walk)
276                 dcache_wb_pou((vm_offset_t)pte2p, size);
277 #endif
278 }
279
280 static __inline void
281 pte2_store(pt2_entry_t *pte2p, pt2_entry_t pte2)
282 {
283
284         dmb();
285         *pte2p = pte2;
286         pte2_sync(pte2p);
287 }
288
289 static __inline void
290 pte2_clear(pt2_entry_t *pte2p)
291 {
292
293         pte2_store(pte2p, 0);
294 }
295
296 static __inline void
297 pte2_clear_bit(pt2_entry_t *pte2p, uint32_t bit)
298 {
299
300         *pte2p &= ~bit;
301         pte2_sync(pte2p);
302 }
303
304 static __inline boolean_t
305 pte2_is_dirty(pt2_entry_t pte2)
306 {
307
308         return ((pte2 & (PTE2_NM | PTE2_RO)) == 0);
309 }
310
311 static __inline boolean_t
312 pte2_is_global(pt2_entry_t pte2)
313 {
314
315         return ((pte2 & PTE2_NG) == 0);
316 }
317
318 static __inline boolean_t
319 pte2_is_valid(pt2_entry_t pte2)
320 {
321
322         return (pte2 & PTE2_V);
323 }
324
325 static __inline boolean_t
326 pte2_is_wired(pt2_entry_t pte2)
327 {
328
329         return (pte2 & PTE2_W);
330 }
331
332 static __inline pt2_entry_t
333 pte2_load(pt2_entry_t *pte2p)
334 {
335         pt2_entry_t pte2;
336
337         pte2 = *pte2p;
338         return (pte2);
339 }
340
341 static __inline pt2_entry_t
342 pte2_load_clear(pt2_entry_t *pte2p)
343 {
344         pt2_entry_t opte2;
345
346         opte2 = *pte2p;
347         *pte2p = 0;
348         pte2_sync(pte2p);
349         return (opte2);
350 }
351
352 static __inline void
353 pte2_set_bit(pt2_entry_t *pte2p, uint32_t bit)
354 {
355
356         *pte2p |= bit;
357         pte2_sync(pte2p);
358 }
359
360 static __inline void
361 pte2_set_wired(pt2_entry_t *pte2p, boolean_t wired)
362 {
363
364         /*
365          * Wired bit is transparent for page table walk,
366          * so pte2_sync() is not needed.
367          */
368         if (wired)
369                 *pte2p |= PTE2_W;
370         else
371                 *pte2p &= ~PTE2_W;
372 }
373
374 static __inline vm_paddr_t
375 pte2_pa(pt2_entry_t pte2)
376 {
377
378         return ((vm_paddr_t)(pte2 & PTE2_FRAME));
379 }
380
381 static __inline u_int
382 pte2_attr(pt2_entry_t pte2)
383 {
384
385         return ((u_int)(pte2 & PTE2_ATTR_MASK));
386 }
387
388 /*
389  *  Virtual interface for L2 page tables mapping management.
390  */
391
392 static __inline u_int
393 pt2tab_index(vm_offset_t va)
394 {
395
396         return (va >> PT2TAB_SHIFT);
397 }
398
399 static __inline pt2_entry_t *
400 pt2tab_entry(pt2_entry_t *pt2tab, vm_offset_t va)
401 {
402
403         return (pt2tab + pt2tab_index(va));
404 }
405
406 static __inline void
407 pt2tab_store(pt2_entry_t *pte2p, pt2_entry_t pte2)
408 {
409
410         pte2_store(pte2p,pte2);
411 }
412
413 static __inline pt2_entry_t
414 pt2tab_load(pt2_entry_t *pte2p)
415 {
416
417         return (pte2_load(pte2p));
418 }
419
420 static __inline pt2_entry_t
421 pt2tab_load_clear(pt2_entry_t *pte2p)
422 {
423
424         return (pte2_load_clear(pte2p));
425 }
426
427 static __inline u_int
428 pt2map_index(vm_offset_t va)
429 {
430
431         return (va >> PT2MAP_SHIFT);
432 }
433
434 static __inline pt2_entry_t *
435 pt2map_entry(vm_offset_t va)
436 {
437
438         return (PT2MAP + pt2map_index(va));
439 }
440
441 /*
442  *  Virtual interface for pmap structure & kernel shortcuts.
443  */
444
445 static __inline pt1_entry_t *
446 pmap_pte1(pmap_t pmap, vm_offset_t va)
447 {
448
449         return (pte1_ptr(pmap->pm_pt1, va));
450 }
451
452 static __inline pt1_entry_t *
453 kern_pte1(vm_offset_t va)
454 {
455
456         return (pte1_ptr(kern_pt1, va));
457 }
458
459 static __inline pt2_entry_t *
460 pmap_pt2tab_entry(pmap_t pmap, vm_offset_t va)
461 {
462
463         return (pt2tab_entry(pmap->pm_pt2tab, va));
464 }
465
466 static __inline pt2_entry_t *
467 kern_pt2tab_entry(vm_offset_t va)
468 {
469
470         return (pt2tab_entry(kern_pt2tab, va));
471 }
472
473 static __inline vm_page_t
474 pmap_pt2_page(pmap_t pmap, vm_offset_t va)
475 {
476         pt2_entry_t pte2;
477
478         pte2 = pte2_load(pmap_pt2tab_entry(pmap, va));
479         return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME));
480 }
481
482 static __inline vm_page_t
483 kern_pt2_page(vm_offset_t va)
484 {
485         pt2_entry_t pte2;
486
487         pte2 = pte2_load(kern_pt2tab_entry(va));
488         return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME));
489 }
490
491 #endif  /* _KERNEL */
492 #endif  /* !_MACHINE_PMAP_VAR_H_ */