pmap_var.h revision 280712
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: head/sys/arm/include/pmap_var.h 280712 2015-03-26 21:13:53Z ian $
28280712Sian */
29280712Sian
30280712Sian#ifndef _MACHINE_PMAP_VAR_H_
31280712Sian#define _MACHINE_PMAP_VAR_H_
32280712Sian
33280712Sian#include <machine/cpu-v6.h>
34280712Sian/*
35280712Sian *  Various PMAP defines, exports, and inline functions
36280712Sian *  definitions also usable in other MD code.
37280712Sian */
38280712Sian
39280712Sian/*  A number of pages in L1 page table. */
40280712Sian#define NPG_IN_PT1	(NB_IN_PT1 / PAGE_SIZE)
41280712Sian
42280712Sian/*  A number of L2 page tables in a page. */
43280712Sian#define NPT2_IN_PG	(PAGE_SIZE / NB_IN_PT2)
44280712Sian
45280712Sian/*  A number of L2 page table entries in a page. */
46280712Sian#define NPTE2_IN_PG	(NPT2_IN_PG * NPTE2_IN_PT2)
47280712Sian
48280712Sian#ifdef _KERNEL
49280712Sian
50280712Sian/*
51280712Sian *  A L2 page tables page contains NPT2_IN_PG L2 page tables. Masking of
52280712Sian *  pte1_idx by PT2PG_MASK gives us an index to associated L2 page table
53280712Sian *  in a page. The PT2PG_SHIFT definition depends on NPT2_IN_PG strictly.
54280712Sian *  I.e., (1 << PT2PG_SHIFT) == NPT2_IN_PG must be fulfilled.
55280712Sian */
56280712Sian#define PT2PG_SHIFT	2
57280712Sian#define PT2PG_MASK	((1 << PT2PG_SHIFT) - 1)
58280712Sian
59280712Sian/*
60280712Sian *  A PT2TAB holds all allocated L2 page table pages in a pmap.
61280712Sian *  Right shifting of virtual address by PT2TAB_SHIFT gives us an index
62280712Sian *  to L2 page table page in PT2TAB which holds the address mapping.
63280712Sian */
64280712Sian#define PT2TAB_ENTRIES  (NPTE1_IN_PT1 / NPT2_IN_PG)
65280712Sian#define PT2TAB_SHIFT	(PTE1_SHIFT + PT2PG_SHIFT)
66280712Sian
67280712Sian/*
68280712Sian *  All allocated L2 page table pages in a pmap are mapped into PT2MAP space.
69280712Sian *  An virtual address right shifting by PT2MAP_SHIFT gives us an index to PTE2
70280712Sian *  which maps the address.
71280712Sian */
72280712Sian#define PT2MAP_SIZE	(NPTE1_IN_PT1 * NB_IN_PT2)
73280712Sian#define PT2MAP_SHIFT	PTE2_SHIFT
74280712Sian
75280712Sianextern pt1_entry_t *kern_pt1;
76280712Sianextern pt2_entry_t *kern_pt2tab;
77280712Sianextern pt2_entry_t *PT2MAP;
78280712Sian
79280712Sian/*
80280712Sian *  Virtual interface for L1 page table management.
81280712Sian */
82280712Sian
83280712Sianstatic __inline u_int
84280712Sianpte1_index(vm_offset_t va)
85280712Sian{
86280712Sian
87280712Sian	return (va >> PTE1_SHIFT);
88280712Sian}
89280712Sian
90280712Sianstatic __inline pt1_entry_t *
91280712Sianpte1_ptr(pt1_entry_t *pt1, vm_offset_t va)
92280712Sian{
93280712Sian
94280712Sian	return (pt1 + pte1_index(va));
95280712Sian}
96280712Sian
97280712Sianstatic __inline vm_offset_t
98280712Sianpte1_trunc(vm_offset_t va)
99280712Sian{
100280712Sian
101280712Sian	return (va & PTE1_FRAME);
102280712Sian}
103280712Sian
104280712Sianstatic __inline vm_offset_t
105280712Sianpte1_roundup(vm_offset_t va)
106280712Sian{
107280712Sian
108280712Sian	return ((va + PTE1_OFFSET) & PTE1_FRAME);
109280712Sian}
110280712Sian
111280712Sian/*
112280712Sian *  Virtual interface for L1 page table entries management.
113280712Sian *
114280712Sian *  XXX: Some of the following functions now with a synchronization barrier
115280712Sian *  are called in a loop, so it could be useful to have two versions of them.
116280712Sian *  One with the barrier and one without the barrier. In this case, pure
117280712Sian *  barrier pte1_sync() should be implemented as well.
118280712Sian */
119280712Sianstatic __inline void
120280712Sianpte1_sync(pt1_entry_t *pte1p)
121280712Sian{
122280712Sian
123280712Sian	dsb();
124280712Sian#ifndef PMAP_PTE_NOCACHE
125280712Sian	if (!cpuinfo.coherent_walk)
126280712Sian		dcache_wb_pou((vm_offset_t)pte1p, sizeof(*pte1p));
127280712Sian#endif
128280712Sian}
129280712Sian
130280712Sianstatic __inline void
131280712Sianpte1_sync_range(pt1_entry_t *pte1p, vm_size_t size)
132280712Sian{
133280712Sian
134280712Sian	dsb();
135280712Sian#ifndef PMAP_PTE_NOCACHE
136280712Sian	if (!cpuinfo.coherent_walk)
137280712Sian		dcache_wb_pou((vm_offset_t)pte1p, size);
138280712Sian#endif
139280712Sian}
140280712Sian
141280712Sianstatic __inline void
142280712Sianpte1_store(pt1_entry_t *pte1p, pt1_entry_t pte1)
143280712Sian{
144280712Sian
145280712Sian	atomic_store_rel_int(pte1p, pte1);
146280712Sian	pte1_sync(pte1p);
147280712Sian}
148280712Sian
149280712Sianstatic __inline void
150280712Sianpte1_clear(pt1_entry_t *pte1p)
151280712Sian{
152280712Sian
153280712Sian	pte1_store(pte1p, 0);
154280712Sian}
155280712Sian
156280712Sianstatic __inline void
157280712Sianpte1_clear_bit(pt1_entry_t *pte1p, uint32_t bit)
158280712Sian{
159280712Sian
160280712Sian	atomic_clear_int(pte1p, bit);
161280712Sian	pte1_sync(pte1p);
162280712Sian}
163280712Sian
164280712Sianstatic __inline boolean_t
165280712Sianpte1_cmpset(pt1_entry_t *pte1p, pt1_entry_t opte1, pt1_entry_t npte1)
166280712Sian{
167280712Sian	boolean_t ret;
168280712Sian
169280712Sian	ret = atomic_cmpset_int(pte1p, opte1, npte1);
170280712Sian	if (ret) pte1_sync(pte1p);
171280712Sian
172280712Sian	return (ret);
173280712Sian}
174280712Sian
175280712Sianstatic __inline boolean_t
176280712Sianpte1_is_link(pt1_entry_t pte1)
177280712Sian{
178280712Sian
179280712Sian	return ((pte1 & L1_TYPE_MASK) == L1_TYPE_C);
180280712Sian}
181280712Sian
182280712Sianstatic __inline int
183280712Sianpte1_is_section(pt1_entry_t pte1)
184280712Sian{
185280712Sian
186280712Sian	return ((pte1 & L1_TYPE_MASK) == L1_TYPE_S);
187280712Sian}
188280712Sian
189280712Sianstatic __inline boolean_t
190280712Sianpte1_is_dirty(pt1_entry_t pte1)
191280712Sian{
192280712Sian
193280712Sian	return ((pte1 & (PTE1_NM | PTE1_RO)) == 0);
194280712Sian}
195280712Sian
196280712Sianstatic __inline boolean_t
197280712Sianpte1_is_global(pt1_entry_t pte1)
198280712Sian{
199280712Sian
200280712Sian	return ((pte1 & PTE1_NG) == 0);
201280712Sian}
202280712Sian
203280712Sianstatic __inline boolean_t
204280712Sianpte1_is_valid(pt1_entry_t pte1)
205280712Sian{
206280712Sian	int l1_type;
207280712Sian
208280712Sian	l1_type = pte1 & L1_TYPE_MASK;
209280712Sian	return ((l1_type == L1_TYPE_C) || (l1_type == L1_TYPE_S));
210280712Sian}
211280712Sian
212280712Sianstatic __inline boolean_t
213280712Sianpte1_is_wired(pt1_entry_t pte1)
214280712Sian{
215280712Sian
216280712Sian	return (pte1 & PTE1_W);
217280712Sian}
218280712Sian
219280712Sianstatic __inline pt1_entry_t
220280712Sianpte1_load(pt1_entry_t *pte1p)
221280712Sian{
222280712Sian	pt1_entry_t pte1;
223280712Sian
224280712Sian	pte1 = *pte1p;
225280712Sian	return (pte1);
226280712Sian}
227280712Sian
228280712Sianstatic __inline pt1_entry_t
229280712Sianpte1_load_clear(pt1_entry_t *pte1p)
230280712Sian{
231280712Sian	pt1_entry_t opte1;
232280712Sian
233280712Sian	opte1 = atomic_readandclear_int(pte1p);
234280712Sian	pte1_sync(pte1p);
235280712Sian	return (opte1);
236280712Sian}
237280712Sian
238280712Sianstatic __inline void
239280712Sianpte1_set_bit(pt1_entry_t *pte1p, uint32_t bit)
240280712Sian{
241280712Sian
242280712Sian	atomic_set_int(pte1p, bit);
243280712Sian	pte1_sync(pte1p);
244280712Sian}
245280712Sian
246280712Sianstatic __inline vm_paddr_t
247280712Sianpte1_pa(pt1_entry_t pte1)
248280712Sian{
249280712Sian
250280712Sian	return ((vm_paddr_t)(pte1 & PTE1_FRAME));
251280712Sian}
252280712Sian
253280712Sianstatic __inline vm_paddr_t
254280712Sianpte1_link_pa(pt1_entry_t pte1)
255280712Sian{
256280712Sian
257280712Sian	return ((vm_paddr_t)(pte1 & L1_C_ADDR_MASK));
258280712Sian}
259280712Sian
260280712Sian/*
261280712Sian *  Virtual interface for L2 page table entries management.
262280712Sian *
263280712Sian *  XXX: Some of the following functions now with a synchronization barrier
264280712Sian *  are called in a loop, so it could be useful to have two versions of them.
265280712Sian *  One with the barrier and one without the barrier.
266280712Sian */
267280712Sian
268280712Sianstatic __inline void
269280712Sianpte2_sync(pt2_entry_t *pte2p)
270280712Sian{
271280712Sian
272280712Sian	dsb();
273280712Sian#ifndef PMAP_PTE_NOCACHE
274280712Sian	if (!cpuinfo.coherent_walk)
275280712Sian		dcache_wb_pou((vm_offset_t)pte2p, sizeof(*pte2p));
276280712Sian#endif
277280712Sian}
278280712Sian
279280712Sianstatic __inline void
280280712Sianpte2_sync_range(pt2_entry_t *pte2p, vm_size_t size)
281280712Sian{
282280712Sian
283280712Sian	dsb();
284280712Sian#ifndef PMAP_PTE_NOCACHE
285280712Sian	if (!cpuinfo.coherent_walk)
286280712Sian		dcache_wb_pou((vm_offset_t)pte2p, size);
287280712Sian#endif
288280712Sian}
289280712Sian
290280712Sianstatic __inline void
291280712Sianpte2_store(pt2_entry_t *pte2p, pt2_entry_t pte2)
292280712Sian{
293280712Sian
294280712Sian	atomic_store_rel_int(pte2p, pte2);
295280712Sian	pte2_sync(pte2p);
296280712Sian}
297280712Sian
298280712Sianstatic __inline void
299280712Sianpte2_clear(pt2_entry_t *pte2p)
300280712Sian{
301280712Sian
302280712Sian	pte2_store(pte2p, 0);
303280712Sian}
304280712Sian
305280712Sianstatic __inline void
306280712Sianpte2_clear_bit(pt2_entry_t *pte2p, uint32_t bit)
307280712Sian{
308280712Sian
309280712Sian	atomic_clear_int(pte2p, bit);
310280712Sian	pte2_sync(pte2p);
311280712Sian}
312280712Sian
313280712Sianstatic __inline boolean_t
314280712Sianpte2_cmpset(pt2_entry_t *pte2p, pt2_entry_t opte2, pt2_entry_t npte2)
315280712Sian{
316280712Sian	boolean_t ret;
317280712Sian
318280712Sian	ret = atomic_cmpset_int(pte2p, opte2, npte2);
319280712Sian	if (ret) pte2_sync(pte2p);
320280712Sian
321280712Sian	return (ret);
322280712Sian}
323280712Sian
324280712Sianstatic __inline boolean_t
325280712Sianpte2_is_dirty(pt2_entry_t pte2)
326280712Sian{
327280712Sian
328280712Sian	return ((pte2 & (PTE2_NM | PTE2_RO)) == 0);
329280712Sian}
330280712Sian
331280712Sianstatic __inline boolean_t
332280712Sianpte2_is_global(pt2_entry_t pte2)
333280712Sian{
334280712Sian
335280712Sian	return ((pte2 & PTE2_NG) == 0);
336280712Sian}
337280712Sian
338280712Sianstatic __inline boolean_t
339280712Sianpte2_is_valid(pt2_entry_t pte2)
340280712Sian{
341280712Sian
342280712Sian	return (pte2 & PTE2_V);
343280712Sian}
344280712Sian
345280712Sianstatic __inline boolean_t
346280712Sianpte2_is_wired(pt2_entry_t pte2)
347280712Sian{
348280712Sian
349280712Sian	return (pte2 & PTE2_W);
350280712Sian}
351280712Sian
352280712Sianstatic __inline pt2_entry_t
353280712Sianpte2_load(pt2_entry_t *pte2p)
354280712Sian{
355280712Sian	pt2_entry_t pte2;
356280712Sian
357280712Sian	pte2 = *pte2p;
358280712Sian	return (pte2);
359280712Sian}
360280712Sian
361280712Sianstatic __inline pt2_entry_t
362280712Sianpte2_load_clear(pt2_entry_t *pte2p)
363280712Sian{
364280712Sian	pt2_entry_t opte2;
365280712Sian
366280712Sian	opte2 = atomic_readandclear_int(pte2p);
367280712Sian	pte2_sync(pte2p);
368280712Sian	return (opte2);
369280712Sian}
370280712Sian
371280712Sianstatic __inline void
372280712Sianpte2_set_bit(pt2_entry_t *pte2p, uint32_t bit)
373280712Sian{
374280712Sian
375280712Sian	atomic_set_int(pte2p, bit);
376280712Sian	pte2_sync(pte2p);
377280712Sian}
378280712Sian
379280712Sianstatic __inline void
380280712Sianpte2_set_wired(pt2_entry_t *pte2p, boolean_t wired)
381280712Sian{
382280712Sian
383280712Sian	/*
384280712Sian	 * Wired bit is transparent for page table walk,
385280712Sian	 * so pte2_sync() is not needed.
386280712Sian	 */
387280712Sian	if (wired)
388280712Sian		atomic_set_int(pte2p, PTE2_W);
389280712Sian	else
390280712Sian		atomic_clear_int(pte2p, PTE2_W);
391280712Sian}
392280712Sian
393280712Sianstatic __inline vm_paddr_t
394280712Sianpte2_pa(pt2_entry_t pte2)
395280712Sian{
396280712Sian
397280712Sian	return ((vm_paddr_t)(pte2 & PTE2_FRAME));
398280712Sian}
399280712Sian
400280712Sianstatic __inline u_int
401280712Sianpte2_attr(pt2_entry_t pte2)
402280712Sian{
403280712Sian
404280712Sian	return ((u_int)(pte2 & PTE2_ATTR_MASK));
405280712Sian}
406280712Sian
407280712Sian/*
408280712Sian *  Virtual interface for L2 page tables mapping management.
409280712Sian */
410280712Sian
411280712Sianstatic __inline u_int
412280712Sianpt2tab_index(vm_offset_t va)
413280712Sian{
414280712Sian
415280712Sian	return (va >> PT2TAB_SHIFT);
416280712Sian}
417280712Sian
418280712Sianstatic __inline pt2_entry_t *
419280712Sianpt2tab_entry(pt2_entry_t *pt2tab, vm_offset_t va)
420280712Sian{
421280712Sian
422280712Sian	return (pt2tab + pt2tab_index(va));
423280712Sian}
424280712Sian
425280712Sianstatic __inline void
426280712Sianpt2tab_store(pt2_entry_t *pte2p, pt2_entry_t pte2)
427280712Sian{
428280712Sian
429280712Sian	pte2_store(pte2p,pte2);
430280712Sian}
431280712Sian
432280712Sianstatic __inline pt2_entry_t
433280712Sianpt2tab_load(pt2_entry_t *pte2p)
434280712Sian{
435280712Sian
436280712Sian	return (pte2_load(pte2p));
437280712Sian}
438280712Sian
439280712Sianstatic __inline pt2_entry_t
440280712Sianpt2tab_load_clear(pt2_entry_t *pte2p)
441280712Sian{
442280712Sian
443280712Sian	return (pte2_load_clear(pte2p));
444280712Sian}
445280712Sian
446280712Sianstatic __inline u_int
447280712Sianpt2map_index(vm_offset_t va)
448280712Sian{
449280712Sian
450280712Sian	return (va >> PT2MAP_SHIFT);
451280712Sian}
452280712Sian
453280712Sianstatic __inline pt2_entry_t *
454280712Sianpt2map_entry(vm_offset_t va)
455280712Sian{
456280712Sian
457280712Sian	return (PT2MAP + pt2map_index(va));
458280712Sian}
459280712Sian
460280712Sian/*
461280712Sian *  Virtual interface for pmap structure & kernel shortcuts.
462280712Sian */
463280712Sian
464280712Sianstatic __inline pt1_entry_t *
465280712Sianpmap_pte1(pmap_t pmap, vm_offset_t va)
466280712Sian{
467280712Sian
468280712Sian	return (pte1_ptr(pmap->pm_pt1, va));
469280712Sian}
470280712Sian
471280712Sianstatic __inline pt1_entry_t *
472280712Siankern_pte1(vm_offset_t va)
473280712Sian{
474280712Sian
475280712Sian	return (pte1_ptr(kern_pt1, va));
476280712Sian}
477280712Sian
478280712Sianstatic __inline pt2_entry_t *
479280712Sianpmap_pt2tab_entry(pmap_t pmap, vm_offset_t va)
480280712Sian{
481280712Sian
482280712Sian	return (pt2tab_entry(pmap->pm_pt2tab, va));
483280712Sian}
484280712Sian
485280712Sianstatic __inline pt2_entry_t *
486280712Siankern_pt2tab_entry(vm_offset_t va)
487280712Sian{
488280712Sian
489280712Sian	return (pt2tab_entry(kern_pt2tab, va));
490280712Sian}
491280712Sian
492280712Sianstatic __inline vm_page_t
493280712Sianpmap_pt2_page(pmap_t pmap, vm_offset_t va)
494280712Sian{
495280712Sian	pt2_entry_t pte2;
496280712Sian
497280712Sian	pte2 = pte2_load(pmap_pt2tab_entry(pmap, va));
498280712Sian	return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME));
499280712Sian}
500280712Sian
501280712Sianstatic __inline vm_page_t
502280712Siankern_pt2_page(vm_offset_t va)
503280712Sian{
504280712Sian	pt2_entry_t pte2;
505280712Sian
506280712Sian	pte2 = pte2_load(kern_pt2tab_entry(va));
507280712Sian	return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME));
508280712Sian}
509280712Sian
510280712Sian#endif	/* _KERNEL */
511280712Sian#endif	/* !_MACHINE_PMAP_VAR_H_ */
512