1 /* $NetBSD: pmap.c,v 1.117 2022/03/20 18:56:29 andvar Exp $ */ 2 3 /*- 4 * Copyright (c) 2011 Reinoud Zandijk <reinoud (at) NetBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.117 2022/03/20 18:56:29 andvar Exp $"); 31 32 #include "opt_memsize.h" 33 #include "opt_kmempages.h" 34 #include "opt_misc.h" 35 36 #include <sys/types.h> 37 #include <sys/param.h> 38 #include <sys/mutex.h> 39 #include <sys/buf.h> 40 #include <sys/kmem.h> 41 #include <sys/malloc.h> 42 #include <sys/pool.h> 43 #include <machine/thunk.h> 44 #include <machine/machdep.h> 45 #include <machine/pcb.h> 46 47 #include <uvm/uvm.h> 48 49 struct pv_entry { 50 struct pv_entry *pv_next; 51 pmap_t pv_pmap; 52 uintptr_t pv_ppn; /* physical page number */ 53 uintptr_t pv_lpn; /* logical page number */ 54 vm_prot_t pv_prot; /* logical protection */ 55 uint8_t pv_mmap_ppl; /* programmed protection */ 56 uint8_t pv_vflags; /* per mapping flags */ 57 #define PV_WIRED 0x01 /* wired mapping */ 58 #define PV_UNMANAGED 0x02 /* entered by pmap_kenter_ */ 59 uint8_t pv_pflags; /* per phys page flags */ 60 #define PV_REFERENCED 0x01 61 #define PV_MODIFIED 0x02 62 }; 63 64 #define PMAP_L2_SIZE PAGE_SIZE 65 #define PMAP_L2_NENTRY (PMAP_L2_SIZE / sizeof(struct pv_entry *)) 66 67 struct pmap_l2 { 68 struct pv_entry *pm_l2[PMAP_L2_NENTRY]; 69 }; 70 71 struct pmap { 72 int pm_count; 73 int pm_flags; 74 #define PM_ACTIVE 0x01 75 struct pmap_statistics pm_stats; 76 struct pmap_l2 **pm_l1; 77 }; 78 79 /* 80 * pv_table is list of pv_entry structs completely spanning the total memory. 81 * It is indexed on physical page number. Each entry will be daisy chained 82 * with pv_entry records for each usage in all the pmaps. 83 * 84 * kernel_pm_entries contains all kernel L2 pages for its complete map. 85 * 86 */ 87 88 static struct pv_entry **kernel_pm_entries; 89 static struct pv_entry *pv_table; /* physical pages info (direct mapped) */ 90 static struct pv_entry **tlb; /* current tlb mappings (direct mapped) */ 91 static struct pmap pmap_kernel_store; 92 struct pmap * const kernel_pmap_ptr = &pmap_kernel_store; 93 94 static pmap_t active_pmap = NULL; 95 96 static char mem_name[20] = ""; 97 static int mem_fh; 98 99 static int phys_npages = 0; 100 static int pm_nentries = 0; 101 static int pm_nl1 = 0; 102 static int pm_l1_size = 0; 103 static uint64_t pm_entries_size = 0; 104 static void *pm_tmp_p0; 105 static void *pm_tmp_p1; 106 107 static struct pool pmap_pool; 108 static struct pool pmap_pventry_pool; 109 110 /* forwards */ 111 void pmap_bootstrap(void); 112 static void pmap_page_activate(struct pv_entry *pv); 113 static void pmap_page_deactivate(struct pv_entry *pv); 114 static void pv_update(struct pv_entry *pv); 115 static void pmap_update_page(uintptr_t ppn); 116 bool pmap_fault(pmap_t pmap, vaddr_t va, vm_prot_t *atype); 117 118 static struct pv_entry *pv_get(pmap_t pmap, uintptr_t ppn, uintptr_t lpn); 119 static struct pv_entry *pv_alloc(void); 120 static void pv_free(struct pv_entry *pv); 121 static void pmap_deferred_init(void); 122 123 extern void setup_signal_handlers(void); 124 125 /* exposed (to signal handler f.e.) */ 126 vaddr_t kmem_k_start, kmem_k_end; 127 vaddr_t kmem_kvm_start, kmem_kvm_end; 128 vaddr_t kmem_user_start, kmem_user_end; 129 vaddr_t kmem_kvm_cur_start, kmem_kvm_cur_end; 130 131 /* amount of physical memory */ 132 int num_pv_entries = 0; 133 int num_pmaps = 0; 134 135 #define SPARSE_MEMFILE 136 137 138 void 139 pmap_bootstrap(void) 140 { 141 struct pmap *pmap; 142 paddr_t DRAM_cfg; 143 paddr_t fpos, file_len; 144 paddr_t kernel_fpos, pv_fpos, tlb_fpos, pm_l1_fpos, pm_fpos; 145 paddr_t wlen; 146 paddr_t barrier_len; 147 paddr_t pv_table_size; 148 vaddr_t free_start, free_end; 149 paddr_t pa; 150 vaddr_t va; 151 size_t kmem_k_length, written; 152 uintptr_t pg, l1; 153 void *addr; 154 int err; 155 156 extern void _start(void); /* start of kernel */ 157 extern int etext; /* end of the kernel */ 158 extern int edata; /* end of the init. data segment */ 159 extern int end; /* end of bss */ 160 vaddr_t vm_min_addr; 161 162 vm_min_addr = thunk_get_vm_min_address(); 163 vm_min_addr = vm_min_addr < PAGE_SIZE ? PAGE_SIZE : vm_min_addr; 164 165 thunk_printf_debug("Information retrieved from system and elf image\n"); 166 thunk_printf_debug("min VM address at %p\n", (void *) vm_min_addr); 167 thunk_printf_debug("start kernel at %p\n", _start); 168 thunk_printf_debug(" end kernel at %p\n", &etext); 169 thunk_printf_debug(" end of init. data at %p\n", &edata); 170 thunk_printf_debug("1st end of data at %p\n", &end); 171 thunk_printf_debug("CUR end data at %p\n", thunk_sbrk(0)); 172 173 barrier_len = 2 * 1024 * 1024; 174 175 /* calculate kernel section (R-X) */ 176 kmem_k_start = (vaddr_t) PAGE_SIZE * (atop(_start) ); 177 kmem_k_end = (vaddr_t) PAGE_SIZE * (atop(&etext) + 1); 178 kmem_k_length = kmem_k_end - kmem_k_start; 179 180 /* calculate total available memory space & available pages */ 181 DRAM_cfg = (vaddr_t) TEXTADDR; 182 physmem = DRAM_cfg / PAGE_SIZE; 183 184 /* kvm at the top */ 185 kmem_kvm_end = kmem_k_start - barrier_len; 186 kmem_kvm_start = kmem_kvm_end - KVMSIZE; 187 188 /* allow some pmap scratch space */ 189 pm_tmp_p0 = (void *) (kmem_kvm_start); 190 pm_tmp_p1 = (void *) (kmem_kvm_start + PAGE_SIZE); 191 kmem_kvm_start += 2*PAGE_SIZE; 192 193 /* claim an area for userland (---/R--/RW-/RWX) */ 194 kmem_user_start = vm_min_addr; 195 kmem_user_end = kmem_kvm_start - barrier_len; 196 197 /* print summary */ 198 aprint_verbose("\nMemory summary\n"); 199 aprint_verbose("\tkmem_user_start\t%p\n", (void *) kmem_user_start); 200 aprint_verbose("\tkmem_user_end\t%p\n", (void *) kmem_user_end); 201 aprint_verbose("\tkmem_k_start\t%p\n", (void *) kmem_k_start); 202 aprint_verbose("\tkmem_k_end\t%p\n", (void *) kmem_k_end); 203 aprint_verbose("\tkmem_kvm_start\t%p\n", (void *) kmem_kvm_start); 204 aprint_verbose("\tkmem_kvm_end\t%p\n", (void *) kmem_kvm_end); 205 206 aprint_verbose("\tDRAM_cfg\t%10d\n", (int) DRAM_cfg); 207 aprint_verbose("\tkvmsize\t\t%10d\n", (int) KVMSIZE); 208 aprint_verbose("\tuser_len\t%10d\n", 209 (int) (kmem_user_end - kmem_user_start)); 210 211 aprint_verbose("\n\n"); 212 213 /* make critical assertions before modifying anything */ 214 if (sizeof(struct pcb) > USPACE) { 215 panic("sizeof(struct pcb) is %d bytes too big for USPACE. " 216 "Please adjust TRAPSTACKSIZE calculation", 217 (int) (USPACE - sizeof(struct pcb))); 218 } 219 if (TRAPSTACKSIZE < 4*PAGE_SIZE) { 220 panic("TRAPSTACKSIZE is too small, please increase UPAGES"); 221 } 222 if (sizeof(struct pmap_l2) > PAGE_SIZE) { 223 panic("struct pmap_l2 bigger than one page?\n"); 224 } 225 226 /* protect user memory UVM area (---) */ 227 err = thunk_munmap((void *) kmem_user_start, 228 kmem_k_start - kmem_user_start); 229 if (err) 230 panic("pmap_bootstrap: userland uvm space protection " 231 "failed (%d)\n", thunk_geterrno()); 232 233 #if 0 234 /* protect kvm UVM area if separate (---) */ 235 err = thunk_munmap((void *) kmem_kvm_start, 236 kmem_kvm_end - kmem_kvm_start); 237 if (err) 238 panic("pmap_bootstrap: kvm uvm space protection " 239 "failed (%d)\n", thunk_geterrno()); 240 #endif 241 242 thunk_printf_debug("Creating memory mapped backend\n"); 243 244 /* create memory file since mmap/maccess only can be on files */ 245 strlcpy(mem_name, "/tmp/netbsd.XXXXXX", sizeof(mem_name)); 246 mem_fh = thunk_mkstemp(mem_name); 247 if (mem_fh < 0) 248 panic("pmap_bootstrap: can't create memory file\n"); 249 250 /* unlink the file so space is freed when we quit */ 251 if (thunk_unlink(mem_name) == -1) 252 panic("pmap_bootstrap: can't unlink %s", mem_name); 253 254 /* file_len is the backing store length, nothing to do with placement */ 255 file_len = DRAM_cfg; 256 257 #ifdef SPARSE_MEMFILE 258 { 259 char dummy; 260 261 wlen = thunk_pwrite(mem_fh, &dummy, 1, file_len - 1); 262 if (wlen != 1) 263 panic("pmap_bootstrap: can't grow file\n"); 264 } 265 #else 266 { 267 char block[PAGE_SIZE]; 268 269 printf("Creating memory file\r"); 270 for (pg = 0; pg < file_len; pg += PAGE_SIZE) { 271 wlen = thunk_pwrite(mem_fh, block, PAGE_SIZE, pg); 272 if (wlen != PAGE_SIZE) 273 panic("pmap_bootstrap: write fails, disc full?"); 274 } 275 } 276 #endif 277 278 /* protect the current kernel section */ 279 err = thunk_mprotect((void *) kmem_k_start, kmem_k_length, 280 THUNK_PROT_READ | THUNK_PROT_EXEC); 281 assert(err == 0); 282 283 /* madvise the host kernel about our intentions with the memory */ 284 /* no measured effect, but might make a difference on high load */ 285 err = thunk_madvise((void *) kmem_user_start, 286 kmem_k_start - kmem_user_start, 287 THUNK_MADV_WILLNEED | THUNK_MADV_RANDOM); 288 assert(err == 0); 289 290 /* map the kernel at the start of the 'memory' file */ 291 kernel_fpos = 0; 292 written = thunk_pwrite(mem_fh, (void *) kmem_k_start, kmem_k_length, 293 kernel_fpos); 294 assert(written == kmem_k_length); 295 fpos = kernel_fpos + kmem_k_length; 296 297 /* initialize counters */ 298 free_start = fpos; /* in physical space ! */ 299 free_end = file_len; /* in physical space ! */ 300 kmem_kvm_cur_start = kmem_kvm_start; 301 302 /* calculate pv table size */ 303 phys_npages = file_len / PAGE_SIZE; 304 pv_table_size = round_page(phys_npages * sizeof(struct pv_entry)); 305 thunk_printf_debug("claiming %"PRIu64" KB of pv_table for " 306 "%"PRIdPTR" pages of physical memory\n", 307 (uint64_t) pv_table_size/1024, (uintptr_t) phys_npages); 308 309 /* calculate number of pmap entries needed for a complete map */ 310 pm_nentries = (kmem_k_end - VM_MIN_ADDRESS) / PAGE_SIZE; 311 pm_entries_size = round_page(pm_nentries * sizeof(struct pv_entry *)); 312 thunk_printf_debug("tlb va->pa lookup table is %"PRIu64" KB for " 313 "%d logical pages\n", pm_entries_size/1024, pm_nentries); 314 315 /* calculate how big the l1 tables are going to be */ 316 pm_nl1 = pm_nentries / PMAP_L2_NENTRY; 317 pm_l1_size = round_page(pm_nl1 * sizeof(struct pmap_l1 *)); 318 319 /* claim pv table */ 320 pv_fpos = fpos; 321 pv_table = (struct pv_entry *) kmem_kvm_cur_start; 322 addr = thunk_mmap(pv_table, pv_table_size, 323 THUNK_PROT_READ | THUNK_PROT_WRITE, 324 THUNK_MAP_FILE | THUNK_MAP_FIXED | THUNK_MAP_SHARED, 325 mem_fh, pv_fpos); 326 if (addr != (void *) pv_table) 327 panic("pmap_bootstrap: can't map in pv table\n"); 328 329 memset(pv_table, 0, pv_table_size); /* test and clear */ 330 331 thunk_printf_debug("pv_table initialised correctly, mmap works\n"); 332 333 /* advance */ 334 kmem_kvm_cur_start += pv_table_size; 335 fpos += pv_table_size; 336 337 /* set up tlb space */ 338 tlb = (struct pv_entry **) kmem_kvm_cur_start; 339 tlb_fpos = fpos; 340 addr = thunk_mmap(tlb, pm_entries_size, 341 THUNK_PROT_READ | THUNK_PROT_WRITE, 342 THUNK_MAP_FILE | THUNK_MAP_FIXED | THUNK_MAP_SHARED, 343 mem_fh, tlb_fpos); 344 if (addr != (void *) tlb) 345 panic("pmap_bootstrap: can't map in tlb entries\n"); 346 347 memset(tlb, 0, pm_entries_size); /* test and clear */ 348 349 thunk_printf_debug("kernel tlb entries initialized correctly\n"); 350 351 /* advance */ 352 kmem_kvm_cur_start += pm_entries_size; 353 fpos += pm_entries_size; 354 355 /* set up kernel pmap and add a l1 map */ 356 pmap = pmap_kernel(); 357 memset(pmap, 0, sizeof(*pmap)); 358 pmap->pm_count = 1; /* reference */ 359 pmap->pm_flags = PM_ACTIVE; /* kernel pmap is always active */ 360 pmap->pm_l1 = (struct pmap_l2 **) kmem_kvm_cur_start; 361 362 pm_l1_fpos = fpos; 363 addr = thunk_mmap(pmap->pm_l1, pm_l1_size, 364 THUNK_PROT_READ | THUNK_PROT_WRITE, 365 THUNK_MAP_FILE | THUNK_MAP_FIXED | THUNK_MAP_SHARED, 366 mem_fh, pm_l1_fpos); 367 if (addr != (void *) pmap->pm_l1) 368 panic("pmap_bootstrap: can't map in pmap l1 entries\n"); 369 370 memset(pmap->pm_l1, 0, pm_l1_size); /* test and clear */ 371 372 thunk_printf_debug("kernel pmap l1 table initialised correctly\n"); 373 374 /* advance for l1 tables */ 375 kmem_kvm_cur_start += round_page(pm_l1_size); 376 fpos += round_page(pm_l1_size); 377 378 /* followed by the pm entries */ 379 pm_fpos = fpos; 380 kernel_pm_entries = (struct pv_entry **) kmem_kvm_cur_start; 381 addr = thunk_mmap(kernel_pm_entries, pm_entries_size, 382 THUNK_PROT_READ | THUNK_PROT_WRITE, 383 THUNK_MAP_FILE | THUNK_MAP_FIXED | THUNK_MAP_SHARED, 384 mem_fh, pm_fpos); 385 if (addr != (void *) kernel_pm_entries) 386 panic("pmap_bootstrap: can't map in kernel pmap entries\n"); 387 388 memset(kernel_pm_entries, 0, pm_entries_size); /* test and clear */ 389 390 /* advance for the statically allocated pm_entries */ 391 kmem_kvm_cur_start += pm_entries_size; 392 fpos += pm_entries_size; 393 394 /* put pointers in the l1 to point to the pv_entry space */ 395 for (l1 = 0; l1 < pm_nl1; l1++) { 396 pmap = pmap_kernel(); 397 pmap->pm_l1[l1] = (struct pmap_l2 *) 398 ((vaddr_t) kernel_pm_entries + l1 * PMAP_L2_SIZE); 399 } 400 401 /* kmem used [kmem_kvm_start - kmem_kvm_cur_start] */ 402 kmem_kvm_cur_end = kmem_kvm_cur_start; 403 404 /* manually enter the mappings into the kernel map */ 405 for (pg = 0; pg < pv_table_size; pg += PAGE_SIZE) { 406 pa = pv_fpos + pg; 407 va = (vaddr_t) pv_table + pg; 408 pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE, 0); 409 } 410 thunk_printf_debug("pv_table mem added to the kernel pmap\n"); 411 for (pg = 0; pg < pm_entries_size; pg += PAGE_SIZE) { 412 pa = tlb_fpos + pg; 413 va = (vaddr_t) tlb + pg; 414 pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE, 0); 415 } 416 thunk_printf_debug("kernel tlb entries mem added to the kernel pmap\n"); 417 for (pg = 0; pg < pm_l1_size; pg += PAGE_SIZE) { 418 pa = pm_l1_fpos + pg; 419 va = (vaddr_t) pmap->pm_l1 + pg; 420 pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE, 0); 421 } 422 thunk_printf_debug("kernel pmap l1 mem added to the kernel pmap\n"); 423 for (pg = 0; pg < pm_entries_size; pg += PAGE_SIZE) { 424 pa = pm_fpos + pg; 425 va = (vaddr_t) kernel_pm_entries + pg; 426 pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE, 0); 427 } 428 thunk_printf_debug("kernel pmap entries mem added to the kernel pmap\n"); 429 #if 0 430 /* not yet, or not needed */ 431 for (pg = 0; pg < kmem_k_length; pg += PAGE_SIZE) { 432 pa = kernel_fpos + pg; 433 va = (vaddr_t) kmem_k_start + pg; 434 pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE, 0); 435 } 436 thunk_printf_debug("kernel mem added to the kernel pmap\n"); 437 #endif 438 439 /* add file space to uvm's FREELIST */ 440 uvm_page_physload(atop(0), 441 atop(free_end), 442 atop(free_start + fpos), /* mark used till fpos */ 443 atop(free_end), 444 VM_FREELIST_DEFAULT); 445 446 /* setup syscall emulation */ 447 if (thunk_syscallemu_init((void *)VM_MIN_ADDRESS, 448 (void *)VM_MAXUSER_ADDRESS) != 0) 449 panic("couldn't enable syscall emulation"); 450 451 aprint_verbose("leaving pmap_bootstrap:\n"); 452 aprint_verbose("\t%"PRIu64" MB of physical pages left\n", 453 (uint64_t) (free_end - (free_start + fpos))/1024/1024); 454 aprint_verbose("\t%"PRIu64" MB of kmem left\n", 455 (uint64_t) (kmem_kvm_end - kmem_kvm_cur_end)/1024/1024); 456 457 setup_signal_handlers(); 458 } 459 460 void 461 pmap_init(void) 462 { 463 } 464 465 /* return kernel space start and end (including growth) */ 466 void 467 pmap_virtual_space(vaddr_t *vstartp, vaddr_t *vendp) 468 { 469 if (vstartp) 470 *vstartp = kmem_kvm_cur_start; /* min to map in */ 471 if (vendp) 472 *vendp = kmem_kvm_end - PAGE_SIZE; /* max available */ 473 } 474 475 static void 476 pmap_deferred_init(void) 477 { 478 /* XXX we COULD realloc our pv_table etc with malloc() but for what? */ 479 480 /* create pmap pool */ 481 pool_init(&pmap_pool, sizeof(struct pmap), 0, 0, 0, 482 "pmappool", NULL, IPL_NONE); 483 pool_init(&pmap_pventry_pool, sizeof(struct pv_entry), 0, 0, 0, 484 "pventry", NULL, IPL_HIGH); 485 } 486 487 pmap_t 488 pmap_create(void) 489 { 490 static int pmap_initialised = 0; 491 struct pmap *pmap; 492 493 if (!pmap_initialised) { 494 pmap_deferred_init(); 495 pmap_initialised = 1; 496 } 497 498 thunk_printf_debug("pmap_create\n"); 499 num_pmaps++; 500 #if 0 501 printf("%s: pre alloc: num_pmaps %"PRIu64" (%"PRIu64" kb), " 502 "num_pv_entries %"PRIu64" (%"PRIu64" kb)\n", 503 __func__, 504 (uint64_t) num_pmaps, 505 (uint64_t) num_pmaps * (sizeof(*pmap) + pm_l1_size) / 1024, 506 (uint64_t) num_pv_entries, 507 (uint64_t) num_pv_entries * (sizeof(struct pv_entry)) / 1024); 508 #endif 509 510 pmap = pool_get(&pmap_pool, PR_WAITOK); 511 memset(pmap, 0, sizeof(*pmap)); 512 pmap->pm_count = 1; 513 pmap->pm_flags = 0; 514 515 /* claim l1 table */ 516 pmap->pm_l1 = kmem_zalloc(pm_l1_size, KM_SLEEP); 517 assert(pmap->pm_l1); 518 519 thunk_printf_debug("\tpmap %p\n", pmap); 520 521 return pmap; 522 } 523 524 void 525 pmap_destroy(pmap_t pmap) 526 { 527 struct pmap_l2 *l2tbl; 528 int l1; 529 530 /* if multiple references exist just remove a reference */ 531 thunk_printf_debug("pmap_destroy %p\n", pmap); 532 if (--pmap->pm_count > 0) 533 return; 534 num_pmaps--; 535 536 /* safe guard against silly errors */ 537 KASSERT((pmap->pm_flags & PM_ACTIVE) == 0); 538 KASSERT(pmap->pm_stats.resident_count == 0); 539 KASSERT(pmap->pm_stats.wired_count == 0); 540 #ifdef DIAGNOSTIC 541 for (l1 = 0; l1 < pm_nl1; l1++) { 542 int l2; 543 544 l2tbl = pmap->pm_l1[l1]; 545 if (!l2tbl) 546 continue; 547 for (l2 = 0; l2 < PMAP_L2_NENTRY; l2++) { 548 if (l2tbl->pm_l2[l2]) 549 panic("pmap_destroy: pmap isn't empty"); 550 } 551 } 552 #endif 553 for (l1 = 0; l1 < pm_nl1; l1++) { 554 l2tbl = pmap->pm_l1[l1]; 555 if (!l2tbl) 556 continue; 557 kmem_free(l2tbl, PMAP_L2_SIZE); 558 } 559 kmem_free(pmap->pm_l1, pm_l1_size); 560 pool_put(&pmap_pool, pmap); 561 } 562 563 void 564 pmap_reference(pmap_t pmap) 565 { 566 thunk_printf_debug("pmap_reference %p\n", (void *) pmap); 567 pmap->pm_count++; 568 } 569 570 long 571 pmap_resident_count(pmap_t pmap) 572 { 573 return pmap->pm_stats.resident_count; 574 } 575 576 long 577 pmap_wired_count(pmap_t pmap) 578 { 579 return pmap->pm_stats.wired_count; 580 } 581 582 static struct pv_entry * 583 pv_alloc(void) 584 { 585 struct pv_entry *pv; 586 587 num_pv_entries++; 588 pv = pool_get(&pmap_pventry_pool, PR_WAITOK); 589 memset(pv, 0, sizeof(struct pv_entry)); 590 591 return pv; 592 } 593 594 static void 595 pv_free(struct pv_entry *pv) 596 { 597 num_pv_entries--; 598 pool_put(&pmap_pventry_pool, pv); 599 } 600 601 static struct pv_entry * 602 pv_get(pmap_t pmap, uintptr_t ppn, uintptr_t lpn) 603 { 604 struct pv_entry *pv; 605 606 /* If the head entry's free use that. */ 607 pv = &pv_table[ppn]; 608 if (pv->pv_pmap == NULL) { 609 pmap->pm_stats.resident_count++; 610 return pv; 611 } 612 /* If this mapping exists already, use that. */ 613 for (pv = pv; pv != NULL; pv = pv->pv_next) { 614 if ((pv->pv_pmap == pmap) && (pv->pv_lpn == lpn)) { 615 return pv; 616 } 617 } 618 /* Otherwise, allocate a new entry and link it in after the head. */ 619 thunk_printf_debug("pv_get: multiple mapped page ppn %"PRIdPTR", " 620 "lpn %"PRIdPTR"\n", ppn, lpn); 621 622 /* extra sanity */ 623 assert(ppn < phys_npages); 624 625 pv = pv_alloc(); 626 if (pv == NULL) 627 return NULL; 628 629 pv->pv_next = pv_table[ppn].pv_next; 630 pv_table[ppn].pv_next = pv; 631 pmap->pm_stats.resident_count++; 632 633 return pv; 634 } 635 636 static void 637 pmap_set_pv(pmap_t pmap, uintptr_t lpn, struct pv_entry *pv) 638 { 639 struct pmap_l2 *l2tbl; 640 int l1 = lpn / PMAP_L2_NENTRY; 641 int l2 = lpn % PMAP_L2_NENTRY; 642 643 #ifdef DIAGNOSTIC 644 if (lpn >= pm_nentries) 645 panic("peeing outside box : addr in page around %"PRIx64"\n", 646 (uint64_t) lpn*PAGE_SIZE); 647 #endif 648 649 l2tbl = pmap->pm_l1[l1]; 650 if (!l2tbl) { 651 l2tbl = pmap->pm_l1[l1] = kmem_zalloc(PMAP_L2_SIZE, KM_SLEEP); 652 /* should be zero filled */ 653 } 654 l2tbl->pm_l2[l2] = pv; 655 } 656 657 static struct pv_entry * 658 pmap_lookup_pv(pmap_t pmap, uintptr_t lpn) 659 { 660 struct pmap_l2 *l2tbl; 661 int l1 = lpn / PMAP_L2_NENTRY; 662 int l2 = lpn % PMAP_L2_NENTRY; 663 664 if (lpn >= pm_nentries) 665 return NULL; 666 667 l2tbl = pmap->pm_l1[l1]; 668 if (l2tbl) 669 return l2tbl->pm_l2[l2]; 670 return NULL; 671 } 672 673 /* 674 * Check if the given page fault was our reference / modified emulation fault; 675 * if so return true otherwise return false and let uvm handle it 676 */ 677 bool 678 pmap_fault(pmap_t pmap, vaddr_t va, vm_prot_t *atype) 679 { 680 struct pv_entry *pv, *ppv; 681 uintptr_t lpn, ppn; 682 int prot, cur_prot, diff; 683 684 thunk_printf_debug("pmap_fault pmap %p, va %p\n", pmap, (void *) va); 685 686 /* get logical page from vaddr */ 687 lpn = atop(va - VM_MIN_ADDRESS); /* V->L */ 688 pv = pmap_lookup_pv(pmap, lpn); 689 690 /* not known! then it must be UVM's work */ 691 if (pv == NULL) { 692 //thunk_printf("%s: no mapping yet for %p\n", 693 // __func__, (void *) va); 694 *atype = VM_PROT_READ; /* assume it was a read */ 695 return false; 696 } 697 698 /* determine physical address and lookup 'root' pv_entry */ 699 ppn = pv->pv_ppn; 700 ppv = &pv_table[ppn]; 701 702 /* if unmanaged we just make sure it is there! */ 703 if (ppv->pv_vflags & PV_UNMANAGED) { 704 printf("%s: oops warning unmanaged page %"PRIiPTR" faulted\n", 705 __func__, ppn); 706 /* atype not set */ 707 pmap_page_activate(pv); 708 return true; 709 } 710 711 /* check the TLB, if NULL we have a TLB fault */ 712 if (tlb[pv->pv_lpn] == NULL) { 713 if (pv->pv_mmap_ppl != THUNK_PROT_NONE) { 714 thunk_printf_debug("%s: tlb fault page lpn %"PRIiPTR"\n", 715 __func__, pv->pv_lpn); 716 pmap_page_activate(pv); 717 return true; 718 } 719 } 720 721 /* determine pmap access type (mmap doesnt need to be 1:1 on VM_PROT_) */ 722 prot = pv->pv_prot; 723 cur_prot = VM_PROT_NONE; 724 if (pv->pv_mmap_ppl & THUNK_PROT_READ) 725 cur_prot |= VM_PROT_READ; 726 if (pv->pv_mmap_ppl & THUNK_PROT_WRITE) 727 cur_prot |= VM_PROT_WRITE; 728 if (pv->pv_mmap_ppl & THUNK_PROT_EXEC) 729 cur_prot |= VM_PROT_EXECUTE; 730 731 diff = prot & (prot ^ cur_prot); 732 733 thunk_printf_debug("%s: prot = %d, cur_prot = %d, diff = %d\n", 734 __func__, prot, cur_prot, diff); 735 *atype = VM_PROT_READ; /* assume its a read error */ 736 if (diff & VM_PROT_READ) { 737 if ((ppv->pv_pflags & PV_REFERENCED) == 0) { 738 ppv->pv_pflags |= PV_REFERENCED; 739 pmap_update_page(ppn); 740 return true; 741 } 742 panic("pmap: page not readable but marked referenced?"); 743 return false; 744 } 745 746 #if 0 747 /* this might be questionable */ 748 if (diff & VM_PROT_EXECUTE) { 749 *atype = VM_PROT_EXECUTE; /* assume it was executing */ 750 if (prot & VM_PROT_EXECUTE) { 751 if ((ppv->pv_pflags & PV_REFERENCED) == 0) { 752 ppv->pv_pflags |= PV_REFERENCED; 753 pmap_update_page(ppn); 754 return true; 755 } 756 } 757 return false; 758 } 759 #endif 760 761 *atype = VM_PROT_WRITE; /* assume its a write error */ 762 if (diff & VM_PROT_WRITE) { 763 if (prot & VM_PROT_WRITE) { 764 /* should be allowed to write */ 765 if ((ppv->pv_pflags & PV_MODIFIED) == 0) { 766 /* was marked unmodified */ 767 ppv->pv_pflags |= PV_MODIFIED; 768 pmap_update_page(ppn); 769 return true; 770 } 771 } 772 panic("pmap: page not writable but marked modified?"); 773 return false; 774 } 775 776 /* not due to our r/m handling, let uvm handle it ! */ 777 return false; 778 } 779 780 781 static void 782 pmap_page_activate(struct pv_entry *pv) 783 { 784 paddr_t pa = pv->pv_ppn * PAGE_SIZE; 785 vaddr_t va = pv->pv_lpn * PAGE_SIZE + VM_MIN_ADDRESS; /* L->V */ 786 uint32_t map_flags; 787 void *addr; 788 789 map_flags = THUNK_MAP_FILE | THUNK_MAP_FIXED | THUNK_MAP_SHARED; 790 791 addr = thunk_mmap((void *) va, PAGE_SIZE, pv->pv_mmap_ppl, 792 map_flags, mem_fh, pa); 793 thunk_printf_debug("page_activate: (va %p, pa %p, prot %d, ppl %d) -> %p\n", 794 (void *) va, (void *) pa, pv->pv_prot, pv->pv_mmap_ppl, 795 (void *) addr); 796 if (addr != (void *) va) 797 panic("pmap_page_activate: mmap failed (expected %p got %p): %d", 798 (void *)va, addr, thunk_geterrno()); 799 800 tlb[pv->pv_lpn] = NULL; 801 if (pv->pv_mmap_ppl != THUNK_PROT_NONE) 802 tlb[pv->pv_lpn] = pv; 803 } 804 805 static void 806 pmap_page_deactivate(struct pv_entry *pv) 807 { 808 paddr_t pa = pv->pv_ppn * PAGE_SIZE; 809 vaddr_t va = pv->pv_lpn * PAGE_SIZE + VM_MIN_ADDRESS; /* L->V */ 810 uint32_t map_flags; 811 void *addr; 812 813 /* don't try to unmap pv entries that are already unmapped */ 814 if (!tlb[pv->pv_lpn]) 815 return; 816 817 if (tlb[pv->pv_lpn]->pv_mmap_ppl == THUNK_PROT_NONE) 818 goto deactivate; 819 820 map_flags = THUNK_MAP_FILE | THUNK_MAP_FIXED | THUNK_MAP_SHARED; 821 addr = thunk_mmap((void *) va, PAGE_SIZE, THUNK_PROT_NONE, 822 map_flags, mem_fh, pa); 823 thunk_printf_debug("page_deactivate: (va %p, pa %p, ppl %d) -> %p\n", 824 (void *) va, (void *) pa, pv->pv_mmap_ppl, (void *) addr); 825 if (addr != (void *) va) 826 panic("pmap_page_deactivate: mmap failed"); 827 828 deactivate: 829 tlb[pv->pv_lpn] = NULL; 830 } 831 832 static void 833 pv_update(struct pv_entry *pv) 834 { 835 int pflags, vflags; 836 int mmap_ppl; 837 838 /* get our per-physical-page flags */ 839 pflags = pv_table[pv->pv_ppn].pv_pflags; 840 vflags = pv_table[pv->pv_ppn].pv_vflags; 841 842 KASSERT(THUNK_PROT_READ == VM_PROT_READ); 843 KASSERT(THUNK_PROT_WRITE == VM_PROT_WRITE); 844 KASSERT(THUNK_PROT_EXEC == VM_PROT_EXECUTE); 845 846 /* create referenced/modified emulation */ 847 if ((pv->pv_prot & VM_PROT_WRITE) && 848 (pflags & PV_REFERENCED) && (pflags & PV_MODIFIED)) { 849 mmap_ppl = THUNK_PROT_READ | THUNK_PROT_WRITE; 850 } else if ((pv->pv_prot & (VM_PROT_READ | VM_PROT_EXECUTE)) && 851 (pflags & PV_REFERENCED)) { 852 mmap_ppl = THUNK_PROT_READ; 853 if (pv->pv_prot & VM_PROT_EXECUTE) 854 mmap_ppl |= THUNK_PROT_EXEC; 855 } else { 856 mmap_ppl = THUNK_PROT_NONE; 857 } 858 859 /* unmanaged or wired pages are special; they dont track r/m */ 860 if (vflags & (PV_UNMANAGED | PV_WIRED)) 861 mmap_ppl = THUNK_PROT_READ | THUNK_PROT_WRITE; 862 863 pv->pv_mmap_ppl = mmap_ppl; 864 } 865 866 /* update mapping of a physical page */ 867 static void 868 pmap_update_page(uintptr_t ppn) 869 { 870 struct pv_entry *pv; 871 872 for (pv = &pv_table[ppn]; pv != NULL; pv = pv->pv_next) { 873 thunk_printf_debug("pmap_update_page: ppn %"PRIdPTR", pv->pv_map = %p\n", 874 ppn, pv->pv_pmap); 875 if (pv->pv_pmap != NULL) { 876 pv_update(pv); 877 if (pv->pv_pmap->pm_flags & PM_ACTIVE) 878 pmap_page_activate(pv); 879 else 880 pmap_page_deactivate(pv) 881 ; 882 } 883 } 884 } 885 886 static int 887 pmap_do_enter(pmap_t pmap, vaddr_t va, paddr_t pa, vm_prot_t prot, uint flags, int unmanaged) 888 { 889 struct pv_entry *pv, *ppv; 890 uintptr_t ppn, lpn; 891 int s; 892 893 /* to page numbers */ 894 ppn = atop(pa); 895 lpn = atop(va - VM_MIN_ADDRESS); /* V->L */ 896 #ifdef DIAGNOSTIC 897 if ((va < VM_MIN_ADDRESS) || (va > VM_MAX_KERNEL_ADDRESS)) 898 panic("pmap_do_enter: invalid va issued\n"); 899 #endif 900 901 /* raise interrupt level */ 902 s = splvm(); 903 904 /* remove existing mapping at this lpn */ 905 pv = pmap_lookup_pv(pmap, lpn); 906 if (pv && pv->pv_ppn != ppn) 907 pmap_remove(pmap, va, va + PAGE_SIZE); 908 909 /* get our entry */ 910 ppv = &pv_table[ppn]; 911 pv = pv_get(pmap, ppn, lpn); /* get our (copy) of pv entry */ 912 913 /* and adjust stats */ 914 if (pv == NULL) 915 panic("pamp_do_enter: didn't find pv entry!"); 916 if (pv->pv_vflags & PV_WIRED) 917 pmap->pm_stats.wired_count--; 918 919 /* enter our details */ 920 pv->pv_pmap = pmap; 921 pv->pv_ppn = ppn; 922 pv->pv_lpn = lpn; 923 pv->pv_prot = prot; 924 pv->pv_vflags = 0; 925 /* pv->pv_next = NULL; */ /* might confuse linked list? */ 926 if (flags & PMAP_WIRED) 927 pv->pv_vflags |= PV_WIRED; 928 929 if (unmanaged) { 930 /* dont track r/m */ 931 pv->pv_vflags |= PV_UNMANAGED; 932 } else { 933 if (flags & VM_PROT_WRITE) 934 ppv->pv_pflags |= PV_REFERENCED | PV_MODIFIED; 935 else if (flags & (VM_PROT_ALL)) 936 ppv->pv_pflags |= PV_REFERENCED; 937 } 938 939 /* map it in */ 940 pmap_update_page(ppn); 941 pmap_set_pv(pmap, lpn, pv); 942 943 /* adjust stats */ 944 if (pv->pv_vflags & PV_WIRED) 945 pmap->pm_stats.wired_count++; 946 947 splx(s); 948 949 /* activate page directly when on active pmap */ 950 if (pmap->pm_flags & PM_ACTIVE) 951 pmap_page_activate(pv); 952 953 return 0; 954 } 955 956 int 957 pmap_enter(pmap_t pmap, vaddr_t va, paddr_t pa, vm_prot_t prot, u_int flags) 958 { 959 thunk_printf_debug("pmap_enter %p : v %p, p %p, prot %d, flags %d\n", 960 (void *) pmap, (void *) va, (void *) pa, (int) prot, (int) flags); 961 return pmap_do_enter(pmap, va, pa, prot, flags, 0); 962 } 963 964 /* release the pv_entry for a mapping. Code derived also from hp300 pmap */ 965 static void 966 pv_release(pmap_t pmap, uintptr_t ppn, uintptr_t lpn) 967 { 968 struct pv_entry *pv, *npv; 969 970 thunk_printf_debug("pv_release ppn %"PRIdPTR", lpn %"PRIdPTR"\n", ppn, lpn); 971 pv = &pv_table[ppn]; 972 /* 973 * If it is the first entry on the list, it is actually 974 * in the header and we must copy the following entry up 975 * to the header. Otherwise we must search the list for 976 * the entry. In either case we free the now unused entry. 977 */ 978 if ((pmap == pv->pv_pmap) && (lpn == pv->pv_lpn)) { 979 npv = pv->pv_next; 980 if (npv) { 981 /* pull up first entry from chain. */ 982 memcpy(pv, npv, offsetof(struct pv_entry, pv_pflags)); 983 pmap_set_pv(pv->pv_pmap, pv->pv_lpn, pv); 984 pv_free(npv); 985 } else { 986 memset(pv, 0, offsetof(struct pv_entry, pv_pflags)); 987 } 988 } else { 989 for (npv = pv->pv_next; npv; npv = npv->pv_next) { 990 if ((pmap == npv->pv_pmap) && (lpn == npv->pv_lpn)) 991 break; 992 pv = npv; 993 } 994 KASSERT(npv != NULL); 995 pv->pv_next = npv->pv_next; 996 pv_free(npv); 997 } 998 pmap_set_pv(pmap, lpn, NULL); 999 pmap->pm_stats.resident_count--; 1000 } 1001 1002 void 1003 pmap_remove(pmap_t pmap, vaddr_t sva, vaddr_t eva) 1004 { 1005 uintptr_t slpn, elpn, lpn; 1006 struct pv_entry *pv; 1007 int s; 1008 1009 slpn = atop(sva - VM_MIN_ADDRESS); /* V->L */ 1010 elpn = atop(eva - VM_MIN_ADDRESS); /* V->L */ 1011 1012 thunk_printf_debug("pmap_remove() called from " 1013 "lpn %"PRIdPTR" to lpn %"PRIdPTR"\n", slpn, elpn); 1014 1015 s = splvm(); 1016 for (lpn = slpn; lpn < elpn; lpn++) { 1017 pv = pmap_lookup_pv(pmap, lpn); 1018 if (pv != NULL) { 1019 if (pmap->pm_flags & PM_ACTIVE) { 1020 pmap_page_deactivate(pv); 1021 // MEMC_WRITE(pv->pv_deactivate); 1022 // cpu_cache_flush(); 1023 } 1024 pmap_set_pv(pmap, lpn, NULL); 1025 if (pv->pv_vflags & PV_WIRED) 1026 pmap->pm_stats.wired_count--; 1027 pv_release(pmap, pv->pv_ppn, lpn); 1028 } 1029 } 1030 splx(s); 1031 } 1032 1033 bool 1034 pmap_remove_all(pmap_t pmap) 1035 { 1036 /* just a hint that all the entries are to be removed */ 1037 thunk_printf_debug("pmap_remove_all() dummy called\n"); 1038 1039 /* we dont do anything with the kernel pmap */ 1040 if (pmap == pmap_kernel()) 1041 return false; 1042 1043 #if 0 1044 /* remove all mappings in one-go; not needed */ 1045 pmap_remove(pmap, VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS); 1046 thunk_munmap((void *) VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS - VM_MIN_ADDRESS); 1047 #endif 1048 #if 0 1049 /* remove all cached info from the pages */ 1050 thunk_msync(VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS - VM_MIN_ADDRESS, 1051 THUNK_MS_SYNC | THUNK_MS_INVALIDATE); 1052 #endif 1053 return false; 1054 } 1055 1056 void 1057 pmap_protect(pmap_t pmap, vaddr_t sva, vaddr_t eva, vm_prot_t prot) 1058 { 1059 struct pv_entry *pv; 1060 intptr_t slpn, elpn, lpn; 1061 int s; 1062 1063 if (prot == VM_PROT_NONE) { 1064 pmap_remove(pmap, sva, eva); 1065 return; 1066 } 1067 if (prot & VM_PROT_WRITE) 1068 return; /* apparently we're meant to */ 1069 if (pmap == pmap_kernel()) 1070 return; /* can't restrict kernel w/o unmapping. */ 1071 1072 slpn = atop(sva - VM_MIN_ADDRESS); /* V->L */ 1073 elpn = atop(eva - VM_MIN_ADDRESS); /* V->L */ 1074 1075 thunk_printf_debug("pmap_protect() called from " 1076 "lpn %"PRIdPTR" to lpn %"PRIdPTR"\n", slpn, elpn); 1077 1078 s = splvm(); 1079 for (lpn = slpn; lpn < elpn; lpn++) { 1080 pv = pmap_lookup_pv(pmap, lpn); 1081 if (pv != NULL) { 1082 pv->pv_prot &= prot; 1083 pv_update(pv); 1084 if (pv->pv_pmap->pm_flags & PM_ACTIVE) 1085 pmap_page_activate(pv); 1086 } 1087 } 1088 splx(s); 1089 } 1090 1091 void 1092 pmap_unwire(pmap_t pmap, vaddr_t va) 1093 { 1094 struct pv_entry *pv; 1095 intptr_t lpn; 1096 1097 thunk_printf_debug("pmap_unwire called va = %p\n", (void *) va); 1098 if (pmap == NULL) 1099 return; 1100 1101 lpn = atop(va - VM_MIN_ADDRESS); /* V->L */ 1102 pv = pmap_lookup_pv(pmap, lpn); 1103 if (pv == NULL) 1104 return; 1105 /* but is it wired? */ 1106 if ((pv->pv_vflags & PV_WIRED) == 0) 1107 return; 1108 pmap->pm_stats.wired_count--; 1109 pv->pv_vflags &= ~PV_WIRED; 1110 1111 /* XXX needed? */ 1112 pmap_update_page(pv->pv_ppn); 1113 } 1114 1115 bool 1116 pmap_extract(pmap_t pmap, vaddr_t va, paddr_t *ppa) 1117 { 1118 struct pv_entry *pv; 1119 intptr_t lpn; 1120 1121 thunk_printf_debug("pmap_extract: extracting va %p\n", (void *) va); 1122 #ifdef DIAGNOSTIC 1123 if ((va < VM_MIN_ADDRESS) || (va > VM_MAX_KERNEL_ADDRESS)) { 1124 thunk_printf_debug("pmap_extract: invalid va issued\n"); 1125 thunk_printf("%p not in [%p, %p]\n", (void *) va, 1126 (void *) VM_MIN_ADDRESS, (void *) VM_MAX_KERNEL_ADDRESS); 1127 return false; 1128 } 1129 #endif 1130 lpn = atop(va - VM_MIN_ADDRESS); /* V->L */ 1131 pv = pmap_lookup_pv(pmap, lpn); 1132 1133 if (pv == NULL) 1134 return false; 1135 if (ppa) 1136 *ppa = ptoa(pv->pv_ppn); 1137 return true; 1138 } 1139 1140 /* 1141 * Enter an unmanaged, `wired' kernel mapping. 1142 * Only to be removed by pmap_kremove() 1143 */ 1144 void 1145 pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot, u_int flags) 1146 { 1147 thunk_printf_debug("pmap_kenter_pa : v %p, p %p, prot %d, flags %d\n", 1148 (void *) va, (void *) pa, (int) prot, (int) flags); 1149 pmap_do_enter(pmap_kernel(), va, pa, prot, prot | PMAP_WIRED, 1); 1150 } 1151 1152 void 1153 pmap_kremove(vaddr_t va, vsize_t size) 1154 { 1155 pmap_remove(pmap_kernel(), va, va + size); 1156 } 1157 1158 void 1159 pmap_copy(pmap_t dst_map, pmap_t src_map, vaddr_t dst_addr, vsize_t len, 1160 vaddr_t src_addr) 1161 { 1162 thunk_printf_debug("pmap_copy (dummy)\n"); 1163 } 1164 1165 void 1166 pmap_update(pmap_t pmap) 1167 { 1168 thunk_printf_debug("pmap_update (dummy)\n"); 1169 } 1170 1171 void 1172 pmap_activate(struct lwp *l) 1173 { 1174 struct proc *p = l->l_proc; 1175 pmap_t pmap; 1176 1177 pmap = p->p_vmspace->vm_map.pmap; 1178 thunk_printf_debug("pmap_activate for lwp %p, pmap = %p\n", l, pmap); 1179 1180 if (pmap == pmap_kernel()) 1181 return; /* kernel pmap is always active */ 1182 1183 KASSERT(active_pmap == NULL); 1184 KASSERT((pmap->pm_flags & PM_ACTIVE) == 0); 1185 1186 active_pmap = pmap; 1187 pmap->pm_flags |= PM_ACTIVE; 1188 } 1189 1190 void 1191 pmap_deactivate(struct lwp *l) 1192 { 1193 struct proc *p = l->l_proc; 1194 struct pv_entry *pv; 1195 struct pmap_l2 *l2tbl; 1196 pmap_t pmap; 1197 int l1, l2; 1198 1199 pmap = p->p_vmspace->vm_map.pmap; 1200 thunk_printf_debug("pmap_DEactivate for lwp %p, pmap = %p\n", l, pmap); 1201 1202 if (pmap == pmap_kernel()) 1203 return; /* kernel pmap is always active */ 1204 1205 KASSERT(pmap == active_pmap); 1206 KASSERT(pmap->pm_flags & PM_ACTIVE); 1207 1208 active_pmap = NULL; 1209 pmap->pm_flags &=~ PM_ACTIVE; 1210 1211 for (l1 = 0; l1 < pm_nl1; l1++) { 1212 l2tbl = pmap->pm_l1[l1]; 1213 if (!l2tbl) 1214 continue; 1215 for (l2 = 0; l2 < PMAP_L2_NENTRY; l2++) { 1216 pv = l2tbl->pm_l2[l2]; 1217 if (pv) { 1218 pmap_page_deactivate(pv); 1219 // MEMC_WRITE(pmap->pm_entries[i]->pv_deactivate); 1220 } 1221 } 1222 } 1223 1224 /* dummy */ 1225 // cpu_cache_flush(); 1226 } 1227 1228 void 1229 pmap_zero_page(paddr_t pa) 1230 { 1231 char *blob; 1232 1233 thunk_printf_debug("pmap_zero_page: pa %p\n", (void *) pa); 1234 1235 if (pa & (PAGE_SIZE-1)) 1236 panic("%s: unaligned address passed : %p\n", __func__, (void *) pa); 1237 1238 blob = thunk_mmap(pm_tmp_p0, PAGE_SIZE, 1239 THUNK_PROT_READ | THUNK_PROT_WRITE, 1240 THUNK_MAP_FILE | THUNK_MAP_FIXED | THUNK_MAP_SHARED, 1241 mem_fh, pa); 1242 if (blob != pm_tmp_p0) 1243 panic("%s: couldn't get mapping", __func__); 1244 1245 memset(blob, 0, PAGE_SIZE); 1246 1247 thunk_munmap(blob, PAGE_SIZE); 1248 } 1249 1250 void 1251 pmap_copy_page(paddr_t src_pa, paddr_t dst_pa) 1252 { 1253 char *sblob, *dblob; 1254 1255 if (src_pa & (PAGE_SIZE-1)) 1256 panic("%s: unaligned address passed : %p\n", __func__, (void *) src_pa); 1257 if (dst_pa & (PAGE_SIZE-1)) 1258 panic("%s: unaligned address passed : %p\n", __func__, (void *) dst_pa); 1259 1260 thunk_printf_debug("pmap_copy_page: pa src %p, pa dst %p\n", 1261 (void *) src_pa, (void *) dst_pa); 1262 1263 /* source */ 1264 sblob = thunk_mmap(pm_tmp_p0, PAGE_SIZE, 1265 THUNK_PROT_READ, 1266 THUNK_MAP_FILE | THUNK_MAP_FIXED | THUNK_MAP_SHARED, 1267 mem_fh, src_pa); 1268 if (sblob != pm_tmp_p0) 1269 panic("%s: couldn't get src mapping", __func__); 1270 1271 /* destination */ 1272 dblob = thunk_mmap(pm_tmp_p1, PAGE_SIZE, 1273 THUNK_PROT_READ | THUNK_PROT_WRITE, 1274 THUNK_MAP_FILE | THUNK_MAP_FIXED | THUNK_MAP_SHARED, 1275 mem_fh, dst_pa); 1276 if (dblob != pm_tmp_p1) 1277 panic("%s: couldn't get dst mapping", __func__); 1278 1279 memcpy(dblob, sblob, PAGE_SIZE); 1280 1281 thunk_munmap(sblob, PAGE_SIZE); 1282 thunk_munmap(dblob, PAGE_SIZE); 1283 } 1284 1285 /* change access permissions on a given physical page */ 1286 void 1287 pmap_page_protect(struct vm_page *page, vm_prot_t prot) 1288 { 1289 intptr_t ppn; 1290 struct pv_entry *pv, *npv; 1291 1292 ppn = atop(VM_PAGE_TO_PHYS(page)); 1293 thunk_printf_debug("pmap_page_protect page %"PRIiPTR" to prot %d\n", ppn, prot); 1294 1295 if (prot == VM_PROT_NONE) { 1296 /* visit all mappings */ 1297 npv = pv = &pv_table[ppn]; 1298 while ((pv != NULL) && (pv->pv_pmap != NULL)) { 1299 /* skip unmanaged entries */ 1300 if (pv->pv_vflags & PV_UNMANAGED) { 1301 pv = pv->pv_next; 1302 continue; 1303 } 1304 1305 /* if in an active pmap deactivate */ 1306 if (pv->pv_pmap->pm_flags & PM_ACTIVE) 1307 pmap_page_deactivate(pv); 1308 1309 /* if not on the head, remember our next */ 1310 if (pv != &pv_table[ppn]) 1311 npv = pv->pv_next; 1312 1313 /* remove from pmap */ 1314 pmap_set_pv(pv->pv_pmap, pv->pv_lpn, NULL); 1315 if (pv->pv_vflags & PV_WIRED) 1316 pv->pv_pmap->pm_stats.wired_count--; 1317 pv_release(pv->pv_pmap, ppn, pv->pv_lpn); 1318 1319 pv = npv; 1320 } 1321 } else if (prot != VM_PROT_ALL) { 1322 /* visit all mappings */ 1323 for (pv = &pv_table[ppn]; pv != NULL; pv = pv->pv_next) { 1324 /* if managed and in a pmap restrict access */ 1325 if ((pv->pv_pmap != NULL) && 1326 ((pv->pv_vflags & PV_UNMANAGED) == 0)) { 1327 pv->pv_prot &= prot; 1328 pv_update(pv); 1329 /* if in active pmap (re)activate page */ 1330 if (pv->pv_pmap->pm_flags & PM_ACTIVE) 1331 pmap_page_activate(pv); 1332 } 1333 } 1334 } 1335 } 1336 1337 bool 1338 pmap_clear_modify(struct vm_page *page) 1339 { 1340 struct pv_entry *pv; 1341 uintptr_t ppn; 1342 bool rv; 1343 1344 ppn = atop(VM_PAGE_TO_PHYS(page)); 1345 rv = pmap_is_modified(page); 1346 1347 thunk_printf_debug("pmap_clear_modify page %"PRIiPTR"\n", ppn); 1348 1349 /* if marked modified, clear it in all the pmap's referencing it */ 1350 if (rv) { 1351 /* if its marked modified in a kernel mapping, don't clear it */ 1352 for (pv = &pv_table[ppn]; pv != NULL; pv = pv->pv_next) 1353 if (pv->pv_pmap == pmap_kernel() && 1354 (pv->pv_prot & VM_PROT_WRITE)) 1355 return rv; 1356 /* clear it */ 1357 pv_table[ppn].pv_pflags &= ~PV_MODIFIED; 1358 pmap_update_page(ppn); 1359 } 1360 return rv; 1361 } 1362 1363 bool 1364 pmap_clear_reference(struct vm_page *page) 1365 { 1366 uintptr_t ppn; 1367 bool rv; 1368 1369 ppn = atop(VM_PAGE_TO_PHYS(page)); 1370 rv = pmap_is_referenced(page); 1371 1372 thunk_printf_debug("pmap_clear_reference page %"PRIiPTR"\n", ppn); 1373 1374 if (rv) { 1375 pv_table[ppn].pv_pflags &= ~PV_REFERENCED; 1376 pmap_update_page(ppn); 1377 } 1378 return rv; 1379 } 1380 1381 bool 1382 pmap_is_modified(struct vm_page *page) 1383 { 1384 intptr_t ppn; 1385 bool rv; 1386 1387 ppn = atop(VM_PAGE_TO_PHYS(page)); 1388 rv = (pv_table[ppn].pv_pflags & PV_MODIFIED) != 0; 1389 1390 thunk_printf_debug("pmap_is_modified page %"PRIiPTR" : %s\n", ppn, rv?"yes":"no"); 1391 1392 return rv; 1393 } 1394 1395 bool 1396 pmap_is_referenced(struct vm_page *page) 1397 { 1398 intptr_t ppn; 1399 1400 ppn = atop(VM_PAGE_TO_PHYS(page)); 1401 thunk_printf_debug("pmap_is_referenced page %"PRIiPTR"\n", ppn); 1402 1403 return (pv_table[ppn].pv_pflags & PV_REFERENCED) != 0; 1404 } 1405 1406 paddr_t 1407 pmap_phys_address(paddr_t cookie) 1408 { 1409 return ptoa(cookie); 1410 } 1411 1412 vaddr_t 1413 pmap_growkernel(vaddr_t maxkvaddr) 1414 { 1415 thunk_printf_debug("pmap_growkernel: till %p (adding %"PRIu64" KB)\n", 1416 (void *) maxkvaddr, 1417 (uint64_t) (maxkvaddr - kmem_kvm_cur_end)/1024); 1418 if (maxkvaddr > kmem_kvm_end) 1419 return kmem_kvm_end; 1420 kmem_kvm_cur_end = maxkvaddr; 1421 return kmem_kvm_cur_end; 1422 } 1423 1424