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 2007 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 /* 29 * cprboot - prom client that restores kadb/kernel pages 30 * 31 * simple cprboot overview: 32 * reset boot-file/boot-device to their original values 33 * open cpr statefile, usually "/.CPR" 34 * read in statefile 35 * close statefile 36 * restore kernel pages 37 * jump back into kernel text 38 * 39 * 40 * cprboot supports a restartable statefile for FAA/STARS, 41 * Federal Aviation Administration 42 * Standard Terminal Automation Replacement System 43 */ 44 45 #include <sys/types.h> 46 #include <sys/cpr.h> 47 #include <sys/promimpl.h> 48 #include <sys/ddi.h> 49 #include "cprboot.h" 50 51 52 /* 53 * local defs 54 */ 55 #define CB_MAXPROP 256 56 #define CB_MAXARGS 8 57 58 59 /* 60 * globals 61 */ 62 struct statefile sfile; 63 64 char cpr_statefile[OBP_MAXPATHLEN]; 65 char cpr_filesystem[OBP_MAXPATHLEN]; 66 67 int cpr_debug; /* cpr debug, set with uadmin 3 10x */ 68 uint_t cb_msec; /* cprboot start runtime */ 69 uint_t cb_dents; /* number of dtlb entries */ 70 71 int do_halt = 0; /* halt (enter mon) after load */ 72 int verbose = 0; /* verbose, traces cprboot ops */ 73 74 char rsvp[] = "please reboot"; 75 char prog[] = "cprboot"; 76 char entry[] = "ENTRY"; 77 char ent_fmt[] = "\n%s %s\n"; 78 79 80 /* 81 * file scope 82 */ 83 static char cb_argbuf[CB_MAXPROP]; 84 static char *cb_args[CB_MAXARGS]; 85 86 static int reusable; 87 char *specialstate; 88 89 90 static int 91 cb_intro(void) 92 { 93 static char cstr[] = "\014" "\033[1P" "\033[18;21H"; 94 95 CB_VENTRY(cb_intro); 96 97 /* 98 * build/debug aid; this condition should not occur 99 */ 100 if ((uintptr_t)_end > CB_SRC_VIRT) { 101 prom_printf("\ndata collision:\n" 102 "(_end=0x%p > CB_LOW_VIRT=0x%x), recompile...\n", 103 _end, CB_SRC_VIRT); 104 return (ERR); 105 } 106 107 /* clear console */ 108 prom_printf(cstr); 109 110 prom_printf("Restoring the System. Please Wait... "); 111 return (0); 112 } 113 114 115 /* 116 * read bootargs and convert to arg vector 117 * 118 * sets globals: 119 * cb_argbuf 120 * cb_args 121 */ 122 static void 123 get_bootargs(void) 124 { 125 char *cp, *tail, *argp, **argv; 126 127 CB_VENTRY(get_bootargs); 128 129 (void) prom_strcpy(cb_argbuf, prom_bootargs()); 130 tail = cb_argbuf + prom_strlen(cb_argbuf); 131 132 /* 133 * scan to the trailing NULL so the last arg 134 * will be found without any special-case code 135 */ 136 argv = cb_args; 137 for (cp = argp = cb_argbuf; cp <= tail; cp++) { 138 if (prom_strchr(" \t\n\r", *cp) == NULL) 139 continue; 140 *cp = '\0'; 141 if (cp - argp) { 142 *argv++ = argp; 143 if ((argv - cb_args) == (CB_MAXARGS - 1)) 144 break; 145 } 146 argp = cp + 1; 147 } 148 *argv = NULLP; 149 150 if (verbose) { 151 for (argv = cb_args; *argv; argv++) { 152 prom_printf(" %ld: \"%s\"\n", 153 (argv - cb_args), *argv); 154 } 155 } 156 } 157 158 159 static void 160 usage(char *expect, char *got) 161 { 162 if (got == NULL) 163 got = "(NULL)"; 164 prom_printf("\nbad OBP boot args: expect %s, got %s\n" 165 "Usage: boot -F %s [-R] [-S <diskpath>]\n%s\n\n", 166 expect, got, prog, rsvp); 167 prom_exit_to_mon(); 168 } 169 170 171 /* 172 * bootargs should start with "-F cprboot" 173 * 174 * may set globals: 175 * specialstate 176 * reusable 177 * do_halt 178 * verbose 179 */ 180 static void 181 check_bootargs(void) 182 { 183 char **argv, *str, *cp; 184 185 argv = cb_args; 186 187 /* expect "-F" */ 188 str = "-F"; 189 if (*argv == NULL || prom_strcmp(*argv, str)) 190 usage(str, *argv); 191 argv++; 192 193 /* expect "cprboot*" */ 194 if (*argv == NULL || prom_strncmp(*argv, prog, sizeof (prog) - 1)) 195 usage(prog, *argv); 196 197 /* 198 * optional args 199 */ 200 str = "-[SR]"; 201 for (argv++; *argv; argv++) { 202 cp = *argv; 203 if (*cp != '-') 204 usage(str, *argv); 205 206 switch (*++cp) { 207 case 'R': 208 case 'r': 209 reusable = 1; 210 break; 211 case 'S': 212 case 's': 213 if (*++argv) 214 specialstate = *argv; 215 else 216 usage("statefile-path", *argv); 217 break; 218 case 'h': 219 do_halt = 1; 220 break; 221 case 'v': 222 verbose = 1; 223 break; 224 default: 225 usage(str, *argv); 226 break; 227 } 228 } 229 } 230 231 232 /* 233 * reset prom props and get statefile info 234 * 235 * sets globals: 236 * cpr_filesystem 237 * cpr_statefile 238 */ 239 static int 240 cb_startup(void) 241 { 242 CB_VENTRY(cb_startup); 243 244 if (!reusable) { 245 /* 246 * Restore the original values of the nvram properties modified 247 * during suspend. Note: if we can't get this info from the 248 * defaults file, the state file may be obsolete or bad, so we 249 * abort. However, failure to restore one or more properties 250 * is NOT fatal (better to continue the resume). 251 */ 252 if (cpr_reset_properties() == -1) { 253 prom_printf("\n%s: cannot read saved " 254 "nvram info, %s\n", prog, rsvp); 255 return (ERR); 256 } 257 } 258 259 /* 260 * simple copy if using specialstate, 261 * otherwise read in fs and statefile from a config file 262 */ 263 if (specialstate) 264 (void) prom_strcpy(cpr_statefile, specialstate); 265 else if (cpr_locate_statefile(cpr_statefile, cpr_filesystem) == -1) { 266 prom_printf("\n%s: cannot find cpr statefile, %s\n", 267 prog, rsvp); 268 return (ERR); 269 } 270 271 return (0); 272 } 273 274 275 static int 276 cb_open_sf(void) 277 { 278 CB_VENTRY(cb_open_sf); 279 280 sfile.fd = cpr_statefile_open(cpr_statefile, cpr_filesystem); 281 if (sfile.fd == -1) { 282 prom_printf("\n%s: can't open %s", prog, cpr_statefile); 283 if (specialstate) 284 prom_printf(" on %s", cpr_filesystem); 285 prom_printf("\n%s\n", rsvp); 286 return (ERR); 287 } 288 289 /* 290 * for block devices, seek past the disk label and bootblock 291 */ 292 if (specialstate) 293 (void) prom_seek(sfile.fd, CPR_SPEC_OFFSET); 294 295 return (0); 296 } 297 298 299 static int 300 cb_close_sf(void) 301 { 302 CB_VENTRY(cb_close_sf); 303 304 /* 305 * close the device so the prom will free up 20+ pages 306 */ 307 (void) cpr_statefile_close(sfile.fd); 308 return (0); 309 } 310 311 312 /* 313 * to restore kernel pages, we have to open a prom device to read-in 314 * the statefile contents; a prom "open" request triggers the driver 315 * and various packages to allocate 20+ pages; unfortunately, some or 316 * all of those pages always clash with kernel pages, and we cant write 317 * to them without corrupting the prom. 318 * 319 * to solve that problem, the only real solution is to close the device 320 * to free up those pages; this means we need to open, read-in the entire 321 * statefile, and close; and to store the statefile, we need to allocate 322 * plenty of space, usually around 2 to 60 MB. 323 * 324 * the simplest alloc means is prom_alloc(), which will "claim" both 325 * virt and phys pages, and creates mappings with a "map" request; 326 * "map" also causes the prom to alloc pages, and again these clash 327 * with kernel pages... 328 * 329 * to solve the "map" problem, we just reserve virt and phys pages and 330 * manage the translations by creating our own tlb entries instead of 331 * relying on the prom. 332 * 333 * sets globals: 334 * cpr_test_mode 335 * sfile.kpages 336 * sfile.size 337 * sfile.buf 338 * sfile.low_ppn 339 * sfile.high_ppn 340 */ 341 static int 342 cb_read_statefile(void) 343 { 344 size_t alsize, len, resid; 345 physaddr_t phys, dst_phys; 346 char *str, *dst_virt; 347 int err, cnt, mmask; 348 uint_t dtlb_index; 349 ssize_t nread; 350 cdd_t cdump; 351 352 str = "cb_read_statefile"; 353 CB_VPRINTF((ent_fmt, str, entry)); 354 355 /* 356 * read-in and check cpr dump header 357 */ 358 if (cpr_read_cdump(sfile.fd, &cdump, CPR_MACHTYPE_4U)) 359 return (ERR); 360 if (cpr_debug) 361 prom_printf("\n"); 362 cb_nbitmaps = cdump.cdd_bitmaprec; 363 cpr_test_mode = cdump.cdd_test_mode; 364 sfile.kpages = cdump.cdd_dumppgsize; 365 CPR_DEBUG(CPR_DEBUG4, "%s: total kpages %d\n", prog, sfile.kpages); 366 367 /* 368 * alloc virt and phys space with 512K alignment; 369 * alloc size should be (n * tte size); 370 */ 371 sfile.size = PAGE_ROUNDUP(cdump.cdd_filesize); 372 alsize = (cdump.cdd_filesize + MMU_PAGEOFFSET512K) & 373 MMU_PAGEMASK512K; 374 phys = 0; 375 err = cb_alloc(alsize, MMU_PAGESIZE512K, &sfile.buf, &phys); 376 CB_VPRINTF(("%s:\n alloc size 0x%lx, buf size 0x%lx\n" 377 " virt 0x%p, phys 0x%llx\n", 378 str, alsize, sfile.size, sfile.buf, phys)); 379 if (err) { 380 prom_printf("%s: cant alloc statefile buf, size 0x%lx\n%s\n", 381 str, sfile.size, rsvp); 382 return (ERR); 383 } 384 385 /* 386 * record low and high phys page numbers for sfile.buf 387 */ 388 sfile.low_ppn = ADDR_TO_PN(phys); 389 sfile.high_ppn = sfile.low_ppn + mmu_btop(sfile.size) - 1; 390 391 /* 392 * setup destination virt and phys addrs for reads; 393 * mapin-mask tells when to create a new tlb entry for the 394 * next set of reads; NB: the read and tlb method needs 395 * ((big-pagesize % read-size) == 0) 396 */ 397 dst_phys = phys; 398 mmask = (MMU_PAGESIZE512K / PROM_MAX_READ) - 1; 399 400 cnt = 0; 401 dtlb_index = cb_dents - 1; 402 if (specialstate) 403 (void) prom_seek(sfile.fd, CPR_SPEC_OFFSET); 404 else 405 (void) cpr_fs_seek(sfile.fd, 0); 406 CPR_DEBUG(CPR_DEBUG1, "%s: reading statefile... ", prog); 407 for (resid = cdump.cdd_filesize; resid; resid -= len) { 408 /* 409 * do a full spin (4 spin chars) 410 * for every MB read (8 reads = 256K) 411 */ 412 if ((cnt & 0x7) == 0) 413 cb_spin(); 414 415 /* 416 * map-in statefile buf pages in 512K blocks; 417 * see MMU_PAGESIZE512K above 418 */ 419 if ((cnt & mmask) == 0) { 420 dst_virt = sfile.buf; 421 cb_mapin(dst_virt, ADDR_TO_PN(dst_phys), 422 TTE512K, TTE_HWWR_INT, dtlb_index); 423 } 424 425 cnt++; 426 427 len = min(PROM_MAX_READ, resid); 428 nread = cpr_read(sfile.fd, dst_virt, len); 429 if (nread != (ssize_t)len) { 430 prom_printf("\n%s: prom read error, " 431 "expect %ld, got %ld\n", str, len, nread); 432 return (ERR); 433 } 434 dst_virt += len; 435 dst_phys += len; 436 } 437 CPR_DEBUG(CPR_DEBUG1, " \b\n"); 438 439 /* 440 * free up any unused phys pages trailing the statefile buffer; 441 * these pages will later appear on the physavail list 442 */ 443 if (alsize > sfile.size) { 444 len = alsize - sfile.size; 445 prom_free_phys(len, phys + sfile.size); 446 CB_VPRINTF(("%s: freed %ld phys pages (0x%lx - 0x%lx)\n", 447 str, mmu_btop(len), phys + sfile.size, phys + alsize)); 448 } 449 450 /* 451 * start the statefile buffer offset at the base of 452 * the statefile buffer and skip past the dump header 453 */ 454 sfile.buf_offset = 0; 455 SF_ADV(sizeof (cdump)); 456 457 /* 458 * finish with the first block mapped-in to provide easy virt access 459 * to machdep structs and the bitmap; for 2.8, the combined size of 460 * (cdd_t + cmd_t + csu_md_t + prom_words + cbd_t) is about 1K, 461 * leaving room for a bitmap representing nearly 32GB 462 */ 463 cb_mapin(sfile.buf, sfile.low_ppn, 464 TTE512K, TTE_HWWR_INT, dtlb_index); 465 466 return (0); 467 } 468 469 470 /* 471 * cprboot first stage worklist 472 */ 473 static int (*first_worklist[])(void) = { 474 cb_intro, 475 cb_mountroot, 476 cb_startup, 477 cb_get_props, 478 cb_usb_setup, 479 cb_unmountroot, 480 cb_open_sf, 481 cb_read_statefile, 482 cb_close_sf, 483 cb_check_machdep, 484 cb_interpret, 485 cb_get_physavail, 486 cb_set_bitmap, 487 cb_get_newstack, 488 NULL 489 }; 490 491 /* 492 * cprboot second stage worklist 493 */ 494 static int (*second_worklist[])(void) = { 495 cb_relocate, 496 cb_tracking_setup, 497 cb_restore_kpages, 498 cb_terminator, 499 cb_ksetup, 500 cb_mpsetup, 501 NULL 502 }; 503 504 505 /* 506 * simple loop driving major cprboot operations; 507 * exits to prom if any error is returned 508 */ 509 static void 510 cb_drive(int (**worklist)(void)) 511 { 512 int i; 513 514 for (i = 0; worklist[i] != NULL; i++) { 515 if (worklist[i]()) 516 cb_exit_to_mon(); 517 } 518 } 519 520 521 /* 522 * debugging support: drop to prom if do_halt is set 523 */ 524 static void 525 check_halt(char *str) 526 { 527 if (do_halt) { 528 prom_printf("\n%s halted by -h flag\n==> before %s\n\n", 529 prog, str); 530 cb_enter_mon(); 531 } 532 } 533 534 535 /* 536 * main is called twice from "cb_srt0.s", args are: 537 * cookie ieee1275 cif handle 538 * first (true): first stage, (false): second stage 539 * 540 * first stage summary: 541 * various setup 542 * allocate a big statefile buffer 543 * read in the statefile 544 * setup the bitmap 545 * create a new stack 546 * 547 * return to "cb_srt0.s", switch to new stack 548 * 549 * second stage summary: 550 * relocate cprboot phys pages 551 * setup tracking for statefile buffer pages 552 * restore kernel pages 553 * various cleanup 554 * install tlb entries for the nucleus and cpr module 555 * restore registers and jump into cpr module 556 */ 557 int 558 main(void *cookie, int first) 559 { 560 if (first) { 561 prom_init(prog, cookie); 562 cb_msec = prom_gettime(); 563 get_bootargs(); 564 check_bootargs(); 565 check_halt("first_worklist"); 566 cb_drive(first_worklist); 567 return (0); 568 } else { 569 cb_drive(second_worklist); 570 if (verbose || CPR_DBG(1)) { 571 prom_printf("%s: milliseconds %d\n", 572 prog, prom_gettime() - cb_msec); 573 prom_printf("%s: resume pc 0x%lx\n", 574 prog, mdinfo.func); 575 prom_printf("%s: exit_to_kernel(0x%p, 0x%p)\n\n", 576 prog, cookie, &mdinfo); 577 } 578 check_halt("exit_to_kernel"); 579 exit_to_kernel(cookie, &mdinfo); 580 return (ERR); 581 } 582 } 583