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
pte1_index(vm_offset_t va)83 pte1_index(vm_offset_t va)
84 {
85
86 return (va >> PTE1_SHIFT);
87 }
88
89 static __inline pt1_entry_t *
pte1_ptr(pt1_entry_t * pt1,vm_offset_t va)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
pte1_trunc(vm_offset_t va)97 pte1_trunc(vm_offset_t va)
98 {
99
100 return (va & PTE1_FRAME);
101 }
102
103 static __inline vm_offset_t
pte1_roundup(vm_offset_t va)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
pte1_sync(pt1_entry_t * pte1p)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
pte1_sync_range(pt1_entry_t * pte1p,vm_size_t size)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
pte1_store(pt1_entry_t * pte1p,pt1_entry_t pte1)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
pte1_clear(pt1_entry_t * pte1p)150 pte1_clear(pt1_entry_t *pte1p)
151 {
152
153 pte1_store(pte1p, 0);
154 }
155
156 static __inline void
pte1_clear_bit(pt1_entry_t * pte1p,uint32_t bit)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 bool
pte1_is_link(pt1_entry_t pte1)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
pte1_is_section(pt1_entry_t pte1)172 pte1_is_section(pt1_entry_t pte1)
173 {
174
175 return ((pte1 & L1_TYPE_MASK) == L1_TYPE_S);
176 }
177
178 static __inline bool
pte1_is_dirty(pt1_entry_t pte1)179 pte1_is_dirty(pt1_entry_t pte1)
180 {
181
182 return ((pte1 & (PTE1_NM | PTE1_RO)) == 0);
183 }
184
185 static __inline bool
pte1_is_global(pt1_entry_t pte1)186 pte1_is_global(pt1_entry_t pte1)
187 {
188
189 return ((pte1 & PTE1_NG) == 0);
190 }
191
192 static __inline bool
pte1_is_valid(pt1_entry_t pte1)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 bool
pte1_is_wired(pt1_entry_t pte1)202 pte1_is_wired(pt1_entry_t pte1)
203 {
204
205 return (pte1 & PTE1_W);
206 }
207
208 static __inline pt1_entry_t
pte1_load(pt1_entry_t * pte1p)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
pte1_load_clear(pt1_entry_t * pte1p)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
pte1_set_bit(pt1_entry_t * pte1p,uint32_t bit)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
pte1_pa(pt1_entry_t pte1)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
pte1_link_pa(pt1_entry_t pte1)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
pte2_sync(pt2_entry_t * pte2p)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
pte2_sync_range(pt2_entry_t * pte2p,vm_size_t size)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
pte2_store(pt2_entry_t * pte2p,pt2_entry_t pte2)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
pte2_clear(pt2_entry_t * pte2p)290 pte2_clear(pt2_entry_t *pte2p)
291 {
292
293 pte2_store(pte2p, 0);
294 }
295
296 static __inline void
pte2_clear_bit(pt2_entry_t * pte2p,uint32_t bit)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 bool
pte2_is_dirty(pt2_entry_t pte2)305 pte2_is_dirty(pt2_entry_t pte2)
306 {
307
308 return ((pte2 & (PTE2_NM | PTE2_RO)) == 0);
309 }
310
311 static __inline bool
pte2_is_global(pt2_entry_t pte2)312 pte2_is_global(pt2_entry_t pte2)
313 {
314
315 return ((pte2 & PTE2_NG) == 0);
316 }
317
318 static __inline bool
pte2_is_valid(pt2_entry_t pte2)319 pte2_is_valid(pt2_entry_t pte2)
320 {
321
322 return (pte2 & PTE2_V);
323 }
324
325 static __inline bool
pte2_is_wired(pt2_entry_t pte2)326 pte2_is_wired(pt2_entry_t pte2)
327 {
328
329 return (pte2 & PTE2_W);
330 }
331
332 static __inline pt2_entry_t
pte2_load(pt2_entry_t * pte2p)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
pte2_load_clear(pt2_entry_t * pte2p)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
pte2_set_bit(pt2_entry_t * pte2p,uint32_t bit)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
pte2_set_wired(pt2_entry_t * pte2p,bool wired)361 pte2_set_wired(pt2_entry_t *pte2p, bool 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
pte2_pa(pt2_entry_t pte2)375 pte2_pa(pt2_entry_t pte2)
376 {
377
378 return ((vm_paddr_t)(pte2 & PTE2_FRAME));
379 }
380
381 static __inline u_int
pte2_attr(pt2_entry_t pte2)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
pt2tab_index(vm_offset_t va)393 pt2tab_index(vm_offset_t va)
394 {
395
396 return (va >> PT2TAB_SHIFT);
397 }
398
399 static __inline pt2_entry_t *
pt2tab_entry(pt2_entry_t * pt2tab,vm_offset_t va)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
pt2tab_store(pt2_entry_t * pte2p,pt2_entry_t pte2)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
pt2tab_load(pt2_entry_t * pte2p)414 pt2tab_load(pt2_entry_t *pte2p)
415 {
416
417 return (pte2_load(pte2p));
418 }
419
420 static __inline pt2_entry_t
pt2tab_load_clear(pt2_entry_t * pte2p)421 pt2tab_load_clear(pt2_entry_t *pte2p)
422 {
423
424 return (pte2_load_clear(pte2p));
425 }
426
427 static __inline u_int
pt2map_index(vm_offset_t va)428 pt2map_index(vm_offset_t va)
429 {
430
431 return (va >> PT2MAP_SHIFT);
432 }
433
434 static __inline pt2_entry_t *
pt2map_entry(vm_offset_t va)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 *
pmap_pte1(pmap_t pmap,vm_offset_t va)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 *
kern_pte1(vm_offset_t va)453 kern_pte1(vm_offset_t va)
454 {
455
456 return (pte1_ptr(kern_pt1, va));
457 }
458
459 static __inline pt2_entry_t *
pmap_pt2tab_entry(pmap_t pmap,vm_offset_t va)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 *
kern_pt2tab_entry(vm_offset_t va)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
pmap_pt2_page(pmap_t pmap,vm_offset_t va)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
kern_pt2_page(vm_offset_t va)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_ */
493