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 2009 Sun Microsystems, Inc. All rights reserved. 23\ Use is subject to license terms. 24\ 25 26purpose: boot block for OBP systems 27copyright: Copyright 2009 Sun Microsystems, Inc. All Rights Reserved 28 29 30headerless 31d# 1024 dup * constant 1meg 32d# 4 1meg * constant 4meg 33d# 32 1meg * constant 32meg 34 35headers 36" /" get-package constant root-ph 37 380 value fs-ih 39false value nested? 400 value file-sz 41 42/buf-len buffer: boot-dev 43: boot-dev$ ( -- dev$ ) boot-dev cscount ; 44 45: loader-base ( -- base ) 46 nested? if 47 h# 5000.0000 48 else 49 h# 5100.0000 50 then 51; 52 53 54\ 55\ methods we expect of fs reader packages 56\ 57headerless 58: fs-open ( file$ -- fd true | false ) 59 " open-file" fs-ih $call-method 60; 61 62: fs-close ( fd -- ) 63 " close-file" fs-ih $call-method 64; 65 66: fs-size ( fd -- size ) 67 " size-file" fs-ih $call-method 68; 69 70: fs-read ( adr len fd -- #read ) 71 " read-file" fs-ih $call-method 72; 73 74: fs-getrd ( adr len -- ) 75 " get-rd" fs-ih $call-method 76; 77 78: fs-bootprop ( -- propval propname true | false ) 79 " bootprop" fs-ih $call-method 80; 81headers 82 83 84: check-elf ( base -- is-elf? ) 85 l@ h# 7f454c46 ( \x7fELF ) = 86; 87 88: check-fcode ( base -- is-fcode? ) 89 c@ dup h# f0 h# f3 between swap h# fd = or 90; 91 92 93\ zfs bootblks with all headers exceeds 7.5k 94\ 'bigbootblk' allows us to load the fs reader from elsewhere 95[ifdef] bigbootblk 96 97: load-pkg ( -- ) 98 boot-dev$ ( dev$ ) 99 2dup dev-open ?dup 0= if 100 open-abort 101 then >r 2drop ( r: ih ) 102 103 /fs-fcode mem-alloc ( adr r: ih ) 104 dup /fs-fcode fs-offset r@ read-disk 105 106 dup check-fcode invert if 107 " No fs fcode found" die 108 then 109 dup 1 byte-load 110 111 /fs-fcode mem-free ( r: ih ) 112 r> dev-close 113; 114 115[else] 116 117: load-pkg ( -- ) ; 118 119[then] 120 121 122: get-bootdev ( -- ) 123 \ first try boot archive (nested boot from ramdisk) 124 \ then try boot device (direct boot from disk) 125 " bootarchive" chosen-ph get-package-property if 126 " bootpath" chosen-ph get-string-prop ( bootpath$ ) 127 else ( archiveprop$ ) 128 decode-string 2swap 2drop ( archivepath$ ) 129 true to nested? 130 then ( bootpath$ ) 131 boot-dev swap move ( ) 132; 133 134: mount-root ( -- ) 135 boot-dev$ fs-pkg$ $open-package to fs-ih 136 fs-ih 0= if 137 " Can't mount root" die 138 then 139; 140 141\ 142\ cheap entertainment for those watching 143\ boot progress 144\ 145headerless 146create spin-data 147 ascii | c, ascii / c, ascii - c, ascii \ c, 148 149variable spindex 150 151headers 152: spinner ( -- ) 153 spindex @ 3 and spin-data + ( c-adr ) 154 c@ emit (cr 155 1 spindex +! 156; 157 158\ allocate and return physical allocation size 159: vmem-alloc-prop ( size virt -- alloc-size virt ) 160 2dup ['] vmem-alloc catch if ( size virt ??? ??? ) 161 2drop ( size virt ) 162 2dup begin ( size virt len adr ) 163 over 32meg min >r ( size virt len adr r: alloc-sz ) 164 r@ over vmem-alloc ( size virt len adr adr r: alloc-sz ) 165 nip r@ + ( size virt len adr' r: alloc-sz ) 166 swap r> - ( size virt adr len' ) 167 swap over 0= ( size virt len' adr done? ) 168 until ( size virt len' adr ) 169 2drop nip 32meg ( virt 32meg ) 170 else ( size virt virt ) 171 nip nip 0 ( virt 0 ) 172 then ( virt alloc-sz ) 173 swap 174; 175 176\ read file in chunks so we can toggle the spinner 177: read-file ( virt size fd -- failed? ) 178 >r ( virt sz-left r: fd ) 179 begin dup while 180 spinner 181 dup 4meg min ( virt sz-left read-sz r: fd ) 182 3dup nip r@ fs-read ( virt sz-left read-sz size-read r: fd ) 183 over <> if ( virt sz-left read-sz r: fd ) 184 r> 2drop 2drop ( ) 185 true exit ( failed ) 186 then 187 rot over + ( sz-left read-sz virt' r: fd ) 188 -rot - ( virt' sz-left' r: fd ) 189 repeat 190 r> 3drop ( ) 191 false ( succeeded ) 192; 193 194\ read in file and return buffer 195\ if base==0, vmem-alloc will allocate virt 196\ NB returned size is 8k rounded since the 197\ memory allocator rounded it for us 198: get-file ( base fd -- [ alloc-sz virt size ] failed? ) 199 dup >r fs-size ( base size r: fd ) 200 dup rot vmem-alloc-prop ( size alloc-sz virt r: fd ) 201 rot 2dup ( alloc-sz virt size virt size r: fd ) 202 r> read-file if ( alloc-sz virt size ) 203 3drop true exit ( failed ) 204 then 205 h# 2000 roundup ( alloc-sz virt size' ) 206 false ( alloc-sz virt size' succeeded ) 207; 208 209 210false value is-elf? 211false value is-archive? 212 213 214: >bootblk ( adr -- adr' ) d# 512 + ; 215 216\ figure out what we just loaded 217: get-type ( adr -- ) 218 dup check-elf to is-elf? 219 220 \ if not nested, check for boot archive (executable after label) 221 nested? invert if 222 >bootblk 223 dup check-fcode ( adr is-fcode? ) 224 over check-elf ( adr is-fcode? is-elf? ) 225 or to is-archive? 226 then 227 drop 228; 229 230 231\ 232\ file name routines 233\ 234 235\ boot file (-F name or boot archive) 236false value fflag? 237/buf-len buffer: boot-file 238: boot-file$ ( -- file$ ) boot-file cscount ; 239 240\ kernel name (final name or unix) 241false value kern? 242/buf-len buffer: kern-file 243: kern-file$ ( -- file$ ) kern-file cscount ; 244 245\ platform name 246/buf-len buffer: plat-name 247: plat-name$ ( -- plat$ ) plat-name cscount ; 248 249\ arch name 250/buf-len buffer: arch-name 251: arch-name$ ( -- arch$ ) arch-name cscount ; 252 253\ final name after /platform massaging 254/buf-len buffer: targ-file 255: targ-file$ ( -- file$ ) targ-file cscount ; 256 257: init-targ ( -- ) 258 targ-file /buf-len erase 259 " /platform/" targ-file swap move 260; 261 262\ remove illegal file name chars (e.g., '/') 263: munge-name ( name$ -- name$' ) 264 2dup ( name$ name$ ) 265 begin dup while 266 over c@ ascii / = if 267 over ascii _ swap c! ( name$ name$' ) 268 then str++ 269 repeat 2drop ( name$ ) 270; 271 272\ does /platform/<name> exist? 273: try-platname ( name$ -- name$ true | false ) 274 munge-name ( name$' ) 275 init-targ 2dup targ-file$ $append 276 targ-file$ fs-open if ( name$ fd ) 277 fs-close true ( name$ true ) 278 else ( name$ ) 279 2drop false ( false ) 280 then ( name$ true | false ) 281; 282 283\ setup arch-name 284\ sun4v -or- sun4u 285: get-def-arch ( -- ) 286 " device_type" root-ph get-package-property if 287 \ some older sunfires don't have device_type set 288 false ( sun4u ) 289 else ( devtype-prop$ ) 290 decode-string 2swap 2drop ( devtype$ ) 291 " sun4v" $= ( sun4v? ) 292 then ( sun4v? ) 293 if " sun4v" else " sun4u" then ( arch$ ) 294 arch-name swap move 295; 296 297\ setup plat-name 298\ platform name -or- 299\ compatible name -or- 300\ default name 301: get-arch ( -- ) 302 get-def-arch 303 304 \ first try "name" in root 305 " name" root-ph get-string-prop ( name$ ) 306 try-platname if 307 plat-name swap move exit ( ) 308 then ( ) 309 310 \ next try "compatible" 311 " compatible" root-ph ( prop$ ph ) 312 get-package-property invert if ( compat$ ) 313 begin decode-string dup while ( compat$ name$ ) 314 try-platname if 315 plat-name swap move 2drop exit ( ) 316 then ( compat$ ) 317 repeat 2drop 2drop ( ) 318 then ( ) 319 320 \ else use default name 321 arch-name$ plat-name swap move 322; 323 324\ make <pre> <file> into /platform/<pre>/<file> 325: $plat-prepend ( file$ pre$ -- file$' ) 326 init-targ 327 targ-file$ $append ( file$ ) 328 " /" targ-file$ $append 329 targ-file$ $append ( ) 330 targ-file$ ( new$ ) 331; 332 333: get-boot ( -- file$ ) 334 fflag? if 335 boot-file$ 336 else 337 " boot_archive" 338 then 339; 340 341: get-kern ( -- file$ ) 342 kern? if 343 kern-file$ 344 else 345 " kernel/sparcv9/unix" 346 then 347; 348 349\ if we're nested, load the kernel, else load the bootarchive 350: get-targ ( -- file$ ) 351 nested? if 352 get-kern 353 else 354 get-boot 355 then 356; 357 358 359: try-file ( file$ -- [ fd ] error? ) 360 diagnostic-mode? if 361 2dup ." Loading: " type cr 362 then 363 fs-open invert ( fd false | true ) 364; 365 366\ try "/platform/<plat-name>/<file>" e.g., SUNW,Sun-Blade-1000 367\ then "/platform/<arch-name>/<file>" e.g., sun4u 368: open-path ( file$ - fd ) 369 over c@ ascii / <> if 370 2dup plat-name$ $plat-prepend ( file$ file$' ) 371 try-file if ( file$ ) 372 2dup arch-name$ $plat-prepend ( file$ file$' ) 373 try-file if ( file$ ) 374 open-abort 375 then ( file$ fd ) 376 then ( file$ fd ) 377 else ( file$ ) 378 \ copy to targ-file for 'whoami' prop 379 targ-file /buf-len erase 380 2dup targ-file swap move 381 2dup try-file if ( file$ ) 382 open-abort 383 then ( file$ fd ) 384 then ( file$ fd ) 385 -rot 2drop ( fd ) 386; 387 388 389false value lflag? 390 391\ ZFS support 392\ -Z fsname opens specified filesystem in disk pool 393 394false value zflag? 395/buf-len buffer: fs-name 396: fs-name$ ( -- fs$ ) fs-name cscount ; 397 398[ifdef] zfs 399 400: open-zfs-fs ( fs$ -- ) 401 2dup " open-fs" fs-ih $call-method 0= if 402 open-abort 403 then 404 2drop ( ) 405; 406 407[else] 408 409: open-zfs-fs ( fs$ -- ) 410 \ ignore on -L 411 lflag? invert if 412 " -Z not supported on non-zfs root" die 413 then 414; 415 416[then] 417 418 419\ 420\ arg parsing 421\ 422 423headerless 424: printable? ( n -- flag ) \ true if n is a printable ascii character 425 dup bl th 7f within swap th 80 th ff between or 426; 427: white-space? ( n -- flag ) \ true is n is non-printable? or a blank 428 dup printable? 0= swap bl = or 429; 430 431: skip-blanks ( adr len -- adr' len' ) 432 begin dup while ( adr' len' ) 433 over c@ white-space? 0= if exit then 434 str++ 435 repeat 436; 437 438: skip-non-blanks ( adr len -- adr' len' ) 439 begin dup while ( adr' len' ) 440 over c@ white-space? if exit then 441 str++ 442 repeat 443; 444 445headers 446\ left-parse-string w/ any white space as delimeter 447: next-str ( adr len -- adr' len' s-adr s-len ) 448 2dup skip-non-blanks ( s-adr len adr' len' ) 449 dup >r 2swap r> - ( adr' len' s-adr s-len ) 450; 451 452\ next char or 0 if eol 453: next-c ( adr len -- adr' len' c ) 454 dup if over c@ >r str++ r> else 0 then 455; 456 457false value halt? 458 459: parse-bootargs ( -- ) 460 " bootargs" chosen-ph get-string-prop ( arg$ ) 461 462 \ check for explicit kernel name 463 skip-blanks dup if 464 over c@ ascii - <> if 465 next-str ( arg$ kern$ ) 466 \ use default kernel if user specific a debugger 467 2dup " kadb" $= >r ( arg$ kern$ r: kadb? ) 468 2dup " kmdb" $= r> or ( arg$ kern$ debugger? ) 469 invert if ( arg$ kern$ ) 470 kern-file swap move ( arg$ ) 471 true to kern? 472 else 2drop then ( arg$ ) 473 then 474 then 475 476 \ process args 477 begin 478 skip-blanks dup ( arg$ len ) 479 while 480 next-c ascii - = if 481 next-c case 482 ascii D of 483 \ for "boot kadb -D kernel.foo/unix" 484 skip-blanks next-str ( arg$ file$ ) 485 kern? invert if 486 ?dup if 487 kern-file swap move ( arg$ ) 488 true to kern? 489 else drop then ( arg$ ) 490 else 2drop then ( arg$ ) 491 endof 492 ascii F of 493 skip-blanks next-str ( arg$ file$ ) 494 ?dup if 495 boot-file swap move ( arg$ ) 496 true to fflag? 497 else drop then ( arg$ ) 498 endof 499 ascii H of 500 true to halt? 501 endof 502 ascii L of 503 " /" fs-name swap move 504 true to zflag? 505 " bootlst" boot-file swap move 506 true to fflag? 507 true to lflag? 508 endof 509 ascii Z of 510 skip-blanks next-str ( arg$ fs-name$ ) 511 ?dup if 512 fs-name swap move ( arg$ ) 513 true to zflag? 514 else drop then ( arg$ ) 515 endof 516 endcase 517 then 518 repeat 519 2drop ( ) 520; 521 522 5230 value rd-alloc-sz 524 525: "ramdisk" ( -- dev$ ) " /ramdisk-root" ; 526 527: setup-bootprops ( -- ) 528 chosen-ph push-package 529 530 nested? invert if 531 fs-type$ encode-string " fstype" property 532 fs-ih encode-int " bootfs" property 533 fs-bootprop if property then 534 else 535 fs-type$ encode-string " archive-fstype" property 536 fs-ih encode-int " archfs" property 537 then 538 539 is-archive? if 540 "ramdisk" encode-string " bootarchive" property 541 else 542 loader-base encode-int " elfheader-address" property 543 file-sz encode-int " elfheader-length" property 544 plat-name$ encode-string " impl-arch-name" property 545 targ-file$ encode-string " whoami" property 546 fs-pkg$ encode-string " fs-package" property 547 then 548 549 pop-package 550; 551 552 553\ load ramdisk fcode and tell the driver where 554\ we put the ramdisk data 555: setup-ramdisk ( base size -- ) 556 /rd-fcode mem-alloc ( base size adr ) 557 dup /rd-fcode fs-getrd 558 559 root-ph push-package 560 new-device 561 "ramdisk" str++ device-name 562 dup 1 byte-load 563 finish-device 564 pop-package 565 566 /rd-fcode mem-free ( base size ) 567 568 "ramdisk" dev-open dup 0= if 569 "ramdisk" open-abort 570 then >r ( base size r: ih ) 571 rd-alloc-sz ( base size alloc-sz r: ih ) 572 " create" r@ $call-method ( r: ih ) 573 r> dev-close ( ) 574; 575 576 577\ 578\ ELF parsing 579\ 580 581headerless 5820 value elfhdr 5830 value phdr 584 585: +elfhdr ( index -- value ) elfhdr swap ca+ ; 586: e_machine ( -- n ) h# 12 +elfhdr w@ ; 587: e_entry ( -- n ) h# 18 +elfhdr x@ ; 588: e_phoff ( -- n ) h# 20 +elfhdr x@ ; 589: e_phentsize ( -- n ) h# 36 +elfhdr w@ ; 590: e_phnum ( -- n ) h# 38 +elfhdr w@ ; 591 5921 constant pt_load 593: +phdr ( index -- value ) phdr swap ca+ ; 594: p_type ( -- n ) h# 0 +phdr l@ ; 595: p_vaddr ( -- n ) h# 10 +phdr x@ ; 596: p_memsz ( -- n ) h# 28 +phdr x@ ; 597 598: get-phdr ( filebase index -- phdr ) 599 e_phentsize * e_phoff + + ( phdr ) 600; 601 602\ alloc 4MB pages for kernel text/data 603: vmem-alloc-4mb ( size virt -- base ) 604 swap 4meg roundup swap 605 4meg (mem-alloc) 606; 607 608headers 609\ OBP doesn't allocate memory for elf 610\ programs, it assumes they'll fit 611\ under the default 10MB limit 612: fix-elf-mem ( base -- ) 613 dup to elfhdr 614 e_machine d# 43 <> if drop exit then \ 64b only 615 616 e_phnum 0 ?do 617 dup i get-phdr to phdr 618 p_type pt_load = p_vaddr h# a0.0000 > and if 619 \ allocate 4MB segs for text & data 620 p_vaddr 4meg 1- and if 621 p_memsz p_vaddr vmem-alloc drop 622 else 623 p_memsz p_vaddr vmem-alloc-4mb drop 624 then 625 then 626 loop drop ( ) 627; 628 629 630: load-file ( -- virt ) 631 get-arch 632 get-targ open-path ( fd ) 633 loader-base over get-file if ( fd alloc-sz virt size ) 634 " Boot load failed" die 635 then 636 to file-sz ( fd alloc-sz virt ) 637 swap to rd-alloc-sz ( fd virt ) 638 swap fs-close ( virt ) 639; 640 641: setup-props ( virt -- virt ) 642 dup get-type 643 setup-bootprops 644 is-archive? if 645 dup file-sz setup-ramdisk 646 then 647; 648 649: exec-file ( virt -- ) 650 is-elf? if 651 dup fix-elf-mem 652 then 653 is-archive? if >bootblk then ( virt' ) 654 " to load-base init-program" evaluate 655; 656 657: do-boot ( -- ) 658 parse-bootargs 659 halt? if 660 ." Halted with -H flag. " cr 661 exit 662 then 663 get-bootdev 664 load-pkg 665 mount-root 666 zflag? nested? invert and if 667 fs-name$ open-zfs-fs 668 then 669 load-file ( virt ) 670 setup-props 671 exec-file ( ) 672; 673 674\ Tadpole proms don't initialize my-self 6750 to my-self 676 677do-boot 678