446 lines
15 KiB
C
446 lines
15 KiB
C
/* $NetBSD: pmap.h,v 1.63 2003/03/23 15:59:24 chris Exp $ */
|
|
|
|
/*
|
|
* Copyright (c 2002 Wasabi Systems, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
|
|
*
|
|
* 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.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed for the NetBSD Project by
|
|
* Wasabi Systems, Inc.
|
|
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
|
|
* or promote products derived from this software without specific prior
|
|
* written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
|
|
* 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.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 1994,1995 Mark Brinicombe.
|
|
* 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.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Mark Brinicombe
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 _ARM32_PMAP_H_
|
|
#define _ARM32_PMAP_H_
|
|
|
|
#ifdef _KERNEL
|
|
|
|
#include <arm/cpuconf.h>
|
|
#include <arm/cpufunc.h>
|
|
#include <arm/arm32/pte.h>
|
|
#include <uvm/uvm_object.h>
|
|
|
|
/*
|
|
* a pmap describes a processes' 4GB virtual address space. this
|
|
* virtual address space can be broken up into 4096 1MB regions which
|
|
* are described by L1 PTEs in the L1 table.
|
|
*
|
|
* There is a line drawn at KERNEL_BASE. Everything below that line
|
|
* changes when the VM context is switched. Everything above that line
|
|
* is the same no matter which VM context is running. This is achieved
|
|
* by making the L1 PTEs for those slots above KERNEL_BASE reference
|
|
* kernel L2 tables.
|
|
*
|
|
* The L2 tables are mapped linearly starting at PTE_BASE. PTE_BASE
|
|
* is below KERNEL_BASE, which means that the current process's PTEs
|
|
* are always available starting at PTE_BASE. Another region of KVA
|
|
* above KERNEL_BASE, APTE_BASE, is reserved for mapping in the PTEs
|
|
* of another process, should we need to manipulate them.
|
|
*
|
|
* The basic layout of the virtual address space thus looks like this:
|
|
*
|
|
* 0xffffffff
|
|
* .
|
|
* .
|
|
* .
|
|
* KERNEL_BASE
|
|
* --------------------
|
|
* PTE_BASE
|
|
* .
|
|
* .
|
|
* .
|
|
* 0x00000000
|
|
*/
|
|
|
|
/*
|
|
* The pmap structure itself.
|
|
*/
|
|
struct pmap {
|
|
struct uvm_object pm_obj; /* uvm_object */
|
|
#define pm_lock pm_obj.vmobjlock
|
|
LIST_ENTRY(pmap) pm_list; /* list (lck by pm_list lock) */
|
|
pd_entry_t *pm_pdir; /* KVA of page directory */
|
|
struct l1pt *pm_l1pt; /* L1 table metadata */
|
|
paddr_t pm_pptpt; /* PA of pt's page table */
|
|
vaddr_t pm_vptpt; /* VA of pt's page table */
|
|
struct pmap_statistics pm_stats; /* pmap statistics */
|
|
struct vm_page *pm_ptphint; /* recently used PT */
|
|
};
|
|
|
|
typedef struct pmap *pmap_t;
|
|
|
|
/*
|
|
* Physical / virtual address structure. In a number of places (particularly
|
|
* during bootstrapping) we need to keep track of the physical and virtual
|
|
* addresses of various pages
|
|
*/
|
|
typedef struct pv_addr {
|
|
SLIST_ENTRY(pv_addr) pv_list;
|
|
paddr_t pv_pa;
|
|
vaddr_t pv_va;
|
|
} pv_addr_t;
|
|
|
|
/*
|
|
* Determine various modes for PTEs (user vs. kernel, cacheable
|
|
* vs. non-cacheable).
|
|
*/
|
|
#define PTE_KERNEL 0
|
|
#define PTE_USER 1
|
|
#define PTE_NOCACHE 0
|
|
#define PTE_CACHE 1
|
|
|
|
/*
|
|
* Flags that indicate attributes of pages or mappings of pages.
|
|
*
|
|
* The PVF_MOD and PVF_REF flags are stored in the mdpage for each
|
|
* page. PVF_WIRED, PVF_WRITE, and PVF_NC are kept in individual
|
|
* pv_entry's for each page. They live in the same "namespace" so
|
|
* that we can clear multiple attributes at a time.
|
|
*
|
|
* Note the "non-cacheable" flag generally means the page has
|
|
* multiple mappings in a given address space.
|
|
*/
|
|
#define PVF_MOD 0x01 /* page is modified */
|
|
#define PVF_REF 0x02 /* page is referenced */
|
|
#define PVF_WIRED 0x04 /* mapping is wired */
|
|
#define PVF_WRITE 0x08 /* mapping is writable */
|
|
#define PVF_EXEC 0x10 /* mapping is executable */
|
|
#define PVF_NC 0x20 /* mapping is non-cacheable */
|
|
|
|
/*
|
|
* Commonly referenced structures
|
|
*/
|
|
extern struct pmap kernel_pmap_store;
|
|
extern int pmap_debug_level; /* Only exists if PMAP_DEBUG */
|
|
|
|
/*
|
|
* Macros that we need to export
|
|
*/
|
|
#define pmap_kernel() (&kernel_pmap_store)
|
|
#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count)
|
|
#define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count)
|
|
|
|
#define pmap_is_modified(pg) \
|
|
(((pg)->mdpage.pvh_attrs & PVF_MOD) != 0)
|
|
#define pmap_is_referenced(pg) \
|
|
(((pg)->mdpage.pvh_attrs & PVF_REF) != 0)
|
|
|
|
#define pmap_copy(dp, sp, da, l, sa) /* nothing */
|
|
|
|
/* ARGSUSED */
|
|
static __inline void
|
|
pmap_remove_all(struct pmap *pmap)
|
|
{
|
|
/* Nothing. */
|
|
}
|
|
|
|
#define pmap_phys_address(ppn) (arm_ptob((ppn)))
|
|
|
|
/*
|
|
* Functions that we need to export
|
|
*/
|
|
void pmap_procwr(struct proc *, vaddr_t, int);
|
|
|
|
#define PMAP_NEED_PROCWR
|
|
#define PMAP_GROWKERNEL /* turn on pmap_growkernel interface */
|
|
|
|
/* Functions we use internally. */
|
|
void pmap_bootstrap(pd_entry_t *, pv_addr_t);
|
|
void pmap_debug(int);
|
|
int pmap_handled_emulation(struct pmap *, vaddr_t);
|
|
int pmap_modified_emulation(struct pmap *, vaddr_t);
|
|
void pmap_postinit(void);
|
|
|
|
void vector_page_setprot(int);
|
|
|
|
/* Bootstrapping routines. */
|
|
void pmap_map_section(vaddr_t, vaddr_t, paddr_t, int, int);
|
|
void pmap_map_entry(vaddr_t, vaddr_t, paddr_t, int, int);
|
|
vsize_t pmap_map_chunk(vaddr_t, vaddr_t, paddr_t, vsize_t, int, int);
|
|
void pmap_link_l2pt(vaddr_t, vaddr_t, pv_addr_t *);
|
|
|
|
/*
|
|
* Special page zero routine for use by the idle loop (no cache cleans).
|
|
*/
|
|
boolean_t pmap_pageidlezero __P((paddr_t));
|
|
#define PMAP_PAGEIDLEZERO(pa) pmap_pageidlezero((pa))
|
|
|
|
/*
|
|
* The current top of kernel VM
|
|
*/
|
|
extern vaddr_t pmap_curmaxkvaddr;
|
|
|
|
/*
|
|
* Useful macros and constants
|
|
*/
|
|
|
|
/*
|
|
* While the ARM MMU's L1 descriptors describe a 1M "section", each
|
|
* one pointing to a 1K L2 table, NetBSD's VM system allocates the
|
|
* page tables in 4K chunks, and thus we describe 4M "super sections".
|
|
*
|
|
* We'll lift terminology from another architecture and refer to this as
|
|
* the "page directory" size.
|
|
*/
|
|
#define PD_SIZE (L1_S_SIZE * 4) /* 4M */
|
|
#define PD_OFFSET (PD_SIZE - 1)
|
|
#define PD_FRAME (~PD_OFFSET)
|
|
#define PD_SHIFT 22
|
|
|
|
/* Virtual address to page table entry */
|
|
#define vtopte(va) \
|
|
(((pt_entry_t *)PTE_BASE) + arm_btop((vaddr_t) (va)))
|
|
|
|
/* Virtual address to physical address */
|
|
#define vtophys(va) \
|
|
((*vtopte(va) & L2_S_FRAME) | ((vaddr_t) (va) & L2_S_OFFSET))
|
|
|
|
#define PTE_SYNC(pte) \
|
|
cpu_dcache_wb_range((vaddr_t)(pte), sizeof(pt_entry_t))
|
|
#define PTE_FLUSH(pte) \
|
|
cpu_dcache_wbinv_range((vaddr_t)(pte), sizeof(pt_entry_t))
|
|
|
|
#define PTE_SYNC_RANGE(pte, cnt) \
|
|
cpu_dcache_wb_range((vaddr_t)(pte), (cnt) << 2) /* * sizeof(...) */
|
|
#define PTE_FLUSH_RANGE(pte, cnt) \
|
|
cpu_dcache_wbinv_range((vaddr_t)(pte), (cnt) << 2) /* * sizeof(...) */
|
|
|
|
#define l1pte_valid(pde) ((pde) != 0)
|
|
#define l1pte_section_p(pde) (((pde) & L1_TYPE_MASK) == L1_TYPE_S)
|
|
#define l1pte_page_p(pde) (((pde) & L1_TYPE_MASK) == L1_TYPE_C)
|
|
#define l1pte_fpage_p(pde) (((pde) & L1_TYPE_MASK) == L1_TYPE_F)
|
|
|
|
#define l2pte_valid(pte) ((pte) != 0)
|
|
#define l2pte_pa(pte) ((pte) & L2_S_FRAME)
|
|
|
|
/* L1 and L2 page table macros */
|
|
#define pmap_pdei(v) ((v & L1_S_FRAME) >> L1_S_SHIFT)
|
|
#define pmap_pde(m, v) (&((m)->pm_pdir[pmap_pdei(v)]))
|
|
|
|
#define pmap_pde_v(pde) l1pte_valid(*(pde))
|
|
#define pmap_pde_section(pde) l1pte_section_p(*(pde))
|
|
#define pmap_pde_page(pde) l1pte_page_p(*(pde))
|
|
#define pmap_pde_fpage(pde) l1pte_fpage_p(*(pde))
|
|
|
|
#define pmap_pte_v(pte) l2pte_valid(*(pte))
|
|
#define pmap_pte_pa(pte) l2pte_pa(*(pte))
|
|
|
|
|
|
/* Size of the kernel part of the L1 page table */
|
|
#define KERNEL_PD_SIZE \
|
|
(L1_TABLE_SIZE - (KERNEL_BASE >> L1_S_SHIFT) * sizeof(pd_entry_t))
|
|
|
|
/************************* ARM MMU configuration *****************************/
|
|
|
|
#if ARM_MMU_GENERIC == 1
|
|
void pmap_copy_page_generic(paddr_t, paddr_t);
|
|
void pmap_zero_page_generic(paddr_t);
|
|
|
|
void pmap_pte_init_generic(void);
|
|
#if defined(CPU_ARM9)
|
|
void pmap_pte_init_arm9(void);
|
|
#endif /* CPU_ARM9 */
|
|
#endif /* ARM_MMU_GENERIC == 1 */
|
|
|
|
#if ARM_MMU_XSCALE == 1
|
|
void pmap_copy_page_xscale(paddr_t, paddr_t);
|
|
void pmap_zero_page_xscale(paddr_t);
|
|
|
|
void pmap_pte_init_xscale(void);
|
|
|
|
void xscale_setup_minidata(vaddr_t, vaddr_t, paddr_t);
|
|
#endif /* ARM_MMU_XSCALE == 1 */
|
|
|
|
extern pt_entry_t pte_l1_s_cache_mode;
|
|
extern pt_entry_t pte_l1_s_cache_mask;
|
|
|
|
extern pt_entry_t pte_l2_l_cache_mode;
|
|
extern pt_entry_t pte_l2_l_cache_mask;
|
|
|
|
extern pt_entry_t pte_l2_s_cache_mode;
|
|
extern pt_entry_t pte_l2_s_cache_mask;
|
|
|
|
extern pt_entry_t pte_l2_s_prot_u;
|
|
extern pt_entry_t pte_l2_s_prot_w;
|
|
extern pt_entry_t pte_l2_s_prot_mask;
|
|
|
|
extern pt_entry_t pte_l1_s_proto;
|
|
extern pt_entry_t pte_l1_c_proto;
|
|
extern pt_entry_t pte_l2_s_proto;
|
|
|
|
extern void (*pmap_copy_page_func)(paddr_t, paddr_t);
|
|
extern void (*pmap_zero_page_func)(paddr_t);
|
|
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
* tell MI code that the cache is virtually-indexed *and* virtually-tagged.
|
|
*/
|
|
#define PMAP_CACHE_VIVT
|
|
|
|
/*
|
|
* These macros define the various bit masks in the PTE.
|
|
*
|
|
* We use these macros since we use different bits on different processor
|
|
* models.
|
|
*/
|
|
#define L1_S_PROT_U (L1_S_AP(AP_U))
|
|
#define L1_S_PROT_W (L1_S_AP(AP_W))
|
|
#define L1_S_PROT_MASK (L1_S_PROT_U|L1_S_PROT_W)
|
|
|
|
#define L1_S_CACHE_MASK_generic (L1_S_B|L1_S_C)
|
|
#define L1_S_CACHE_MASK_xscale (L1_S_B|L1_S_C|L1_S_XSCALE_TEX(TEX_XSCALE_X))
|
|
|
|
#define L2_L_PROT_U (L2_AP(AP_U))
|
|
#define L2_L_PROT_W (L2_AP(AP_W))
|
|
#define L2_L_PROT_MASK (L2_L_PROT_U|L2_L_PROT_W)
|
|
|
|
#define L2_L_CACHE_MASK_generic (L2_B|L2_C)
|
|
#define L2_L_CACHE_MASK_xscale (L2_B|L2_C|L2_XSCALE_L_TEX(TEX_XSCALE_X))
|
|
|
|
#define L2_S_PROT_U_generic (L2_AP(AP_U))
|
|
#define L2_S_PROT_W_generic (L2_AP(AP_W))
|
|
#define L2_S_PROT_MASK_generic (L2_S_PROT_U|L2_S_PROT_W)
|
|
|
|
#define L2_S_PROT_U_xscale (L2_AP0(AP_U))
|
|
#define L2_S_PROT_W_xscale (L2_AP0(AP_W))
|
|
#define L2_S_PROT_MASK_xscale (L2_S_PROT_U|L2_S_PROT_W)
|
|
|
|
#define L2_S_CACHE_MASK_generic (L2_B|L2_C)
|
|
#define L2_S_CACHE_MASK_xscale (L2_B|L2_C|L2_XSCALE_T_TEX(TEX_XSCALE_X))
|
|
|
|
#define L1_S_PROTO_generic (L1_TYPE_S | L1_S_IMP)
|
|
#define L1_S_PROTO_xscale (L1_TYPE_S)
|
|
|
|
#define L1_C_PROTO_generic (L1_TYPE_C | L1_C_IMP2)
|
|
#define L1_C_PROTO_xscale (L1_TYPE_C)
|
|
|
|
#define L2_L_PROTO (L2_TYPE_L)
|
|
|
|
#define L2_S_PROTO_generic (L2_TYPE_S)
|
|
#define L2_S_PROTO_xscale (L2_TYPE_XSCALE_XS)
|
|
|
|
/*
|
|
* User-visible names for the ones that vary with MMU class.
|
|
*/
|
|
|
|
#if ARM_NMMUS > 1
|
|
/* More than one MMU class configured; use variables. */
|
|
#define L2_S_PROT_U pte_l2_s_prot_u
|
|
#define L2_S_PROT_W pte_l2_s_prot_w
|
|
#define L2_S_PROT_MASK pte_l2_s_prot_mask
|
|
|
|
#define L1_S_CACHE_MASK pte_l1_s_cache_mask
|
|
#define L2_L_CACHE_MASK pte_l2_l_cache_mask
|
|
#define L2_S_CACHE_MASK pte_l2_s_cache_mask
|
|
|
|
#define L1_S_PROTO pte_l1_s_proto
|
|
#define L1_C_PROTO pte_l1_c_proto
|
|
#define L2_S_PROTO pte_l2_s_proto
|
|
|
|
#define pmap_copy_page(s, d) (*pmap_copy_page_func)((s), (d))
|
|
#define pmap_zero_page(d) (*pmap_zero_page_func)((d))
|
|
#elif ARM_MMU_GENERIC == 1
|
|
#define L2_S_PROT_U L2_S_PROT_U_generic
|
|
#define L2_S_PROT_W L2_S_PROT_W_generic
|
|
#define L2_S_PROT_MASK L2_S_PROT_MASK_generic
|
|
|
|
#define L1_S_CACHE_MASK L1_S_CACHE_MASK_generic
|
|
#define L2_L_CACHE_MASK L2_L_CACHE_MASK_generic
|
|
#define L2_S_CACHE_MASK L2_S_CACHE_MASK_generic
|
|
|
|
#define L1_S_PROTO L1_S_PROTO_generic
|
|
#define L1_C_PROTO L1_C_PROTO_generic
|
|
#define L2_S_PROTO L2_S_PROTO_generic
|
|
|
|
#define pmap_copy_page(s, d) pmap_copy_page_generic((s), (d))
|
|
#define pmap_zero_page(d) pmap_zero_page_generic((d))
|
|
#elif ARM_MMU_XSCALE == 1
|
|
#define L2_S_PROT_U L2_S_PROT_U_xscale
|
|
#define L2_S_PROT_W L2_S_PROT_W_xscale
|
|
#define L2_S_PROT_MASK L2_S_PROT_MASK_xscale
|
|
|
|
#define L1_S_CACHE_MASK L1_S_CACHE_MASK_xscale
|
|
#define L2_L_CACHE_MASK L2_L_CACHE_MASK_xscale
|
|
#define L2_S_CACHE_MASK L2_S_CACHE_MASK_xscale
|
|
|
|
#define L1_S_PROTO L1_S_PROTO_xscale
|
|
#define L1_C_PROTO L1_C_PROTO_xscale
|
|
#define L2_S_PROTO L2_S_PROTO_xscale
|
|
|
|
#define pmap_copy_page(s, d) pmap_copy_page_xscale((s), (d))
|
|
#define pmap_zero_page(d) pmap_zero_page_xscale((d))
|
|
#endif /* ARM_NMMUS > 1 */
|
|
|
|
/*
|
|
* These macros return various bits based on kernel/user and protection.
|
|
* Note that the compiler will usually fold these at compile time.
|
|
*/
|
|
#define L1_S_PROT(ku, pr) ((((ku) == PTE_USER) ? L1_S_PROT_U : 0) | \
|
|
(((pr) & VM_PROT_WRITE) ? L1_S_PROT_W : 0))
|
|
|
|
#define L2_L_PROT(ku, pr) ((((ku) == PTE_USER) ? L2_L_PROT_U : 0) | \
|
|
(((pr) & VM_PROT_WRITE) ? L2_L_PROT_W : 0))
|
|
|
|
#define L2_S_PROT(ku, pr) ((((ku) == PTE_USER) ? L2_S_PROT_U : 0) | \
|
|
(((pr) & VM_PROT_WRITE) ? L2_S_PROT_W : 0))
|
|
|
|
#endif /* _KERNEL */
|
|
|
|
#endif /* _ARM32_PMAP_H_ */
|