1280712Sian/*-
2280712Sian * Copyright 2014 Svatopluk Kraus <onwahe@gmail.com>
3280712Sian * Copyright 2014 Michal Meloun <meloun@miracle.cz>
4280712Sian * All rights reserved.
5280712Sian *
6280712Sian * Redistribution and use in source and binary forms, with or without
7280712Sian * modification, are permitted provided that the following conditions
8280712Sian * are met:
9280712Sian * 1. Redistributions of source code must retain the above copyright
10280712Sian *    notice, this list of conditions and the following disclaimer.
11280712Sian * 2. Redistributions in binary form must reproduce the above copyright
12280712Sian *    notice, this list of conditions and the following disclaimer in the
13280712Sian *    documentation and/or other materials provided with the distribution.
14280712Sian *
15280712Sian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16280712Sian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17280712Sian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18280712Sian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19280712Sian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20280712Sian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21280712Sian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22280712Sian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23280712Sian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24280712Sian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25280712Sian * SUCH DAMAGE.
26280712Sian *
27280712Sian * $FreeBSD$
28280712Sian */
29280712Sian
30280712Sian#ifndef _MACHINE_PMAP_VAR_H_
31280712Sian#define _MACHINE_PMAP_VAR_H_
32280712Sian
33280712Sian#include <machine/cpu-v6.h>
34295695Sskra#include <machine/pte-v6.h>
35280712Sian/*
36280712Sian *  Various PMAP defines, exports, and inline functions
37280712Sian *  definitions also usable in other MD code.
38280712Sian */
39280712Sian
40280712Sian/*  A number of pages in L1 page table. */
41280712Sian#define NPG_IN_PT1	(NB_IN_PT1 / PAGE_SIZE)
42280712Sian
43280712Sian/*  A number of L2 page tables in a page. */
44280712Sian#define NPT2_IN_PG	(PAGE_SIZE / NB_IN_PT2)
45280712Sian
46280712Sian/*  A number of L2 page table entries in a page. */
47280712Sian#define NPTE2_IN_PG	(NPT2_IN_PG * NPTE2_IN_PT2)
48280712Sian
49280712Sian#ifdef _KERNEL
50280712Sian
51280712Sian/*
52280712Sian *  A L2 page tables page contains NPT2_IN_PG L2 page tables. Masking of
53280712Sian *  pte1_idx by PT2PG_MASK gives us an index to associated L2 page table
54280712Sian *  in a page. The PT2PG_SHIFT definition depends on NPT2_IN_PG strictly.
55280712Sian *  I.e., (1 << PT2PG_SHIFT) == NPT2_IN_PG must be fulfilled.
56280712Sian */
57280712Sian#define PT2PG_SHIFT	2
58280712Sian#define PT2PG_MASK	((1 << PT2PG_SHIFT) - 1)
59280712Sian
60280712Sian/*
61280712Sian *  A PT2TAB holds all allocated L2 page table pages in a pmap.
62280712Sian *  Right shifting of virtual address by PT2TAB_SHIFT gives us an index
63280712Sian *  to L2 page table page in PT2TAB which holds the address mapping.
64280712Sian */
65280712Sian#define PT2TAB_ENTRIES  (NPTE1_IN_PT1 / NPT2_IN_PG)
66280712Sian#define PT2TAB_SHIFT	(PTE1_SHIFT + PT2PG_SHIFT)
67280712Sian
68280712Sian/*
69280712Sian *  All allocated L2 page table pages in a pmap are mapped into PT2MAP space.
70280712Sian *  An virtual address right shifting by PT2MAP_SHIFT gives us an index to PTE2
71280712Sian *  which maps the address.
72280712Sian */
73280712Sian#define PT2MAP_SIZE	(NPTE1_IN_PT1 * NB_IN_PT2)
74280712Sian#define PT2MAP_SHIFT	PTE2_SHIFT
75280712Sian
76280712Sianextern pt1_entry_t *kern_pt1;
77280712Sianextern pt2_entry_t *kern_pt2tab;
78280712Sianextern pt2_entry_t *PT2MAP;
79280712Sian
80280712Sian/*
81280712Sian *  Virtual interface for L1 page table management.
82280712Sian */
83280712Sian
84280712Sianstatic __inline u_int
85280712Sianpte1_index(vm_offset_t va)
86280712Sian{
87280712Sian
88280712Sian	return (va >> PTE1_SHIFT);
89280712Sian}
90280712Sian
91280712Sianstatic __inline pt1_entry_t *
92280712Sianpte1_ptr(pt1_entry_t *pt1, vm_offset_t va)
93280712Sian{
94280712Sian
95280712Sian	return (pt1 + pte1_index(va));
96280712Sian}
97280712Sian
98280712Sianstatic __inline vm_offset_t
99280712Sianpte1_trunc(vm_offset_t va)
100280712Sian{
101280712Sian
102280712Sian	return (va & PTE1_FRAME);
103280712Sian}
104280712Sian
105280712Sianstatic __inline vm_offset_t
106280712Sianpte1_roundup(vm_offset_t va)
107280712Sian{
108280712Sian
109280712Sian	return ((va + PTE1_OFFSET) & PTE1_FRAME);
110280712Sian}
111280712Sian
112280712Sian/*
113280712Sian *  Virtual interface for L1 page table entries management.
114280712Sian *
115280712Sian *  XXX: Some of the following functions now with a synchronization barrier
116280712Sian *  are called in a loop, so it could be useful to have two versions of them.
117280712Sian *  One with the barrier and one without the barrier. In this case, pure
118280712Sian *  barrier pte1_sync() should be implemented as well.
119280712Sian */
120280712Sianstatic __inline void
121280712Sianpte1_sync(pt1_entry_t *pte1p)
122280712Sian{
123280712Sian
124280712Sian	dsb();
125280712Sian#ifndef PMAP_PTE_NOCACHE
126280712Sian	if (!cpuinfo.coherent_walk)
127280712Sian		dcache_wb_pou((vm_offset_t)pte1p, sizeof(*pte1p));
128280712Sian#endif
129280712Sian}
130280712Sian
131280712Sianstatic __inline void
132280712Sianpte1_sync_range(pt1_entry_t *pte1p, vm_size_t size)
133280712Sian{
134280712Sian
135280712Sian	dsb();
136280712Sian#ifndef PMAP_PTE_NOCACHE
137280712Sian	if (!cpuinfo.coherent_walk)
138280712Sian		dcache_wb_pou((vm_offset_t)pte1p, size);
139280712Sian#endif
140280712Sian}
141280712Sian
142280712Sianstatic __inline void
143280712Sianpte1_store(pt1_entry_t *pte1p, pt1_entry_t pte1)
144280712Sian{
145280712Sian
146298457Sskra	dmb();
147298457Sskra	*pte1p = pte1;
148280712Sian	pte1_sync(pte1p);
149280712Sian}
150280712Sian
151280712Sianstatic __inline void
152280712Sianpte1_clear(pt1_entry_t *pte1p)
153280712Sian{
154280712Sian
155280712Sian	pte1_store(pte1p, 0);
156280712Sian}
157280712Sian
158280712Sianstatic __inline void
159280712Sianpte1_clear_bit(pt1_entry_t *pte1p, uint32_t bit)
160280712Sian{
161280712Sian
162298457Sskra	*pte1p &= ~bit;
163280712Sian	pte1_sync(pte1p);
164280712Sian}
165280712Sian
166280712Sianstatic __inline boolean_t
167280712Sianpte1_is_link(pt1_entry_t pte1)
168280712Sian{
169280712Sian
170280712Sian	return ((pte1 & L1_TYPE_MASK) == L1_TYPE_C);
171280712Sian}
172280712Sian
173280712Sianstatic __inline int
174280712Sianpte1_is_section(pt1_entry_t pte1)
175280712Sian{
176280712Sian
177280712Sian	return ((pte1 & L1_TYPE_MASK) == L1_TYPE_S);
178280712Sian}
179280712Sian
180280712Sianstatic __inline boolean_t
181280712Sianpte1_is_dirty(pt1_entry_t pte1)
182280712Sian{
183280712Sian
184280712Sian	return ((pte1 & (PTE1_NM | PTE1_RO)) == 0);
185280712Sian}
186280712Sian
187280712Sianstatic __inline boolean_t
188280712Sianpte1_is_global(pt1_entry_t pte1)
189280712Sian{
190280712Sian
191280712Sian	return ((pte1 & PTE1_NG) == 0);
192280712Sian}
193280712Sian
194280712Sianstatic __inline boolean_t
195280712Sianpte1_is_valid(pt1_entry_t pte1)
196280712Sian{
197280712Sian	int l1_type;
198280712Sian
199280712Sian	l1_type = pte1 & L1_TYPE_MASK;
200280712Sian	return ((l1_type == L1_TYPE_C) || (l1_type == L1_TYPE_S));
201280712Sian}
202280712Sian
203280712Sianstatic __inline boolean_t
204280712Sianpte1_is_wired(pt1_entry_t pte1)
205280712Sian{
206280712Sian
207280712Sian	return (pte1 & PTE1_W);
208280712Sian}
209280712Sian
210280712Sianstatic __inline pt1_entry_t
211280712Sianpte1_load(pt1_entry_t *pte1p)
212280712Sian{
213280712Sian	pt1_entry_t pte1;
214280712Sian
215280712Sian	pte1 = *pte1p;
216280712Sian	return (pte1);
217280712Sian}
218280712Sian
219280712Sianstatic __inline pt1_entry_t
220280712Sianpte1_load_clear(pt1_entry_t *pte1p)
221280712Sian{
222280712Sian	pt1_entry_t opte1;
223280712Sian
224298457Sskra	opte1 = *pte1p;
225298457Sskra	*pte1p = 0;
226280712Sian	pte1_sync(pte1p);
227280712Sian	return (opte1);
228280712Sian}
229280712Sian
230280712Sianstatic __inline void
231280712Sianpte1_set_bit(pt1_entry_t *pte1p, uint32_t bit)
232280712Sian{
233280712Sian
234298457Sskra	*pte1p |= bit;
235280712Sian	pte1_sync(pte1p);
236280712Sian}
237280712Sian
238280712Sianstatic __inline vm_paddr_t
239280712Sianpte1_pa(pt1_entry_t pte1)
240280712Sian{
241280712Sian
242280712Sian	return ((vm_paddr_t)(pte1 & PTE1_FRAME));
243280712Sian}
244280712Sian
245280712Sianstatic __inline vm_paddr_t
246280712Sianpte1_link_pa(pt1_entry_t pte1)
247280712Sian{
248280712Sian
249280712Sian	return ((vm_paddr_t)(pte1 & L1_C_ADDR_MASK));
250280712Sian}
251280712Sian
252280712Sian/*
253280712Sian *  Virtual interface for L2 page table entries management.
254280712Sian *
255280712Sian *  XXX: Some of the following functions now with a synchronization barrier
256280712Sian *  are called in a loop, so it could be useful to have two versions of them.
257280712Sian *  One with the barrier and one without the barrier.
258280712Sian */
259280712Sian
260280712Sianstatic __inline void
261280712Sianpte2_sync(pt2_entry_t *pte2p)
262280712Sian{
263280712Sian
264280712Sian	dsb();
265280712Sian#ifndef PMAP_PTE_NOCACHE
266280712Sian	if (!cpuinfo.coherent_walk)
267280712Sian		dcache_wb_pou((vm_offset_t)pte2p, sizeof(*pte2p));
268280712Sian#endif
269280712Sian}
270280712Sian
271280712Sianstatic __inline void
272280712Sianpte2_sync_range(pt2_entry_t *pte2p, vm_size_t size)
273280712Sian{
274280712Sian
275280712Sian	dsb();
276280712Sian#ifndef PMAP_PTE_NOCACHE
277280712Sian	if (!cpuinfo.coherent_walk)
278280712Sian		dcache_wb_pou((vm_offset_t)pte2p, size);
279280712Sian#endif
280280712Sian}
281280712Sian
282280712Sianstatic __inline void
283280712Sianpte2_store(pt2_entry_t *pte2p, pt2_entry_t pte2)
284280712Sian{
285280712Sian
286298457Sskra	dmb();
287298457Sskra	*pte2p = pte2;
288280712Sian	pte2_sync(pte2p);
289280712Sian}
290280712Sian
291280712Sianstatic __inline void
292280712Sianpte2_clear(pt2_entry_t *pte2p)
293280712Sian{
294280712Sian
295280712Sian	pte2_store(pte2p, 0);
296280712Sian}
297280712Sian
298280712Sianstatic __inline void
299280712Sianpte2_clear_bit(pt2_entry_t *pte2p, uint32_t bit)
300280712Sian{
301280712Sian
302298457Sskra	*pte2p &= ~bit;
303280712Sian	pte2_sync(pte2p);
304280712Sian}
305280712Sian
306280712Sianstatic __inline boolean_t
307280712Sianpte2_is_dirty(pt2_entry_t pte2)
308280712Sian{
309280712Sian
310280712Sian	return ((pte2 & (PTE2_NM | PTE2_RO)) == 0);
311280712Sian}
312280712Sian
313280712Sianstatic __inline boolean_t
314280712Sianpte2_is_global(pt2_entry_t pte2)
315280712Sian{
316280712Sian
317280712Sian	return ((pte2 & PTE2_NG) == 0);
318280712Sian}
319280712Sian
320280712Sianstatic __inline boolean_t
321280712Sianpte2_is_valid(pt2_entry_t pte2)
322280712Sian{
323280712Sian
324280712Sian	return (pte2 & PTE2_V);
325280712Sian}
326280712Sian
327280712Sianstatic __inline boolean_t
328280712Sianpte2_is_wired(pt2_entry_t pte2)
329280712Sian{
330280712Sian
331280712Sian	return (pte2 & PTE2_W);
332280712Sian}
333280712Sian
334280712Sianstatic __inline pt2_entry_t
335280712Sianpte2_load(pt2_entry_t *pte2p)
336280712Sian{
337280712Sian	pt2_entry_t pte2;
338280712Sian
339280712Sian	pte2 = *pte2p;
340280712Sian	return (pte2);
341280712Sian}
342280712Sian
343280712Sianstatic __inline pt2_entry_t
344280712Sianpte2_load_clear(pt2_entry_t *pte2p)
345280712Sian{
346280712Sian	pt2_entry_t opte2;
347280712Sian
348298457Sskra	opte2 = *pte2p;
349298457Sskra	*pte2p = 0;
350280712Sian	pte2_sync(pte2p);
351280712Sian	return (opte2);
352280712Sian}
353280712Sian
354280712Sianstatic __inline void
355280712Sianpte2_set_bit(pt2_entry_t *pte2p, uint32_t bit)
356280712Sian{
357280712Sian
358298457Sskra	*pte2p |= bit;
359280712Sian	pte2_sync(pte2p);
360280712Sian}
361280712Sian
362280712Sianstatic __inline void
363280712Sianpte2_set_wired(pt2_entry_t *pte2p, boolean_t wired)
364280712Sian{
365280712Sian
366280712Sian	/*
367280712Sian	 * Wired bit is transparent for page table walk,
368280712Sian	 * so pte2_sync() is not needed.
369280712Sian	 */
370280712Sian	if (wired)
371298457Sskra		*pte2p |= PTE2_W;
372280712Sian	else
373298457Sskra		*pte2p &= ~PTE2_W;
374280712Sian}
375280712Sian
376280712Sianstatic __inline vm_paddr_t
377280712Sianpte2_pa(pt2_entry_t pte2)
378280712Sian{
379280712Sian
380280712Sian	return ((vm_paddr_t)(pte2 & PTE2_FRAME));
381280712Sian}
382280712Sian
383280712Sianstatic __inline u_int
384280712Sianpte2_attr(pt2_entry_t pte2)
385280712Sian{
386280712Sian
387280712Sian	return ((u_int)(pte2 & PTE2_ATTR_MASK));
388280712Sian}
389280712Sian
390280712Sian/*
391280712Sian *  Virtual interface for L2 page tables mapping management.
392280712Sian */
393280712Sian
394280712Sianstatic __inline u_int
395280712Sianpt2tab_index(vm_offset_t va)
396280712Sian{
397280712Sian
398280712Sian	return (va >> PT2TAB_SHIFT);
399280712Sian}
400280712Sian
401280712Sianstatic __inline pt2_entry_t *
402280712Sianpt2tab_entry(pt2_entry_t *pt2tab, vm_offset_t va)
403280712Sian{
404280712Sian
405280712Sian	return (pt2tab + pt2tab_index(va));
406280712Sian}
407280712Sian
408280712Sianstatic __inline void
409280712Sianpt2tab_store(pt2_entry_t *pte2p, pt2_entry_t pte2)
410280712Sian{
411280712Sian
412280712Sian	pte2_store(pte2p,pte2);
413280712Sian}
414280712Sian
415280712Sianstatic __inline pt2_entry_t
416280712Sianpt2tab_load(pt2_entry_t *pte2p)
417280712Sian{
418280712Sian
419280712Sian	return (pte2_load(pte2p));
420280712Sian}
421280712Sian
422280712Sianstatic __inline pt2_entry_t
423280712Sianpt2tab_load_clear(pt2_entry_t *pte2p)
424280712Sian{
425280712Sian
426280712Sian	return (pte2_load_clear(pte2p));
427280712Sian}
428280712Sian
429280712Sianstatic __inline u_int
430280712Sianpt2map_index(vm_offset_t va)
431280712Sian{
432280712Sian
433280712Sian	return (va >> PT2MAP_SHIFT);
434280712Sian}
435280712Sian
436280712Sianstatic __inline pt2_entry_t *
437280712Sianpt2map_entry(vm_offset_t va)
438280712Sian{
439280712Sian
440280712Sian	return (PT2MAP + pt2map_index(va));
441280712Sian}
442280712Sian
443280712Sian/*
444280712Sian *  Virtual interface for pmap structure & kernel shortcuts.
445280712Sian */
446280712Sian
447280712Sianstatic __inline pt1_entry_t *
448280712Sianpmap_pte1(pmap_t pmap, vm_offset_t va)
449280712Sian{
450280712Sian
451280712Sian	return (pte1_ptr(pmap->pm_pt1, va));
452280712Sian}
453280712Sian
454280712Sianstatic __inline pt1_entry_t *
455280712Siankern_pte1(vm_offset_t va)
456280712Sian{
457280712Sian
458280712Sian	return (pte1_ptr(kern_pt1, va));
459280712Sian}
460280712Sian
461280712Sianstatic __inline pt2_entry_t *
462280712Sianpmap_pt2tab_entry(pmap_t pmap, vm_offset_t va)
463280712Sian{
464280712Sian
465280712Sian	return (pt2tab_entry(pmap->pm_pt2tab, va));
466280712Sian}
467280712Sian
468280712Sianstatic __inline pt2_entry_t *
469280712Siankern_pt2tab_entry(vm_offset_t va)
470280712Sian{
471280712Sian
472280712Sian	return (pt2tab_entry(kern_pt2tab, va));
473280712Sian}
474280712Sian
475280712Sianstatic __inline vm_page_t
476280712Sianpmap_pt2_page(pmap_t pmap, vm_offset_t va)
477280712Sian{
478280712Sian	pt2_entry_t pte2;
479280712Sian
480280712Sian	pte2 = pte2_load(pmap_pt2tab_entry(pmap, va));
481280712Sian	return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME));
482280712Sian}
483280712Sian
484280712Sianstatic __inline vm_page_t
485280712Siankern_pt2_page(vm_offset_t va)
486280712Sian{
487280712Sian	pt2_entry_t pte2;
488280712Sian
489280712Sian	pte2 = pte2_load(kern_pt2tab_entry(va));
490280712Sian	return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME));
491280712Sian}
492280712Sian
493280712Sian#endif	/* _KERNEL */
494280712Sian#endif	/* !_MACHINE_PMAP_VAR_H_ */
495