aboutsummaryrefslogtreecommitdiff
path: root/sys/arm/include/pmap_var.h
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arm/include/pmap_var.h')
-rw-r--r--sys/arm/include/pmap_var.h492
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_ */