diff options
Diffstat (limited to 'sys/arm/include/pmap_var.h')
-rw-r--r-- | sys/arm/include/pmap_var.h | 492 |
1 files changed, 492 insertions, 0 deletions
diff --git a/sys/arm/include/pmap_var.h b/sys/arm/include/pmap_var.h new file mode 100644 index 000000000000..9a200dcc9529 --- /dev/null +++ b/sys/arm/include/pmap_var.h @@ -0,0 +1,492 @@ +/*- + * Copyright 2014 Svatopluk Kraus <onwahe@gmail.com> + * Copyright 2014 Michal Meloun <meloun@miracle.cz> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MACHINE_PMAP_VAR_H_ +#define _MACHINE_PMAP_VAR_H_ + +#include <machine/pte.h> + +/* + * Various PMAP defines, exports, and inline functions + * definitions also usable in other MD code. + */ + +/* A number of pages in L1 page table. */ +#define NPG_IN_PT1 (NB_IN_PT1 / PAGE_SIZE) + +/* A number of L2 page tables in a page. */ +#define NPT2_IN_PG (PAGE_SIZE / NB_IN_PT2) + +/* A number of L2 page table entries in a page. */ +#define NPTE2_IN_PG (NPT2_IN_PG * NPTE2_IN_PT2) + +#ifdef _KERNEL + +/* + * A L2 page tables page contains NPT2_IN_PG L2 page tables. Masking of + * pte1_idx by PT2PG_MASK gives us an index to associated L2 page table + * in a page. The PT2PG_SHIFT definition depends on NPT2_IN_PG strictly. + * I.e., (1 << PT2PG_SHIFT) == NPT2_IN_PG must be fulfilled. + */ +#define PT2PG_SHIFT 2 +#define PT2PG_MASK ((1 << PT2PG_SHIFT) - 1) + +/* + * A PT2TAB holds all allocated L2 page table pages in a pmap. + * Right shifting of virtual address by PT2TAB_SHIFT gives us an index + * to L2 page table page in PT2TAB which holds the address mapping. + */ +#define PT2TAB_ENTRIES (NPTE1_IN_PT1 / NPT2_IN_PG) +#define PT2TAB_SHIFT (PTE1_SHIFT + PT2PG_SHIFT) + +/* + * All allocated L2 page table pages in a pmap are mapped into PT2MAP space. + * An virtual address right shifting by PT2MAP_SHIFT gives us an index to PTE2 + * which maps the address. + */ +#define PT2MAP_SIZE (NPTE1_IN_PT1 * NB_IN_PT2) +#define PT2MAP_SHIFT PTE2_SHIFT + +extern pt1_entry_t *kern_pt1; +extern pt2_entry_t *kern_pt2tab; +extern pt2_entry_t *PT2MAP; + +/* + * Virtual interface for L1 page table management. + */ + +static __inline u_int +pte1_index(vm_offset_t va) +{ + + return (va >> PTE1_SHIFT); +} + +static __inline pt1_entry_t * +pte1_ptr(pt1_entry_t *pt1, vm_offset_t va) +{ + + return (pt1 + pte1_index(va)); +} + +static __inline vm_offset_t +pte1_trunc(vm_offset_t va) +{ + + return (va & PTE1_FRAME); +} + +static __inline vm_offset_t +pte1_roundup(vm_offset_t va) +{ + + return ((va + PTE1_OFFSET) & PTE1_FRAME); +} + +/* + * Virtual interface for L1 page table entries management. + * + * XXX: Some of the following functions now with a synchronization barrier + * are called in a loop, so it could be useful to have two versions of them. + * One with the barrier and one without the barrier. In this case, pure + * barrier pte1_sync() should be implemented as well. + */ +static __inline void +pte1_sync(pt1_entry_t *pte1p) +{ + + dsb(); +#ifndef PMAP_PTE_NOCACHE + if (!cpuinfo.coherent_walk) + dcache_wb_pou((vm_offset_t)pte1p, sizeof(*pte1p)); +#endif +} + +static __inline void +pte1_sync_range(pt1_entry_t *pte1p, vm_size_t size) +{ + + dsb(); +#ifndef PMAP_PTE_NOCACHE + if (!cpuinfo.coherent_walk) + dcache_wb_pou((vm_offset_t)pte1p, size); +#endif +} + +static __inline void +pte1_store(pt1_entry_t *pte1p, pt1_entry_t pte1) +{ + + dmb(); + *pte1p = pte1; + pte1_sync(pte1p); +} + +static __inline void +pte1_clear(pt1_entry_t *pte1p) +{ + + pte1_store(pte1p, 0); +} + +static __inline void +pte1_clear_bit(pt1_entry_t *pte1p, uint32_t bit) +{ + + *pte1p &= ~bit; + pte1_sync(pte1p); +} + +static __inline bool +pte1_is_link(pt1_entry_t pte1) +{ + + return ((pte1 & L1_TYPE_MASK) == L1_TYPE_C); +} + +static __inline int +pte1_is_section(pt1_entry_t pte1) +{ + + return ((pte1 & L1_TYPE_MASK) == L1_TYPE_S); +} + +static __inline bool +pte1_is_dirty(pt1_entry_t pte1) +{ + + return ((pte1 & (PTE1_NM | PTE1_RO)) == 0); +} + +static __inline bool +pte1_is_global(pt1_entry_t pte1) +{ + + return ((pte1 & PTE1_NG) == 0); +} + +static __inline bool +pte1_is_valid(pt1_entry_t pte1) +{ + int l1_type; + + l1_type = pte1 & L1_TYPE_MASK; + return ((l1_type == L1_TYPE_C) || (l1_type == L1_TYPE_S)); +} + +static __inline bool +pte1_is_wired(pt1_entry_t pte1) +{ + + return (pte1 & PTE1_W); +} + +static __inline pt1_entry_t +pte1_load(pt1_entry_t *pte1p) +{ + pt1_entry_t pte1; + + pte1 = *pte1p; + return (pte1); +} + +static __inline pt1_entry_t +pte1_load_clear(pt1_entry_t *pte1p) +{ + pt1_entry_t opte1; + + opte1 = *pte1p; + *pte1p = 0; + pte1_sync(pte1p); + return (opte1); +} + +static __inline void +pte1_set_bit(pt1_entry_t *pte1p, uint32_t bit) +{ + + *pte1p |= bit; + pte1_sync(pte1p); +} + +static __inline vm_paddr_t +pte1_pa(pt1_entry_t pte1) +{ + + return ((vm_paddr_t)(pte1 & PTE1_FRAME)); +} + +static __inline vm_paddr_t +pte1_link_pa(pt1_entry_t pte1) +{ + + return ((vm_paddr_t)(pte1 & L1_C_ADDR_MASK)); +} + +/* + * Virtual interface for L2 page table entries management. + * + * XXX: Some of the following functions now with a synchronization barrier + * are called in a loop, so it could be useful to have two versions of them. + * One with the barrier and one without the barrier. + */ + +static __inline void +pte2_sync(pt2_entry_t *pte2p) +{ + + dsb(); +#ifndef PMAP_PTE_NOCACHE + if (!cpuinfo.coherent_walk) + dcache_wb_pou((vm_offset_t)pte2p, sizeof(*pte2p)); +#endif +} + +static __inline void +pte2_sync_range(pt2_entry_t *pte2p, vm_size_t size) +{ + + dsb(); +#ifndef PMAP_PTE_NOCACHE + if (!cpuinfo.coherent_walk) + dcache_wb_pou((vm_offset_t)pte2p, size); +#endif +} + +static __inline void +pte2_store(pt2_entry_t *pte2p, pt2_entry_t pte2) +{ + + dmb(); + *pte2p = pte2; + pte2_sync(pte2p); +} + +static __inline void +pte2_clear(pt2_entry_t *pte2p) +{ + + pte2_store(pte2p, 0); +} + +static __inline void +pte2_clear_bit(pt2_entry_t *pte2p, uint32_t bit) +{ + + *pte2p &= ~bit; + pte2_sync(pte2p); +} + +static __inline bool +pte2_is_dirty(pt2_entry_t pte2) +{ + + return ((pte2 & (PTE2_NM | PTE2_RO)) == 0); +} + +static __inline bool +pte2_is_global(pt2_entry_t pte2) +{ + + return ((pte2 & PTE2_NG) == 0); +} + +static __inline bool +pte2_is_valid(pt2_entry_t pte2) +{ + + return (pte2 & PTE2_V); +} + +static __inline bool +pte2_is_wired(pt2_entry_t pte2) +{ + + return (pte2 & PTE2_W); +} + +static __inline pt2_entry_t +pte2_load(pt2_entry_t *pte2p) +{ + pt2_entry_t pte2; + + pte2 = *pte2p; + return (pte2); +} + +static __inline pt2_entry_t +pte2_load_clear(pt2_entry_t *pte2p) +{ + pt2_entry_t opte2; + + opte2 = *pte2p; + *pte2p = 0; + pte2_sync(pte2p); + return (opte2); +} + +static __inline void +pte2_set_bit(pt2_entry_t *pte2p, uint32_t bit) +{ + + *pte2p |= bit; + pte2_sync(pte2p); +} + +static __inline void +pte2_set_wired(pt2_entry_t *pte2p, bool wired) +{ + + /* + * Wired bit is transparent for page table walk, + * so pte2_sync() is not needed. + */ + if (wired) + *pte2p |= PTE2_W; + else + *pte2p &= ~PTE2_W; +} + +static __inline vm_paddr_t +pte2_pa(pt2_entry_t pte2) +{ + + return ((vm_paddr_t)(pte2 & PTE2_FRAME)); +} + +static __inline u_int +pte2_attr(pt2_entry_t pte2) +{ + + return ((u_int)(pte2 & PTE2_ATTR_MASK)); +} + +/* + * Virtual interface for L2 page tables mapping management. + */ + +static __inline u_int +pt2tab_index(vm_offset_t va) +{ + + return (va >> PT2TAB_SHIFT); +} + +static __inline pt2_entry_t * +pt2tab_entry(pt2_entry_t *pt2tab, vm_offset_t va) +{ + + return (pt2tab + pt2tab_index(va)); +} + +static __inline void +pt2tab_store(pt2_entry_t *pte2p, pt2_entry_t pte2) +{ + + pte2_store(pte2p,pte2); +} + +static __inline pt2_entry_t +pt2tab_load(pt2_entry_t *pte2p) +{ + + return (pte2_load(pte2p)); +} + +static __inline pt2_entry_t +pt2tab_load_clear(pt2_entry_t *pte2p) +{ + + return (pte2_load_clear(pte2p)); +} + +static __inline u_int +pt2map_index(vm_offset_t va) +{ + + return (va >> PT2MAP_SHIFT); +} + +static __inline pt2_entry_t * +pt2map_entry(vm_offset_t va) +{ + + return (PT2MAP + pt2map_index(va)); +} + +/* + * Virtual interface for pmap structure & kernel shortcuts. + */ + +static __inline pt1_entry_t * +pmap_pte1(pmap_t pmap, vm_offset_t va) +{ + + return (pte1_ptr(pmap->pm_pt1, va)); +} + +static __inline pt1_entry_t * +kern_pte1(vm_offset_t va) +{ + + return (pte1_ptr(kern_pt1, va)); +} + +static __inline pt2_entry_t * +pmap_pt2tab_entry(pmap_t pmap, vm_offset_t va) +{ + + return (pt2tab_entry(pmap->pm_pt2tab, va)); +} + +static __inline pt2_entry_t * +kern_pt2tab_entry(vm_offset_t va) +{ + + return (pt2tab_entry(kern_pt2tab, va)); +} + +static __inline vm_page_t +pmap_pt2_page(pmap_t pmap, vm_offset_t va) +{ + pt2_entry_t pte2; + + pte2 = pte2_load(pmap_pt2tab_entry(pmap, va)); + return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME)); +} + +static __inline vm_page_t +kern_pt2_page(vm_offset_t va) +{ + pt2_entry_t pte2; + + pte2 = pte2_load(kern_pt2tab_entry(va)); + return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME)); +} + +#endif /* _KERNEL */ +#endif /* !_MACHINE_PMAP_VAR_H_ */ |