1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/cpr.h> 30 #include <sys/fs/ufs_fs.h> 31 #include <sys/prom_plat.h> 32 #include "cprboot.h" 33 34 35 /* 36 * max space for a copy of physavail data 37 * prop size is usually 80 to 128 bytes 38 */ 39 #define PA_BUFSIZE 1024 40 41 #define CB_SETBIT 1 42 #define CB_ISSET 2 43 #define CB_ISCLR 3 44 45 /* 46 * globals 47 */ 48 int cb_nbitmaps; 49 50 /* 51 * file scope 52 */ 53 static arange_t *cb_physavail; 54 static char pabuf[PA_BUFSIZE]; 55 static caddr_t high_virt; 56 57 static cbd_t cb_bmda[CPR_MAX_BMDESC]; 58 static int tracking_init; 59 60 61 static int 62 cb_bitop(pfn_t ppn, int op) 63 { 64 int rel, rval = 0; 65 char *bitmap; 66 cbd_t *dp; 67 68 for (dp = cb_bmda; dp->cbd_size; dp++) { 69 if (PPN_IN_RANGE(ppn, dp)) { 70 bitmap = (char *)dp->cbd_reg_bitmap; 71 rel = ppn - dp->cbd_spfn; 72 if (op == CB_SETBIT) 73 setbit(bitmap, rel); 74 else if (op == CB_ISSET) 75 rval = isset(bitmap, rel); 76 else if (op == CB_ISCLR) 77 rval = isclr(bitmap, rel); 78 break; 79 } 80 } 81 82 return (rval); 83 } 84 85 86 /* 87 * count pages that are isolated from the kernel 88 * within each available range 89 */ 90 static void 91 count_free_pages(void) 92 { 93 arange_t *arp; 94 pfn_t bitno; 95 int cnt; 96 97 for (arp = cb_physavail; arp->high; arp++) { 98 cnt = 0; 99 for (bitno = arp->low; bitno <= arp->high; bitno++) { 100 if (cb_bitop(bitno, CB_ISCLR)) 101 cnt++; 102 } 103 arp->nfree = cnt; 104 } 105 } 106 107 108 /* 109 * scan the physavail list for a page 110 * that doesn't clash with the kernel 111 */ 112 static pfn_t 113 search_phav_pages(void) 114 { 115 static arange_t *arp; 116 static pfn_t bitno; 117 int rescan; 118 119 if (arp == NULL) { 120 count_free_pages(); 121 arp = cb_physavail; 122 bitno = arp->low; 123 } 124 125 /* 126 * begin scanning from the previous position and if the scan 127 * reaches the end of the list, scan a second time from the top; 128 * nfree is checked to eliminate scanning overhead when most 129 * of the available space gets used up. when a page is found, 130 * set a bit so the page wont be found by another scan. 131 */ 132 for (rescan = 0; rescan < 2; rescan++) { 133 for (; arp->high; bitno = (++arp)->low) { 134 if (arp->nfree == 0) 135 continue; 136 for (; bitno <= arp->high; bitno++) { 137 if (cb_bitop(bitno, CB_ISCLR)) { 138 (void) cb_bitop(bitno, CB_SETBIT); 139 arp->nfree--; 140 return (bitno++); 141 } 142 } 143 } 144 arp = cb_physavail; 145 bitno = arp->low; 146 } 147 148 return (PFN_INVALID); 149 } 150 151 152 /* 153 * scan statefile buffer pages for reusable tmp space 154 */ 155 static pfn_t 156 search_buf_pages(void) 157 { 158 size_t coff, src_base; 159 static size_t lboff; 160 pfn_t ppn; 161 162 if (tracking_init == 0) 163 return (PFN_INVALID); 164 165 /* 166 * when scanning the list of statefile buffer ppns, we know that 167 * all pages from lboff to the page boundary of buf_offset have 168 * already been restored; when the associated page bit is clear, 169 * that page is isolated from the kernel and we can reuse it for 170 * tmp space; otherwise, when SF_DIFF_PPN indicates a page had 171 * been moved, we know the page bit was previously clear and 172 * later set, and we can reuse the new page. 173 */ 174 src_base = sfile.buf_offset & MMU_PAGEMASK; 175 while (lboff < src_base) { 176 coff = lboff; 177 lboff += MMU_PAGESIZE; 178 ppn = SF_ORIG_PPN(coff); 179 if (cb_bitop(ppn, CB_ISCLR)) { 180 (void) cb_bitop(ppn, CB_SETBIT); 181 SF_STAT_INC(recycle); 182 return (ppn); 183 } else if (SF_DIFF_PPN(coff)) { 184 SF_STAT_INC(recycle); 185 return (SF_BUF_PPN(coff)); 186 } 187 } 188 189 return (PFN_INVALID); 190 } 191 192 193 /* 194 * scan physavail and statefile buffer page lists 195 * for a page that doesn't clash with the kernel 196 */ 197 pfn_t 198 find_apage(void) 199 { 200 pfn_t ppn; 201 202 ppn = search_phav_pages(); 203 if (ppn != PFN_INVALID) 204 return (ppn); 205 ppn = search_buf_pages(); 206 if (ppn != PFN_INVALID) 207 return (ppn); 208 209 prom_printf("\n%s: ran out of available/free pages!\n%s\n", 210 prog, rsvp); 211 cb_exit_to_mon(); 212 213 /* NOTREACHED */ 214 return (PFN_INVALID); 215 } 216 217 218 /* 219 * reserve virt range, find available phys pages, 220 * and map-in each phys starting at vaddr 221 */ 222 static caddr_t 223 map_free_phys(caddr_t vaddr, size_t size, char *name) 224 { 225 int pages, ppn, err; 226 physaddr_t phys; 227 caddr_t virt; 228 char *str; 229 230 str = "map_free_phys"; 231 virt = prom_claim_virt(size, vaddr); 232 CB_VPRINTF(("\n%s: claim vaddr 0x%p, size 0x%lx, ret 0x%p\n", 233 str, (void *)vaddr, size, (void *)virt)); 234 if (virt != vaddr) { 235 prom_printf("\n%s: cant reserve (0x%p - 0x%p) for \"%s\"\n", 236 str, (void *)vaddr, (void *)(vaddr + size), name); 237 return (virt); 238 } 239 240 for (pages = mmu_btop(size); pages--; virt += MMU_PAGESIZE) { 241 /* 242 * map virt page to free phys 243 */ 244 ppn = find_apage(); 245 phys = PN_TO_ADDR(ppn); 246 247 err = prom_map_phys(-1, MMU_PAGESIZE, virt, phys); 248 if (err || verbose) { 249 prom_printf(" map virt 0x%p, phys 0x%llx, " 250 "ppn 0x%x, ret %d\n", (void *)virt, phys, ppn, err); 251 } 252 if (err) 253 return ((caddr_t)ERR); 254 } 255 256 return (vaddr); 257 } 258 259 260 /* 261 * check bitmap desc and relocate bitmap data 262 * to pages isolated from the kernel 263 * 264 * sets globals: 265 * high_virt 266 */ 267 int 268 cb_set_bitmap(void) 269 { 270 size_t bmda_size, all_bitmap_size, alloc_size; 271 caddr_t newvirt, src, dst, base; 272 cbd_t *dp; 273 char *str; 274 275 str = "cb_set_bitmap"; 276 CB_VPRINTF((ent_fmt, str, entry)); 277 278 /* 279 * max is checked in the cpr module; 280 * this condition should never occur 281 */ 282 if (cb_nbitmaps > (CPR_MAX_BMDESC - 1)) { 283 prom_printf("%s: too many bitmap descriptors %d, max %d\n", 284 str, cb_nbitmaps, (CPR_MAX_BMDESC - 1)); 285 return (ERR); 286 } 287 288 /* 289 * copy bitmap descriptors to aligned space, check magic numbers, 290 * and set the total size of all bitmaps 291 */ 292 bmda_size = cb_nbitmaps * sizeof (cbd_t); 293 src = SF_DATA(); 294 bcopy(src, cb_bmda, bmda_size); 295 base = src + bmda_size; 296 all_bitmap_size = 0; 297 for (dp = cb_bmda; dp < &cb_bmda[cb_nbitmaps]; dp++) { 298 if (dp->cbd_magic != CPR_BITMAP_MAGIC) { 299 prom_printf("%s: bad magic 0x%x, expect 0x%x\n", 300 str, dp->cbd_magic, CPR_BITMAP_MAGIC); 301 return (ERR); 302 } 303 all_bitmap_size += dp->cbd_size; 304 dp->cbd_reg_bitmap = (cpr_ptr)base; 305 base += dp->cbd_size; 306 } 307 308 /* 309 * reserve new space for bitmaps 310 */ 311 alloc_size = PAGE_ROUNDUP(all_bitmap_size); 312 if (verbose || CPR_DBG(7)) { 313 prom_printf("%s: nbitmaps %d, bmda_size 0x%lx\n", 314 str, cb_nbitmaps, bmda_size); 315 prom_printf("%s: all_bitmap_size 0x%lx, alloc_size 0x%lx\n", 316 str, all_bitmap_size, alloc_size); 317 } 318 high_virt = (caddr_t)CB_HIGH_VIRT; 319 newvirt = map_free_phys(high_virt, alloc_size, "bitmaps"); 320 if (newvirt != high_virt) 321 return (ERR); 322 323 /* 324 * copy the bitmaps, clear any unused space trailing them, 325 * and set references into the new space 326 */ 327 base = src + bmda_size; 328 dst = newvirt; 329 bcopy(base, dst, all_bitmap_size); 330 if (alloc_size > all_bitmap_size) 331 bzero(dst + all_bitmap_size, alloc_size - all_bitmap_size); 332 for (dp = cb_bmda; dp->cbd_size; dp++) { 333 dp->cbd_reg_bitmap = (cpr_ptr)dst; 334 dst += dp->cbd_size; 335 } 336 337 /* advance past all the bitmap data */ 338 SF_ADV(bmda_size + all_bitmap_size); 339 high_virt += alloc_size; 340 341 return (0); 342 } 343 344 345 /* 346 * create a new stack for cprboot; 347 * this stack is used to avoid clashes with kernel pages and 348 * to avoid exceptions while remapping cprboot virt pages 349 */ 350 int 351 cb_get_newstack(void) 352 { 353 caddr_t newstack; 354 355 CB_VENTRY(cb_get_newstack); 356 newstack = map_free_phys((caddr_t)CB_STACK_VIRT, 357 CB_STACK_SIZE, "new stack"); 358 if (newstack != (caddr_t)CB_STACK_VIRT) 359 return (ERR); 360 return (0); 361 } 362 363 364 /* 365 * since kernel phys pages span most of the installed memory range, 366 * some statefile buffer pages will likely clash with the kernel 367 * and need to be moved before kernel pages are restored; a list 368 * of buf phys page numbers is created here and later updated as 369 * buf pages are moved 370 * 371 * sets globals: 372 * sfile.buf_map 373 * tracking_init 374 */ 375 int 376 cb_tracking_setup(void) 377 { 378 pfn_t ppn, lppn; 379 uint_t *imap; 380 caddr_t newvirt; 381 size_t size; 382 int pages; 383 384 CB_VENTRY(cb_tracking_setup); 385 386 pages = mmu_btop(sfile.size); 387 size = PAGE_ROUNDUP(pages * sizeof (*imap)); 388 newvirt = map_free_phys(high_virt, size, "buf tracking"); 389 if (newvirt != high_virt) 390 return (ERR); 391 sfile.buf_map = (uint_t *)newvirt; 392 high_virt += size; 393 394 /* 395 * create identity map of sfile.buf phys pages 396 */ 397 imap = sfile.buf_map; 398 lppn = sfile.low_ppn + pages; 399 for (ppn = sfile.low_ppn; ppn < lppn; ppn++, imap++) 400 *imap = (uint_t)ppn; 401 tracking_init = 1; 402 403 return (0); 404 } 405 406 407 /* 408 * get "available" prop from /memory node 409 * 410 * sets globals: 411 * cb_physavail 412 */ 413 int 414 cb_get_physavail(void) 415 { 416 int len, glen, scnt, need, space; 417 char *str, *pdev, *mem_prop; 418 pnode_t mem_node; 419 physaddr_t phys; 420 pgcnt_t pages; 421 arange_t *arp; 422 pphav_t *pap; 423 size_t size; 424 pfn_t ppn; 425 int err; 426 427 str = "cb_get_physavail"; 428 CB_VPRINTF((ent_fmt, str, entry)); 429 430 /* 431 * first move cprboot pages off the physavail list 432 */ 433 size = PAGE_ROUNDUP((uintptr_t)_end) - (uintptr_t)_start; 434 ppn = cpr_vatopfn((caddr_t)_start); 435 phys = PN_TO_ADDR(ppn); 436 err = prom_claim_phys(size, phys); 437 CB_VPRINTF((" text/data claim (0x%lx - 0x%lx) = %d\n", 438 ppn, ppn + mmu_btop(size) - 1, err)); 439 if (err) 440 return (ERR); 441 442 pdev = "/memory"; 443 mem_node = prom_finddevice(pdev); 444 if (mem_node == OBP_BADNODE) { 445 prom_printf("%s: cant find \"%s\" node\n", str, pdev); 446 return (ERR); 447 } 448 mem_prop = "available"; 449 450 /* 451 * prop data is treated as a struct array; 452 * verify pabuf has enough room for the array 453 * in the original and converted forms 454 */ 455 len = prom_getproplen(mem_node, mem_prop); 456 scnt = len / sizeof (*pap); 457 need = len + (sizeof (*arp) * (scnt + 1)); 458 space = sizeof (pabuf); 459 CB_VPRINTF((" %s node 0x%x, len %d\n", pdev, mem_node, len)); 460 if (len == -1 || need > space) { 461 prom_printf("\n%s: bad \"%s\" length %d, min %d, max %d\n", 462 str, mem_prop, len, need, space); 463 return (ERR); 464 } 465 466 /* 467 * read-in prop data and clear trailing space 468 */ 469 glen = prom_getprop(mem_node, mem_prop, pabuf); 470 if (glen != len) { 471 prom_printf("\n%s: 0x%x,%s: expected len %d, got %d\n", 472 str, mem_node, mem_prop, len, glen); 473 return (ERR); 474 } 475 bzero(&pabuf[len], space - len); 476 477 /* 478 * convert the physavail list in place 479 * from (phys_base, phys_size) to (low_ppn, high_ppn) 480 */ 481 if (verbose) 482 prom_printf("\nphysavail list:\n"); 483 cb_physavail = (arange_t *)pabuf; 484 arp = cb_physavail + scnt - 1; 485 pap = (pphav_t *)cb_physavail + scnt - 1; 486 for (; scnt--; pap--, arp--) { 487 pages = mmu_btop(pap->size); 488 arp->low = ADDR_TO_PN(pap->base); 489 arp->high = arp->low + pages - 1; 490 if (verbose) { 491 prom_printf(" %d: (0x%lx - 0x%lx),\tpages %ld\n", 492 (int)(arp - cb_physavail), 493 arp->low, arp->high, (arp->high - arp->low + 1)); 494 } 495 } 496 497 return (0); 498 } 499 500 501 /* 502 * search for an available phys page, 503 * copy the old phys page to the new one 504 * and remap the virt page to the new phys 505 */ 506 static int 507 move_page(caddr_t vaddr, pfn_t oldppn) 508 { 509 physaddr_t oldphys, newphys; 510 pfn_t newppn; 511 int err; 512 513 newppn = find_apage(); 514 newphys = PN_TO_ADDR(newppn); 515 oldphys = PN_TO_ADDR(oldppn); 516 CB_VPRINTF((" remap vaddr 0x%p, old 0x%lx/0x%llx," 517 " new 0x%lx/0x%llx\n", 518 (void *)vaddr, oldppn, oldphys, newppn, newphys)); 519 phys_xcopy(oldphys, newphys, MMU_PAGESIZE); 520 err = prom_remap(MMU_PAGESIZE, vaddr, newphys); 521 if (err) 522 prom_printf("\nmove_page: remap error\n"); 523 return (err); 524 } 525 526 527 /* 528 * physically relocate any text/data pages that clash 529 * with the kernel; since we're already running on 530 * a new stack, the original stack area is skipped 531 */ 532 int 533 cb_relocate(void) 534 { 535 int is_ostk, is_clash, clash_cnt, ok_cnt; 536 char *str, *desc, *skip_fmt; 537 caddr_t ostk_low, ostk_high; 538 caddr_t virt, saddr, eaddr; 539 pfn_t ppn; 540 541 str = "cb_relocate"; 542 CB_VPRINTF((ent_fmt, str, entry)); 543 544 ostk_low = (caddr_t)&estack - CB_STACK_SIZE; 545 ostk_high = (caddr_t)&estack - MMU_PAGESIZE; 546 saddr = (caddr_t)_start; 547 eaddr = (caddr_t)PAGE_ROUNDUP((uintptr_t)_end); 548 549 install_remap(); 550 551 skip_fmt = " skip vaddr 0x%p, clash=%d, %s\n"; 552 clash_cnt = ok_cnt = 0; 553 ppn = cpr_vatopfn(saddr); 554 555 for (virt = saddr; virt < eaddr; virt += MMU_PAGESIZE, ppn++) { 556 is_clash = (cb_bitop(ppn, CB_ISSET) != 0); 557 if (is_clash) 558 clash_cnt++; 559 else 560 ok_cnt++; 561 562 is_ostk = (virt >= ostk_low && virt <= ostk_high); 563 if (is_ostk) 564 desc = "orig stack"; 565 else 566 desc = "text/data"; 567 568 /* 569 * page logic: 570 * 571 * if (original stack page) 572 * clash doesn't matter, just skip the page 573 * else (not original stack page) 574 * if (no clash) 575 * setbit to avoid later alloc and overwrite 576 * else (clash) 577 * relocate phys page 578 */ 579 if (is_ostk) { 580 CB_VPRINTF((skip_fmt, virt, is_clash, desc)); 581 } else if (is_clash == 0) { 582 CB_VPRINTF((skip_fmt, virt, is_clash, desc)); 583 (void) cb_bitop(ppn, CB_SETBIT); 584 } else if (move_page(virt, ppn)) 585 return (ERR); 586 } 587 CB_VPRINTF(("%s: total %d, clash %d, ok %d\n", 588 str, clash_cnt + ok_cnt, clash_cnt, ok_cnt)); 589 590 /* 591 * free original stack area for reuse 592 */ 593 ppn = cpr_vatopfn(ostk_low); 594 prom_free_phys(CB_STACK_SIZE, PN_TO_ADDR(ppn)); 595 CB_VPRINTF(("%s: free old stack (0x%lx - 0x%lx)\n", 596 str, ppn, ppn + mmu_btop(CB_STACK_SIZE) - 1)); 597 598 return (0); 599 } 600