xref: /xnu-8792.61.2/osfmk/arm/pmap/pmap_pt_geometry.h (revision 42e220869062b56f8d7d0726fd4c88954f87902c)
1 /*
2  * Copyright (c) 2020 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /**
29  * PMAP Page Table Geometry.
30  *
31  * This header file is used to store the types, and inline functions related to
32  * retrieving information about and parsing page table hierarchies.
33  *
34  * To prevent circular dependencies, this file shouldn't include any of the
35  * other internal osfmk/arm/pmap/ header files.
36  */
37 #ifndef _ARM_PMAP_PMAP_PT_GEOMETRY_H_
38 #define _ARM_PMAP_PMAP_PT_GEOMETRY_H_
39 
40 #include <stdint.h>
41 
42 #include <kern/debug.h>
43 #include <kern/locks.h>
44 #include <mach/vm_types.h>
45 #include <mach_assert.h>
46 
47 #include <arm64/proc_reg.h>
48 
49 /**
50  * arm/pmap.h is safe to be included in this file since it shouldn't rely on any
51  * of the internal pmap header files (so no circular dependencies).
52  */
53 #include <arm/pmap.h>
54 
55 /**
56  * Structure representing parameters of a single page table level. An array of
57  * these structures are used to represent the geometry for an entire page table
58  * hierarchy.
59  */
60 struct page_table_level_info {
61 	const uint64_t size;
62 	const uint64_t offmask;
63 	const uint64_t shift;
64 	const uint64_t index_mask;
65 	const uint64_t valid_mask;
66 	const uint64_t type_mask;
67 	const uint64_t type_block;
68 };
69 
70 /**
71  * Operations that are dependent on the type of page table. This is useful, for
72  * instance, when dealing with stage 1 vs stage 2 pmaps.
73  */
74 struct page_table_ops {
75 	bool (*alloc_id)(pmap_t pmap);
76 	void (*free_id)(pmap_t pmap);
77 	void (*flush_tlb_region_async)(vm_offset_t va, size_t length, pmap_t pmap, bool last_level_only);
78 	void (*flush_tlb_async)(pmap_t pmap);
79 	pt_entry_t (*wimg_to_pte)(unsigned int wimg, pmap_paddr_t pa);
80 };
81 
82 /**
83  * The Page Table Attribute structure is used for both parameterizing the
84  * different possible page table geometries, but also for abstracting out the
85  * differences between stage 1 and stage 2 page tables. This allows one set of
86  * code to seamlessly handle the differences between various address space
87  * layouts as well as stage 1 vs stage 2 page tables on the fly. See
88  * doc/arm_pmap.md for more details.
89  *
90  * Instead of accessing the fields in this structure directly, it is recommended
91  * to use the page table attribute getter functions defined below.
92  */
93 struct page_table_attr {
94 	/* Sizes and offsets for each level in the page table hierarchy. */
95 	const struct page_table_level_info * const pta_level_info;
96 
97 	/* Operations that are dependent on the type of page table. */
98 	const struct page_table_ops * const pta_ops;
99 
100 	/**
101 	 * The Access Permissions bits have different layouts within a page table
102 	 * entry depending on whether it's an entry for a stage 1 or stage 2 pmap.
103 	 *
104 	 * These fields describe the correct PTE bits to set to get the wanted
105 	 * permissions for the page tables described by this attribute structure.
106 	 */
107 	const uintptr_t ap_ro;
108 	const uintptr_t ap_rw;
109 	const uintptr_t ap_rona;
110 	const uintptr_t ap_rwna;
111 	const uintptr_t ap_xn;
112 	const uintptr_t ap_x;
113 
114 	/* The page table level at which the hierarchy begins. */
115 	const unsigned int pta_root_level;
116 
117 	/* The page table level at which the commpage is nested into an address space. */
118 	const unsigned int pta_commpage_level;
119 
120 	/* The last level in the page table hierarchy (ARM supports up to four levels). */
121 	const unsigned int pta_max_level;
122 
123 
124 #if __ARM_MIXED_PAGE_SIZE__
125 	/**
126 	 * Value to set the Translation Control Register (TCR) to in order to inform
127 	 * the hardware of this page table geometry.
128 	 */
129 	const uint64_t pta_tcr_value;
130 #endif /* __ARM_MIXED_PAGE_SIZE__ */
131 
132 	/* Page Table/Granule Size. */
133 	const uint64_t pta_page_size;
134 
135 	/**
136 	 * How many bits to shift "1" by to get the page table size. Alternatively,
137 	 * could also be thought of as how many bits make up the page offset in a
138 	 * virtual address.
139 	 */
140 	const uint64_t pta_page_shift;
141 };
142 
143 typedef struct page_table_attr pt_attr_t;
144 
145 /* The default page table attributes for a system. */
146 extern const struct page_table_attr * const native_pt_attr;
147 
148 /**
149  * Macros for getting pmap attributes/operations; not functions for const
150  * propagation.
151  */
152 #if ARM_PARAMETERIZED_PMAP
153 
154 /* The page table attributes are linked to the pmap */
155 #define pmap_get_pt_attr(pmap) ((pmap)->pmap_pt_attr)
156 #define pmap_get_pt_ops(pmap) ((pmap)->pmap_pt_attr->pta_ops)
157 
158 #else /* ARM_PARAMETERIZED_PMAP */
159 
160 /* The page table attributes are fixed (to allow for const propagation) */
161 #define pmap_get_pt_attr(pmap) (native_pt_attr)
162 #define pmap_get_pt_ops(pmap) (&native_pt_ops)
163 
164 #endif /* ARM_PARAMETERIZED_PMAP */
165 
166 /* Defines representing a level in a page table hierarchy. */
167 #define PMAP_TT_L0_LEVEL 0x0
168 #define PMAP_TT_L1_LEVEL 0x1
169 #define PMAP_TT_L2_LEVEL 0x2
170 #define PMAP_TT_L3_LEVEL 0x3
171 
172 /**
173  * Inline functions exported for usage by other pmap modules.
174  *
175  * In an effort to not cause any performance regressions while breaking up the
176  * pmap, I'm keeping all functions originally marked as "static inline", as
177  * inline and moving them into header files to be shared across the pmap
178  * modules. In reality, many of these functions probably don't need to be inline
179  * and can be moved back into a .c file.
180  *
181  * TODO: rdar://70538514 (PMAP Cleanup: re-evaluate whether inline functions should actually be inline)
182  */
183 
184 /**
185  * Keep the following in mind when looking at the available attribute getters:
186  *
187  * We tend to use standard terms to describe various levels in a page table
188  * hierarchy. The "root" level is the top of a hierarchy. The root page table is
189  * the one that will programmed into the Translation Table Base Register (TTBR)
190  * to inform the hardware of where to begin when performing page table walks.
191  * The "twig" level is always one up from the last level, and the "leaf" level
192  * is the last page table level in a hierarchy. The leaf page tables always
193  * contain block entries, but the higher levels can contain either table or
194  * block entries.
195  *
196  * ARM supports up to four levels of page tables. The levels start at L0 and
197  * increase to L3 the deeper into a hierarchy you get, although L0 isn't
198  * necessarily always the root level. For example, in a four-level hierarchy,
199  * the root would be L0, the twig would be L2, and the leaf would be L3. But for
200  * a three-level hierarchy, the root would be L1, the twig would be L2, and the
201  * leaf would be L3.
202  */
203 /* Page size getter. */
204 static inline uint64_t
pt_attr_page_size(const pt_attr_t * const pt_attr)205 pt_attr_page_size(const pt_attr_t * const pt_attr)
206 {
207 	return pt_attr->pta_page_size;
208 }
209 
210 /**
211  * Return the size of the virtual address space covered by a single TTE at a
212  * specified level in the hierarchy.
213  */
214 __unused static inline uint64_t
pt_attr_ln_size(const pt_attr_t * const pt_attr,unsigned int level)215 pt_attr_ln_size(const pt_attr_t * const pt_attr, unsigned int level)
216 {
217 	return pt_attr->pta_level_info[level].size;
218 }
219 
220 /**
221  * Return the page descriptor shift for a specified level in the hierarchy. This
222  * shift value can be used to get the index into a page table at this level in
223  * the hierarchy from a given virtual address.
224  */
225 __unused static inline uint64_t
pt_attr_ln_shift(const pt_attr_t * const pt_attr,unsigned int level)226 pt_attr_ln_shift(const pt_attr_t * const pt_attr, unsigned int level)
227 {
228 	return pt_attr->pta_level_info[level].shift;
229 }
230 
231 /**
232  * Return a mask of the offset for a specified level in the hierarchy.
233  *
234  * This should be equivalent to the value returned by pt_attr_ln_size() - 1.
235  */
236 static inline uint64_t
pt_attr_ln_offmask(const pt_attr_t * const pt_attr,unsigned int level)237 pt_attr_ln_offmask(const pt_attr_t * const pt_attr, unsigned int level)
238 {
239 	return pt_attr->pta_level_info[level].offmask;
240 }
241 
242 /**
243  * Return the mask for getting a page table index out of a virtual address for a
244  * specified level in the hierarchy. This can be combined with the value
245  * returned by pt_attr_ln_shift() to get the index into a page table.
246  */
247 __unused static inline uint64_t
pt_attr_ln_index_mask(const pt_attr_t * const pt_attr,unsigned int level)248 pt_attr_ln_index_mask(const pt_attr_t * const pt_attr, unsigned int level)
249 {
250 	return pt_attr->pta_level_info[level].index_mask;
251 }
252 
253 /**
254  * Return the second to last page table level.
255  */
256 static inline unsigned int
pt_attr_twig_level(const pt_attr_t * const pt_attr)257 pt_attr_twig_level(const pt_attr_t * const pt_attr)
258 {
259 	return pt_attr->pta_max_level - 1;
260 }
261 
262 /**
263  * Return the first page table level. This is what will be programmed into the
264  * Translation Table Base Register (TTBR) to inform the hardware of where to
265  * begin page table walks.
266  */
267 static inline unsigned int
pt_attr_root_level(const pt_attr_t * const pt_attr)268 pt_attr_root_level(const pt_attr_t * const pt_attr)
269 {
270 	return pt_attr->pta_root_level;
271 }
272 
273 /**
274  * Return the level at which to nest the commpage pmap into userspace pmaps.
275  * Since the commpage is shared across all userspace address maps, memory is
276  * saved by sharing the commpage page tables with every userspace pmap. The
277  * level at which to nest the commpage is dependent on the page table geometry.
278  *
279  * Typically this is L1 for 4KB page tables, and L2 for 16KB page tables. In
280  * this way, the commpage's L2/L3 page tables are reused in every 4KB task, and
281  * the L3 page table is reused in every 16KB task.
282  */
283 static inline unsigned int
pt_attr_commpage_level(const pt_attr_t * const pt_attr)284 pt_attr_commpage_level(const pt_attr_t * const pt_attr)
285 {
286 	return pt_attr->pta_commpage_level;
287 }
288 
289 /**
290  * Return the size of the virtual address space covered by a single PTE at the
291  * leaf level.
292  */
293 static __unused inline uint64_t
pt_attr_leaf_size(const pt_attr_t * const pt_attr)294 pt_attr_leaf_size(const pt_attr_t * const pt_attr)
295 {
296 	return pt_attr->pta_level_info[pt_attr->pta_max_level].size;
297 }
298 
299 /**
300  * Return a mask of the offset for a leaf table.
301  *
302  * This should be equivalent to the value returned by pt_attr_leaf_size() - 1.
303  */
304 static __unused inline uint64_t
pt_attr_leaf_offmask(const pt_attr_t * const pt_attr)305 pt_attr_leaf_offmask(const pt_attr_t * const pt_attr)
306 {
307 	return pt_attr->pta_level_info[pt_attr->pta_max_level].offmask;
308 }
309 
310 /**
311  * Return the page descriptor shift for a leaf table entry. This shift value can
312  * be used to get the index into a leaf page table from a given virtual address.
313  */
314 static inline uint64_t
pt_attr_leaf_shift(const pt_attr_t * const pt_attr)315 pt_attr_leaf_shift(const pt_attr_t * const pt_attr)
316 {
317 	return pt_attr->pta_level_info[pt_attr->pta_max_level].shift;
318 }
319 
320 /**
321  * Return the mask for getting a leaf table index out of a virtual address. This
322  * can be combined with the value returned by pt_attr_leaf_shift() to get the
323  * index into a leaf table.
324  */
325 static __unused inline uint64_t
pt_attr_leaf_index_mask(const pt_attr_t * const pt_attr)326 pt_attr_leaf_index_mask(const pt_attr_t * const pt_attr)
327 {
328 	return pt_attr->pta_level_info[pt_attr->pta_max_level].index_mask;
329 }
330 
331 /**
332  * Return the size of the virtual address space covered by a single TTE at the
333  * twig level.
334  */
335 static inline uint64_t
pt_attr_twig_size(const pt_attr_t * const pt_attr)336 pt_attr_twig_size(const pt_attr_t * const pt_attr)
337 {
338 	return pt_attr->pta_level_info[pt_attr->pta_max_level - 1].size;
339 }
340 
341 /**
342  * Return a mask of the offset for a twig table.
343  *
344  * This should be equivalent to the value returned by pt_attr_twig_size() - 1.
345  */
346 static inline uint64_t
pt_attr_twig_offmask(const pt_attr_t * const pt_attr)347 pt_attr_twig_offmask(const pt_attr_t * const pt_attr)
348 {
349 	return pt_attr->pta_level_info[pt_attr->pta_max_level - 1].offmask;
350 }
351 
352 /**
353  * Return the page descriptor shift for a twig table entry. This shift value can
354  * be used to get the index into a twig page table from a given virtual address.
355  */
356 static inline uint64_t
pt_attr_twig_shift(const pt_attr_t * const pt_attr)357 pt_attr_twig_shift(const pt_attr_t * const pt_attr)
358 {
359 	return pt_attr->pta_level_info[pt_attr->pta_max_level - 1].shift;
360 }
361 
362 /**
363  * Return the mask for getting a twig table index out of a virtual address. This
364  * can be combined with the value returned by pt_attr_twig_shift() to get the
365  * index into a twig table.
366  */
367 static __unused inline uint64_t
pt_attr_twig_index_mask(const pt_attr_t * const pt_attr)368 pt_attr_twig_index_mask(const pt_attr_t * const pt_attr)
369 {
370 	return pt_attr->pta_level_info[pt_attr->pta_max_level - 1].index_mask;
371 }
372 
373 /**
374  * Return the amount of memory that a leaf table takes up. This is equivalent
375  * to the amount of virtual address space covered by a single twig TTE.
376  */
377 static inline uint64_t
pt_attr_leaf_table_size(const pt_attr_t * const pt_attr)378 pt_attr_leaf_table_size(const pt_attr_t * const pt_attr)
379 {
380 	return pt_attr_twig_size(pt_attr);
381 }
382 
383 /**
384  * Return the offset mask for the memory used by a leaf page table.
385  *
386  * This should be equivalent to the value returned by pt_attr_twig_size() - 1.
387  */
388 static inline uint64_t
pt_attr_leaf_table_offmask(const pt_attr_t * const pt_attr)389 pt_attr_leaf_table_offmask(const pt_attr_t * const pt_attr)
390 {
391 	return pt_attr_twig_offmask(pt_attr);
392 }
393 
394 /**
395  * Return the Access Permissions bits required to specify User and Kernel
396  * Read/Write permissions on a PTE in this type of page table hierarchy (stage 1
397  * vs stage 2).
398  */
399 static inline uintptr_t
pt_attr_leaf_rw(const pt_attr_t * const pt_attr)400 pt_attr_leaf_rw(const pt_attr_t * const pt_attr)
401 {
402 	return pt_attr->ap_rw;
403 }
404 
405 /**
406  * Return the Access Permissions bits required to specify User and Kernel
407  * Read-Only permissions on a PTE in this type of page table hierarchy (stage 1
408  * vs stage 2).
409  */
410 static inline uintptr_t
pt_attr_leaf_ro(const pt_attr_t * const pt_attr)411 pt_attr_leaf_ro(const pt_attr_t * const pt_attr)
412 {
413 	return pt_attr->ap_ro;
414 }
415 
416 /**
417  * Return the Access Permissions bits required to specify just Kernel Read-Only
418  * permissions on a PTE in this type of page table hierarchy (stage 1 vs stage
419  * 2).
420  */
421 static inline uintptr_t
pt_attr_leaf_rona(const pt_attr_t * const pt_attr)422 pt_attr_leaf_rona(const pt_attr_t * const pt_attr)
423 {
424 	return pt_attr->ap_rona;
425 }
426 
427 /**
428  * Return the Access Permissions bits required to specify just Kernel Read/Write
429  * permissions on a PTE in this type of page table hierarchy (stage 1 vs stage
430  * 2).
431  */
432 static inline uintptr_t
pt_attr_leaf_rwna(const pt_attr_t * const pt_attr)433 pt_attr_leaf_rwna(const pt_attr_t * const pt_attr)
434 {
435 	return pt_attr->ap_rwna;
436 }
437 
438 /**
439  * Return the mask of the page table entry bits required to set both the
440  * privileged and unprivileged execute never bits.
441  */
442 static inline uintptr_t
pt_attr_leaf_xn(const pt_attr_t * const pt_attr)443 pt_attr_leaf_xn(const pt_attr_t * const pt_attr)
444 {
445 	return pt_attr->ap_xn;
446 }
447 
448 /**
449  * Return the mask of the page table entry bits required to set just the
450  * privileged execute never bit.
451  */
452 static inline uintptr_t
pt_attr_leaf_x(const pt_attr_t * const pt_attr)453 pt_attr_leaf_x(const pt_attr_t * const pt_attr)
454 {
455 	return pt_attr->ap_x;
456 }
457 
458 
459 /**
460  * Return the last level in the page table hierarchy.
461  */
462 static inline unsigned int
pt_attr_leaf_level(const pt_attr_t * const pt_attr)463 pt_attr_leaf_level(const pt_attr_t * const pt_attr)
464 {
465 	return pt_attr_twig_level(pt_attr) + 1;
466 }
467 
468 
469 /**
470  * Return the index into a specific level of page table for a given virtual
471  * address.
472  *
473  * @param pt_attr Page table attribute structure describing the hierarchy.
474  * @param addr The virtual address to get the index from.
475  * @param pt_level The page table whose index should be returned.
476  */
477 static inline unsigned int
ttn_index(const pt_attr_t * const pt_attr,vm_map_address_t addr,unsigned int pt_level)478 ttn_index(const pt_attr_t * const pt_attr, vm_map_address_t addr, unsigned int pt_level)
479 {
480 	const uint64_t index_unshifted = addr & pt_attr_ln_index_mask(pt_attr, pt_level);
481 	return (unsigned int)(index_unshifted >> pt_attr_ln_shift(pt_attr, pt_level));
482 }
483 
484 /**
485  * Return the index into a twig page table for a given virtual address.
486  *
487  * @param pt_attr Page table attribute structure describing the hierarchy.
488  * @param addr The virtual address to get the index from.
489  */
490 static inline unsigned int
tte_index(const pt_attr_t * const pt_attr,vm_map_address_t addr)491 tte_index(const pt_attr_t * const pt_attr, vm_map_address_t addr)
492 {
493 	return ttn_index(pt_attr, addr, PMAP_TT_L2_LEVEL);
494 }
495 
496 /**
497  * Return the index into a leaf page table for a given virtual address.
498  *
499  * @param pt_attr Page table attribute structure describing the hierarchy.
500  * @param addr The virtual address to get the index from.
501  */
502 static inline unsigned int
pte_index(const pt_attr_t * const pt_attr,vm_map_address_t addr)503 pte_index(const pt_attr_t * const pt_attr, vm_map_address_t addr)
504 {
505 	return ttn_index(pt_attr, addr, PMAP_TT_L3_LEVEL);
506 }
507 
508 
509 
510 /**
511  * Given an address and a map, compute the address of the table entry at the
512  * specified page table level. If the address is invalid with respect to the map
513  * then TT_ENTRY_NULL is returned.
514  *
515  * @param pmap The pmap whose page tables to parse.
516  * @param target_level The page table level at which to stop parsing the
517  *                     hierarchy at.
518  * @param addr The virtual address to calculate the table indices off of.
519  */
520 static inline tt_entry_t *
pmap_ttne(pmap_t pmap,unsigned int target_level,vm_map_address_t addr)521 pmap_ttne(pmap_t pmap, unsigned int target_level, vm_map_address_t addr)
522 {
523 	tt_entry_t *table_ttep = TT_ENTRY_NULL;
524 	tt_entry_t *ttep = TT_ENTRY_NULL;
525 	tt_entry_t tte = ARM_TTE_EMPTY;
526 	unsigned int cur_level;
527 
528 	const pt_attr_t * const pt_attr = pmap_get_pt_attr(pmap);
529 
530 	if (__improbable((addr < pmap->min) || (addr >= pmap->max))) {
531 		return TT_ENTRY_NULL;
532 	}
533 	/* Start parsing at the root page table. */
534 	table_ttep = pmap->tte;
535 
536 	assert(target_level <= pt_attr->pta_max_level);
537 
538 	for (cur_level = pt_attr->pta_root_level; cur_level <= target_level; cur_level++) {
539 		ttep = &table_ttep[ttn_index(pt_attr, addr, cur_level)];
540 
541 		if (cur_level == target_level) {
542 			break;
543 		}
544 
545 		tte = *ttep;
546 
547 #if MACH_ASSERT
548 		if ((tte & (ARM_TTE_TYPE_MASK | ARM_TTE_VALID)) == (ARM_TTE_TYPE_BLOCK | ARM_TTE_VALID)) {
549 			panic("%s: Attempt to demote L%u block, tte=0x%llx, pmap=%p, target_level=%u, addr=%p",
550 			    __func__, cur_level, tte, pmap, target_level, (void*)addr);
551 		}
552 #endif
553 		if ((tte & (ARM_TTE_TYPE_MASK | ARM_TTE_VALID)) != (ARM_TTE_TYPE_TABLE | ARM_TTE_VALID)) {
554 			return TT_ENTRY_NULL;
555 		}
556 
557 		table_ttep = (tt_entry_t*)phystokv(tte & ARM_TTE_TABLE_MASK);
558 	}
559 
560 	return ttep;
561 }
562 
563 /**
564  * Given an address and a map, compute the address of the level 1 translation
565  * table entry. If the address is invalid with respect to the map then
566  * TT_ENTRY_NULL is returned.
567  *
568  * @param pmap The pmap whose page tables to parse.
569  * @param addr The virtual address to calculate the table indices off of.
570  */
571 static inline tt_entry_t *
pmap_tt1e(pmap_t pmap,vm_map_address_t addr)572 pmap_tt1e(pmap_t pmap, vm_map_address_t addr)
573 {
574 	return pmap_ttne(pmap, PMAP_TT_L1_LEVEL, addr);
575 }
576 
577 /**
578  * Given an address and a map, compute the address of the level 2 translation
579  * table entry. If the address is invalid with respect to the map then
580  * TT_ENTRY_NULL is returned.
581  *
582  * @param pmap The pmap whose page tables to parse.
583  * @param addr The virtual address to calculate the table indices off of.
584  */
585 static inline tt_entry_t *
pmap_tt2e(pmap_t pmap,vm_map_address_t addr)586 pmap_tt2e(pmap_t pmap, vm_map_address_t addr)
587 {
588 	return pmap_ttne(pmap, PMAP_TT_L2_LEVEL, addr);
589 }
590 
591 /**
592  * Given an address and a map, compute the address of the level 3 page table
593  * entry. If the address is invalid with respect to the map then PT_ENTRY_NULL
594  * is returned.
595  *
596  * @param pmap The pmap whose page tables to parse.
597  * @param addr The virtual address to calculate the table indices off of.
598  */
599 static inline pt_entry_t *
pmap_tt3e(pmap_t pmap,vm_map_address_t addr)600 pmap_tt3e(pmap_t pmap, vm_map_address_t addr)
601 {
602 	return (pt_entry_t*)pmap_ttne(pmap, PMAP_TT_L3_LEVEL, addr);
603 }
604 
605 /**
606  * Given an address and a map, compute the address of the twig translation table
607  * entry. If the address is invalid with respect to the map then TT_ENTRY_NULL
608  * is returned.
609  *
610  * @param pmap The pmap whose page tables to parse.
611  * @param addr The virtual address to calculate the table indices off of.
612  */
613 static inline tt_entry_t *
pmap_tte(pmap_t pmap,vm_map_address_t addr)614 pmap_tte(pmap_t pmap, vm_map_address_t addr)
615 {
616 	return pmap_tt2e(pmap, addr);
617 }
618 
619 /**
620  * Given an address and a map, compute the address of the leaf page table entry.
621  * If the address is invalid with respect to the map then PT_ENTRY_NULL is
622  * returned.
623  *
624  * @param pmap The pmap whose page tables to parse.
625  * @param addr The virtual address to calculate the table indices off of.
626  */
627 static inline pt_entry_t *
pmap_pte(pmap_t pmap,vm_map_address_t addr)628 pmap_pte(pmap_t pmap, vm_map_address_t addr)
629 {
630 	return pmap_tt3e(pmap, addr);
631 }
632 
633 
634 #endif /* _ARM_PMAP_PMAP_PT_GEOMETRY_H_ */
635