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