1 1.1 thorpej /* $NetBSD: pmap_pgmmu.c,v 1.1 2026/07/19 01:48:24 thorpej Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /*- 4 1.1 thorpej * Copyright (c) 2025, 2026 The NetBSD Foundation, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * This code is derived from software contributed to The NetBSD Foundation 8 1.1 thorpej * by Jason R. Thorpe. 9 1.1 thorpej * 10 1.1 thorpej * Redistribution and use in source and binary forms, with or without 11 1.1 thorpej * modification, are permitted provided that the following conditions 12 1.1 thorpej * are met: 13 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 14 1.1 thorpej * notice, this list of conditions and the following disclaimer. 15 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 17 1.1 thorpej * documentation and/or other materials provided with the distribution. 18 1.1 thorpej * 19 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 30 1.1 thorpej */ 31 1.1 thorpej 32 1.1 thorpej /* 33 1.1 thorpej * Pmap module for the 68K Playground MMU, as found on the 68010-based 34 1.1 thorpej * Phaethon 1. 35 1.1 thorpej * 36 1.1 thorpej * The PGMMU is similar to the Sun3 MMU, but there are some differences, 37 1.1 thorpej * and they are not software-compatible. 38 1.1 thorpej * 39 1.1 thorpej * ==> Generally speaking, the MMU must be enabled for the system to 40 1.1 thorpej * function; if the MMU is disabled, all {User,Supervisor} {Data,Prog} 41 1.1 thorpej * cycles select the system ROM. This means not even the stack is 42 1.1 thorpej * accessible until the firmware sets up the MMU and enbles it, and 43 1.1 thorpej * the firmware runs in a virtual environment. When the kernel starts, 44 1.1 thorpej * it is running in the virtual environment set up by the firmware. 45 1.1 thorpej * 46 1.1 thorpej * ==> PGMMU has 64 contexts. Supervisor {Data,Prog} cycles are hard-wired 47 1.1 thorpej * to context 0. User {Data,Prog} cycles use the context specified by 48 1.1 thorpej * the Context Register (which, BTW, can be 0!). 49 1.1 thorpej * 50 1.1 thorpej * ==> Context 0's Segment Map has its own selector so that changing the 51 1.1 thorpej * kernel's Segment Map doesn't require setting the Context Register. 52 1.1 thorpej * 53 1.1 thorpej * ==> Each context has 512 32KB segments in the Segment Map. Each 54 1.1 thorpej * 16-bit Segment Map entry (SME) has a valid bit and a 15-bit 55 1.1 thorpej * number representing the Page Map Entry Group (PMEG) that maps 56 1.1 thorpej * the segment. 57 1.1 thorpej * 58 1.1 thorpej * ==> Each PMEG is comprised of 8 4KB pages, each with independent 59 1.1 thorpej * Page Map entries (PMEs). There are 32,768 total PMEGs shared 60 1.1 thorpej * by all processes in the system. 61 1.1 thorpej * 62 1.1 thorpej * ==> All PMEGs used by the kernel are static. The kernel pmap makes a 63 1.1 thorpej * best effort to use PMEGs already used by the system firmware. 64 1.1 thorpej * 65 1.1 thorpej * ==> There is sufficient SRAM in the MMU to fully map all 64 contexts. 66 1.1 thorpej * If there are more than 64 concurrent processes in the system 67 1.1 thorpej * (including the kernel), then user processes will have to compete 68 1.1 thorpej * with one another for contexts and PMEGs. 69 1.1 thorpej * 70 1.1 thorpej * ==> No systems with this MMU have a data cache, so cache management is 71 1.1 thorpej * not a concern. 72 1.1 thorpej */ 73 1.1 thorpej 74 1.1 thorpej #include "opt_ddb.h" 75 1.1 thorpej #include "opt_kgdb.h" 76 1.1 thorpej 77 1.1 thorpej #include <sys/cdefs.h> 78 1.1 thorpej __KERNEL_RCSID(0, "$NetBSD: pmap_pgmmu.c,v 1.1 2026/07/19 01:48:24 thorpej Exp $"); 79 1.1 thorpej 80 1.1 thorpej #include <sys/param.h> 81 1.1 thorpej #include <sys/systm.h> 82 1.1 thorpej #include <sys/evcnt.h> 83 1.1 thorpej #include <sys/proc.h> 84 1.1 thorpej #include <sys/pool.h> 85 1.1 thorpej #include <sys/cpu.h> 86 1.1 thorpej #include <sys/atomic.h> 87 1.1 thorpej #include <sys/kmem.h> 88 1.1 thorpej 89 1.1 thorpej #include <machine/pcb.h> 90 1.1 thorpej 91 1.1 thorpej #include <uvm/uvm.h> 92 1.1 thorpej #include <uvm/uvm_physseg.h> 93 1.1 thorpej 94 1.1 thorpej /****************************** SERIALIZATION ********************************/ 95 1.1 thorpej 96 1.1 thorpej /* 97 1.1 thorpej * XXX Would like to make these do something lightweight-ish in 98 1.1 thorpej * XXX DIAGNOSTIC kernels (and also make ASSERT_SLEEPABLE() trip 99 1.1 thorpej * XXX if we're in a critical section). 100 1.1 thorpej */ 101 1.1 thorpej 102 1.1 thorpej #define PMAP_CRIT_ENTER(code) code 103 1.1 thorpej #define PMAP_CRIT_EXIT(code) code 104 1.1 thorpej #define PMAP_CRIT_ASSERT() __nothing 105 1.1 thorpej 106 1.1 thorpej /**************************** MMU CONFIGURATION ******************************/ 107 1.1 thorpej 108 1.1 thorpej #include <hb68k/pg68k/pgmmu.h> 109 1.1 thorpej 110 1.1 thorpej __CTASSERT(PAGE_SIZE == PGMMU_PAGE_SIZE); 111 1.1 thorpej __CTASSERT(NBPG == PGMMU_PAGE_SIZE); 112 1.1 thorpej 113 1.1 thorpej #ifdef __mc68010__ 114 1.1 thorpej #define KERNEL_MAX_ADDRESS (1U << 24) 115 1.1 thorpej #else 116 1.1 thorpej #error KERNEL_MAX_ADDRESS TBD 117 1.1 thorpej #endif 118 1.1 thorpej static vaddr_t kernel_virtual_start; 119 1.1 thorpej vaddr_t kernel_virtual_max = KERNEL_MAX_ADDRESS; 120 1.1 thorpej 121 1.1 thorpej /***************************** INSTRUMENTATION *******************************/ 122 1.1 thorpej 123 1.1 thorpej #ifdef PMAP_EVENT_COUNTERS 124 1.1 thorpej static struct evcnt pmap_ctx_alloc_static_ev = 125 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap ctx_alloc", "static"); 126 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_ctx_alloc_static_ev); 127 1.1 thorpej 128 1.1 thorpej static struct evcnt pmap_ctx_alloc_dynamic_ev = 129 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap ctx_alloc", "dynamic"); 130 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_ctx_alloc_dynamic_ev); 131 1.1 thorpej 132 1.1 thorpej static struct evcnt pmap_ctx_alloc_steal_ev = 133 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap ctx_alloc", "steal"); 134 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_ctx_alloc_steal_ev); 135 1.1 thorpej 136 1.1 thorpej static struct evcnt pmap_pv_alloc_wait_ev = 137 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap pv_alloc", "wait"); 138 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_pv_alloc_wait_ev); 139 1.1 thorpej 140 1.1 thorpej static struct evcnt pmap_pv_alloc_nowait_ev = 141 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap pv_alloc", "nowait"); 142 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_pv_alloc_nowait_ev); 143 1.1 thorpej 144 1.1 thorpej static struct evcnt pmap_pv_enter_called_ev = 145 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap pv_enter", "called"); 146 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_pv_enter_called_ev); 147 1.1 thorpej 148 1.1 thorpej static struct evcnt pmap_pv_remove_called_ev = 149 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap pv_remove", "called"); 150 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_pv_remove_called_ev); 151 1.1 thorpej 152 1.1 thorpej static struct evcnt pmap_enter_nowait_ev = 153 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap enter", "nowait"); 154 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_enter_nowait_ev); 155 1.1 thorpej 156 1.1 thorpej static struct evcnt pmap_enter_yeswait_ev = 157 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap enter", "yeswait"); 158 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_enter_yeswait_ev); 159 1.1 thorpej 160 1.1 thorpej static struct evcnt pmap_enter_wire_change_ev = 161 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap enter", "wire change"); 162 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_enter_wire_change_ev); 163 1.1 thorpej 164 1.1 thorpej static struct evcnt pmap_enter_prot_change_ev = 165 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap enter", "prot change"); 166 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_enter_prot_change_ev); 167 1.1 thorpej 168 1.1 thorpej static struct evcnt pmap_enter_pa_change_ev = 169 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap enter", "pa change"); 170 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_enter_pa_change_ev); 171 1.1 thorpej 172 1.1 thorpej static struct evcnt pmap_enter_pv_alloc_fail_ev = 173 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap enter", "pv alloc failed"); 174 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_enter_pv_alloc_fail_ev); 175 1.1 thorpej 176 1.1 thorpej static struct evcnt pmap_enter_pv_recycle_ev = 177 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap enter", "pv recycle"); 178 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_enter_pv_recycle_ev); 179 1.1 thorpej 180 1.1 thorpej static struct evcnt pmap_prm_got_pg_ev = 181 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap prm", "got pg"); 182 1.1 thorpej static struct evcnt pmap_prm_lookup_pg_hit_ev = 183 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap prm", "lookup pg hit"); 184 1.1 thorpej static struct evcnt pmap_prm_lookup_pg_miss_ev = 185 1.1 thorpej EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap prm", "lookup pg miss"); 186 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_prm_got_pg_ev); 187 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_prm_lookup_pg_hit_ev); 188 1.1 thorpej EVCNT_ATTACH_STATIC(pmap_prm_lookup_pg_miss_ev); 189 1.1 thorpej 190 1.1 thorpej #define pmap_evcnt(e) pmap_ ## e ## _ev.ev_count++ 191 1.1 thorpej #else 192 1.1 thorpej #define pmap_evcnt(e) __nothing 193 1.1 thorpej #endif 194 1.1 thorpej 195 1.1 thorpej /************************** FORWARD DECLARATIONS *****************************/ 196 1.1 thorpej 197 1.1 thorpej struct pmap_completion; 198 1.1 thorpej 199 1.1 thorpej static void pmap_segment_retain(pmap_t, vaddr_t); 200 1.1 thorpej static void pmap_segment_release(pmap_t, vaddr_t, int); 201 1.1 thorpej 202 1.1 thorpej static void pmap_remove_mapping(pmap_t, vaddr_t, unsigned int, 203 1.1 thorpej struct vm_page *pg, struct pmap_completion *); 204 1.1 thorpej static void pmap_remove_all_internal(pmap_t, struct pmap_completion *); 205 1.1 thorpej 206 1.1 thorpej /***************************** PHYS <-> VM PAGE ******************************/ 207 1.1 thorpej 208 1.1 thorpej static bool pmap_initialized_p; 209 1.1 thorpej 210 1.1 thorpej static inline struct vm_page * 211 1.1 thorpej pmap_pa_to_pg(paddr_t pa) 212 1.1 thorpej { 213 1.1 thorpej if (__predict_true(pmap_initialized_p)) { 214 1.1 thorpej return PHYS_TO_VM_PAGE(pa); 215 1.1 thorpej } 216 1.1 thorpej return NULL; 217 1.1 thorpej } 218 1.1 thorpej 219 1.1 thorpej static pm_entry_t pmap_changebit(struct vm_page *, pm_entry_t, pm_entry_t); 220 1.1 thorpej 221 1.1 thorpej /*************************** RESOURCE MANAGEMENT *****************************/ 222 1.1 thorpej 223 1.1 thorpej static struct pmap kernel_pmap_store; 224 1.1 thorpej struct pmap * const kernel_pmap_ptr = &kernel_pmap_store; 225 1.1 thorpej 226 1.1 thorpej /* 227 1.1 thorpej * Avoid a memory load when doing comparisons against pmap_kernel() 228 1.1 thorpej * within this compilation unit. 229 1.1 thorpej */ 230 1.1 thorpej #undef pmap_kernel 231 1.1 thorpej #define pmap_kernel() (&kernel_pmap_store) 232 1.1 thorpej 233 1.1 thorpej static struct pool pmap_pool; 234 1.1 thorpej static struct pool pmap_pv_pool; 235 1.1 thorpej 236 1.1 thorpej #define PMAP_PV_LOWAT 16 237 1.1 thorpej 238 1.1 thorpej static void 239 1.1 thorpej pmap_alloc_init(void) 240 1.1 thorpej { 241 1.1 thorpej pool_init(&pmap_pv_pool, sizeof(struct pv_entry), 242 1.1 thorpej PVH_ATTR_MASK + 1, /* align */ 243 1.1 thorpej 0, /* ioff */ 244 1.1 thorpej 0, /* flags */ 245 1.1 thorpej "pmappv", /* wchan */ 246 1.1 thorpej &pool_allocator_meta, /* palloc */ 247 1.1 thorpej IPL_VM); /* ipl */ 248 1.1 thorpej 249 1.1 thorpej /* 250 1.1 thorpej * Set a low water mark on the pv_entry pool, so that we are 251 1.1 thorpej * more likely to have these around even in extreme memory 252 1.1 thorpej * starvation. 253 1.1 thorpej */ 254 1.1 thorpej pool_setlowat(&pmap_pv_pool, PMAP_PV_LOWAT); 255 1.1 thorpej 256 1.1 thorpej pool_init(&pmap_pool, sizeof(struct pmap), 257 1.1 thorpej 0, /* align */ 258 1.1 thorpej 0, /* ioff */ 259 1.1 thorpej 0, /* flags */ 260 1.1 thorpej "pmappl", /* wchan */ 261 1.1 thorpej &pool_allocator_kmem, /* palloc */ 262 1.1 thorpej IPL_NONE); /* ipl */ 263 1.1 thorpej } 264 1.1 thorpej 265 1.1 thorpej static inline pmap_t 266 1.1 thorpej pmap_alloc(void) 267 1.1 thorpej { 268 1.1 thorpej pmap_t pmap = pool_get(&pmap_pool, PR_WAITOK); 269 1.1 thorpej memset(pmap, 0, sizeof(*pmap)); 270 1.1 thorpej return pmap; 271 1.1 thorpej } 272 1.1 thorpej 273 1.1 thorpej static inline void 274 1.1 thorpej pmap_free(pmap_t pmap) 275 1.1 thorpej { 276 1.1 thorpej pool_put(&pmap_pool, pmap); 277 1.1 thorpej } 278 1.1 thorpej 279 1.1 thorpej static struct pv_entry * 280 1.1 thorpej pmap_pv_alloc(bool nowait) 281 1.1 thorpej { 282 1.1 thorpej struct pv_entry *pv; 283 1.1 thorpej 284 1.1 thorpej #ifdef PMAP_EVENT_COUNTERS 285 1.1 thorpej if (nowait) { 286 1.1 thorpej pmap_evcnt(pv_alloc_nowait); 287 1.1 thorpej } else { 288 1.1 thorpej pmap_evcnt(pv_alloc_wait); 289 1.1 thorpej } 290 1.1 thorpej #endif 291 1.1 thorpej 292 1.1 thorpej pv = pool_get(&pmap_pv_pool, nowait ? PR_NOWAIT : 0); 293 1.1 thorpej if (__predict_true(pv != NULL)) { 294 1.1 thorpej KASSERT((((uintptr_t)pv) & PVH_ATTR_MASK) == 0); 295 1.1 thorpej } 296 1.1 thorpej return pv; 297 1.1 thorpej } 298 1.1 thorpej 299 1.1 thorpej static void 300 1.1 thorpej pmap_pv_free(struct pv_entry *pv) 301 1.1 thorpej { 302 1.1 thorpej pool_put(&pmap_pv_pool, pv); 303 1.1 thorpej } 304 1.1 thorpej 305 1.1 thorpej /* 306 1.1 thorpej * Whenever we need to free resources back to the system, we want to 307 1.1 thorpej * do it in a batch with any locks released. So, we have this around 308 1.1 thorpej * to collect the garbage, as needed. 309 1.1 thorpej */ 310 1.1 thorpej struct pmap_completion { 311 1.1 thorpej struct pv_entry *pc_pvlist; 312 1.1 thorpej }; 313 1.1 thorpej 314 1.1 thorpej static inline void 315 1.1 thorpej pmap_completion_init(struct pmap_completion *pc) 316 1.1 thorpej { 317 1.1 thorpej pc->pc_pvlist = NULL; 318 1.1 thorpej } 319 1.1 thorpej 320 1.1 thorpej static void 321 1.1 thorpej pmap_completion_fini(struct pmap_completion *pc) 322 1.1 thorpej { 323 1.1 thorpej struct pv_entry *pv; 324 1.1 thorpej 325 1.1 thorpej while ((pv = pc->pc_pvlist) != NULL) { 326 1.1 thorpej pc->pc_pvlist = pv->pv_next; 327 1.1 thorpej pmap_pv_free(pv); 328 1.1 thorpej } 329 1.1 thorpej } 330 1.1 thorpej 331 1.1 thorpej /* 332 1.1 thorpej * List of all user pmaps, used to identify potential marks for 333 1.1 thorpej * resource theft. This list is kept LRU-ordered by pmap_activate(). 334 1.1 thorpej */ 335 1.1 thorpej static TAILQ_HEAD(, pmap) pmap_all_user_pmaps; 336 1.1 thorpej 337 1.1 thorpej /* 338 1.1 thorpej * pmap_find_victim: 339 1.1 thorpej * 340 1.1 thorpej * Identify a pmap we can steal some resources from. 341 1.1 thorpej */ 342 1.1 thorpej static pmap_t 343 1.1 thorpej pmap_find_victim(void) 344 1.1 thorpej { 345 1.1 thorpej pmap_t pm, best_victim = NULL; 346 1.1 thorpej 347 1.1 thorpej /* 348 1.1 thorpej * Maybe not the best selection criteria, but: 349 1.1 thorpej * the least-recently-used pmap with the fewest 350 1.1 thorpej * number of wired mappings. 351 1.1 thorpej */ 352 1.1 thorpej 353 1.1 thorpej TAILQ_FOREACH(pm, &pmap_all_user_pmaps, pm_list) { 354 1.1 thorpej if (pm->pm_busy) { 355 1.1 thorpej continue; 356 1.1 thorpej } 357 1.1 thorpej if (pm->pm_context == NULL) { 358 1.1 thorpej continue; 359 1.1 thorpej } 360 1.1 thorpej if (pm->pm_stats.wired_count == 0) { 361 1.1 thorpej best_victim = pm; 362 1.1 thorpej break; 363 1.1 thorpej } 364 1.1 thorpej if (best_victim == NULL || 365 1.1 thorpej best_victim->pm_stats.wired_count > 366 1.1 thorpej pm->pm_stats.wired_count) { 367 1.1 thorpej best_victim = pm; 368 1.1 thorpej } 369 1.1 thorpej } 370 1.1 thorpej KASSERT(best_victim != NULL); 371 1.1 thorpej KASSERT(best_victim->pm_context != NULL); 372 1.1 thorpej 373 1.1 thorpej return best_victim; 374 1.1 thorpej } 375 1.1 thorpej 376 1.1 thorpej /* 377 1.1 thorpej * Generic bitmap management, used for pmegs. 378 1.1 thorpej */ 379 1.1 thorpej struct pmap_bitmap { 380 1.1 thorpej uint32_t * const bitmap_words; 381 1.1 thorpej unsigned int const bitmap_nwords; 382 1.1 thorpej unsigned int bitmap_alloc_hint; 383 1.1 thorpej }; 384 1.1 thorpej 385 1.1 thorpej #define PMAP_BITMAP_DECL(bm, bits) \ 386 1.1 thorpej __CTASSERT((bits) >= 32); \ 387 1.1 thorpej __CTASSERT(powerof2(bits)); \ 388 1.1 thorpej static uint32_t bm ## _bitmap_words[(bits) >> 5]; \ 389 1.1 thorpej static struct pmap_bitmap bm ## _bitmap = { \ 390 1.1 thorpej .bitmap_words = bm ## _bitmap_words, \ 391 1.1 thorpej .bitmap_nwords = (bits) >> 5, \ 392 1.1 thorpej }; 393 1.1 thorpej 394 1.1 thorpej #define BITMAP_NEXT_WORD(bm, x) \ 395 1.1 thorpej (((x) + 1) & ((bm)->bitmap_nwords - 1)) 396 1.1 thorpej 397 1.1 thorpej #define BITMAP_WORD(x) ((x) >> 5) 398 1.1 thorpej #define BITMAP_WORDOFFS(x) ((x) << 5) 399 1.1 thorpej #define BITMAP_BIT(x) (1U << ((x) & 31)) 400 1.1 thorpej 401 1.1 thorpej static void 402 1.1 thorpej pmap_bitmap_init(struct pmap_bitmap *bm) 403 1.1 thorpej { 404 1.1 thorpej for (unsigned int i = 0; i < bm->bitmap_nwords; i++) { 405 1.1 thorpej bm->bitmap_words[i] = 0xffffffffU; 406 1.1 thorpej } 407 1.1 thorpej } 408 1.1 thorpej 409 1.1 thorpej static void 410 1.1 thorpej pmap_bitmap_claim(struct pmap_bitmap *bm, unsigned int v) 411 1.1 thorpej { 412 1.1 thorpej KASSERT(v < BITMAP_WORDOFFS(bm->bitmap_nwords)); 413 1.1 thorpej bm->bitmap_words[BITMAP_WORD(v)] &= ~BITMAP_BIT(v); 414 1.1 thorpej } 415 1.1 thorpej 416 1.1 thorpej static bool 417 1.1 thorpej pmap_bitmap_claimed_p(struct pmap_bitmap *bm, unsigned int v) 418 1.1 thorpej { 419 1.1 thorpej KASSERT(v < BITMAP_WORDOFFS(bm->bitmap_nwords)); 420 1.1 thorpej return !(bm->bitmap_words[BITMAP_WORD(v)] & BITMAP_BIT(v)); 421 1.1 thorpej } 422 1.1 thorpej 423 1.1 thorpej static int 424 1.1 thorpej pmap_bitmap_alloc(struct pmap_bitmap *bm) 425 1.1 thorpej { 426 1.1 thorpej unsigned int i; 427 1.1 thorpej int v; 428 1.1 thorpej 429 1.1 thorpej for (i = bm->bitmap_alloc_hint;; 430 1.1 thorpej i = BITMAP_NEXT_WORD(bm, i)) { 431 1.1 thorpej v = ffs(bm->bitmap_words[i]) - 1; 432 1.1 thorpej if (v != -1) { 433 1.1 thorpej bm->bitmap_alloc_hint = i; 434 1.1 thorpej bm->bitmap_words[i] &= ~BITMAP_BIT(v); 435 1.1 thorpej return BITMAP_WORDOFFS(i) | v; 436 1.1 thorpej } 437 1.1 thorpej if (BITMAP_NEXT_WORD(bm, i) == bm->bitmap_alloc_hint) { 438 1.1 thorpej break; 439 1.1 thorpej } 440 1.1 thorpej } 441 1.1 thorpej 442 1.1 thorpej return -1; 443 1.1 thorpej } 444 1.1 thorpej 445 1.1 thorpej static void 446 1.1 thorpej pmap_bitmap_free(struct pmap_bitmap *bm, unsigned int v) 447 1.1 thorpej { 448 1.1 thorpej KASSERT(v < BITMAP_WORDOFFS(bm->bitmap_nwords)); 449 1.1 thorpej bm->bitmap_words[BITMAP_WORD(v)] |= BITMAP_BIT(v); 450 1.1 thorpej bm->bitmap_alloc_hint = BITMAP_WORD(v); 451 1.1 thorpej } 452 1.1 thorpej 453 1.1 thorpej /************************ SME MANIPULATION HELPERS ***************************/ 454 1.1 thorpej 455 1.1 thorpej static inline sm_entry_t 456 1.1 thorpej pmap_getsme(pmap_t pmap, vaddr_t va) 457 1.1 thorpej { 458 1.1 thorpej if (pmap == pmap_kernel()) { 459 1.1 thorpej return pgmmu_getsme0(va); 460 1.1 thorpej } 461 1.1 thorpej KASSERT(pmap->pm_context != NULL); 462 1.1 thorpej KASSERT(pmap->pm_context->ctx_num == pgmmu_getcontext()); 463 1.1 thorpej return pgmmu_getsme(va); 464 1.1 thorpej } 465 1.1 thorpej 466 1.1 thorpej static inline void 467 1.1 thorpej pmap_setsme(pmap_t pmap, vaddr_t va, sm_entry_t sme) 468 1.1 thorpej { 469 1.1 thorpej if (pmap == pmap_kernel()) { 470 1.1 thorpej pgmmu_setsme0(va, sme); 471 1.1 thorpej } else { 472 1.1 thorpej KASSERT(pmap->pm_context != NULL); 473 1.1 thorpej KASSERT(pmap->pm_context->ctx_num == pgmmu_getcontext()); 474 1.1 thorpej pgmmu_setsme(va, sme); 475 1.1 thorpej } 476 1.1 thorpej } 477 1.1 thorpej 478 1.1 thorpej static inline uint16_t 479 1.1 thorpej sme_pmeg(sm_entry_t sme) 480 1.1 thorpej { 481 1.1 thorpej return sme & SME_PMEG; 482 1.1 thorpej } 483 1.1 thorpej 484 1.1 thorpej static inline bool 485 1.1 thorpej sme_valid_p(sm_entry_t sme) 486 1.1 thorpej { 487 1.1 thorpej return !!(sme & SME_V); 488 1.1 thorpej } 489 1.1 thorpej 490 1.1 thorpej /************************ PME MANIPULATION HELPERS ***************************/ 491 1.1 thorpej 492 1.1 thorpej static inline paddr_t 493 1.1 thorpej pme_pa(pm_entry_t pme) 494 1.1 thorpej { 495 1.1 thorpej return pgmmu_ptob(pme & PME_PFN); 496 1.1 thorpej } 497 1.1 thorpej 498 1.1 thorpej static inline bool 499 1.1 thorpej pme_valid_p(pm_entry_t pme) 500 1.1 thorpej { 501 1.1 thorpej return !!(pme & PME_V); 502 1.1 thorpej } 503 1.1 thorpej 504 1.1 thorpej static inline bool 505 1.1 thorpej pme_wired_p(pm_entry_t pme) 506 1.1 thorpej { 507 1.1 thorpej return !!(pme & PME_WIRED); 508 1.1 thorpej } 509 1.1 thorpej 510 1.1 thorpej static inline bool 511 1.1 thorpej pme_managed_p(pm_entry_t pme) 512 1.1 thorpej { 513 1.1 thorpej return !!(pme & PME_PVLIST); 514 1.1 thorpej } 515 1.1 thorpej 516 1.1 thorpej static inline pm_entry_t 517 1.1 thorpej pme_change_prot(pm_entry_t opme, vm_prot_t prot) 518 1.1 thorpej { 519 1.1 thorpej return (opme & ~PME_W) | ((prot & UVM_PROT_WRITE) ? PME_W : 0); 520 1.1 thorpej } 521 1.1 thorpej 522 1.1 thorpej static inline unsigned int 523 1.1 thorpej pme_index(uint16_t pmeg, vaddr_t va) 524 1.1 thorpej { 525 1.1 thorpej return (((uint32_t)pmeg) << PGMMU_PMEG_SHIFT) + 526 1.1 thorpej (pgmmu_btop(va) & PGMMU_PMEG_OFFSET); 527 1.1 thorpej } 528 1.1 thorpej 529 1.1 thorpej static inline pm_entry_t 530 1.1 thorpej pmap_make_pme(pmap_t pmap, paddr_t pa, vm_prot_t prot, u_int flags) 531 1.1 thorpej { 532 1.1 thorpej pm_entry_t npme = PME_V | 533 1.1 thorpej (pmap == pmap_kernel() ? PME_K : 0) | 534 1.1 thorpej ((prot & UVM_PROT_WRITE) ? PME_W : 0) | 535 1.1 thorpej pgmmu_btop(pa); 536 1.1 thorpej if (flags & UVM_PROT_WRITE) { 537 1.1 thorpej npme |= PME_M | PME_R; 538 1.1 thorpej } else if (flags & (UVM_PROT_READ | UVM_PROT_EXEC)) { 539 1.1 thorpej npme |= PME_R; 540 1.1 thorpej } 541 1.1 thorpej if (flags & PMAP_WIRED) { 542 1.1 thorpej npme |= PME_WIRED; 543 1.1 thorpej } 544 1.1 thorpej 545 1.1 thorpej return npme; 546 1.1 thorpej } 547 1.1 thorpej 548 1.1 thorpej /* These helpers assume that all kernel segments have valid pmegs. */ 549 1.1 thorpej static pm_entry_t 550 1.1 thorpej pmap_getkpme(vaddr_t va) 551 1.1 thorpej { 552 1.1 thorpej sm_entry_t sme = pgmmu_getsme0(va); 553 1.1 thorpej return pgmmu_getpme(pme_index(sme_pmeg(sme), va)); 554 1.1 thorpej } 555 1.1 thorpej 556 1.1 thorpej static void 557 1.1 thorpej pmap_setkpme(vaddr_t va, pm_entry_t pme) 558 1.1 thorpej { 559 1.1 thorpej sm_entry_t sme = pgmmu_getsme0(va); 560 1.1 thorpej pgmmu_setpme(pme_index(sme_pmeg(sme), va), pme); 561 1.1 thorpej } 562 1.1 thorpej 563 1.1 thorpej /*************************** CONTEXT MANAGEMENT ******************************/ 564 1.1 thorpej 565 1.1 thorpej /* 566 1.1 thorpej * This MMU can do 64 contexts, which, to be honest, for a 68010 is kind 567 1.1 thorpej * of a lot! We're going to just assume that if a context has to be stolen 568 1.1 thorpej * from another pmap, that the PMEGs are going to get slurped up, too. So, 569 1.1 thorpej * if a context has to get stolen, then we are going to forcefully remove 570 1.1 thorpej * the entire thing, segmap included; it can all be reconstructed from the 571 1.1 thorpej * VM map. We will TRY to honor pmaps with wired mappings, but ultimately, 572 1.1 thorpej * the resources have to be shared. 573 1.1 thorpej * 574 1.1 thorpej * The upshot of this is that there's really no reason to keep a software 575 1.1 thorpej * copy of the segmap because, realistically, it's not very likely that 576 1.1 thorpej * a context will get stolen from another pmap, and thus there is no need 577 1.1 thorpej * for us to be able to reload a context quickly. 578 1.1 thorpej * 579 1.1 thorpej * So, it's all just kept in the hardware. 580 1.1 thorpej */ 581 1.1 thorpej 582 1.1 thorpej /* 583 1.1 thorpej * We have a static context for the kernel (the segrefs aren't used 584 1.1 thorpej * at all, but this makes the logic easier), and we statically allocate 585 1.1 thorpej * a handful of contexts for user pmaps as well. This ensures that 586 1.1 thorpej * there's at least a few around to steal at any given time. 587 1.1 thorpej */ 588 1.1 thorpej #define STATIC_CONTEXTS 9 589 1.1 thorpej static struct pmap_context static_contexts[STATIC_CONTEXTS]; 590 1.1 thorpej static struct pmap_context *context_freelist; 591 1.1 thorpej static unsigned int context_last; 592 1.1 thorpej 593 1.1 thorpej static unsigned int pmap_current_context; 594 1.1 thorpej 595 1.1 thorpej static unsigned int 596 1.1 thorpej pmap_swap_context(unsigned int ctx) 597 1.1 thorpej { 598 1.1 thorpej const unsigned int rv = pmap_current_context; 599 1.1 thorpej if (ctx != rv) { 600 1.1 thorpej pgmmu_setcontext(ctx); 601 1.1 thorpej pmap_current_context = ctx; 602 1.1 thorpej } 603 1.1 thorpej 604 1.1 thorpej return rv; 605 1.1 thorpej } 606 1.1 thorpej 607 1.1 thorpej static inline unsigned int 608 1.1 thorpej pmap_context_enter(pmap_t pmap) 609 1.1 thorpej { 610 1.1 thorpej struct pmap_context * const ctx = pmap->pm_context; 611 1.1 thorpej 612 1.1 thorpej KASSERT(ctx != NULL); 613 1.1 thorpej return pmap_swap_context(ctx->ctx_num); 614 1.1 thorpej } 615 1.1 thorpej 616 1.1 thorpej static inline void 617 1.1 thorpej pmap_context_exit(unsigned int saved_ctx) 618 1.1 thorpej { 619 1.1 thorpej (void) pmap_swap_context(saved_ctx); 620 1.1 thorpej } 621 1.1 thorpej 622 1.1 thorpej static struct pmap_context * 623 1.1 thorpej pmap_context_new(bool nowait) 624 1.1 thorpej { 625 1.1 thorpej struct pmap_context *ctx = NULL; 626 1.1 thorpej unsigned int ctx_num; 627 1.1 thorpej 628 1.1 thorpej ctx_num = context_last + 1; 629 1.1 thorpej if (__predict_false(ctx_num == PGMMU_NUM_CONTEXTS)) { 630 1.1 thorpej return NULL; 631 1.1 thorpej } 632 1.1 thorpej 633 1.1 thorpej if (ctx_num < STATIC_CONTEXTS) { 634 1.1 thorpej ctx = &static_contexts[ctx_num]; 635 1.1 thorpej pmap_evcnt(ctx_alloc_static); 636 1.1 thorpej } else { 637 1.1 thorpej PMAP_CRIT_EXIT(); 638 1.1 thorpej ctx = kmem_zalloc(sizeof(*ctx), 639 1.1 thorpej nowait ? KM_NOSLEEP : KM_SLEEP); 640 1.1 thorpej PMAP_CRIT_ENTER(); 641 1.1 thorpej if (!nowait) { 642 1.1 thorpej ctx_num = context_last + 1; 643 1.1 thorpej if (__predict_false(ctx_num >= 644 1.1 thorpej PGMMU_NUM_CONTEXTS)) { 645 1.1 thorpej kmem_free(ctx, sizeof(*ctx)); 646 1.1 thorpej return NULL; 647 1.1 thorpej } 648 1.1 thorpej } 649 1.1 thorpej pmap_evcnt(ctx_alloc_dynamic); 650 1.1 thorpej } 651 1.1 thorpej 652 1.1 thorpej ctx->ctx_num = context_last = ctx_num; 653 1.1 thorpej return ctx; 654 1.1 thorpej } 655 1.1 thorpej 656 1.1 thorpej static void 657 1.1 thorpej pmap_context_alloc(pmap_t pmap, bool nowait, struct pmap_completion *pc) 658 1.1 thorpej { 659 1.1 thorpej struct pmap_context *ctx; 660 1.1 thorpej 661 1.1 thorpej KASSERT(pmap != pmap_kernel()); 662 1.1 thorpej KASSERT(pmap->pm_context == NULL); 663 1.1 thorpej 664 1.1 thorpej if (__predict_true((ctx = context_freelist) != NULL)) { 665 1.1 thorpej context_freelist = ctx->ctx_next; 666 1.1 thorpej memset(ctx->ctx_segrefs, 0, sizeof(ctx->ctx_segrefs)); 667 1.1 thorpej goto got_one; 668 1.1 thorpej } 669 1.1 thorpej 670 1.1 thorpej if (__predict_true((ctx = pmap_context_new(true)) != NULL)) { 671 1.1 thorpej /* 672 1.1 thorpej * We may have blocked while allocating memory, in 673 1.1 thorpej * which case, another thread may have succeeded in 674 1.1 thorpej * nabbing a context for this pmap. If that's the 675 1.1 thorpej * case, then put the new one we just created onto 676 1.1 thorpej * the free list and proceed with the one we now 677 1.1 thorpej * find ourselves in possession of. 678 1.1 thorpej */ 679 1.1 thorpej if (__predict_false(pmap->pm_context != NULL)) { 680 1.1 thorpej ctx->ctx_next = context_freelist; 681 1.1 thorpej context_freelist = ctx; 682 1.1 thorpej return; 683 1.1 thorpej } 684 1.1 thorpej goto got_one; 685 1.1 thorpej } 686 1.1 thorpej 687 1.1 thorpej /* 688 1.1 thorpej * We're going to have to steal a context from someone else. 689 1.1 thorpej */ 690 1.1 thorpej pmap_t victim = pmap_find_victim(); 691 1.1 thorpej 692 1.1 thorpej ctx = victim->pm_context; 693 1.1 thorpej pmap_remove_all_internal(victim, pc); 694 1.1 thorpej victim->pm_context = NULL; 695 1.1 thorpej pmap_evcnt(ctx_alloc_steal); 696 1.1 thorpej got_one: 697 1.1 thorpej pmap->pm_context = ctx; 698 1.1 thorpej if (__predict_true(curproc != NULL && 699 1.1 thorpej pmap == curproc->p_vmspace->vm_map.pmap)) { 700 1.1 thorpej pmap_context_enter(pmap); 701 1.1 thorpej } 702 1.1 thorpej } 703 1.1 thorpej 704 1.1 thorpej static void 705 1.1 thorpej pmap_context_free(pmap_t pmap) 706 1.1 thorpej { 707 1.1 thorpej struct pmap_context *ctx; 708 1.1 thorpej 709 1.1 thorpej if (__predict_true((ctx = pmap->pm_context) != NULL)) { 710 1.1 thorpej pmap->pm_context = NULL; 711 1.1 thorpej ctx->ctx_next = context_freelist; 712 1.1 thorpej context_freelist = ctx; 713 1.1 thorpej } 714 1.1 thorpej } 715 1.1 thorpej 716 1.1 thorpej /***************************** PMEG MANAGEMENT *******************************/ 717 1.1 thorpej 718 1.1 thorpej /* 719 1.1 thorpej * This MMU has a lot of PMEGs, plenty to go around. We'll almost always 720 1.1 thorpej * be able to find a free one. Because of this, the victim selection for 721 1.1 thorpej * the situation where we need to steal one does not need to be particularly 722 1.1 thorpej * sophisticated. 723 1.1 thorpej */ 724 1.1 thorpej 725 1.1 thorpej PMAP_BITMAP_DECL(pmeg, PGMMU_NUM_PMEGS) 726 1.1 thorpej 727 1.1 thorpej static unsigned int 728 1.1 thorpej pmap_pmeg_alloc(pmap_t pmap, struct pmap_completion *pc) 729 1.1 thorpej { 730 1.1 thorpej vaddr_t va, nextva; 731 1.1 thorpej sm_entry_t sme; 732 1.1 thorpej unsigned int seg, i, saved_ctx; 733 1.1 thorpej int pmeg; 734 1.1 thorpej 735 1.1 thorpej pmeg = pmap_bitmap_alloc(&pmeg_bitmap); 736 1.1 thorpej if (pmeg != -1) { 737 1.1 thorpej return pmeg; 738 1.1 thorpej } 739 1.1 thorpej 740 1.1 thorpej /* 741 1.1 thorpej * We're going to have to steal a pmeg from someone else. 742 1.1 thorpej */ 743 1.1 thorpej pmap_t victim = pmap_find_victim(); 744 1.1 thorpej 745 1.1 thorpej /* 746 1.1 thorpej * Just steal the pmeg of the first valid segment we find. 747 1.1 thorpej */ 748 1.1 thorpej saved_ctx = pmap_context_enter(victim); 749 1.1 thorpej for (seg = 0, va = 0; seg < PGMMU_NUM_SEGS; seg++, va = nextva) { 750 1.1 thorpej nextva = va + PGMMU_SEG_SIZE; 751 1.1 thorpej sme = pgmmu_getsme(va); 752 1.1 thorpej if (sme_valid_p(sme)) { 753 1.1 thorpej pmap_segment_retain(victim, va); 754 1.1 thorpej pmeg = sme_pmeg(sme); 755 1.1 thorpej for (i = 0; i < PGMMU_PMEG_SIZE; i++) { 756 1.1 thorpej pmap_remove_mapping(victim, 757 1.1 thorpej va + (i * PAGE_SIZE), pmeg, NULL, pc); 758 1.1 thorpej } 759 1.1 thorpej pmap_segment_release(victim, va, -1); 760 1.1 thorpej break; 761 1.1 thorpej } 762 1.1 thorpej /* 763 1.1 thorpej * We are guaranteed to find something because the victim 764 1.1 thorpej * will have something to steal. If we go past the max 765 1.1 thorpej * user address or roll over back to 0, then we're well and 766 1.1 thorpej * truly <fill in the blank>. 767 1.1 thorpej */ 768 1.1 thorpej KASSERT(nextva < VM_MAXUSER_ADDRESS); 769 1.1 thorpej KASSERT(nextva != 0); 770 1.1 thorpej } 771 1.1 thorpej pmap_context_exit(saved_ctx); 772 1.1 thorpej KASSERT(pmeg != -1); 773 1.1 thorpej 774 1.1 thorpej return pmeg; 775 1.1 thorpej } 776 1.1 thorpej 777 1.1 thorpej static inline void 778 1.1 thorpej pmap_pmeg_free(unsigned int pmeg) 779 1.1 thorpej { 780 1.1 thorpej pmap_bitmap_free(&pmeg_bitmap, pmeg); 781 1.1 thorpej } 782 1.1 thorpej 783 1.1 thorpej static void 784 1.1 thorpej pmap_segment_retain(pmap_t pmap, vaddr_t va) 785 1.1 thorpej { 786 1.1 thorpej const unsigned int seg = pgmmu_btos(va); 787 1.1 thorpej struct pmap_context * const ctx = pmap->pm_context; 788 1.1 thorpej 789 1.1 thorpej if (__predict_true(pmap != pmap_kernel())) { 790 1.1 thorpej KASSERT(ctx != NULL); 791 1.1 thorpej ctx->ctx_segrefs[seg]++; 792 1.1 thorpej KASSERT(ctx->ctx_segrefs[seg] != 0); 793 1.1 thorpej } 794 1.1 thorpej } 795 1.1 thorpej 796 1.1 thorpej static void 797 1.1 thorpej pmap_segment_release(pmap_t pmap, vaddr_t va, int pmeg) 798 1.1 thorpej { 799 1.1 thorpej const unsigned int seg = pgmmu_btos(va); 800 1.1 thorpej struct pmap_context * const ctx = pmap->pm_context; 801 1.1 thorpej 802 1.1 thorpej if (__predict_true(pmap != pmap_kernel())) { 803 1.1 thorpej KASSERT(ctx != NULL); 804 1.1 thorpej KASSERT(ctx->ctx_segrefs[seg] != 0); 805 1.1 thorpej if (--ctx->ctx_segrefs[seg] == 0 && pmeg != -1) { 806 1.1 thorpej pmap_setsme(pmap, va, 0); 807 1.1 thorpej pmap_pmeg_free(pmeg); 808 1.1 thorpej } 809 1.1 thorpej } 810 1.1 thorpej } 811 1.1 thorpej 812 1.1 thorpej /************************** P->V ENTRY MANAGEMENT ****************************/ 813 1.1 thorpej 814 1.1 thorpej /* 815 1.1 thorpej * pmap_pv_enter: 816 1.1 thorpej * 817 1.1 thorpej * Add a physical->virtual entry to the pv table. Caller must provide 818 1.1 thorpej * the storage for the new PV entry. 819 1.1 thorpej */ 820 1.1 thorpej static void 821 1.1 thorpej pmap_pv_enter(pmap_t pmap, struct vm_page *pg, vaddr_t va, 822 1.1 thorpej unsigned int pmeg, struct pv_entry *newpv) 823 1.1 thorpej { 824 1.1 thorpej pmap_evcnt(pv_enter_called); 825 1.1 thorpej 826 1.1 thorpej PMAP_CRIT_ASSERT(); 827 1.1 thorpej KASSERT(newpv != NULL); 828 1.1 thorpej 829 1.1 thorpej newpv->pv_pmap = pmap; 830 1.1 thorpej newpv->pv_vf = va; 831 1.1 thorpej newpv->pv_pmeg = pmeg; 832 1.1 thorpej newpv->pv_next = VM_MDPAGE_PVS(pg); 833 1.1 thorpej VM_MDPAGE_SETPVP(VM_MDPAGE_HEAD_PVP(pg), newpv); 834 1.1 thorpej } 835 1.1 thorpej 836 1.1 thorpej /* 837 1.1 thorpej * pmap_pv_remove: 838 1.1 thorpej * 839 1.1 thorpej * Remove a physical->virtual entry from the pv table. 840 1.1 thorpej */ 841 1.1 thorpej static void 842 1.1 thorpej pmap_pv_remove(pmap_t pmap, struct vm_page *pg, vaddr_t va, 843 1.1 thorpej struct pmap_completion *pc) 844 1.1 thorpej { 845 1.1 thorpej struct pv_entry **pvp, *pv; 846 1.1 thorpej 847 1.1 thorpej pmap_evcnt(pv_remove_called); 848 1.1 thorpej 849 1.1 thorpej PMAP_CRIT_ASSERT(); 850 1.1 thorpej 851 1.1 thorpej for (pvp = VM_MDPAGE_HEAD_PVP(pg), pv = VM_MDPAGE_PVS(pg); 852 1.1 thorpej pv != NULL; 853 1.1 thorpej pvp = &pv->pv_next, pv = *pvp) { 854 1.1 thorpej if (pmap == pv->pv_pmap && va == PV_VA(pv)) { 855 1.1 thorpej break; 856 1.1 thorpej } 857 1.1 thorpej } 858 1.1 thorpej 859 1.1 thorpej KASSERT(pv != NULL); 860 1.1 thorpej VM_MDPAGE_SETPVP(pvp, pv->pv_next); 861 1.1 thorpej 862 1.1 thorpej KASSERT(pc != NULL); 863 1.1 thorpej pv->pv_next = pc->pc_pvlist; 864 1.1 thorpej pc->pc_pvlist = pv; 865 1.1 thorpej } 866 1.1 thorpej 867 1.1 thorpej /***************** PMAP INTERFACE (AND ADJACENT) FUNCTIONS *******************/ 868 1.1 thorpej 869 1.1 thorpej static inline void 870 1.1 thorpej pmap_stat_update_impl(long *valp, int val) 871 1.1 thorpej { 872 1.1 thorpej *valp += val; 873 1.1 thorpej } 874 1.1 thorpej 875 1.1 thorpej #define pmap_stat_update(pm, stat, delta) \ 876 1.1 thorpej pmap_stat_update_impl(&(pm)->pm_stats.stat, (delta)) 877 1.1 thorpej 878 1.1 thorpej static inline void 879 1.1 thorpej pmap_stat_set_impl(long *valp, int val) 880 1.1 thorpej { 881 1.1 thorpej atomic_store_relaxed(valp, val); 882 1.1 thorpej } 883 1.1 thorpej 884 1.1 thorpej #define pmap_stat_set(pm, stat, val) \ 885 1.1 thorpej pmap_stat_set_impl(&(pm)->pm_stats.stat, (val)) 886 1.1 thorpej 887 1.1 thorpej /* 888 1.1 thorpej * pmap_pinit: 889 1.1 thorpej * 890 1.1 thorpej * Common bits of pmap structure initialization shared between 891 1.1 thorpej * the kernel pmap and user pmaps. 892 1.1 thorpej */ 893 1.1 thorpej static void 894 1.1 thorpej pmap_pinit(pmap_t pmap, struct pmap_context *ctx) 895 1.1 thorpej { 896 1.1 thorpej pmap->pm_context = ctx; 897 1.1 thorpej atomic_store_relaxed(&pmap->pm_refcnt, 1); 898 1.1 thorpej } 899 1.1 thorpej 900 1.1 thorpej /* 901 1.1 thorpej * pmap_virtual_space: [ INTERFACE ] 902 1.1 thorpej * 903 1.1 thorpej * Define the initial bounds of the kernel virtual address space. 904 1.1 thorpej * 905 1.1 thorpej * In this implementation, the start address we return marks the 906 1.1 thorpej * end of the statically allocated special kernel virtual addresses 907 1.1 thorpej * set up in pmap_bootstrap1(). And since we have fixed mapping 908 1.1 thorpej * resources and thus don't need to have a pmap_growkernel(), we 909 1.1 thorpej * return the fill limit right away (clamped by whatever top-of 910 1.1 thorpej * address-space mappings that we need to keep around, like firmware 911 1.1 thorpej * and device mappings). 912 1.1 thorpej */ 913 1.1 thorpej void 914 1.1 thorpej pmap_virtual_space(vaddr_t *vstartp, vaddr_t *vendp) 915 1.1 thorpej { 916 1.1 thorpej *vstartp = kernel_virtual_start; 917 1.1 thorpej *vendp = kernel_virtual_max; 918 1.1 thorpej } 919 1.1 thorpej 920 1.1 thorpej /* 921 1.1 thorpej * pmap_init: [ INTERFACE ] 922 1.1 thorpej * 923 1.1 thorpej * Initialize the pmap module. Called by vm_init(), to initialize any 924 1.1 thorpej * structures that the pmap system needs to map virtual memory. 925 1.1 thorpej */ 926 1.1 thorpej void 927 1.1 thorpej pmap_init(void) 928 1.1 thorpej { 929 1.1 thorpej /* Initialize the pmap / pv_entry allocators. */ 930 1.1 thorpej pmap_alloc_init(); 931 1.1 thorpej 932 1.1 thorpej /* Now it's safe to do P->V entry recording! */ 933 1.1 thorpej pmap_initialized_p = true; 934 1.1 thorpej } 935 1.1 thorpej 936 1.1 thorpej /* 937 1.1 thorpej * pmap_create: [ INTERFACE ] 938 1.1 thorpej * 939 1.1 thorpej * Create and return a physical map. 940 1.1 thorpej */ 941 1.1 thorpej pmap_t 942 1.1 thorpej pmap_create(void) 943 1.1 thorpej { 944 1.1 thorpej pmap_t pmap; 945 1.1 thorpej 946 1.1 thorpej /* 947 1.1 thorpej * We don't allocate a context until the first mapping is 948 1.1 thorpej * entered. 949 1.1 thorpej */ 950 1.1 thorpej pmap = pmap_alloc(); 951 1.1 thorpej pmap_pinit(pmap, NULL); 952 1.1 thorpej 953 1.1 thorpej PMAP_CRIT_ENTER(); 954 1.1 thorpej TAILQ_INSERT_TAIL(&pmap_all_user_pmaps, pmap, pm_list); 955 1.1 thorpej PMAP_CRIT_EXIT(); 956 1.1 thorpej 957 1.1 thorpej return pmap; 958 1.1 thorpej } 959 1.1 thorpej 960 1.1 thorpej /* 961 1.1 thorpej * pmap_destroy: [ INTERFACE ] 962 1.1 thorpej * 963 1.1 thorpej * Drop the reference count on the specified pmap, releasing 964 1.1 thorpej * all resources if the reference count drops to zero. 965 1.1 thorpej */ 966 1.1 thorpej void 967 1.1 thorpej pmap_destroy(pmap_t pmap) 968 1.1 thorpej { 969 1.1 thorpej unsigned int newval; 970 1.1 thorpej 971 1.1 thorpej PMAP_CRIT_ENTER(); 972 1.1 thorpej KASSERT(pmap->pm_refcnt > 0); 973 1.1 thorpej newval = --pmap->pm_refcnt; 974 1.1 thorpej 975 1.1 thorpej if (newval) { 976 1.1 thorpej PMAP_CRIT_EXIT(); 977 1.1 thorpej return; 978 1.1 thorpej } 979 1.1 thorpej 980 1.1 thorpej /* We assume all mappings have been removed. */ 981 1.1 thorpej KASSERT(pmap->pm_stats.resident_count == 0); 982 1.1 thorpej if (pmap->pm_context != NULL) { 983 1.1 thorpej pmap_context_free(pmap); 984 1.1 thorpej } 985 1.1 thorpej 986 1.1 thorpej TAILQ_REMOVE(&pmap_all_user_pmaps, pmap, pm_list); 987 1.1 thorpej 988 1.1 thorpej PMAP_CRIT_EXIT(); 989 1.1 thorpej 990 1.1 thorpej pmap_free(pmap); 991 1.1 thorpej } 992 1.1 thorpej 993 1.1 thorpej /* 994 1.1 thorpej * pmap_reference: [ INTERFACE ] 995 1.1 thorpej * 996 1.1 thorpej * Add a reference to the specified pmap. 997 1.1 thorpej */ 998 1.1 thorpej void 999 1.1 thorpej pmap_reference(pmap_t pmap) 1000 1.1 thorpej { 1001 1.1 thorpej PMAP_CRIT_ENTER(); 1002 1.1 thorpej pmap->pm_refcnt++; 1003 1.1 thorpej KASSERT(pmap->pm_refcnt > 0); 1004 1.1 thorpej PMAP_CRIT_EXIT(); 1005 1.1 thorpej } 1006 1.1 thorpej 1007 1.1 thorpej /* 1008 1.1 thorpej * pmap_remove_mapping: 1009 1.1 thorpej * 1010 1.1 thorpej * Invalidate a single page denoted by pmap/va. 1011 1.1 thorpej */ 1012 1.1 thorpej static void 1013 1.1 thorpej pmap_remove_mapping(pmap_t pmap, vaddr_t va, unsigned int pmeg, 1014 1.1 thorpej struct vm_page *pg, struct pmap_completion *pc) 1015 1.1 thorpej { 1016 1.1 thorpej const unsigned int pmeidx = pme_index(pmeg, va); 1017 1.1 thorpej const pm_entry_t opme = pgmmu_getpme(pmeidx); 1018 1.1 thorpej 1019 1.1 thorpej if (! pme_valid_p(opme)) { 1020 1.1 thorpej return; 1021 1.1 thorpej } 1022 1.1 thorpej 1023 1.1 thorpej const paddr_t pa = pme_pa(opme); 1024 1.1 thorpej KASSERT(pg == NULL || pa == VM_PAGE_TO_PHYS(pg)); 1025 1.1 thorpej 1026 1.1 thorpej /* Update statistics. */ 1027 1.1 thorpej if (pme_wired_p(opme)) { 1028 1.1 thorpej pmap_stat_update(pmap, wired_count, -1); 1029 1.1 thorpej } 1030 1.1 thorpej pmap_stat_update(pmap, resident_count, -1); 1031 1.1 thorpej 1032 1.1 thorpej if (__predict_true(pg == NULL)) { 1033 1.1 thorpej pg = pmap_pa_to_pg(pa); 1034 1.1 thorpej if (pg != NULL) { 1035 1.1 thorpej pmap_evcnt(prm_lookup_pg_hit); 1036 1.1 thorpej } else { 1037 1.1 thorpej pmap_evcnt(prm_lookup_pg_miss); 1038 1.1 thorpej } 1039 1.1 thorpej } else { 1040 1.1 thorpej pmap_evcnt(prm_got_pg); 1041 1.1 thorpej } 1042 1.1 thorpej if (__predict_true(pg != NULL)) { 1043 1.1 thorpej KASSERT(pme_managed_p(opme)); 1044 1.1 thorpej /* Update cached M/R bits from mapping that's going away. */ 1045 1.1 thorpej VM_MDPAGE_ADD_MR(pg, opme); 1046 1.1 thorpej pmap_pv_remove(pmap, pg, va, pc); 1047 1.1 thorpej } else { 1048 1.1 thorpej KASSERT(! pme_managed_p(opme)); 1049 1.1 thorpej } 1050 1.1 thorpej 1051 1.1 thorpej /* Zap the Page Map entry. */ 1052 1.1 thorpej pgmmu_setpme(pmeidx, 0); 1053 1.1 thorpej pmap_segment_release(pmap, va, pmeg); 1054 1.1 thorpej } 1055 1.1 thorpej 1056 1.1 thorpej /* 1057 1.1 thorpej * pmap_remove: [ INTERFACE ] 1058 1.1 thorpej * 1059 1.1 thorpej * Remove the given range of addresses from the specified map. 1060 1.1 thorpej * 1061 1.1 thorpej * It is assumed that the start and end are properly rounded 1062 1.1 thorpej * to the page size. 1063 1.1 thorpej * 1064 1.1 thorpej * N.B. Callers of pmap_remove_internal() are expected to 1065 1.1 thorpej * provide an initialized completion context, which we 1066 1.1 thorpej * will finalize. 1067 1.1 thorpej */ 1068 1.1 thorpej static void 1069 1.1 thorpej pmap_remove_internal(pmap_t pmap, vaddr_t sva, vaddr_t eva, 1070 1.1 thorpej struct pmap_completion *pc) 1071 1.1 thorpej { 1072 1.1 thorpej sm_entry_t sme; 1073 1.1 thorpej vaddr_t nextseg; 1074 1.1 thorpej unsigned int saved_ctx; 1075 1.1 thorpej unsigned int pmeg; 1076 1.1 thorpej 1077 1.1 thorpej PMAP_CRIT_ENTER(pmap->pm_busy++); 1078 1.1 thorpej 1079 1.1 thorpej if (pmap->pm_context == NULL) { 1080 1.1 thorpej KASSERT(pmap->pm_stats.resident_count == 0); 1081 1.1 thorpej goto out; 1082 1.1 thorpej } 1083 1.1 thorpej saved_ctx = pmap_context_enter(pmap); 1084 1.1 thorpej 1085 1.1 thorpej while (sva < eva) { 1086 1.1 thorpej nextseg = pgmmu_next_seg(sva); 1087 1.1 thorpej if (nextseg == 0 || nextseg > eva) { 1088 1.1 thorpej nextseg = eva; 1089 1.1 thorpej } 1090 1.1 thorpej 1091 1.1 thorpej sme = pmap_getsme(pmap, sva); 1092 1.1 thorpej if (! sme_valid_p(sme)) { 1093 1.1 thorpej /* 1094 1.1 thorpej * No PMEG for this segment; advance to the 1095 1.1 thorpej * next one. 1096 1.1 thorpej */ 1097 1.1 thorpej sva = nextseg; 1098 1.1 thorpej continue; 1099 1.1 thorpej } 1100 1.1 thorpej pmeg = sme_pmeg(sme); 1101 1.1 thorpej 1102 1.1 thorpej for (; sva < nextseg; sva += PAGE_SIZE) { 1103 1.1 thorpej pmap_remove_mapping(pmap, sva, pmeg, NULL, pc); 1104 1.1 thorpej } 1105 1.1 thorpej } 1106 1.1 thorpej 1107 1.1 thorpej pmap_context_exit(saved_ctx); 1108 1.1 thorpej out: 1109 1.1 thorpej PMAP_CRIT_EXIT(pmap->pm_busy--); 1110 1.1 thorpej pmap_completion_fini(pc); 1111 1.1 thorpej } 1112 1.1 thorpej 1113 1.1 thorpej void 1114 1.1 thorpej pmap_remove(pmap_t pmap, vaddr_t sva, vaddr_t eva) 1115 1.1 thorpej { 1116 1.1 thorpej struct pmap_completion pc; 1117 1.1 thorpej pmap_completion_init(&pc); 1118 1.1 thorpej pmap_remove_internal(pmap, sva, eva, &pc); 1119 1.1 thorpej /* pmap_remove_internal() calls pmap_completion_fini(). */ 1120 1.1 thorpej } 1121 1.1 thorpej 1122 1.1 thorpej /* 1123 1.1 thorpej * pmap_remove_all: [ INTERFACE ] 1124 1.1 thorpej * 1125 1.1 thorpej * Remove all mappings from a pmap in bulk. This is only called 1126 1.1 thorpej * when it's known that the address space is no longer visible to 1127 1.1 thorpej * any user process (e.g. during exit or exec). 1128 1.1 thorpej */ 1129 1.1 thorpej static void 1130 1.1 thorpej pmap_remove_all_internal(pmap_t pmap, struct pmap_completion *pc) 1131 1.1 thorpej { 1132 1.1 thorpej unsigned int pmeg, seg, i, saved_ctx; 1133 1.1 thorpej vaddr_t va, nextva; 1134 1.1 thorpej sm_entry_t sme; 1135 1.1 thorpej 1136 1.1 thorpej saved_ctx = pmap_context_enter(pmap); 1137 1.1 thorpej for (seg = 0, va = 0; seg < PGMMU_NUM_SEGS; seg++, va = nextva) { 1138 1.1 thorpej nextva = va + PGMMU_SEG_SIZE; 1139 1.1 thorpej sme = pgmmu_getsme(va); 1140 1.1 thorpej if (sme_valid_p(sme)) { 1141 1.1 thorpej pmeg = sme_pmeg(sme); 1142 1.1 thorpej for (i = 0; i < PGMMU_PMEG_SIZE; 1143 1.1 thorpej i++, va += PAGE_SIZE) { 1144 1.1 thorpej pmap_remove_mapping(pmap, va, pmeg, NULL, pc); 1145 1.1 thorpej } 1146 1.1 thorpej } 1147 1.1 thorpej } 1148 1.1 thorpej pmap_context_exit(saved_ctx); 1149 1.1 thorpej } 1150 1.1 thorpej 1151 1.1 thorpej bool 1152 1.1 thorpej pmap_remove_all(pmap_t pmap) 1153 1.1 thorpej { 1154 1.1 thorpej struct pmap_completion pc; 1155 1.1 thorpej 1156 1.1 thorpej KASSERT(pmap != pmap_kernel()); 1157 1.1 thorpej 1158 1.1 thorpej pmap_completion_init(&pc); 1159 1.1 thorpej 1160 1.1 thorpej PMAP_CRIT_ENTER(pmap->pm_busy++); 1161 1.1 thorpej if (pmap->pm_context != NULL) { 1162 1.1 thorpej pmap_remove_all_internal(pmap, &pc); 1163 1.1 thorpej } 1164 1.1 thorpej PMAP_CRIT_EXIT(pmap->pm_busy--); 1165 1.1 thorpej 1166 1.1 thorpej pmap_completion_fini(&pc); 1167 1.1 thorpej 1168 1.1 thorpej return true; 1169 1.1 thorpej } 1170 1.1 thorpej 1171 1.1 thorpej /* 1172 1.1 thorpej * pmap_page_protect: [ INTERFACE ] 1173 1.1 thorpej * 1174 1.1 thorpej * Lower the permission for all mappings to a given page to 1175 1.1 thorpej * the permissions specified. 1176 1.1 thorpej */ 1177 1.1 thorpej void 1178 1.1 thorpej pmap_page_protect(struct vm_page *pg, vm_prot_t prot) 1179 1.1 thorpej { 1180 1.1 thorpej struct pmap_completion pc; 1181 1.1 thorpej struct pv_entry *pv; 1182 1.1 thorpej 1183 1.1 thorpej if (prot & UVM_PROT_WRITE) { 1184 1.1 thorpej /* No protection to revoke. */ 1185 1.1 thorpej return; 1186 1.1 thorpej } 1187 1.1 thorpej 1188 1.1 thorpej if (prot & UVM_PROT_READ) { 1189 1.1 thorpej /* Making page copy-on-write. */ 1190 1.1 thorpej pmap_changebit(pg, 0, (pm_entry_t)~PME_W); 1191 1.1 thorpej return; 1192 1.1 thorpej } 1193 1.1 thorpej 1194 1.1 thorpej /* Removing all mappings for a page. */ 1195 1.1 thorpej pmap_completion_init(&pc); 1196 1.1 thorpej 1197 1.1 thorpej PMAP_CRIT_ENTER(); 1198 1.1 thorpej 1199 1.1 thorpej unsigned int saved_ctx = pmap_current_context; 1200 1.1 thorpej 1201 1.1 thorpej while ((pv = VM_MDPAGE_PVS(pg)) != NULL) { 1202 1.1 thorpej pmap_context_enter(pv->pv_pmap); 1203 1.1 thorpej pv->pv_pmap->pm_busy++; 1204 1.1 thorpej pmap_remove_mapping(pv->pv_pmap, PV_VA(pv), pv->pv_pmeg, 1205 1.1 thorpej pg, &pc); 1206 1.1 thorpej pv->pv_pmap->pm_busy--; 1207 1.1 thorpej } 1208 1.1 thorpej 1209 1.1 thorpej pmap_context_exit(saved_ctx); 1210 1.1 thorpej 1211 1.1 thorpej PMAP_CRIT_EXIT(); 1212 1.1 thorpej 1213 1.1 thorpej pmap_completion_fini(&pc); 1214 1.1 thorpej } 1215 1.1 thorpej 1216 1.1 thorpej /* 1217 1.1 thorpej * pmap_protect: [ INTERFACE ] 1218 1.1 thorpej * 1219 1.1 thorpej * Set the physical protection on the specified range of this map 1220 1.1 thorpej * as requested. 1221 1.1 thorpej */ 1222 1.1 thorpej void 1223 1.1 thorpej pmap_protect(pmap_t pmap, vaddr_t sva, vaddr_t eva, vm_prot_t prot) 1224 1.1 thorpej { 1225 1.1 thorpej sm_entry_t sme; 1226 1.1 thorpej pm_entry_t opme, npme; 1227 1.1 thorpej vaddr_t nextseg; 1228 1.1 thorpej unsigned int saved_ctx; 1229 1.1 thorpej unsigned int pmeg; 1230 1.1 thorpej unsigned int pmeidx; 1231 1.1 thorpej 1232 1.1 thorpej if ((prot & UVM_PROT_READ) == 0) { 1233 1.1 thorpej struct pmap_completion pc; 1234 1.1 thorpej pmap_completion_init(&pc); 1235 1.1 thorpej pmap_remove_internal(pmap, sva, eva, &pc); 1236 1.1 thorpej /* pmap_remove_internal() calls pmap_completion_fini(). */ 1237 1.1 thorpej return; 1238 1.1 thorpej } 1239 1.1 thorpej 1240 1.1 thorpej PMAP_CRIT_ENTER(pmap->pm_busy++); 1241 1.1 thorpej 1242 1.1 thorpej if (pmap->pm_context == NULL) { 1243 1.1 thorpej KASSERT(pmap->pm_stats.resident_count == 0); 1244 1.1 thorpej goto out; 1245 1.1 thorpej } 1246 1.1 thorpej saved_ctx = pmap_context_enter(pmap); 1247 1.1 thorpej 1248 1.1 thorpej while (sva < eva) { 1249 1.1 thorpej nextseg = pgmmu_next_seg(sva); 1250 1.1 thorpej if (nextseg == 0 || nextseg > eva) { 1251 1.1 thorpej nextseg = eva; 1252 1.1 thorpej } 1253 1.1 thorpej 1254 1.1 thorpej sme = pmap_getsme(pmap, sva); 1255 1.1 thorpej if (! sme_valid_p(sme)) { 1256 1.1 thorpej /* 1257 1.1 thorpej * No PMEG for this segment; advance to the 1258 1.1 thorpej * next one. 1259 1.1 thorpej */ 1260 1.1 thorpej sva = nextseg; 1261 1.1 thorpej continue; 1262 1.1 thorpej } 1263 1.1 thorpej pmeg = sme_pmeg(sme); 1264 1.1 thorpej 1265 1.1 thorpej /* 1266 1.1 thorpej * Change protection on mapping if it is valid and doesn't 1267 1.1 thorpej * already have the correct protection. 1268 1.1 thorpej */ 1269 1.1 thorpej for (pmeidx = pme_index(pmeg, sva); 1270 1.1 thorpej sva < nextseg; pmeidx++, sva += PAGE_SIZE) { 1271 1.1 thorpej opme = pgmmu_getpme(pmeidx); 1272 1.1 thorpej if (! pme_valid_p(opme)) { 1273 1.1 thorpej continue; 1274 1.1 thorpej } 1275 1.1 thorpej npme = pme_change_prot(opme, prot); 1276 1.1 thorpej if (npme == opme) { 1277 1.1 thorpej continue; 1278 1.1 thorpej } 1279 1.1 thorpej pgmmu_setpme(pmeidx, npme); 1280 1.1 thorpej } 1281 1.1 thorpej } 1282 1.1 thorpej pmap_context_exit(saved_ctx); 1283 1.1 thorpej out: 1284 1.1 thorpej PMAP_CRIT_EXIT(pmap->pm_busy--); 1285 1.1 thorpej } 1286 1.1 thorpej 1287 1.1 thorpej /* 1288 1.1 thorpej * pmap_enter: [ INTERFACE ] 1289 1.1 thorpej * 1290 1.1 thorpej * Insert the given physical address (pa) at the specified 1291 1.1 thorpej * virtual address (va) in the target physical map with the 1292 1.1 thorpej * protection requested. 1293 1.1 thorpej * 1294 1.1 thorpej * If specified, the page will be wired down, meaning that 1295 1.1 thorpej * related pme can not be reclaimed. 1296 1.1 thorpej * 1297 1.1 thorpej * Note: This is the only routine which MAY NOT lazy-evaluate 1298 1.1 thorpej * or lose information. That is, this routine must actually 1299 1.1 thorpej * insert this page into the given map NOW. 1300 1.1 thorpej */ 1301 1.1 thorpej int 1302 1.1 thorpej pmap_enter(pmap_t pmap, vaddr_t va, paddr_t pa, vm_prot_t prot, u_int flags) 1303 1.1 thorpej { 1304 1.1 thorpej pm_entry_t npme, opme; 1305 1.1 thorpej sm_entry_t sme; 1306 1.1 thorpej unsigned int pmeg; 1307 1.1 thorpej unsigned int pmeidx; 1308 1.1 thorpej unsigned int saved_ctx; 1309 1.1 thorpej struct pv_entry *newpv; 1310 1.1 thorpej struct pmap_completion pc; 1311 1.1 thorpej int error = 0; 1312 1.1 thorpej const bool nowait = !!(flags & PMAP_CANFAIL); 1313 1.1 thorpej 1314 1.1 thorpej pmap_completion_init(&pc); 1315 1.1 thorpej 1316 1.1 thorpej struct vm_page * const pg = pmap_pa_to_pg(pa); 1317 1.1 thorpej 1318 1.1 thorpej PMAP_CRIT_ENTER(pmap->pm_busy++); 1319 1.1 thorpej 1320 1.1 thorpej if (nowait) { 1321 1.1 thorpej pmap_evcnt(enter_nowait); 1322 1.1 thorpej } else { 1323 1.1 thorpej pmap_evcnt(enter_yeswait); 1324 1.1 thorpej } 1325 1.1 thorpej 1326 1.1 thorpej /* If we don't already have a context, get one. */ 1327 1.1 thorpej if (__predict_false(pmap->pm_context == NULL)) { 1328 1.1 thorpej pmap_context_alloc(pmap, nowait, &pc); 1329 1.1 thorpej } 1330 1.1 thorpej 1331 1.1 thorpej saved_ctx = pmap_context_enter(pmap); 1332 1.1 thorpej 1333 1.1 thorpej /* Check to see if we already have a valid PMEG for this mapping. */ 1334 1.1 thorpej sme = pmap_getsme(pmap, va); 1335 1.1 thorpej if (sme_valid_p(sme)) { 1336 1.1 thorpej /* Yup! */ 1337 1.1 thorpej pmeg = sme_pmeg(sme); 1338 1.1 thorpej } else { 1339 1.1 thorpej /* Need to allocate one. */ 1340 1.1 thorpej pmeg = pmap_pmeg_alloc(pmap, &pc); 1341 1.1 thorpej pmap_setsme(pmap, va, SME_V | pmeg); 1342 1.1 thorpej } 1343 1.1 thorpej pmap_segment_retain(pmap, va); 1344 1.1 thorpej 1345 1.1 thorpej pmeidx = pme_index(pmeg, va); 1346 1.1 thorpej 1347 1.1 thorpej /* Compute the new PME. */ 1348 1.1 thorpej npme = pmap_make_pme(pmap, pa, prot, flags); 1349 1.1 thorpej 1350 1.1 thorpej /* Fetch the old PME. */ 1351 1.1 thorpej opme = pgmmu_getpme(pmeidx); 1352 1.1 thorpej 1353 1.1 thorpej /* 1354 1.1 thorpej * Check to see if there is an old mapping at this address. 1355 1.1 thorpej * It might simply be a wiring or protection change. 1356 1.1 thorpej */ 1357 1.1 thorpej if (pme_valid_p(opme)) { 1358 1.1 thorpej restart: 1359 1.1 thorpej if (pme_pa(opme) == pa) { 1360 1.1 thorpej /* 1361 1.1 thorpej * Just a protection or wiring change. 1362 1.1 thorpej * 1363 1.1 thorpej * Since the old PME is handy, go ahead and update 1364 1.1 thorpej * the cached M/R attributes now. Normally we would 1365 1.1 thorpej * do this in pmap_remove_mapping(), but we're not 1366 1.1 thorpej * taking that path in this case. We also add in 1367 1.1 thorpej * any M/R attributes hinted by the access type 1368 1.1 thorpej * that brought us to pmap_enter() in the first 1369 1.1 thorpej * place (a write-fault on a writable page mapped 1370 1.1 thorpej * read-only during a page-out, for example). 1371 1.1 thorpej * 1372 1.1 thorpej * Also ensure that the PV list status of the mapping 1373 1.1 thorpej * is consistent. 1374 1.1 thorpej */ 1375 1.1 thorpej if (__predict_true(pg != NULL)) { 1376 1.1 thorpej VM_MDPAGE_ADD_MR(pg, opme | npme); 1377 1.1 thorpej KASSERT(pme_managed_p(opme)); 1378 1.1 thorpej npme |= PME_PVLIST; 1379 1.1 thorpej } 1380 1.1 thorpej 1381 1.1 thorpej /* Set the new PME. */ 1382 1.1 thorpej pgmmu_setpme(pmeidx, npme); 1383 1.1 thorpej 1384 1.1 thorpej const pm_entry_t diff = opme ^ npme; 1385 1.1 thorpej 1386 1.1 thorpej #ifdef PMAP_EVENT_COUNTERS 1387 1.1 thorpej if (diff & PME_WIRED) { 1388 1.1 thorpej pmap_evcnt(enter_wire_change); 1389 1.1 thorpej } 1390 1.1 thorpej if (diff & PME_W) { 1391 1.1 thorpej pmap_evcnt(enter_prot_change); 1392 1.1 thorpej } 1393 1.1 thorpej #endif 1394 1.1 thorpej 1395 1.1 thorpej if (pme_wired_p(diff)) { 1396 1.1 thorpej pmap_stat_update(pmap, wired_count, 1397 1.1 thorpej pme_wired_p(npme) ? 1 : -1); 1398 1.1 thorpej } 1399 1.1 thorpej 1400 1.1 thorpej /* All done! */ 1401 1.1 thorpej goto out_release; 1402 1.1 thorpej } 1403 1.1 thorpej 1404 1.1 thorpej /* 1405 1.1 thorpej * The mapping has completely changed. Need to remove 1406 1.1 thorpej * the old one first. 1407 1.1 thorpej * 1408 1.1 thorpej * This will drop the retain count on the segment owned 1409 1.1 thorpej * by the previous mapping, but the newly-entered mapping 1410 1.1 thorpej * will inherit the retain count taken when we validated 1411 1.1 thorpej * the SME. 1412 1.1 thorpej */ 1413 1.1 thorpej pmap_evcnt(enter_pa_change); 1414 1.1 thorpej pmap_remove_mapping(pmap, va, pmeg, NULL, &pc); 1415 1.1 thorpej } 1416 1.1 thorpej 1417 1.1 thorpej /* Update pmap stats now. */ 1418 1.1 thorpej pmap_stat_update(pmap, resident_count, 1); 1419 1.1 thorpej if (__predict_false(pme_wired_p(npme))) { 1420 1.1 thorpej pmap_stat_update(pmap, wired_count, 1); 1421 1.1 thorpej } 1422 1.1 thorpej 1423 1.1 thorpej if (__predict_true(pg != NULL)) { 1424 1.1 thorpej /* 1425 1.1 thorpej * Managed pages also go on the PV list, so we are 1426 1.1 thorpej * going to need a PV entry. 1427 1.1 thorpej */ 1428 1.1 thorpej newpv = pc.pc_pvlist; 1429 1.1 thorpej if (__predict_true(newpv == NULL)) { 1430 1.1 thorpej /* 1431 1.1 thorpej * No PV entry to recycle; allocate a new one. 1432 1.1 thorpej * Because this is an extremely common case, we 1433 1.1 thorpej * are first going to attempt allocation while 1434 1.1 thorpej * still in the critical section. If that fails 1435 1.1 thorpej * and waiting is allowed, we'll leave the critical 1436 1.1 thorpej * section and try a blocking allocation. 1437 1.1 thorpej */ 1438 1.1 thorpej newpv = pmap_pv_alloc(true/*nowait flag*/); 1439 1.1 thorpej if (__predict_false(newpv == NULL)) { 1440 1.1 thorpej if (nowait) { 1441 1.1 thorpej pmap_evcnt(enter_pv_alloc_fail); 1442 1.1 thorpej error = ENOMEM; 1443 1.1 thorpej goto out_release; 1444 1.1 thorpej } 1445 1.1 thorpej /* XXX Should steal a PV */ 1446 1.1 thorpej PMAP_CRIT_EXIT(); 1447 1.1 thorpej newpv = pmap_pv_alloc(false/*nowait flag*/); 1448 1.1 thorpej KASSERT(newpv != NULL); 1449 1.1 thorpej PMAP_CRIT_ENTER(); 1450 1.1 thorpej /* 1451 1.1 thorpej * Because we may have blocked while allocating 1452 1.1 thorpej * the PV entry, we have to re-validate our 1453 1.1 thorpej * environment, as another thread could have 1454 1.1 thorpej * inserted a mapping here behind our back. 1455 1.1 thorpej */ 1456 1.1 thorpej opme = pgmmu_getpme(pmeidx); 1457 1.1 thorpej if (__predict_false(pme_valid_p(opme))) { 1458 1.1 thorpej pmap_stat_update(pmap, 1459 1.1 thorpej resident_count, -1); 1460 1.1 thorpej if (pme_wired_p(npme)) { 1461 1.1 thorpej pmap_stat_update(pmap, 1462 1.1 thorpej wired_count, -1); 1463 1.1 thorpej } 1464 1.1 thorpej newpv->pv_next = pc.pc_pvlist; 1465 1.1 thorpej pc.pc_pvlist = newpv; 1466 1.1 thorpej goto restart; 1467 1.1 thorpej } 1468 1.1 thorpej } 1469 1.1 thorpej } else { 1470 1.1 thorpej pmap_evcnt(enter_pv_recycle); 1471 1.1 thorpej pc.pc_pvlist = newpv->pv_next; 1472 1.1 thorpej newpv->pv_next = NULL; 1473 1.1 thorpej } 1474 1.1 thorpej 1475 1.1 thorpej /* Enter the mapping into the PV list. */ 1476 1.1 thorpej pmap_pv_enter(pmap, pg, va, pmeg, newpv); 1477 1.1 thorpej npme |= PME_PVLIST; 1478 1.1 thorpej 1479 1.1 thorpej /* ...and seed the page attributes. */ 1480 1.1 thorpej VM_MDPAGE_ADD_MR(pg, npme); 1481 1.1 thorpej } 1482 1.1 thorpej 1483 1.1 thorpej /* 1484 1.1 thorpej * Set the new PME. The new mapping takes ownership of the segment 1485 1.1 thorpej * retain count we took earlier. 1486 1.1 thorpej */ 1487 1.1 thorpej pgmmu_setpme(pmeidx, npme); 1488 1.1 thorpej goto out_crit_exit; 1489 1.1 thorpej 1490 1.1 thorpej out_release: 1491 1.1 thorpej pmap_segment_release(pmap, va, pmeg); 1492 1.1 thorpej out_crit_exit: 1493 1.1 thorpej pmap_context_exit(saved_ctx); 1494 1.1 thorpej PMAP_CRIT_EXIT(pmap->pm_busy--); 1495 1.1 thorpej 1496 1.1 thorpej pmap_completion_fini(&pc); 1497 1.1 thorpej return error; 1498 1.1 thorpej } 1499 1.1 thorpej 1500 1.1 thorpej /* 1501 1.1 thorpej * pmap_kenter_pa: [ INTERFACE ] 1502 1.1 thorpej * 1503 1.1 thorpej * Enter a va -> pa mapping into the kernel pmap without any 1504 1.1 thorpej * physical->virtual tracking. 1505 1.1 thorpej */ 1506 1.1 thorpej void 1507 1.1 thorpej pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot, u_int flags) 1508 1.1 thorpej { 1509 1.1 thorpej pmap_t const pmap = pmap_kernel(); 1510 1.1 thorpej 1511 1.1 thorpej const sm_entry_t sme = pgmmu_getsme0(va); 1512 1.1 thorpej 1513 1.1 thorpej /* The kernel context is fully loaded with PMEGs. */ 1514 1.1 thorpej KASSERT(sme_valid_p(sme)); 1515 1.1 thorpej const unsigned int pmeidx = pme_index(sme_pmeg(sme), va); 1516 1.1 thorpej 1517 1.1 thorpej /* Build the new PME. */ 1518 1.1 thorpej const pm_entry_t npme = 1519 1.1 thorpej pmap_make_pme(pmap, pa, prot, flags | PMAP_WIRED); 1520 1.1 thorpej 1521 1.1 thorpej /* There must not be a valid PTE here. */ 1522 1.1 thorpej KASSERT(! pme_valid_p(pgmmu_getpme(pmeidx))); 1523 1.1 thorpej 1524 1.1 thorpej /* Set the new PME. */ 1525 1.1 thorpej pgmmu_setpme(pmeidx, npme); 1526 1.1 thorpej 1527 1.1 thorpej pmap_stat_update(pmap, resident_count, 1); 1528 1.1 thorpej pmap_stat_update(pmap, wired_count, 1); 1529 1.1 thorpej } 1530 1.1 thorpej 1531 1.1 thorpej /* 1532 1.1 thorpej * pmap_kremove: [ INTERFACE ] 1533 1.1 thorpej * 1534 1.1 thorpej * Remove a mapping entered with pmap_kenter_pa() starting at va, 1535 1.1 thorpej * for size bytes (assumed to be page rounded). 1536 1.1 thorpej */ 1537 1.1 thorpej void 1538 1.1 thorpej pmap_kremove(vaddr_t va, vsize_t size) 1539 1.1 thorpej { 1540 1.1 thorpej int count = 0; 1541 1.1 thorpej sm_entry_t sme; 1542 1.1 thorpej pm_entry_t opme; 1543 1.1 thorpej unsigned int pmeidx; 1544 1.1 thorpej unsigned int pmeg; 1545 1.1 thorpej vaddr_t eva = va + size; 1546 1.1 thorpej vaddr_t nextseg; 1547 1.1 thorpej 1548 1.1 thorpej while (va < eva) { 1549 1.1 thorpej nextseg = pgmmu_next_seg(va); 1550 1.1 thorpej if (nextseg == 0 || nextseg > eva) { 1551 1.1 thorpej nextseg = eva; 1552 1.1 thorpej } 1553 1.1 thorpej 1554 1.1 thorpej sme = pgmmu_getsme0(va); 1555 1.1 thorpej KASSERT(sme_valid_p(sme)); 1556 1.1 thorpej 1557 1.1 thorpej pmeg = sme_pmeg(sme); 1558 1.1 thorpej 1559 1.1 thorpej for (pmeidx = pme_index(pmeg, va); 1560 1.1 thorpej va < nextseg; pmeidx++, va += PAGE_SIZE) { 1561 1.1 thorpej opme = pgmmu_getpme(pmeidx); 1562 1.1 thorpej if (pme_valid_p(opme)) { 1563 1.1 thorpej KASSERT(! pme_managed_p(opme)); 1564 1.1 thorpej KASSERT(pme_wired_p(opme)); 1565 1.1 thorpej /* Zap the mapping. */ 1566 1.1 thorpej pgmmu_setpme(pmeidx, 0); 1567 1.1 thorpej count++; 1568 1.1 thorpej } 1569 1.1 thorpej } 1570 1.1 thorpej } 1571 1.1 thorpej 1572 1.1 thorpej /* Update stats. */ 1573 1.1 thorpej if (__predict_true(count != 0)) { 1574 1.1 thorpej pmap_stat_update(pmap_kernel(), resident_count, -count); 1575 1.1 thorpej pmap_stat_update(pmap_kernel(), wired_count, -count); 1576 1.1 thorpej } 1577 1.1 thorpej } 1578 1.1 thorpej 1579 1.1 thorpej /* 1580 1.1 thorpej * pmap_unwire: [ INTERFACE ] 1581 1.1 thorpej * 1582 1.1 thorpej * Clear the wired attribute for a map/virtual-address pair. 1583 1.1 thorpej * 1584 1.1 thorpej * The mapping must already exist in the pmap. 1585 1.1 thorpej * (Except, it might not if we stole it.) 1586 1.1 thorpej */ 1587 1.1 thorpej void 1588 1.1 thorpej pmap_unwire(pmap_t pmap, vaddr_t va) 1589 1.1 thorpej { 1590 1.1 thorpej PMAP_CRIT_ENTER(pmap->pm_busy++); 1591 1.1 thorpej 1592 1.1 thorpej if (pmap->pm_context == NULL) { 1593 1.1 thorpej KASSERT(pmap->pm_stats.resident_count == 0); 1594 1.1 thorpej goto out; 1595 1.1 thorpej } 1596 1.1 thorpej const unsigned int saved_ctx = pmap_context_enter(pmap); 1597 1.1 thorpej 1598 1.1 thorpej const sm_entry_t sme = pmap_getsme(pmap, va); 1599 1.1 thorpej if (sme_valid_p(sme)) { 1600 1.1 thorpej const unsigned int pmeidx = pme_index(sme_pmeg(sme), va); 1601 1.1 thorpej const pm_entry_t pme = pgmmu_getpme(pmeidx); 1602 1.1 thorpej if (pme_valid_p(pme) && pme_wired_p(pme)) { 1603 1.1 thorpej pgmmu_setpme(pmeidx, pme & ~PME_WIRED); 1604 1.1 thorpej pmap_stat_update(pmap, wired_count, -1); 1605 1.1 thorpej } 1606 1.1 thorpej } 1607 1.1 thorpej 1608 1.1 thorpej pmap_context_exit(saved_ctx); 1609 1.1 thorpej out: 1610 1.1 thorpej PMAP_CRIT_EXIT(pmap->pm_busy--); 1611 1.1 thorpej } 1612 1.1 thorpej 1613 1.1 thorpej /* 1614 1.1 thorpej * pmap_extract: [ INTERFACE ] 1615 1.1 thorpej * 1616 1.1 thorpej * Extract the physical address associated with the given 1617 1.1 thorpej * pmap/virtual address pair. 1618 1.1 thorpej * 1619 1.1 thorpej * pmap_extract_info: 1620 1.1 thorpej * 1621 1.1 thorpej * Like pmap_extract(), but also returns information 1622 1.1 thorpej * about the mapping (wired, cache-inhibited, etc.) 1623 1.1 thorpej */ 1624 1.1 thorpej bool 1625 1.1 thorpej pmap_extract_info(pmap_t pmap, vaddr_t va, paddr_t *pap, int *flagsp) 1626 1.1 thorpej { 1627 1.1 thorpej unsigned int saved_ctx; 1628 1.1 thorpej bool rv = false; 1629 1.1 thorpej 1630 1.1 thorpej PMAP_CRIT_ENTER(pmap->pm_busy++); 1631 1.1 thorpej if (pmap->pm_context == NULL) { 1632 1.1 thorpej KASSERT(pmap->pm_stats.resident_count == 0); 1633 1.1 thorpej goto out; 1634 1.1 thorpej } 1635 1.1 thorpej saved_ctx = pmap_context_enter(pmap); 1636 1.1 thorpej 1637 1.1 thorpej const sm_entry_t sme = pmap_getsme(pmap, va); 1638 1.1 thorpej if (__predict_true(sme_valid_p(sme))) { 1639 1.1 thorpej const unsigned int pmeidx = pme_index(sme_pmeg(sme), va); 1640 1.1 thorpej const pm_entry_t pme = pgmmu_getpme(pmeidx); 1641 1.1 thorpej if (__predict_true(pme_valid_p(pme))) { 1642 1.1 thorpej if (__predict_true(pap != NULL)) { 1643 1.1 thorpej *pap = pme_pa(pme) | (va & PGOFSET); 1644 1.1 thorpej } 1645 1.1 thorpej if (__predict_false(flagsp != NULL)) { 1646 1.1 thorpej /* 1647 1.1 thorpej * No systems with this MMU have a data 1648 1.1 thorpej * cache, so always indicate that the 1649 1.1 thorpej * mappings are not cached. 1650 1.1 thorpej */ 1651 1.1 thorpej *flagsp = PMAP_NOCACHE | 1652 1.1 thorpej (pme_wired_p(pme) ? PMAP_WIRED : 0); 1653 1.1 thorpej } 1654 1.1 thorpej rv = true; 1655 1.1 thorpej } 1656 1.1 thorpej } 1657 1.1 thorpej 1658 1.1 thorpej pmap_context_exit(saved_ctx); 1659 1.1 thorpej out: 1660 1.1 thorpej PMAP_CRIT_EXIT(pmap->pm_busy--); 1661 1.1 thorpej return rv; 1662 1.1 thorpej } 1663 1.1 thorpej 1664 1.1 thorpej bool 1665 1.1 thorpej pmap_extract(pmap_t pmap, vaddr_t va, paddr_t *pap) 1666 1.1 thorpej { 1667 1.1 thorpej return pmap_extract_info(pmap, va, pap, NULL); 1668 1.1 thorpej } 1669 1.1 thorpej 1670 1.1 thorpej /* 1671 1.1 thorpej * vtophys: 1672 1.1 thorpej * 1673 1.1 thorpej * Dumber version of pmap_extract(pmap_kernel(), ...) 1674 1.1 thorpej */ 1675 1.1 thorpej paddr_t 1676 1.1 thorpej vtophys(vaddr_t va) 1677 1.1 thorpej { 1678 1.1 thorpej paddr_t pa; 1679 1.1 thorpej bool rv __diagused; 1680 1.1 thorpej 1681 1.1 thorpej rv = pmap_extract_info(pmap_kernel(), va, &pa, NULL); 1682 1.1 thorpej KASSERT(rv); 1683 1.1 thorpej return rv ? pa : -1; 1684 1.1 thorpej } 1685 1.1 thorpej 1686 1.1 thorpej /* 1687 1.1 thorpej * kvtop: 1688 1.1 thorpej * 1689 1.1 thorpej * Sigh. 1690 1.1 thorpej */ 1691 1.1 thorpej int 1692 1.1 thorpej kvtop(void *v) 1693 1.1 thorpej { 1694 1.1 thorpej return (int)vtophys((vaddr_t)v); 1695 1.1 thorpej } 1696 1.1 thorpej 1697 1.1 thorpej /* 1698 1.1 thorpej * pmap_copy: [ INTERFACE ] 1699 1.1 thorpej * 1700 1.1 thorpej * Copy the mapping range specified by src_addr/len 1701 1.1 thorpej * from the source map to the range dst_addr/len 1702 1.1 thorpej * in the destination map. 1703 1.1 thorpej * 1704 1.1 thorpej * This routine is only advisory and need not do anything. 1705 1.1 thorpej */ 1706 1.1 thorpej /* call deleted in <machine/pmap.h> */ 1707 1.1 thorpej 1708 1.1 thorpej /* 1709 1.1 thorpej * pmap_update: [ INTERFACE ] 1710 1.1 thorpej * 1711 1.1 thorpej * Require that all active physical maps contain no 1712 1.1 thorpej * incorrect entries NOW, by processing any deferred 1713 1.1 thorpej * pmap operations. 1714 1.1 thorpej */ 1715 1.1 thorpej /* call deleted in <machine/pmap.h> */ 1716 1.1 thorpej 1717 1.1 thorpej /* 1718 1.1 thorpej * pmap_activate: [ INTERFACE ] 1719 1.1 thorpej * 1720 1.1 thorpej * Activate the pmap used by the specified process. This includes 1721 1.1 thorpej * reloading the MMU context of the current process, and marking 1722 1.1 thorpej * the pmap in use by the processor. 1723 1.1 thorpej */ 1724 1.1 thorpej void 1725 1.1 thorpej pmap_activate(struct lwp *l) 1726 1.1 thorpej { 1727 1.1 thorpej pmap_t pmap = l->l_proc->p_vmspace->vm_map.pmap; 1728 1.1 thorpej 1729 1.1 thorpej KASSERT(l == curlwp); 1730 1.1 thorpej 1731 1.1 thorpej /* 1732 1.1 thorpej * If the pmap doesn't have a valid context, just use 1733 1.1 thorpej * the kernel's context for now (don't worry, the kernel's 1734 1.1 thorpej * mappings are protected with PME_K). 1735 1.1 thorpej */ 1736 1.1 thorpej PMAP_CRIT_ENTER(pmap->pm_busy++); 1737 1.1 thorpej (void) pmap_swap_context(pmap->pm_context != NULL 1738 1.1 thorpej ? pmap->pm_context->ctx_num : 0); 1739 1.1 thorpej if (pmap != pmap_kernel()) { 1740 1.1 thorpej TAILQ_REMOVE(&pmap_all_user_pmaps, pmap, pm_list); 1741 1.1 thorpej TAILQ_INSERT_TAIL(&pmap_all_user_pmaps, pmap, pm_list); 1742 1.1 thorpej } 1743 1.1 thorpej PMAP_CRIT_EXIT(); 1744 1.1 thorpej } 1745 1.1 thorpej 1746 1.1 thorpej /* 1747 1.1 thorpej * pmap_deactivate: [ INTERFACE ] 1748 1.1 thorpej * 1749 1.1 thorpej * Mark that the pmap used by the specified process is no longer 1750 1.1 thorpej * in use by the processor. 1751 1.1 thorpej */ 1752 1.1 thorpej void 1753 1.1 thorpej pmap_deactivate(struct lwp *l) 1754 1.1 thorpej { 1755 1.1 thorpej pmap_t pmap = l->l_proc->p_vmspace->vm_map.pmap; 1756 1.1 thorpej 1757 1.1 thorpej PMAP_CRIT_ENTER(); 1758 1.1 thorpej KASSERT(pmap->pm_busy != 0); 1759 1.1 thorpej PMAP_CRIT_EXIT(pmap->pm_busy--); 1760 1.1 thorpej } 1761 1.1 thorpej 1762 1.1 thorpej static vaddr_t pmap_tmpmap_srcva; 1763 1.1 thorpej static vaddr_t pmap_tmpmap_dstva; 1764 1.1 thorpej 1765 1.1 thorpej static unsigned int pmap_tmpmap_srcidx; 1766 1.1 thorpej static unsigned int pmap_tmpmap_dstidx; 1767 1.1 thorpej 1768 1.1 thorpej /* 1769 1.1 thorpej * pmap_zero_page: [ INTERFACE ] 1770 1.1 thorpej * 1771 1.1 thorpej * Zero the specified VM page by mapping the page into the kernel 1772 1.1 thorpej * and using memset() (or equivalent) to clear its contents. 1773 1.1 thorpej */ 1774 1.1 thorpej void 1775 1.1 thorpej pmap_zero_page(paddr_t pa) 1776 1.1 thorpej { 1777 1.1 thorpej const int flags = PMAP_WIRED; 1778 1.1 thorpej 1779 1.1 thorpej /* Build the new PME. */ 1780 1.1 thorpej const pm_entry_t dst_pme = 1781 1.1 thorpej pmap_make_pme(pmap_kernel(), pa, 1782 1.1 thorpej UVM_PROT_READ | UVM_PROT_WRITE, flags); 1783 1.1 thorpej 1784 1.1 thorpej /* Set the new PME. */ 1785 1.1 thorpej KASSERT(! pme_valid_p(pgmmu_getpme(pmap_tmpmap_dstidx))); 1786 1.1 thorpej pgmmu_setpme(pmap_tmpmap_dstidx, dst_pme); 1787 1.1 thorpej 1788 1.1 thorpej /* Zero the page. */ 1789 1.1 thorpej zeropage((void *)pmap_tmpmap_dstva); 1790 1.1 thorpej 1791 1.1 thorpej /* Invalidate the PME. */ 1792 1.1 thorpej pgmmu_setpme(pmap_tmpmap_dstidx, 0); 1793 1.1 thorpej } 1794 1.1 thorpej 1795 1.1 thorpej /* 1796 1.1 thorpej * pmap_copy_page: [ INTERFACE ] 1797 1.1 thorpej * 1798 1.1 thorpej * Copy the specified VM page by mapping the page(s) into the kernel 1799 1.1 thorpej * and using memcpy() (or equivalent). 1800 1.1 thorpej */ 1801 1.1 thorpej void 1802 1.1 thorpej pmap_copy_page(paddr_t src, paddr_t dst) 1803 1.1 thorpej { 1804 1.1 thorpej const int flags = PMAP_WIRED; 1805 1.1 thorpej 1806 1.1 thorpej /* Build the new PMEs. */ 1807 1.1 thorpej const pm_entry_t src_pme = 1808 1.1 thorpej pmap_make_pme(pmap_kernel(), src, 1809 1.1 thorpej UVM_PROT_READ, flags); 1810 1.1 thorpej const pm_entry_t dst_pme = 1811 1.1 thorpej pmap_make_pme(pmap_kernel(), dst, 1812 1.1 thorpej UVM_PROT_READ | UVM_PROT_WRITE, flags); 1813 1.1 thorpej 1814 1.1 thorpej /* Set the new PMEs. */ 1815 1.1 thorpej KASSERT(! pme_valid_p(pgmmu_getpme(pmap_tmpmap_srcidx))); 1816 1.1 thorpej pgmmu_setpme(pmap_tmpmap_srcidx, src_pme); 1817 1.1 thorpej KASSERT(! pme_valid_p(pgmmu_getpme(pmap_tmpmap_dstidx))); 1818 1.1 thorpej pgmmu_setpme(pmap_tmpmap_dstidx, dst_pme); 1819 1.1 thorpej 1820 1.1 thorpej /* Copy the page. */ 1821 1.1 thorpej copypage((void *)pmap_tmpmap_srcva, (void *)pmap_tmpmap_dstva); 1822 1.1 thorpej 1823 1.1 thorpej /* Invalidate the PMEs. */ 1824 1.1 thorpej pgmmu_setpme(pmap_tmpmap_srcidx, 0); 1825 1.1 thorpej pgmmu_setpme(pmap_tmpmap_dstidx, 0); 1826 1.1 thorpej } 1827 1.1 thorpej 1828 1.1 thorpej /* 1829 1.1 thorpej * pmap_testbit: 1830 1.1 thorpej * 1831 1.1 thorpej * Test the modified / referenced bits of a physical page. 1832 1.1 thorpej */ 1833 1.1 thorpej static bool 1834 1.1 thorpej pmap_testbit(struct vm_page *pg, pm_entry_t bit) 1835 1.1 thorpej { 1836 1.1 thorpej struct pv_entry *pv; 1837 1.1 thorpej pm_entry_t pme; 1838 1.1 thorpej 1839 1.1 thorpej PMAP_CRIT_ENTER(); 1840 1.1 thorpej 1841 1.1 thorpej pme = VM_MDPAGE_MR(pg); 1842 1.1 thorpej 1843 1.1 thorpej for (pv = VM_MDPAGE_PVS(pg); 1844 1.1 thorpej (pme & bit) == 0 && pv != NULL; pv = pv->pv_next) { 1845 1.1 thorpej pme |= pgmmu_getpme(pme_index(pv->pv_pmeg, PV_VA(pv))); 1846 1.1 thorpej } 1847 1.1 thorpej 1848 1.1 thorpej VM_MDPAGE_ADD_MR(pg, pme); 1849 1.1 thorpej 1850 1.1 thorpej PMAP_CRIT_EXIT(); 1851 1.1 thorpej 1852 1.1 thorpej return (pme & bit) != 0; 1853 1.1 thorpej } 1854 1.1 thorpej 1855 1.1 thorpej /* 1856 1.1 thorpej * pmap_is_referenced: [ INTERFACE ] 1857 1.1 thorpej * 1858 1.1 thorpej * Return whether or not the specified physical page has been referenced 1859 1.1 thorpej * by any physical maps. 1860 1.1 thorpej */ 1861 1.1 thorpej bool 1862 1.1 thorpej pmap_is_referenced(struct vm_page *pg) 1863 1.1 thorpej { 1864 1.1 thorpej return pmap_testbit(pg, PME_R); 1865 1.1 thorpej } 1866 1.1 thorpej 1867 1.1 thorpej /* 1868 1.1 thorpej * pmap_is_modified: [ INTERFACE ] 1869 1.1 thorpej * 1870 1.1 thorpej * Return whether or not the specified physical page has been modified 1871 1.1 thorpej * by any physical maps. 1872 1.1 thorpej */ 1873 1.1 thorpej bool 1874 1.1 thorpej pmap_is_modified(struct vm_page *pg) 1875 1.1 thorpej { 1876 1.1 thorpej return pmap_testbit(pg, PME_M); 1877 1.1 thorpej } 1878 1.1 thorpej 1879 1.1 thorpej /* 1880 1.1 thorpej * pmap_changebit: 1881 1.1 thorpej * 1882 1.1 thorpej * Test-and-change various bits (including mod/ref bits). 1883 1.1 thorpej * Returns the accumulated previously-set PME bits. 1884 1.1 thorpej */ 1885 1.1 thorpej static pm_entry_t 1886 1.1 thorpej pmap_changebit(struct vm_page *pg, pm_entry_t set, pm_entry_t mask) 1887 1.1 thorpej { 1888 1.1 thorpej struct pv_entry *pv; 1889 1.1 thorpej pm_entry_t combined_pme, opme, npme; 1890 1.1 thorpej unsigned int pmeidx; 1891 1.1 thorpej 1892 1.1 thorpej PMAP_CRIT_ENTER(); 1893 1.1 thorpej 1894 1.1 thorpej /* 1895 1.1 thorpej * Since we need to report if the page was mod/ref'd before 1896 1.1 thorpej * we cleared the bit, we need to seed ourself with the current 1897 1.1 thorpej * state in the vm_page in the event there are no mappings 1898 1.1 thorpej * left to enumerate. 1899 1.1 thorpej */ 1900 1.1 thorpej combined_pme = VM_MDPAGE_MR(pg); 1901 1.1 thorpej 1902 1.1 thorpej /* 1903 1.1 thorpej * Since we're running over every mapping for the page anyway, 1904 1.1 thorpej * we might as well synchronize any attribute bits that we're 1905 1.1 thorpej * not clearing. 1906 1.1 thorpej */ 1907 1.1 thorpej for (pv = VM_MDPAGE_PVS(pg); pv != NULL; pv = pv->pv_next) { 1908 1.1 thorpej pmeidx = pme_index(pv->pv_pmeg, PV_VA(pv)); 1909 1.1 thorpej opme = pgmmu_getpme(pmeidx); 1910 1.1 thorpej npme = (opme | set) & mask; 1911 1.1 thorpej combined_pme |= opme; 1912 1.1 thorpej if (opme != npme) { 1913 1.1 thorpej pgmmu_setpme(pmeidx, npme); 1914 1.1 thorpej } 1915 1.1 thorpej } 1916 1.1 thorpej 1917 1.1 thorpej /* 1918 1.1 thorpej * Update any attributes we looked at, clear the ones we're clearing. 1919 1.1 thorpej */ 1920 1.1 thorpej VM_MDPAGE_SET_MR(pg, (combined_pme | set) & mask); 1921 1.1 thorpej 1922 1.1 thorpej PMAP_CRIT_EXIT(); 1923 1.1 thorpej 1924 1.1 thorpej return combined_pme; 1925 1.1 thorpej } 1926 1.1 thorpej 1927 1.1 thorpej /* 1928 1.1 thorpej * pmap_clear_modify: [ INTERFACE ] 1929 1.1 thorpej * 1930 1.1 thorpej * Clear the modify bits on the specified physical page. 1931 1.1 thorpej */ 1932 1.1 thorpej bool 1933 1.1 thorpej pmap_clear_modify(struct vm_page *pg) 1934 1.1 thorpej { 1935 1.1 thorpej return (pmap_changebit(pg, 0, (pm_entry_t)~PME_M) & PME_M) != 0; 1936 1.1 thorpej } 1937 1.1 thorpej 1938 1.1 thorpej /* 1939 1.1 thorpej * pmap_clear_reference: [ INTERFACE ] 1940 1.1 thorpej * 1941 1.1 thorpej * Clear the reference bit on the specified physical page. 1942 1.1 thorpej */ 1943 1.1 thorpej bool 1944 1.1 thorpej pmap_clear_reference(struct vm_page *pg) 1945 1.1 thorpej { 1946 1.1 thorpej return (pmap_changebit(pg, 0, (pm_entry_t)~PME_R) & PME_R) != 0; 1947 1.1 thorpej } 1948 1.1 thorpej 1949 1.1 thorpej /* 1950 1.1 thorpej * pmap_phys_address: [ INTERFACE ] 1951 1.1 thorpej * 1952 1.1 thorpej * Return the physical address corresponding to the specified 1953 1.1 thorpej * cookie. Used by the device pager to decode a device driver's 1954 1.1 thorpej * mmap entry point return value. 1955 1.1 thorpej */ 1956 1.1 thorpej paddr_t 1957 1.1 thorpej pmap_phys_address(paddr_t cookie) 1958 1.1 thorpej { 1959 1.1 thorpej return pgmmu_ptob(cookie); 1960 1.1 thorpej } 1961 1.1 thorpej 1962 1.1 thorpej /* 1963 1.1 thorpej * pmap_init_kcore_hdr: 1964 1.1 thorpej * 1965 1.1 thorpej * Initialize the m68k kernel crash dump header with information 1966 1.1 thorpej * necessary to perform KVA -> phys translations. 1967 1.1 thorpej * 1968 1.1 thorpej * Returns a pointer to the crash dump RAM segment entries for 1969 1.1 thorpej * machine-specific code to initialize. 1970 1.1 thorpej */ 1971 1.1 thorpej phys_ram_seg_t * 1972 1.1 thorpej pmap_init_kcore_hdr(cpu_kcore_hdr_t *h) 1973 1.1 thorpej { 1974 1.1 thorpej return NULL; 1975 1.1 thorpej } 1976 1.1 thorpej 1977 1.1 thorpej #if defined(DDB) || defined(KGDB) 1978 1.1 thorpej /* 1979 1.1 thorpej * pmap_db_write_text_enter: 1980 1.1 thorpej * 1981 1.1 thorpej * Temporarily map a page of kernel text read-write for the 1982 1.1 thorpej * kernel debugger. 1983 1.1 thorpej */ 1984 1.1 thorpej bool 1985 1.1 thorpej pmap_db_write_text_enter(vaddr_t pgva, struct pmap_db_write_text_context *ctx) 1986 1.1 thorpej { 1987 1.1 thorpej sm_entry_t sme = pgmmu_getsme0(pgva); 1988 1.1 thorpej if (! sme_valid_p(sme)) { 1989 1.1 thorpej return false; 1990 1.1 thorpej } 1991 1.1 thorpej 1992 1.1 thorpej unsigned int pmeidx = pme_index(sme_pmeg(sme), pgva); 1993 1.1 thorpej pm_entry_t opme = pgmmu_getpme(pmeidx); 1994 1.1 thorpej if (! pme_valid_p(opme)) { 1995 1.1 thorpej return false; 1996 1.1 thorpej } 1997 1.1 thorpej 1998 1.1 thorpej pm_entry_t npme = opme | PME_W; 1999 1.1 thorpej pgmmu_setpme(pmeidx, npme); 2000 1.1 thorpej 2001 1.1 thorpej ctx->pmeidx = pmeidx; 2002 1.1 thorpej ctx->opme = opme; 2003 1.1 thorpej 2004 1.1 thorpej return true; 2005 1.1 thorpej } 2006 1.1 thorpej 2007 1.1 thorpej /* 2008 1.1 thorpej * pmap_db_write_text_exit: 2009 1.1 thorpej * 2010 1.1 thorpej * Undo the effects of pmap_db_write_text_enter(). 2011 1.1 thorpej */ 2012 1.1 thorpej void 2013 1.1 thorpej pmap_db_write_text_exit(struct pmap_db_write_text_context *ctx) 2014 1.1 thorpej { 2015 1.1 thorpej pgmmu_setpme(ctx->pmeidx, ctx->opme); 2016 1.1 thorpej } 2017 1.1 thorpej #endif /* DDB || KGDB */ 2018 1.1 thorpej 2019 1.1 thorpej /***************************** PMAP BOOTSTRAP ********************************/ 2020 1.1 thorpej 2021 1.1 thorpej extern char * kernel_text; 2022 1.1 thorpej extern char * etext; 2023 1.1 thorpej 2024 1.1 thorpej static vaddr_t lwp0uarea; 2025 1.1 thorpej char * vmmap; 2026 1.1 thorpej 2027 1.1 thorpej /* XXX Doesn't belong here. */ 2028 1.1 thorpej paddr_t avail_start; /* PA of first available physical page */ 2029 1.1 thorpej paddr_t avail_end; /* PA of last available physical page */ 2030 1.1 thorpej 2031 1.1 thorpej /* 2032 1.1 thorpej * This structure is used to save firmware mappings that the kernel 2033 1.1 thorpej * can also use. 2034 1.1 thorpej */ 2035 1.1 thorpej struct pmap_static_mapping { 2036 1.1 thorpej vaddr_t psm_va; 2037 1.1 thorpej paddr_t psm_pa; 2038 1.1 thorpej size_t psm_size; 2039 1.1 thorpej pm_entry_t psm_pme; 2040 1.1 thorpej }; 2041 1.1 thorpej 2042 1.1 thorpej #define MAX_STATIC_MAPPINGS 8 2043 1.1 thorpej static struct pmap_static_mapping static_mappings[MAX_STATIC_MAPPINGS]; 2044 1.1 thorpej static int num_static_mappings; 2045 1.1 thorpej 2046 1.1 thorpej /* 2047 1.1 thorpej * pmap_add_static_mapping: 2048 1.1 thorpej * 2049 1.1 thorpej * Add a VA != PA static mapping to the table. This is done 2050 1.1 thorpej * page-by-page, and may extend an existing entry. 2051 1.1 thorpej */ 2052 1.1 thorpej static bool 2053 1.1 thorpej pmap_add_static_mapping(vaddr_t va, paddr_t pa, pm_entry_t pme) 2054 1.1 thorpej { 2055 1.1 thorpej int i; 2056 1.1 thorpej 2057 1.1 thorpej /* only care about writability */ 2058 1.1 thorpej pme &= PME_W; 2059 1.1 thorpej 2060 1.1 thorpej /* 2061 1.1 thorpej * First check to see if this extends an existing entry. 2062 1.1 thorpej */ 2063 1.1 thorpej for (i = 0; i < num_static_mappings; i++) { 2064 1.1 thorpej if (va == static_mappings[i].psm_va + PAGE_SIZE && 2065 1.1 thorpej pa == static_mappings[i].psm_pa + PAGE_SIZE && 2066 1.1 thorpej pme == static_mappings[i].psm_pme) { 2067 1.1 thorpej static_mappings[i].psm_size += PAGE_SIZE; 2068 1.1 thorpej return true; 2069 1.1 thorpej } 2070 1.1 thorpej } 2071 1.1 thorpej 2072 1.1 thorpej /* 2073 1.1 thorpej * Create a new entry. 2074 1.1 thorpej */ 2075 1.1 thorpej if (num_static_mappings == MAX_STATIC_MAPPINGS) { 2076 1.1 thorpej return false; 2077 1.1 thorpej } 2078 1.1 thorpej 2079 1.1 thorpej static_mappings[i].psm_va = va; 2080 1.1 thorpej static_mappings[i].psm_pa = pa; 2081 1.1 thorpej static_mappings[i].psm_pme = pme; 2082 1.1 thorpej static_mappings[i].psm_size = PAGE_SIZE; 2083 1.1 thorpej num_static_mappings++; 2084 1.1 thorpej 2085 1.1 thorpej return true; 2086 1.1 thorpej } 2087 1.1 thorpej 2088 1.1 thorpej /* 2089 1.1 thorpej * pmap_pa_has_static_mapping: 2090 1.1 thorpej * 2091 1.1 thorpej * Returns true if the specified PA (and length) has a static mapping 2092 1.1 thorpej * with the requested permission. PMAP_* flags corresponding to the 2093 1.1 thorpej * mapping's properties are returned via *flagsp. 2094 1.1 thorpej */ 2095 1.1 thorpej bool 2096 1.1 thorpej pmap_pa_has_static_mapping(paddr_t pa, size_t len, vm_prot_t prot, 2097 1.1 thorpej vaddr_t *vap, int *flagsp) 2098 1.1 thorpej { 2099 1.1 thorpej paddr_t lastpg = pgmmu_btop(pa + (len - 1)); 2100 1.1 thorpej paddr_t firstpg = pgmmu_btop(pa); 2101 1.1 thorpej paddr_t tfirst, tlast; 2102 1.1 thorpej bool need_write = !!(prot & UVM_PROT_WRITE); 2103 1.1 thorpej int i; 2104 1.1 thorpej 2105 1.1 thorpej for (i = 0; i < num_static_mappings; i++) { 2106 1.1 thorpej tfirst = pgmmu_btop(static_mappings[i].psm_pa); 2107 1.1 thorpej tlast = pgmmu_btop(static_mappings[i].psm_pa + 2108 1.1 thorpej (static_mappings[i].psm_size - 1)); 2109 1.1 thorpej 2110 1.1 thorpej if (firstpg >= tfirst && lastpg <= tlast) { 2111 1.1 thorpej if (need_write && 2112 1.1 thorpej (static_mappings[i].psm_pme & PME_W) == 0) { 2113 1.1 thorpej return false; 2114 1.1 thorpej } 2115 1.1 thorpej *vap = static_mappings[i].psm_va + 2116 1.1 thorpej (pa - static_mappings[i].psm_pa); 2117 1.1 thorpej /* 2118 1.1 thorpej * No systems with this MMU have a data cache, 2119 1.1 thorpej * so always indocate PMAP_NOCACHE to anyone 2120 1.1 thorpej * making inquiries. 2121 1.1 thorpej */ 2122 1.1 thorpej *flagsp = PMAP_NOCACHE; 2123 1.1 thorpej return true; 2124 1.1 thorpej } 2125 1.1 thorpej } 2126 1.1 thorpej 2127 1.1 thorpej return false; 2128 1.1 thorpej } 2129 1.1 thorpej 2130 1.1 thorpej /* 2131 1.1 thorpej * pmap_va_is_static_mapping: 2132 1.1 thorpej * 2133 1.1 thorpej * Returns true if the specified VA (and length) is a static 2134 1.1 thorpej * mapping. 2135 1.1 thorpej */ 2136 1.1 thorpej bool 2137 1.1 thorpej pmap_va_is_static_mapping(vaddr_t va, size_t len) 2138 1.1 thorpej { 2139 1.1 thorpej vaddr_t lastpg = pgmmu_btop(va + (len - 1)); 2140 1.1 thorpej vaddr_t firstpg = pgmmu_btop(va); 2141 1.1 thorpej vaddr_t tfirst, tlast; 2142 1.1 thorpej int i; 2143 1.1 thorpej 2144 1.1 thorpej for (i = 0; i < num_static_mappings; i++) { 2145 1.1 thorpej tfirst = pgmmu_btop(static_mappings[i].psm_va); 2146 1.1 thorpej tlast = pgmmu_btop(static_mappings[i].psm_va + 2147 1.1 thorpej (static_mappings[i].psm_size - 1)); 2148 1.1 thorpej 2149 1.1 thorpej if (firstpg >= tfirst && lastpg <= tlast) { 2150 1.1 thorpej return true; 2151 1.1 thorpej } 2152 1.1 thorpej } 2153 1.1 thorpej 2154 1.1 thorpej return false; 2155 1.1 thorpej } 2156 1.1 thorpej 2157 1.1 thorpej /* 2158 1.1 thorpej * pmap_bootstrap1: 2159 1.1 thorpej * 2160 1.1 thorpej * Phase 1 of bootstrapping virtual memory. For this implementation, 2161 1.1 thorpej * the MMU is already enabled and we are running on the mappings 2162 1.1 thorpej * set up by the firmware. We need to initialize some of our 2163 1.1 thorpej * data structures, and preserve / adjust some of the mappings that 2164 1.1 thorpej * already exist. 2165 1.1 thorpej * 2166 1.1 thorpej * N.B. reloff is unused in this implementation because the MMU 2167 1.1 thorpej * is already on and thus manual relocations are not necessary. 2168 1.1 thorpej */ 2169 1.1 thorpej paddr_t __attribute__((no_instrument_function)) 2170 1.1 thorpej pmap_bootstrap1(paddr_t nextpa, paddr_t reloff __unused) 2171 1.1 thorpej { 2172 1.1 thorpej int i, seg, pmeg; 2173 1.1 thorpej paddr_t pa; 2174 1.1 thorpej paddr_t lwp0upa; 2175 1.1 thorpej sm_entry_t sme; 2176 1.1 thorpej pm_entry_t pme; 2177 1.1 thorpej vaddr_t va; 2178 1.1 thorpej vaddr_t nextva; 2179 1.1 thorpej vaddr_t endva; 2180 1.1 thorpej vaddr_t alloc_startva; 2181 1.1 thorpej int entry_count = 0; 2182 1.1 thorpej 2183 1.1 thorpej /* Initialize the kernel pmap. */ 2184 1.1 thorpej pmap_pinit(pmap_kernel(), &static_contexts[0]); 2185 1.1 thorpej pmap_kernel()->pm_busy = 1; /* kernel pmap starts out busy */ 2186 1.1 thorpej 2187 1.1 thorpej /* Initialize the pmeg bitmap. */ 2188 1.1 thorpej pmap_bitmap_init(&pmeg_bitmap); 2189 1.1 thorpej 2190 1.1 thorpej TAILQ_INIT(&pmap_all_user_pmaps); 2191 1.1 thorpej 2192 1.1 thorpej /* 2193 1.1 thorpej * Time to tidy up all of the various mappings left for us by the 2194 1.1 thorpej * firmware. 2195 1.1 thorpej * 2196 1.1 thorpej * First pass through SegMap0, claim all of the pmegs that are 2197 1.1 thorpej * currently in-use; we'll use them for kernel mappings, and 2198 1.1 thorpej * they're all pre-allocated. 2199 1.1 thorpej */ 2200 1.1 thorpej for (seg = 0, va = 0; seg < PGMMU_NUM_SEGS; 2201 1.1 thorpej seg++, va += PGMMU_SEG_SIZE) { 2202 1.1 thorpej sme = pgmmu_getsme0(va); 2203 1.1 thorpej if (sme_valid_p(sme)) { 2204 1.1 thorpej pmap_bitmap_claim(&pmeg_bitmap, sme_pmeg(sme)); 2205 1.1 thorpej } 2206 1.1 thorpej } 2207 1.1 thorpej 2208 1.1 thorpej /* 2209 1.1 thorpej * Now we know which pmegs are in-use, we can go through the 2210 1.1 thorpej * entire PageMap and zero-initialize all not-in-use entries. 2211 1.1 thorpej */ 2212 1.1 thorpej for (pmeg = 0; pmeg < PGMMU_NUM_PMEGS; pmeg++) { 2213 1.1 thorpej if (pmap_bitmap_claimed_p(&pmeg_bitmap, pmeg)) { 2214 1.1 thorpej continue; 2215 1.1 thorpej } 2216 1.1 thorpej for (i = 0; i < PGMMU_PMEG_SIZE; i++) { 2217 1.1 thorpej pgmmu_setpme((pmeg << PGMMU_PMEG_SHIFT) + i, 0); 2218 1.1 thorpej } 2219 1.1 thorpej } 2220 1.1 thorpej 2221 1.1 thorpej /* 2222 1.1 thorpej * Now go back through SegMap0 and assign pmegs to each segment 2223 1.1 thorpej * that doesn't already have one. 2224 1.1 thorpej */ 2225 1.1 thorpej for (seg = 0, va = 0; seg < PGMMU_NUM_SEGS; 2226 1.1 thorpej seg++, va += PGMMU_SEG_SIZE) { 2227 1.1 thorpej sme = pgmmu_getsme0(va); 2228 1.1 thorpej if (! sme_valid_p(sme)) { 2229 1.1 thorpej pmeg = pmap_bitmap_alloc(&pmeg_bitmap); 2230 1.1 thorpej pgmmu_setsme0(va, SME_V | pmeg); 2231 1.1 thorpej } 2232 1.1 thorpej } 2233 1.1 thorpej 2234 1.1 thorpej /* 2235 1.1 thorpej * Now go through the SegMaps for all of the user contexts 2236 1.1 thorpej * and zero-initialize them. 2237 1.1 thorpej */ 2238 1.1 thorpej for (i = 1; i < PGMMU_NUM_CONTEXTS; i++) { 2239 1.1 thorpej pgmmu_setcontext(i); 2240 1.1 thorpej for (seg = 0, va = 0; seg < PGMMU_NUM_SEGS; 2241 1.1 thorpej seg++, va += PGMMU_SEG_SIZE) { 2242 1.1 thorpej pgmmu_setsme(va, 0); 2243 1.1 thorpej } 2244 1.1 thorpej } 2245 1.1 thorpej 2246 1.1 thorpej pgmmu_setcontext(0); 2247 1.1 thorpej 2248 1.1 thorpej /* 2249 1.1 thorpej * The system firmware has done a few things: 2250 1.1 thorpej * 2251 1.1 thorpej * ==> (1) Mapped all base RAM VA==PA. The kernel has been loaded 2252 1.1 thorpej * here. We need to invalidate the mappings before and after 2253 1.1 thorpej * the kernel so that we can use the VA space for our own purposes. 2254 1.1 thorpej * NOTE: The stack that we were using when we entered the kernel 2255 1.1 thorpej * is located somewhere in there, so we need to have switched 2256 1.1 thorpej * to a temporary stack within the base kernel image before 2257 1.1 thorpej * getting to pmap_bootstrap1(). 2258 1.1 thorpej * 2259 1.1 thorpej * ==> (2) Mapped the ROM somewhere in the top 1MB of Context 0 2260 1.1 thorpej * (not necessarily the entire 1MB). 2261 1.1 thorpej * 2262 1.1 thorpej * ==> (3) Mapped the on-board devices and firmware reserved memory 2263 1.1 thorpej * just below the ROM. 2264 1.1 thorpej * 2265 1.1 thorpej * For (2) and (3), the mappings are not VA==PA. So, what we're 2266 1.1 thorpej * going to do is preserve all VA!=PA mappings, and then re-use them 2267 1.1 thorpej * whenever asked for them by others (like when drivers map devices), 2268 1.1 thorpej * and we'll clear the mappings for areas not-the-kernel in the 2269 1.1 thorpej * VA==PA areas. For the kernel text, we'll fix up the mappings to 2270 1.1 thorpej * be read-only. 2271 1.1 thorpej * 2272 1.1 thorpej * The physical pages before the kernel will be re-used for the 2273 1.1 thorpej * lwp0 u-area. We've arranged for the kernel to be linked at 2274 1.1 thorpej * 0 + USPACE in order to faciliate this, and we know this will 2275 1.1 thorpej * be in the first segment. 2276 1.1 thorpej * 2277 1.1 thorpej * For all mappings that we preserve, we also ensure that the K 2278 1.1 thorpej * bit is set. 2279 1.1 thorpej * 2280 1.1 thorpej * XXX We're making assumptions about the system firmware and memory 2281 1.1 thorpej * map here, but I can count on one finger the number of systems that 2282 1.1 thorpej * use this MMU. 2283 1.1 thorpej */ 2284 1.1 thorpej 2285 1.1 thorpej /* Unmap the region before the kernel text. */ 2286 1.1 thorpej endva = pgmmu_trunc_page(&kernel_text); 2287 1.1 thorpej lwp0upa = endva - USPACE; 2288 1.1 thorpej for (va = 0; va < endva; va += PAGE_SIZE) { 2289 1.1 thorpej pmap_setkpme(va, 0); 2290 1.1 thorpej } 2291 1.1 thorpej 2292 1.1 thorpej /* Fix kernel text to be read-only. */ 2293 1.1 thorpej endva = pgmmu_trunc_page(&etext); 2294 1.1 thorpej for (; va < endva; va += PAGE_SIZE) { 2295 1.1 thorpej pme = pmap_getkpme(va); 2296 1.1 thorpej pmap_setkpme(va, (pme & ~PME_W) | PME_K); 2297 1.1 thorpej entry_count++; 2298 1.1 thorpej } 2299 1.1 thorpej 2300 1.1 thorpej /* Fixup priv on the rest of the kernel. */ 2301 1.1 thorpej endva = alloc_startva = nextpa = pgmmu_round_page(nextpa); 2302 1.1 thorpej for (; va < endva; va += PAGE_SIZE) { 2303 1.1 thorpej pme = pmap_getkpme(va); 2304 1.1 thorpej pmap_setkpme(va, pme | PME_W | PME_K); 2305 1.1 thorpej entry_count++; 2306 1.1 thorpej } 2307 1.1 thorpej 2308 1.1 thorpej /* 2309 1.1 thorpej * Now walk every remaining kernel PME and check to see if 2310 1.1 thorpej * it's a VA != PA mapping. If so, preserve it (and clamp 2311 1.1 thorpej * the max kernel virtual address as necessary). 2312 1.1 thorpej */ 2313 1.1 thorpej for (; va < KERNEL_MAX_ADDRESS && va >= alloc_startva; 2314 1.1 thorpej va += PAGE_SIZE) { 2315 1.1 thorpej pme = pmap_getkpme(va); 2316 1.1 thorpej if (! pme_valid_p(pme)) { 2317 1.1 thorpej continue; 2318 1.1 thorpej } 2319 1.1 thorpej pa = pme_pa(pme); 2320 1.1 thorpej if (va == pa) { 2321 1.1 thorpej pmap_setkpme(va, 0); 2322 1.1 thorpej continue; 2323 1.1 thorpej } 2324 1.1 thorpej 2325 1.1 thorpej /* Clamp the max kernel virtual address. */ 2326 1.1 thorpej if (va < kernel_virtual_max) { 2327 1.1 thorpej kernel_virtual_max = va; 2328 1.1 thorpej } 2329 1.1 thorpej 2330 1.1 thorpej if (! pmap_add_static_mapping(va, pa, pme)) { 2331 1.1 thorpej /* XXX log a warning? */ 2332 1.1 thorpej } 2333 1.1 thorpej 2334 1.1 thorpej /* Ensure it's kernel-only. */ 2335 1.1 thorpej pmap_setkpme(va, pme | PME_K); 2336 1.1 thorpej entry_count++; 2337 1.1 thorpej } 2338 1.1 thorpej 2339 1.1 thorpej /* 2340 1.1 thorpej * Allocate / map some special purpose VAs: 2341 1.1 thorpej */ 2342 1.1 thorpej nextva = alloc_startva; 2343 1.1 thorpej 2344 1.1 thorpej /* lwp0 u-area. */ 2345 1.1 thorpej lwp0uarea = nextva; 2346 1.1 thorpej nextva += USPACE; 2347 1.1 thorpej 2348 1.1 thorpej pme = pmap_make_pme(pmap_kernel(), lwp0upa, 2349 1.1 thorpej UVM_PROT_READ|UVM_PROT_WRITE, PMAP_WIRED); 2350 1.1 thorpej for (va = lwp0uarea; va < nextva; va += PAGE_SIZE) { 2351 1.1 thorpej pmap_setkpme(va, pme); 2352 1.1 thorpej pme++; /* increment PFN field */ 2353 1.1 thorpej entry_count++; 2354 1.1 thorpej } 2355 1.1 thorpej 2356 1.1 thorpej /* pmap temporary map addresses */ 2357 1.1 thorpej pmap_tmpmap_srcva = nextva; 2358 1.1 thorpej nextva += PAGE_SIZE; 2359 1.1 thorpej sme = pgmmu_getsme0(pmap_tmpmap_srcva); 2360 1.1 thorpej pmap_tmpmap_srcidx = pme_index(sme_pmeg(sme), pmap_tmpmap_srcva); 2361 1.1 thorpej 2362 1.1 thorpej pmap_tmpmap_dstva = nextva; 2363 1.1 thorpej nextva += PAGE_SIZE; 2364 1.1 thorpej sme = pgmmu_getsme0(pmap_tmpmap_dstva); 2365 1.1 thorpej pmap_tmpmap_dstidx = pme_index(sme_pmeg(sme), pmap_tmpmap_dstva); 2366 1.1 thorpej 2367 1.1 thorpej /* vmmap temporary map address */ 2368 1.1 thorpej vmmap = (char *)nextva; 2369 1.1 thorpej nextva += PAGE_SIZE; 2370 1.1 thorpej 2371 1.1 thorpej /* kernel message buffer */ 2372 1.1 thorpej msgbufaddr = (char *)nextva; 2373 1.1 thorpej nextva += pgmmu_round_page(MSGBUFSIZE); 2374 1.1 thorpej 2375 1.1 thorpej /* UVM-managed kernel virtual starts here. */ 2376 1.1 thorpej kernel_virtual_start = nextva; 2377 1.1 thorpej 2378 1.1 thorpej /* 2379 1.1 thorpej * Record the number of wired mappings we create above 2380 1.1 thorpej * in the kernel pmap stats. 2381 1.1 thorpej */ 2382 1.1 thorpej pmap_kernel()->pm_stats.resident_count = entry_count; 2383 1.1 thorpej pmap_kernel()->pm_stats.wired_count = entry_count; 2384 1.1 thorpej 2385 1.1 thorpej return nextpa; 2386 1.1 thorpej } 2387 1.1 thorpej 2388 1.1 thorpej /* 2389 1.1 thorpej * pmap_bootstrap2: 2390 1.1 thorpej * 2391 1.1 thorpej * Phase 2 of bootstrapping virtual memory. For this implementation, 2392 1.1 thorpej * we just have to finish setting up some run-time-computed global 2393 1.1 thorpej * pmap data, plus the lwp0 u-area, curlwp, and curpcb. 2394 1.1 thorpej * 2395 1.1 thorpej * Returns the new kernel %sp value for lwp0. 2396 1.1 thorpej */ 2397 1.1 thorpej void * 2398 1.1 thorpej pmap_bootstrap2(void) 2399 1.1 thorpej { 2400 1.1 thorpej /* Early low-level UVM initialization. */ 2401 1.1 thorpej uvmexp.pagesize = PAGE_SIZE; 2402 1.1 thorpej uvm_md_init(); 2403 1.1 thorpej 2404 1.1 thorpej /* Initialize lwp0 u-area, curlwp, and curpcb. */ 2405 1.1 thorpej memset((void *)lwp0uarea, 0, USPACE); 2406 1.1 thorpej uvm_lwp_setuarea(&lwp0, lwp0uarea); 2407 1.1 thorpej curlwp = &lwp0; 2408 1.1 thorpej curpcb = lwp_getpcb(&lwp0); 2409 1.1 thorpej 2410 1.1 thorpej /* Create a fake exception frame so that cpu_lwp_fork() can copy it. */ 2411 1.1 thorpej struct trapframe *tf = (struct trapframe *)(lwp0uarea + USPACE) - 1; 2412 1.1 thorpej tf->tf_sr = PSL_USER; 2413 1.1 thorpej lwp0.l_md.md_regs = (int *)tf; 2414 1.1 thorpej 2415 1.1 thorpej /* 2416 1.1 thorpej * Initialize the source/destination control registers for 2417 1.1 thorpej * movs. 2418 1.1 thorpej */ 2419 1.1 thorpej setsfc(FC_USERD); 2420 1.1 thorpej setdfc(FC_USERD); 2421 1.1 thorpej 2422 1.1 thorpej return tf; 2423 1.1 thorpej } 2424