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