1 /* $NetBSD: pmap.h,v 1.63 2014/05/11 07:53:28 skrll Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Ralph Campbell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)pmap.h 8.1 (Berkeley) 6/10/93 35 */ 36 37 /* 38 * Copyright (c) 1987 Carnegie-Mellon University 39 * 40 * This code is derived from software contributed to Berkeley by 41 * Ralph Campbell. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by the University of 54 * California, Berkeley and its contributors. 55 * 4. Neither the name of the University nor the names of its contributors 56 * may be used to endorse or promote products derived from this software 57 * without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 * 71 * @(#)pmap.h 8.1 (Berkeley) 6/10/93 72 */ 73 74 #ifndef _MIPS_PMAP_H_ 75 #define _MIPS_PMAP_H_ 76 77 #ifdef _KERNEL_OPT 78 #include "opt_multiprocessor.h" 79 #endif 80 81 #include <mips/cpuregs.h> /* for KSEG0 below */ 82 //#include <mips/pte.h> 83 84 /* 85 * The user address space is 2Gb (0x0 - 0x80000000). 86 * User programs are laid out in memory as follows: 87 * address 88 * USRTEXT 0x00001000 89 * USRDATA USRTEXT + text_size 90 * USRSTACK 0x7FFFFFFF 91 * 92 * The user address space is mapped using a two level structure where 93 * virtual address bits 30..22 are used to index into a segment table which 94 * points to a page worth of PTEs (4096 page can hold 1024 PTEs). 95 * Bits 21..12 are then used to index a PTE which describes a page within 96 * a segment. 97 * 98 * The wired entries in the TLB will contain the following: 99 * 0-1 (UPAGES) for curproc user struct and kernel stack. 100 * 101 * Note: The kernel doesn't use the same data structures as user programs. 102 * All the PTE entries are stored in a single array in Sysmap which is 103 * dynamically allocated at boot time. 104 */ 105 106 #define mips_trunc_seg(x) ((vaddr_t)(x) & ~SEGOFSET) 107 #define mips_round_seg(x) (((vaddr_t)(x) + SEGOFSET) & ~SEGOFSET) 108 109 #ifdef _LP64 110 #define PMAP_SEGTABSIZE NSEGPG 111 #else 112 #define PMAP_SEGTABSIZE (1 << (31 - SEGSHIFT)) 113 #endif 114 115 union pt_entry; 116 117 union segtab { 118 #ifdef _LP64 119 union segtab *seg_seg[PMAP_SEGTABSIZE]; 120 #endif 121 union pt_entry *seg_tab[PMAP_SEGTABSIZE]; 122 }; 123 124 /* 125 * Structure defining an tlb entry data set. 126 */ 127 struct tlb { 128 vaddr_t tlb_hi; /* should be 64 bits */ 129 uint32_t tlb_lo0; /* XXX maybe 64 bits (only 32 really used) */ 130 uint32_t tlb_lo1; /* XXX maybe 64 bits (only 32 really used) */ 131 }; 132 133 struct tlbmask { 134 vaddr_t tlb_hi; /* should be 64 bits */ 135 uint32_t tlb_lo0; /* XXX maybe 64 bits (only 32 really used) */ 136 uint32_t tlb_lo1; /* XXX maybe 64 bits (only 32 really used) */ 137 uint32_t tlb_mask; 138 }; 139 140 #ifdef _KERNEL 141 struct pmap; 142 typedef bool (*pte_callback_t)(struct pmap *, vaddr_t, vaddr_t, 143 union pt_entry *, uintptr_t); 144 union pt_entry *pmap_pte_lookup(struct pmap *, vaddr_t); 145 union pt_entry *pmap_pte_reserve(struct pmap *, vaddr_t, int); 146 void pmap_pte_process(struct pmap *, vaddr_t, vaddr_t, pte_callback_t, 147 uintptr_t); 148 void pmap_segtab_activate(struct pmap *, struct lwp *); 149 void pmap_segtab_init(struct pmap *); 150 void pmap_segtab_destroy(struct pmap *); 151 extern kmutex_t pmap_segtab_lock; 152 #endif /* _KERNEL */ 153 154 /* 155 * Per TLB (normally same as CPU) asid info 156 */ 157 struct pmap_asid_info { 158 LIST_ENTRY(pmap_asid_info) pai_link; 159 uint32_t pai_asid; /* TLB address space tag */ 160 }; 161 162 #define TLBINFO_LOCK(ti) mutex_spin_enter((ti)->ti_lock) 163 #define TLBINFO_UNLOCK(ti) mutex_spin_exit((ti)->ti_lock) 164 #define PMAP_PAI_ASIDVALID_P(pai, ti) ((pai)->pai_asid != 0) 165 #define PMAP_PAI(pmap, ti) (&(pmap)->pm_pai[tlbinfo_index(ti)]) 166 #define PAI_PMAP(pai, ti) \ 167 ((pmap_t)((intptr_t)(pai) \ 168 - offsetof(struct pmap, pm_pai[tlbinfo_index(ti)]))) 169 170 /* 171 * Machine dependent pmap structure. 172 */ 173 struct pmap { 174 #ifdef MULTIPROCESSOR 175 volatile uint32_t pm_active; /* pmap was active on ... */ 176 volatile uint32_t pm_onproc; /* pmap is active on ... */ 177 volatile u_int pm_shootdown_pending; 178 #endif 179 union segtab *pm_segtab; /* pointers to pages of PTEs */ 180 u_int pm_count; /* pmap reference count */ 181 u_int pm_flags; 182 #define PMAP_DEFERRED_ACTIVATE 0x0001 183 struct pmap_statistics pm_stats; /* pmap statistics */ 184 struct pmap_asid_info pm_pai[1]; 185 }; 186 187 enum tlb_invalidate_op { 188 TLBINV_NOBODY=0, 189 TLBINV_ONE=1, 190 TLBINV_ALLUSER=2, 191 TLBINV_ALLKERNEL=3, 192 TLBINV_ALL=4 193 }; 194 195 struct pmap_tlb_info { 196 char ti_name[8]; 197 uint32_t ti_asid_hint; /* probable next ASID to use */ 198 uint32_t ti_asids_free; /* # of ASIDs free */ 199 #define tlbinfo_noasids_p(ti) ((ti)->ti_asids_free == 0) 200 kmutex_t *ti_lock; 201 u_int ti_wired; /* # of wired TLB entries */ 202 uint32_t ti_asid_mask; 203 uint32_t ti_asid_max; 204 LIST_HEAD(, pmap_asid_info) ti_pais; /* list of active ASIDs */ 205 #ifdef MULTIPROCESSOR 206 pmap_t ti_victim; 207 uint32_t ti_synci_page_bitmap; /* page indices needing a syncicache */ 208 uint32_t ti_cpu_mask; /* bitmask of CPUs sharing this TLB */ 209 enum tlb_invalidate_op ti_tlbinvop; 210 u_int ti_index; 211 #define tlbinfo_index(ti) ((ti)->ti_index) 212 struct evcnt ti_evcnt_synci_asts; 213 struct evcnt ti_evcnt_synci_all; 214 struct evcnt ti_evcnt_synci_pages; 215 struct evcnt ti_evcnt_synci_deferred; 216 struct evcnt ti_evcnt_synci_desired; 217 struct evcnt ti_evcnt_synci_duplicate; 218 #else 219 #define tlbinfo_index(ti) (0) 220 #endif 221 struct evcnt ti_evcnt_asid_reinits; 222 u_long ti_asid_bitmap[256 / (sizeof(u_long) * 8)]; 223 }; 224 225 #ifdef _KERNEL 226 227 struct pmap_kernel { 228 struct pmap kernel_pmap; 229 #ifdef MULTIPROCESSOR 230 struct pmap_asid_info kernel_pai[MAXCPUS-1]; 231 #endif 232 }; 233 234 extern struct pmap_kernel kernel_pmap_store; 235 extern struct pmap_tlb_info pmap_tlb0_info; 236 #ifdef MULTIPROCESSOR 237 extern struct pmap_tlb_info *pmap_tlbs[MAXCPUS]; 238 extern u_int pmap_ntlbs; 239 #endif 240 extern paddr_t mips_avail_start; 241 extern paddr_t mips_avail_end; 242 extern vaddr_t mips_virtual_end; 243 244 #define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count) 245 #define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) 246 247 #define pmap_phys_address(x) mips_ptob(x) 248 249 /* 250 * Bootstrap the system enough to run with virtual memory. 251 */ 252 void pmap_bootstrap(void); 253 254 void pmap_remove_all(pmap_t); 255 void pmap_set_modified(paddr_t); 256 void pmap_procwr(struct proc *, vaddr_t, size_t); 257 #define PMAP_NEED_PROCWR 258 259 #ifdef MULTIPROCESSOR 260 void pmap_tlb_shootdown_process(void); 261 bool pmap_tlb_shootdown_bystanders(pmap_t pmap); 262 void pmap_tlb_info_attach(struct pmap_tlb_info *, struct cpu_info *); 263 void pmap_tlb_syncicache_ast(struct cpu_info *); 264 void pmap_tlb_syncicache_wanted(struct cpu_info *); 265 void pmap_tlb_syncicache(vaddr_t, uint32_t); 266 #endif 267 void pmap_tlb_info_init(struct pmap_tlb_info *); 268 void pmap_tlb_info_evcnt_attach(struct pmap_tlb_info *); 269 void pmap_tlb_asid_acquire(pmap_t pmap, struct lwp *l); 270 void pmap_tlb_asid_deactivate(pmap_t pmap); 271 void pmap_tlb_asid_check(void); 272 void pmap_tlb_asid_release_all(pmap_t pmap); 273 int pmap_tlb_update_addr(pmap_t pmap, vaddr_t, uint32_t, bool); 274 void pmap_tlb_invalidate_addr(pmap_t pmap, vaddr_t); 275 276 /* 277 * pmap_prefer() helps reduce virtual-coherency exceptions in 278 * the virtually-indexed cache on mips3 CPUs. 279 */ 280 #ifdef MIPS3_PLUS 281 #define PMAP_PREFER(pa, va, sz, td) pmap_prefer((pa), (va), (sz), (td)) 282 void pmap_prefer(vaddr_t, vaddr_t *, vsize_t, int); 283 #endif /* MIPS3_PLUS */ 284 285 #define PMAP_STEAL_MEMORY /* enable pmap_steal_memory() */ 286 #define PMAP_ENABLE_PMAP_KMPAGE /* enable the PMAP_KMPAGE flag */ 287 288 /* 289 * Alternate mapping hooks for pool pages. Avoids thrashing the TLB. 290 */ 291 vaddr_t mips_pmap_map_poolpage(paddr_t); 292 paddr_t mips_pmap_unmap_poolpage(vaddr_t); 293 struct vm_page *mips_pmap_alloc_poolpage(int); 294 #define PMAP_ALLOC_POOLPAGE(flags) mips_pmap_alloc_poolpage(flags) 295 #define PMAP_MAP_POOLPAGE(pa) mips_pmap_map_poolpage(pa) 296 #define PMAP_UNMAP_POOLPAGE(va) mips_pmap_unmap_poolpage(va) 297 298 /* 299 * Other hooks for the pool allocator. 300 */ 301 #ifdef _LP64 302 #define POOL_VTOPHYS(va) (MIPS_KSEG0_P(va) \ 303 ? MIPS_KSEG0_TO_PHYS(va) \ 304 : MIPS_XKPHYS_TO_PHYS(va)) 305 #else 306 #define POOL_VTOPHYS(va) MIPS_KSEG0_TO_PHYS((vaddr_t)(va)) 307 #endif 308 309 /* 310 * Select CCA to use for unmanaged pages. 311 */ 312 #define PMAP_CCA_FOR_PA(pa) CCA_UNCACHED /* uncached */ 313 314 #if defined(_MIPS_PADDR_T_64BIT) || defined(_LP64) 315 #define PGC_NOCACHE 0x4000000000000000ULL 316 #define PGC_PREFETCH 0x2000000000000000ULL 317 #endif 318 319 #define __HAVE_VM_PAGE_MD 320 321 /* 322 * pmap-specific data stored in the vm_page structure. 323 */ 324 /* 325 * For each struct vm_page, there is a list of all currently valid virtual 326 * mappings of that page. An entry is a pv_entry_t, the list is pv_table. 327 * XXX really should do this as a part of the higher level code. 328 */ 329 typedef struct pv_entry { 330 struct pv_entry *pv_next; /* next pv_entry */ 331 struct pmap *pv_pmap; /* pmap where mapping lies */ 332 vaddr_t pv_va; /* virtual address for mapping */ 333 #define PV_KENTER 0x001 334 } *pv_entry_t; 335 336 #define PG_MD_UNCACHED 0x0001 /* page is mapped uncached */ 337 #define PG_MD_MODIFIED 0x0002 /* page has been modified */ 338 #define PG_MD_REFERENCED 0x0004 /* page has been recently referenced */ 339 #define PG_MD_POOLPAGE 0x0008 /* page is used as a poolpage */ 340 #define PG_MD_EXECPAGE 0x0010 /* page is exec mapped */ 341 342 #define PG_MD_CACHED_P(md) (((md)->pvh_attrs & PG_MD_UNCACHED) == 0) 343 #define PG_MD_UNCACHED_P(md) (((md)->pvh_attrs & PG_MD_UNCACHED) != 0) 344 #define PG_MD_MODIFIED_P(md) (((md)->pvh_attrs & PG_MD_MODIFIED) != 0) 345 #define PG_MD_REFERENCED_P(md) (((md)->pvh_attrs & PG_MD_REFERENCED) != 0) 346 #define PG_MD_POOLPAGE_P(md) (((md)->pvh_attrs & PG_MD_POOLPAGE) != 0) 347 #define PG_MD_EXECPAGE_P(md) (((md)->pvh_attrs & PG_MD_EXECPAGE) != 0) 348 349 struct vm_page_md { 350 struct pv_entry pvh_first; /* pv_entry first */ 351 #ifdef MULTIPROCESSOR 352 volatile u_int pvh_attrs; /* page attributes */ 353 kmutex_t *pvh_lock; /* pv list lock */ 354 #define PG_MD_PVLIST_LOCK_INIT(md) ((md)->pvh_lock = NULL) 355 #define PG_MD_PVLIST_LOCKED_P(md) (mutex_owner((md)->pvh_lock) != 0) 356 #define PG_MD_PVLIST_LOCK(md, lc) pmap_pvlist_lock((md), (lc)) 357 #define PG_MD_PVLIST_UNLOCK(md) mutex_spin_exit((md)->pvh_lock) 358 #define PG_MD_PVLIST_GEN(md) ((uint16_t)((md)->pvh_attrs >> 16)) 359 #else 360 u_int pvh_attrs; /* page attributes */ 361 #define PG_MD_PVLIST_LOCK_INIT(md) do { } while (/*CONSTCOND*/ 0) 362 #define PG_MD_PVLIST_LOCKED_P(md) true 363 #define PG_MD_PVLIST_LOCK(md, lc) (mutex_spin_enter(&pmap_pvlist_mutex), 0) 364 #define PG_MD_PVLIST_UNLOCK(md) mutex_spin_exit(&pmap_pvlist_mutex) 365 #define PG_MD_PVLIST_GEN(md) (0) 366 #endif 367 }; 368 369 #define VM_MDPAGE_INIT(pg) \ 370 do { \ 371 struct vm_page_md * const md = VM_PAGE_TO_MD(pg); \ 372 (md)->pvh_first.pv_next = NULL; \ 373 (md)->pvh_first.pv_pmap = NULL; \ 374 (md)->pvh_first.pv_va = VM_PAGE_TO_PHYS(pg); \ 375 PG_MD_PVLIST_LOCK_INIT(md); \ 376 (md)->pvh_attrs = 0; \ 377 } while (/* CONSTCOND */ 0) 378 379 uint16_t pmap_pvlist_lock(struct vm_page_md *, bool); 380 381 #endif /* _KERNEL */ 382 #endif /* _MIPS_PMAP_H_ */ 383