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