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 2008 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" die 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 367false value lflag? 368 369\ ZFS support 370\ -Z fsname opens specified filesystem in disk pool 371 372false value zflag? 373/buf-len buffer: fs-name 374: fs-name$ ( -- fs$ ) fs-name cscount ; 375 376[ifdef] zfs 377 378: open-zfs-fs ( fs$ -- ) 379 2dup " open-fs" fs-ih $call-method 0= if 380 open-abort 381 then 382 2drop ( ) 383; 384 385[else] 386 387: open-zfs-fs ( fs$ -- ) 388 \ ignore on -L 389 lflag? invert if 390 " -Z not supported on non-zfs root" die 391 then 392; 393 394[then] 395 396 397\ 398\ arg parsing 399\ 400 401headerless 402: printable? ( n -- flag ) \ true if n is a printable ascii character 403 dup bl th 7f within swap th 80 th ff between or 404; 405: white-space? ( n -- flag ) \ true is n is non-printable? or a blank 406 dup printable? 0= swap bl = or 407; 408 409: skip-blanks ( adr len -- adr' len' ) 410 begin dup while ( adr' len' ) 411 over c@ white-space? 0= if exit then 412 str++ 413 repeat 414; 415 416: skip-non-blanks ( adr len -- adr' len' ) 417 begin dup while ( adr' len' ) 418 over c@ white-space? if exit then 419 str++ 420 repeat 421; 422 423headers 424\ left-parse-string w/ any white space as delimeter 425: next-str ( adr len -- adr' len' s-adr s-len ) 426 2dup skip-non-blanks ( s-adr len adr' len' ) 427 dup >r 2swap r> - ( adr' len' s-adr s-len ) 428; 429 430: next-c ( adr len -- adr' len' c ) 431 over c@ >r str++ r> 432; 433 434false value halt? 435 436: parse-bootargs ( -- ) 437 " bootargs" chosen-ph get-string-prop ( arg$ ) 438 439 \ check for explicit kernel name 440 skip-blanks dup if 441 over c@ ascii - <> if 442 next-str ( arg$ kern$ ) 443 \ use default kernel if user specific a debugger 444 2dup " kadb" $= >r ( arg$ kern$ r: kadb? ) 445 2dup " kmdb" $= r> or ( arg$ kern$ debugger? ) 446 invert if ( arg$ kern$ ) 447 kern-file swap move ( arg$ ) 448 true to kern? 449 else 2drop then ( arg$ ) 450 then 451 then 452 453 \ process args 454 begin 455 skip-blanks dup ( arg$ len ) 456 while 457 next-c ascii - = if 458 next-c case 459 ascii D of 460 \ for "boot kadb -D kernel.foo/unix" 461 skip-blanks next-str ( arg$ file$ ) 462 kern? invert if 463 ?dup if 464 kern-file swap move ( arg$ ) 465 true to kern? 466 else drop then ( arg$ ) 467 else 2drop then ( arg$ ) 468 endof 469 ascii F of 470 skip-blanks next-str ( arg$ file$ ) 471 ?dup if 472 boot-file swap move ( arg$ ) 473 true to fflag? 474 else drop then ( arg$ ) 475 endof 476 ascii H of 477 true to halt? 478 endof 479 ascii L of 480 " /" fs-name swap move 481 true to zflag? 482 " bootlst" boot-file swap move 483 true to fflag? 484 true to lflag? 485 endof 486 ascii Z of 487 skip-blanks next-str ( arg$ fs-name$ ) 488 ?dup if 489 fs-name swap move ( arg$ ) 490 true to zflag? 491 else drop then ( arg$ ) 492 endof 493 endcase 494 then 495 repeat 496 2drop ( ) 497; 498 499 5000 value rd-alloc-sz 501 502: "ramdisk" ( -- dev$ ) " /ramdisk-root" ; 503 504: setup-bootprops ( -- ) 505 chosen-ph push-package 506 507 nested? invert if 508 fs-type$ encode-string " fstype" property 509 fs-ih encode-int " bootfs" property 510 fs-bootprop if property then 511 else 512 fs-type$ encode-string " archive-fstype" property 513 fs-ih encode-int " archfs" property 514 then 515 516 is-archive? if 517 "ramdisk" encode-string " bootarchive" property 518 else 519 loader-base encode-int " elfheader-address" property 520 file-sz encode-int " elfheader-length" property 521 plat-name$ encode-string " impl-arch-name" property 522 targ-file$ encode-string " whoami" property 523 fs-pkg$ encode-string " fs-package" property 524 then 525 526 pop-package 527; 528 529 530\ load ramdisk fcode and tell the driver where 531\ we put the ramdisk data 532: setup-ramdisk ( base size -- ) 533 /rd-fcode mem-alloc ( base size adr ) 534 dup /rd-fcode fs-getrd 535 536 root-ph push-package 537 new-device 538 "ramdisk" str++ device-name 539 dup 1 byte-load 540 finish-device 541 pop-package 542 543 /rd-fcode mem-free ( base size ) 544 545 "ramdisk" dev-open dup 0= if 546 "ramdisk" open-abort 547 then >r ( base size r: ih ) 548 rd-alloc-sz ( base size alloc-sz r: ih ) 549 " create" r@ $call-method ( r: ih ) 550 r> dev-close ( ) 551; 552 553 554\ 555\ ELF parsing 556\ 557 558headerless 5590 value elfhdr 5600 value phdr 561 562: +elfhdr ( index -- value ) elfhdr swap ca+ ; 563: e_machine ( -- n ) h# 12 +elfhdr w@ ; 564: e_entry ( -- n ) h# 18 +elfhdr x@ ; 565: e_phoff ( -- n ) h# 20 +elfhdr x@ ; 566: e_phentsize ( -- n ) h# 36 +elfhdr w@ ; 567: e_phnum ( -- n ) h# 38 +elfhdr w@ ; 568 5691 constant pt_load 570: +phdr ( index -- value ) phdr swap ca+ ; 571: p_type ( -- n ) h# 0 +phdr l@ ; 572: p_vaddr ( -- n ) h# 10 +phdr x@ ; 573: p_memsz ( -- n ) h# 28 +phdr x@ ; 574 575: get-phdr ( filebase index -- phdr ) 576 e_phentsize * e_phoff + + ( phdr ) 577; 578 579\ alloc 4MB pages for kernel text/data 580: vmem-alloc-4mb ( size virt -- base ) 581 swap 4meg roundup swap 582 4meg (mem-alloc) 583; 584 585headers 586\ OBP doesn't allocate memory for elf 587\ programs, it assumes they'll fit 588\ under the default 10MB limit 589: fix-elf-mem ( base -- ) 590 dup to elfhdr 591 e_machine d# 43 <> if drop exit then \ 64b only 592 593 e_phnum 0 ?do 594 dup i get-phdr to phdr 595 p_type pt_load = p_vaddr h# a0.0000 > and if 596 \ allocate 4MB segs for text & data 597 p_vaddr 4meg 1- and if 598 p_memsz p_vaddr vmem-alloc drop 599 else 600 p_memsz p_vaddr vmem-alloc-4mb drop 601 then 602 then 603 loop drop ( ) 604; 605 606 607: load-file ( -- virt ) 608 get-arch 609 get-targ open-path ( fd ) 610 loader-base over get-file if ( fd alloc-sz virt size ) 611 " Boot load failed" die 612 then 613 to file-sz ( fd alloc-sz virt ) 614 swap to rd-alloc-sz ( fd virt ) 615 swap fs-close ( virt ) 616; 617 618: setup-props ( virt -- virt ) 619 dup get-type 620 setup-bootprops 621 is-archive? if 622 dup file-sz setup-ramdisk 623 then 624; 625 626: exec-file ( virt -- ) 627 is-elf? if 628 dup fix-elf-mem 629 then 630 is-archive? if >bootblk then ( virt' ) 631 " to load-base init-program" evaluate 632; 633 634: do-boot ( -- ) 635 parse-bootargs 636 halt? if 637 ." Halted with -H flag. " cr 638 exit 639 then 640 get-bootdev 641 load-pkg 642 mount-root 643 zflag? nested? invert and if 644 fs-name$ open-zfs-fs 645 then 646 load-file ( virt ) 647 setup-props 648 exec-file ( ) 649; 650 651\ Tadpole proms don't initialize my-self 6520 to my-self 653 654do-boot 655