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