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
74extern pt1_entry_t *kern_pt1;
75extern pt2_entry_t *kern_pt2tab;
76extern pt2_entry_t *PT2MAP;
77
78/*
79 *  Virtual interface for L1 page table management.
80 */
81
82static __inline u_int
83pte1_index(vm_offset_t va)
84{
85
86	return (va >> PTE1_SHIFT);
87}
88
89static __inline pt1_entry_t *
90pte1_ptr(pt1_entry_t *pt1, vm_offset_t va)
91{
92
93	return (pt1 + pte1_index(va));
94}
95
96static __inline vm_offset_t
97pte1_trunc(vm_offset_t va)
98{
99
100	return (va & PTE1_FRAME);
101}
102
103static __inline vm_offset_t
104pte1_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 */
118static __inline void
119pte1_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
129static __inline void
130pte1_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
140static __inline void
141pte1_store(pt1_entry_t *pte1p, pt1_entry_t pte1)
142{
143
144	dmb();
145	*pte1p = pte1;
146	pte1_sync(pte1p);
147}
148
149static __inline void
150pte1_clear(pt1_entry_t *pte1p)
151{
152
153	pte1_store(pte1p, 0);
154}
155
156static __inline void
157pte1_clear_bit(pt1_entry_t *pte1p, uint32_t bit)
158{
159
160	*pte1p &= ~bit;
161	pte1_sync(pte1p);
162}
163
164static __inline bool
165pte1_is_link(pt1_entry_t pte1)
166{
167
168	return ((pte1 & L1_TYPE_MASK) == L1_TYPE_C);
169}
170
171static __inline int
172pte1_is_section(pt1_entry_t pte1)
173{
174
175	return ((pte1 & L1_TYPE_MASK) == L1_TYPE_S);
176}
177
178static __inline bool
179pte1_is_dirty(pt1_entry_t pte1)
180{
181
182	return ((pte1 & (PTE1_NM | PTE1_RO)) == 0);
183}
184
185static __inline bool
186pte1_is_global(pt1_entry_t pte1)
187{
188
189	return ((pte1 & PTE1_NG) == 0);
190}
191
192static __inline bool
193pte1_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
201static __inline bool
202pte1_is_wired(pt1_entry_t pte1)
203{
204
205	return (pte1 & PTE1_W);
206}
207
208static __inline pt1_entry_t
209pte1_load(pt1_entry_t *pte1p)
210{
211	pt1_entry_t pte1;
212
213	pte1 = *pte1p;
214	return (pte1);
215}
216
217static __inline pt1_entry_t
218pte1_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
228static __inline void
229pte1_set_bit(pt1_entry_t *pte1p, uint32_t bit)
230{
231
232	*pte1p |= bit;
233	pte1_sync(pte1p);
234}
235
236static __inline vm_paddr_t
237pte1_pa(pt1_entry_t pte1)
238{
239
240	return ((vm_paddr_t)(pte1 & PTE1_FRAME));
241}
242
243static __inline vm_paddr_t
244pte1_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
258static __inline void
259pte2_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
269static __inline void
270pte2_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
280static __inline void
281pte2_store(pt2_entry_t *pte2p, pt2_entry_t pte2)
282{
283
284	dmb();
285	*pte2p = pte2;
286	pte2_sync(pte2p);
287}
288
289static __inline void
290pte2_clear(pt2_entry_t *pte2p)
291{
292
293	pte2_store(pte2p, 0);
294}
295
296static __inline void
297pte2_clear_bit(pt2_entry_t *pte2p, uint32_t bit)
298{
299
300	*pte2p &= ~bit;
301	pte2_sync(pte2p);
302}
303
304static __inline bool
305pte2_is_dirty(pt2_entry_t pte2)
306{
307
308	return ((pte2 & (PTE2_NM | PTE2_RO)) == 0);
309}
310
311static __inline bool
312pte2_is_global(pt2_entry_t pte2)
313{
314
315	return ((pte2 & PTE2_NG) == 0);
316}
317
318static __inline bool
319pte2_is_valid(pt2_entry_t pte2)
320{
321
322	return (pte2 & PTE2_V);
323}
324
325static __inline bool
326pte2_is_wired(pt2_entry_t pte2)
327{
328
329	return (pte2 & PTE2_W);
330}
331
332static __inline pt2_entry_t
333pte2_load(pt2_entry_t *pte2p)
334{
335	pt2_entry_t pte2;
336
337	pte2 = *pte2p;
338	return (pte2);
339}
340
341static __inline pt2_entry_t
342pte2_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
352static __inline void
353pte2_set_bit(pt2_entry_t *pte2p, uint32_t bit)
354{
355
356	*pte2p |= bit;
357	pte2_sync(pte2p);
358}
359
360static __inline void
361pte2_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
374static __inline vm_paddr_t
375pte2_pa(pt2_entry_t pte2)
376{
377
378	return ((vm_paddr_t)(pte2 & PTE2_FRAME));
379}
380
381static __inline u_int
382pte2_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
392static __inline u_int
393pt2tab_index(vm_offset_t va)
394{
395
396	return (va >> PT2TAB_SHIFT);
397}
398
399static __inline pt2_entry_t *
400pt2tab_entry(pt2_entry_t *pt2tab, vm_offset_t va)
401{
402
403	return (pt2tab + pt2tab_index(va));
404}
405
406static __inline void
407pt2tab_store(pt2_entry_t *pte2p, pt2_entry_t pte2)
408{
409
410	pte2_store(pte2p,pte2);
411}
412
413static __inline pt2_entry_t
414pt2tab_load(pt2_entry_t *pte2p)
415{
416
417	return (pte2_load(pte2p));
418}
419
420static __inline pt2_entry_t
421pt2tab_load_clear(pt2_entry_t *pte2p)
422{
423
424	return (pte2_load_clear(pte2p));
425}
426
427static __inline u_int
428pt2map_index(vm_offset_t va)
429{
430
431	return (va >> PT2MAP_SHIFT);
432}
433
434static __inline pt2_entry_t *
435pt2map_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
445static __inline pt1_entry_t *
446pmap_pte1(pmap_t pmap, vm_offset_t va)
447{
448
449	return (pte1_ptr(pmap->pm_pt1, va));
450}
451
452static __inline pt1_entry_t *
453kern_pte1(vm_offset_t va)
454{
455
456	return (pte1_ptr(kern_pt1, va));
457}
458
459static __inline pt2_entry_t *
460pmap_pt2tab_entry(pmap_t pmap, vm_offset_t va)
461{
462
463	return (pt2tab_entry(pmap->pm_pt2tab, va));
464}
465
466static __inline pt2_entry_t *
467kern_pt2tab_entry(vm_offset_t va)
468{
469
470	return (pt2tab_entry(kern_pt2tab, va));
471}
472
473static __inline vm_page_t
474pmap_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
482static __inline vm_page_t
483kern_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