xref: /freebsd/sys/arm/include/pmap_var.h (revision 93e779a26c651610ac6e7986d67ecc9ed2cadcbf)
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  * $FreeBSD$
28  */
29 
30 #ifndef _MACHINE_PMAP_VAR_H_
31 #define _MACHINE_PMAP_VAR_H_
32 
33 #include <machine/cpu-v6.h>
34 /*
35  *  Various PMAP defines, exports, and inline functions
36  *  definitions also usable in other MD code.
37  */
38 
39 /*  A number of pages in L1 page table. */
40 #define NPG_IN_PT1	(NB_IN_PT1 / PAGE_SIZE)
41 
42 /*  A number of L2 page tables in a page. */
43 #define NPT2_IN_PG	(PAGE_SIZE / NB_IN_PT2)
44 
45 /*  A number of L2 page table entries in a page. */
46 #define NPTE2_IN_PG	(NPT2_IN_PG * NPTE2_IN_PT2)
47 
48 #ifdef _KERNEL
49 
50 /*
51  *  A L2 page tables page contains NPT2_IN_PG L2 page tables. Masking of
52  *  pte1_idx by PT2PG_MASK gives us an index to associated L2 page table
53  *  in a page. The PT2PG_SHIFT definition depends on NPT2_IN_PG strictly.
54  *  I.e., (1 << PT2PG_SHIFT) == NPT2_IN_PG must be fulfilled.
55  */
56 #define PT2PG_SHIFT	2
57 #define PT2PG_MASK	((1 << PT2PG_SHIFT) - 1)
58 
59 /*
60  *  A PT2TAB holds all allocated L2 page table pages in a pmap.
61  *  Right shifting of virtual address by PT2TAB_SHIFT gives us an index
62  *  to L2 page table page in PT2TAB which holds the address mapping.
63  */
64 #define PT2TAB_ENTRIES  (NPTE1_IN_PT1 / NPT2_IN_PG)
65 #define PT2TAB_SHIFT	(PTE1_SHIFT + PT2PG_SHIFT)
66 
67 /*
68  *  All allocated L2 page table pages in a pmap are mapped into PT2MAP space.
69  *  An virtual address right shifting by PT2MAP_SHIFT gives us an index to PTE2
70  *  which maps the address.
71  */
72 #define PT2MAP_SIZE	(NPTE1_IN_PT1 * NB_IN_PT2)
73 #define PT2MAP_SHIFT	PTE2_SHIFT
74 
75 extern pt1_entry_t *kern_pt1;
76 extern pt2_entry_t *kern_pt2tab;
77 extern pt2_entry_t *PT2MAP;
78 
79 /*
80  *  Virtual interface for L1 page table management.
81  */
82 
83 static __inline u_int
84 pte1_index(vm_offset_t va)
85 {
86 
87 	return (va >> PTE1_SHIFT);
88 }
89 
90 static __inline pt1_entry_t *
91 pte1_ptr(pt1_entry_t *pt1, vm_offset_t va)
92 {
93 
94 	return (pt1 + pte1_index(va));
95 }
96 
97 static __inline vm_offset_t
98 pte1_trunc(vm_offset_t va)
99 {
100 
101 	return (va & PTE1_FRAME);
102 }
103 
104 static __inline vm_offset_t
105 pte1_roundup(vm_offset_t va)
106 {
107 
108 	return ((va + PTE1_OFFSET) & PTE1_FRAME);
109 }
110 
111 /*
112  *  Virtual interface for L1 page table entries management.
113  *
114  *  XXX: Some of the following functions now with a synchronization barrier
115  *  are called in a loop, so it could be useful to have two versions of them.
116  *  One with the barrier and one without the barrier. In this case, pure
117  *  barrier pte1_sync() should be implemented as well.
118  */
119 static __inline void
120 pte1_sync(pt1_entry_t *pte1p)
121 {
122 
123 	dsb();
124 #ifndef PMAP_PTE_NOCACHE
125 	if (!cpuinfo.coherent_walk)
126 		dcache_wb_pou((vm_offset_t)pte1p, sizeof(*pte1p));
127 #endif
128 }
129 
130 static __inline void
131 pte1_sync_range(pt1_entry_t *pte1p, vm_size_t size)
132 {
133 
134 	dsb();
135 #ifndef PMAP_PTE_NOCACHE
136 	if (!cpuinfo.coherent_walk)
137 		dcache_wb_pou((vm_offset_t)pte1p, size);
138 #endif
139 }
140 
141 static __inline void
142 pte1_store(pt1_entry_t *pte1p, pt1_entry_t pte1)
143 {
144 
145 	atomic_store_rel_int(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 	atomic_clear_int(pte1p, bit);
161 	pte1_sync(pte1p);
162 }
163 
164 static __inline boolean_t
165 pte1_cmpset(pt1_entry_t *pte1p, pt1_entry_t opte1, pt1_entry_t npte1)
166 {
167 	boolean_t ret;
168 
169 	ret = atomic_cmpset_int(pte1p, opte1, npte1);
170 	if (ret) pte1_sync(pte1p);
171 
172 	return (ret);
173 }
174 
175 static __inline boolean_t
176 pte1_is_link(pt1_entry_t pte1)
177 {
178 
179 	return ((pte1 & L1_TYPE_MASK) == L1_TYPE_C);
180 }
181 
182 static __inline int
183 pte1_is_section(pt1_entry_t pte1)
184 {
185 
186 	return ((pte1 & L1_TYPE_MASK) == L1_TYPE_S);
187 }
188 
189 static __inline boolean_t
190 pte1_is_dirty(pt1_entry_t pte1)
191 {
192 
193 	return ((pte1 & (PTE1_NM | PTE1_RO)) == 0);
194 }
195 
196 static __inline boolean_t
197 pte1_is_global(pt1_entry_t pte1)
198 {
199 
200 	return ((pte1 & PTE1_NG) == 0);
201 }
202 
203 static __inline boolean_t
204 pte1_is_valid(pt1_entry_t pte1)
205 {
206 	int l1_type;
207 
208 	l1_type = pte1 & L1_TYPE_MASK;
209 	return ((l1_type == L1_TYPE_C) || (l1_type == L1_TYPE_S));
210 }
211 
212 static __inline boolean_t
213 pte1_is_wired(pt1_entry_t pte1)
214 {
215 
216 	return (pte1 & PTE1_W);
217 }
218 
219 static __inline pt1_entry_t
220 pte1_load(pt1_entry_t *pte1p)
221 {
222 	pt1_entry_t pte1;
223 
224 	pte1 = *pte1p;
225 	return (pte1);
226 }
227 
228 static __inline pt1_entry_t
229 pte1_load_clear(pt1_entry_t *pte1p)
230 {
231 	pt1_entry_t opte1;
232 
233 	opte1 = atomic_readandclear_int(pte1p);
234 	pte1_sync(pte1p);
235 	return (opte1);
236 }
237 
238 static __inline void
239 pte1_set_bit(pt1_entry_t *pte1p, uint32_t bit)
240 {
241 
242 	atomic_set_int(pte1p, bit);
243 	pte1_sync(pte1p);
244 }
245 
246 static __inline vm_paddr_t
247 pte1_pa(pt1_entry_t pte1)
248 {
249 
250 	return ((vm_paddr_t)(pte1 & PTE1_FRAME));
251 }
252 
253 static __inline vm_paddr_t
254 pte1_link_pa(pt1_entry_t pte1)
255 {
256 
257 	return ((vm_paddr_t)(pte1 & L1_C_ADDR_MASK));
258 }
259 
260 /*
261  *  Virtual interface for L2 page table entries management.
262  *
263  *  XXX: Some of the following functions now with a synchronization barrier
264  *  are called in a loop, so it could be useful to have two versions of them.
265  *  One with the barrier and one without the barrier.
266  */
267 
268 static __inline void
269 pte2_sync(pt2_entry_t *pte2p)
270 {
271 
272 	dsb();
273 #ifndef PMAP_PTE_NOCACHE
274 	if (!cpuinfo.coherent_walk)
275 		dcache_wb_pou((vm_offset_t)pte2p, sizeof(*pte2p));
276 #endif
277 }
278 
279 static __inline void
280 pte2_sync_range(pt2_entry_t *pte2p, vm_size_t size)
281 {
282 
283 	dsb();
284 #ifndef PMAP_PTE_NOCACHE
285 	if (!cpuinfo.coherent_walk)
286 		dcache_wb_pou((vm_offset_t)pte2p, size);
287 #endif
288 }
289 
290 static __inline void
291 pte2_store(pt2_entry_t *pte2p, pt2_entry_t pte2)
292 {
293 
294 	atomic_store_rel_int(pte2p, pte2);
295 	pte2_sync(pte2p);
296 }
297 
298 static __inline void
299 pte2_clear(pt2_entry_t *pte2p)
300 {
301 
302 	pte2_store(pte2p, 0);
303 }
304 
305 static __inline void
306 pte2_clear_bit(pt2_entry_t *pte2p, uint32_t bit)
307 {
308 
309 	atomic_clear_int(pte2p, bit);
310 	pte2_sync(pte2p);
311 }
312 
313 static __inline boolean_t
314 pte2_cmpset(pt2_entry_t *pte2p, pt2_entry_t opte2, pt2_entry_t npte2)
315 {
316 	boolean_t ret;
317 
318 	ret = atomic_cmpset_int(pte2p, opte2, npte2);
319 	if (ret) pte2_sync(pte2p);
320 
321 	return (ret);
322 }
323 
324 static __inline boolean_t
325 pte2_is_dirty(pt2_entry_t pte2)
326 {
327 
328 	return ((pte2 & (PTE2_NM | PTE2_RO)) == 0);
329 }
330 
331 static __inline boolean_t
332 pte2_is_global(pt2_entry_t pte2)
333 {
334 
335 	return ((pte2 & PTE2_NG) == 0);
336 }
337 
338 static __inline boolean_t
339 pte2_is_valid(pt2_entry_t pte2)
340 {
341 
342 	return (pte2 & PTE2_V);
343 }
344 
345 static __inline boolean_t
346 pte2_is_wired(pt2_entry_t pte2)
347 {
348 
349 	return (pte2 & PTE2_W);
350 }
351 
352 static __inline pt2_entry_t
353 pte2_load(pt2_entry_t *pte2p)
354 {
355 	pt2_entry_t pte2;
356 
357 	pte2 = *pte2p;
358 	return (pte2);
359 }
360 
361 static __inline pt2_entry_t
362 pte2_load_clear(pt2_entry_t *pte2p)
363 {
364 	pt2_entry_t opte2;
365 
366 	opte2 = atomic_readandclear_int(pte2p);
367 	pte2_sync(pte2p);
368 	return (opte2);
369 }
370 
371 static __inline void
372 pte2_set_bit(pt2_entry_t *pte2p, uint32_t bit)
373 {
374 
375 	atomic_set_int(pte2p, bit);
376 	pte2_sync(pte2p);
377 }
378 
379 static __inline void
380 pte2_set_wired(pt2_entry_t *pte2p, boolean_t wired)
381 {
382 
383 	/*
384 	 * Wired bit is transparent for page table walk,
385 	 * so pte2_sync() is not needed.
386 	 */
387 	if (wired)
388 		atomic_set_int(pte2p, PTE2_W);
389 	else
390 		atomic_clear_int(pte2p, PTE2_W);
391 }
392 
393 static __inline vm_paddr_t
394 pte2_pa(pt2_entry_t pte2)
395 {
396 
397 	return ((vm_paddr_t)(pte2 & PTE2_FRAME));
398 }
399 
400 static __inline u_int
401 pte2_attr(pt2_entry_t pte2)
402 {
403 
404 	return ((u_int)(pte2 & PTE2_ATTR_MASK));
405 }
406 
407 /*
408  *  Virtual interface for L2 page tables mapping management.
409  */
410 
411 static __inline u_int
412 pt2tab_index(vm_offset_t va)
413 {
414 
415 	return (va >> PT2TAB_SHIFT);
416 }
417 
418 static __inline pt2_entry_t *
419 pt2tab_entry(pt2_entry_t *pt2tab, vm_offset_t va)
420 {
421 
422 	return (pt2tab + pt2tab_index(va));
423 }
424 
425 static __inline void
426 pt2tab_store(pt2_entry_t *pte2p, pt2_entry_t pte2)
427 {
428 
429 	pte2_store(pte2p,pte2);
430 }
431 
432 static __inline pt2_entry_t
433 pt2tab_load(pt2_entry_t *pte2p)
434 {
435 
436 	return (pte2_load(pte2p));
437 }
438 
439 static __inline pt2_entry_t
440 pt2tab_load_clear(pt2_entry_t *pte2p)
441 {
442 
443 	return (pte2_load_clear(pte2p));
444 }
445 
446 static __inline u_int
447 pt2map_index(vm_offset_t va)
448 {
449 
450 	return (va >> PT2MAP_SHIFT);
451 }
452 
453 static __inline pt2_entry_t *
454 pt2map_entry(vm_offset_t va)
455 {
456 
457 	return (PT2MAP + pt2map_index(va));
458 }
459 
460 /*
461  *  Virtual interface for pmap structure & kernel shortcuts.
462  */
463 
464 static __inline pt1_entry_t *
465 pmap_pte1(pmap_t pmap, vm_offset_t va)
466 {
467 
468 	return (pte1_ptr(pmap->pm_pt1, va));
469 }
470 
471 static __inline pt1_entry_t *
472 kern_pte1(vm_offset_t va)
473 {
474 
475 	return (pte1_ptr(kern_pt1, va));
476 }
477 
478 static __inline pt2_entry_t *
479 pmap_pt2tab_entry(pmap_t pmap, vm_offset_t va)
480 {
481 
482 	return (pt2tab_entry(pmap->pm_pt2tab, va));
483 }
484 
485 static __inline pt2_entry_t *
486 kern_pt2tab_entry(vm_offset_t va)
487 {
488 
489 	return (pt2tab_entry(kern_pt2tab, va));
490 }
491 
492 static __inline vm_page_t
493 pmap_pt2_page(pmap_t pmap, vm_offset_t va)
494 {
495 	pt2_entry_t pte2;
496 
497 	pte2 = pte2_load(pmap_pt2tab_entry(pmap, va));
498 	return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME));
499 }
500 
501 static __inline vm_page_t
502 kern_pt2_page(vm_offset_t va)
503 {
504 	pt2_entry_t pte2;
505 
506 	pte2 = pte2_load(kern_pt2tab_entry(va));
507 	return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME));
508 }
509 
510 #endif	/* _KERNEL */
511 #endif	/* !_MACHINE_PMAP_VAR_H_ */
512