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\ NB returned size is 8k rounded since the 168\ memory allocator rounded it for us 169: get-file ( base fd -- [ alloc-sz virt size ] failed? ) 170 dup >r fs-size ( base size r: fd ) 171 dup rot vmem-alloc-prop ( size alloc-sz virt r: fd ) 172 rot 2dup tuck r> ( alloc-sz virt size size virt size fd ) 173 spin-on fs-read spin-off ( alloc-sz virt size size size-rd ) 174 <> if ( alloc-sz virt size ) 175 3drop true exit ( failed ) 176 then 177 h# 2000 roundup ( alloc-sz virt size' ) 178 false ( alloc-sz virt size' succeeded ) 179; 180 181 182false value is-elf? 183false value is-archive? 184 185: check-elf ( base -- is-elf? ) 186 l@ h# 7f454c46 ( \x7fELF ) = 187; 188 189: check-fcode ( base -- is-fcode? ) 190 c@ dup h# f0 h# f3 between swap h# fd = or 191; 192 193: >bootblk ( adr -- adr' ) d# 512 + ; 194 195\ figure out what we just loaded 196: get-type ( adr -- ) 197 dup check-elf to is-elf? 198 199 \ if not nested, check for boot archive (executable after label) 200 nested? invert if 201 >bootblk 202 dup check-fcode ( adr is-fcode? ) 203 over check-elf ( adr is-fcode? is-elf? ) 204 or to is-archive? 205 then 206 drop 207; 208 209 210\ 211\ file name routines 212\ 213 214\ boot file (-F name or boot archive) 215false value fflag? 216/buf-len buffer: boot-file 217: boot-file$ ( -- file$ ) boot-file cscount ; 218 219\ kernel name (final name or unix) 220false value kern? 221/buf-len buffer: kern-file 222: kern-file$ ( -- file$ ) kern-file cscount ; 223 224\ platform name 225/buf-len buffer: plat-name 226: plat-name$ ( -- plat$ ) plat-name cscount ; 227 228\ arch name 229/buf-len buffer: arch-name 230: arch-name$ ( -- arch$ ) arch-name cscount ; 231 232\ final name after /platform massaging 233/buf-len buffer: targ-file 234: targ-file$ ( -- file$ ) targ-file cscount ; 235 236headerless 237: init-targ ( -- ) 238 targ-file /buf-len erase 239 " /platform/" targ-file swap move 240; 241 242\ remove illegal file name chars (e.g., '/') 243: munge-name ( name$ -- name$' ) 244 2dup ( name$ name$ ) 245 begin dup while 246 over c@ ascii / = if 247 over ascii _ swap c! ( name$ name$' ) 248 then str++ 249 repeat 2drop ( name$ ) 250; 251 252headers 253\ does /platform/<name> exist? 254: try-platname ( name$ -- name$ true | false ) 255 munge-name ( name$' ) 256 init-targ 2dup targ-file$ $append 257 targ-file$ fs-open if ( name$ fd ) 258 fs-close true ( name$ true ) 259 else ( name$ ) 260 2drop false ( false ) 261 then ( name$ true | false ) 262; 263 264\ setup arch-name 265\ sun4v -or- sun4u 266: get-def-arch ( -- ) 267 " device_type" root-ph get-package-property if 268 \ some older sunfires don't have device_type set 269 false ( sun4u ) 270 else ( devtype-prop$ ) 271 decode-string 2swap 2drop ( devtype$ ) 272 " sun4v" $= ( sun4v? ) 273 then ( sun4v? ) 274 if " sun4v" else " sun4u" then ( arch$ ) 275 arch-name swap move 276; 277 278\ setup plat-name 279\ platform name -or- 280\ compatible name -or- 281\ default name 282: get-arch ( -- ) 283 get-def-arch 284 285 \ first try "name" in root 286 " name" root-ph get-string-prop ( name$ ) 287 try-platname if 288 plat-name swap move exit ( ) 289 then ( ) 290 291 \ next try "compatible" 292 " compatible" root-ph ( prop$ ph ) 293 get-package-property invert if ( compat$ ) 294 begin decode-string dup while ( compat$ name$ ) 295 try-platname if 296 plat-name swap move 2drop exit ( ) 297 then ( compat$ ) 298 repeat 2drop 2drop ( ) 299 then ( ) 300 301 \ else use default name 302 arch-name$ plat-name swap move 303; 304 305\ make <pre> <file> into /platform/<pre>/<file> 306: $plat-prepend ( file$ pre$ -- file$' ) 307 init-targ 308 targ-file$ $append ( file$ ) 309 " /" targ-file$ $append 310 targ-file$ $append ( ) 311 targ-file$ ( new$ ) 312; 313 314: get-boot ( -- file$ ) 315 fflag? if 316 boot-file$ 317 else 318 " boot_archive" 319 then 320; 321 322: get-kern ( -- file$ ) 323 kern? if 324 kern-file$ 325 else 326 " kernel/sparcv9/unix" 327 then 328; 329 330\ if we're nested, load the kernel, else load the bootarchive 331: get-targ ( -- file$ ) 332 nested? if 333 get-kern 334 else 335 get-boot 336 then 337; 338 339 340: try-file ( file$ -- [ fd ] error? ) 341 diagnostic-mode? if 342 2dup ." Loading: " type cr 343 then 344 fs-open invert ( fd false | true ) 345; 346 347\ try "/platform/<plat-name>/<file>" e.g., SUNW,Sun-Blade-1000 348\ then "/platform/<arch-name>/<file>" e.g., sun4u 349: open-path ( file$ - fd ) 350 over c@ ascii / <> if 351 2dup plat-name$ $plat-prepend ( file$ file$' ) 352 try-file if ( file$ ) 353 2dup arch-name$ $plat-prepend ( file$ file$' ) 354 try-file if ( file$ ) 355 open-abort 356 then ( file$ fd ) 357 then ( file$ fd ) 358 else ( file$ ) 359 \ copy to targ-file for 'whoami' prop 360 targ-file /buf-len erase 361 2dup targ-file swap move 362 2dup try-file if ( file$ ) 363 open-abort 364 then ( file$ fd ) 365 then ( file$ fd ) 366 -rot 2drop ( fd ) 367; 368 369 370false value lflag? 371 372\ ZFS support 373\ -Z fsname opens specified filesystem in disk pool 374 375false value zflag? 376/buf-len buffer: fs-name 377: fs-name$ ( -- fs$ ) fs-name cscount ; 378 379[ifdef] zfs 380 381: open-zfs-fs ( fs$ -- ) 382 2dup " open-fs" fs-ih $call-method 0= if 383 open-abort 384 then 385 2drop ( ) 386; 387 388[else] 389 390: open-zfs-fs ( fs$ -- ) 391 \ ignore on -L 392 lflag? invert if 393 " -Z not supported on non-zfs root" die 394 then 395; 396 397[then] 398 399 400\ 401\ arg parsing 402\ 403 404headerless 405: printable? ( n -- flag ) \ true if n is a printable ascii character 406 dup bl th 7f within swap th 80 th ff between or 407; 408: white-space? ( n -- flag ) \ true is n is non-printable? or a blank 409 dup printable? 0= swap bl = or 410; 411 412: skip-blanks ( adr len -- adr' len' ) 413 begin dup while ( adr' len' ) 414 over c@ white-space? 0= if exit then 415 str++ 416 repeat 417; 418 419: skip-non-blanks ( adr len -- adr' len' ) 420 begin dup while ( adr' len' ) 421 over c@ white-space? if exit then 422 str++ 423 repeat 424; 425 426headers 427\ left-parse-string w/ any white space as delimeter 428: next-str ( adr len -- adr' len' s-adr s-len ) 429 2dup skip-non-blanks ( s-adr len adr' len' ) 430 dup >r 2swap r> - ( adr' len' s-adr s-len ) 431; 432 433: next-c ( adr len -- adr' len' c ) 434 over c@ >r str++ r> 435; 436 437false value halt? 438 439: parse-bootargs ( -- ) 440 " bootargs" chosen-ph get-string-prop ( arg$ ) 441 442 \ check for explicit kernel name 443 skip-blanks dup if 444 over c@ ascii - <> if 445 next-str ( arg$ kern$ ) 446 \ use default kernel if user specific a debugger 447 2dup " kadb" $= >r ( arg$ kern$ r: kadb? ) 448 2dup " kmdb" $= r> or ( arg$ kern$ debugger? ) 449 invert if ( arg$ kern$ ) 450 kern-file swap move ( arg$ ) 451 true to kern? 452 else 2drop then ( arg$ ) 453 then 454 then 455 456 \ process args 457 begin 458 skip-blanks dup ( arg$ len ) 459 while 460 next-c ascii - = if 461 next-c case 462 ascii D of 463 \ for "boot kadb -D kernel.foo/unix" 464 skip-blanks next-str ( arg$ file$ ) 465 kern? invert if 466 ?dup if 467 kern-file swap move ( arg$ ) 468 true to kern? 469 else drop then ( arg$ ) 470 else 2drop then ( arg$ ) 471 endof 472 ascii F of 473 skip-blanks next-str ( arg$ file$ ) 474 ?dup if 475 boot-file swap move ( arg$ ) 476 true to fflag? 477 else drop then ( arg$ ) 478 endof 479 ascii H of 480 true to halt? 481 endof 482 ascii L of 483 " /" fs-name swap move 484 true to zflag? 485 " bootlst" boot-file swap move 486 true to fflag? 487 true to lflag? 488 endof 489 ascii Z of 490 skip-blanks next-str ( arg$ fs-name$ ) 491 ?dup if 492 fs-name swap move ( arg$ ) 493 true to zflag? 494 else drop then ( arg$ ) 495 endof 496 endcase 497 then 498 repeat 499 2drop ( ) 500; 501 502 5030 value rd-alloc-sz 504 505: "ramdisk" ( -- dev$ ) " /ramdisk-root" ; 506 507: setup-bootprops ( -- ) 508 chosen-ph push-package 509 510 nested? invert if 511 fs-type$ encode-string " fstype" property 512 fs-ih encode-int " bootfs" property 513 fs-bootprop if property then 514 else 515 fs-type$ encode-string " archive-fstype" property 516 fs-ih encode-int " archfs" property 517 then 518 519 is-archive? if 520 "ramdisk" encode-string " bootarchive" property 521 else 522 loader-base encode-int " elfheader-address" property 523 file-sz encode-int " elfheader-length" property 524 plat-name$ encode-string " impl-arch-name" property 525 targ-file$ encode-string " whoami" property 526 fs-pkg$ encode-string " fs-package" property 527 then 528 529 pop-package 530; 531 532 533\ load ramdisk fcode and tell the driver where 534\ we put the ramdisk data 535: setup-ramdisk ( base size -- ) 536 /rd-fcode mem-alloc ( base size adr ) 537 dup /rd-fcode fs-getrd 538 539 root-ph push-package 540 new-device 541 "ramdisk" str++ device-name 542 dup 1 byte-load 543 finish-device 544 pop-package 545 546 /rd-fcode mem-free ( base size ) 547 548 "ramdisk" dev-open dup 0= if 549 "ramdisk" open-abort 550 then >r ( base size r: ih ) 551 rd-alloc-sz ( base size alloc-sz r: ih ) 552 " create" r@ $call-method ( r: ih ) 553 r> dev-close ( ) 554; 555 556 557\ 558\ ELF parsing 559\ 560 561headerless 5620 value elfhdr 5630 value phdr 564 565: +elfhdr ( index -- value ) elfhdr swap ca+ ; 566: e_machine ( -- n ) h# 12 +elfhdr w@ ; 567: e_entry ( -- n ) h# 18 +elfhdr x@ ; 568: e_phoff ( -- n ) h# 20 +elfhdr x@ ; 569: e_phentsize ( -- n ) h# 36 +elfhdr w@ ; 570: e_phnum ( -- n ) h# 38 +elfhdr w@ ; 571 5721 constant pt_load 573: +phdr ( index -- value ) phdr swap ca+ ; 574: p_type ( -- n ) h# 0 +phdr l@ ; 575: p_vaddr ( -- n ) h# 10 +phdr x@ ; 576: p_memsz ( -- n ) h# 28 +phdr x@ ; 577 578: get-phdr ( filebase index -- phdr ) 579 e_phentsize * e_phoff + + ( phdr ) 580; 581 582\ alloc 4MB pages for kernel text/data 583: vmem-alloc-4mb ( size virt -- base ) 584 swap 4meg roundup swap 585 4meg (mem-alloc) 586; 587 588headers 589\ OBP doesn't allocate memory for elf 590\ programs, it assumes they'll fit 591\ under the default 10MB limit 592: fix-elf-mem ( base -- ) 593 dup to elfhdr 594 e_machine d# 43 <> if drop exit then \ 64b only 595 596 e_phnum 0 ?do 597 dup i get-phdr to phdr 598 p_type pt_load = p_vaddr h# a0.0000 > and if 599 \ allocate 4MB segs for text & data 600 p_vaddr 4meg 1- and if 601 p_memsz p_vaddr vmem-alloc drop 602 else 603 p_memsz p_vaddr vmem-alloc-4mb drop 604 then 605 then 606 loop drop ( ) 607; 608 609 610: load-file ( -- virt ) 611 get-arch 612 get-targ open-path ( fd ) 613 loader-base over get-file if ( fd alloc-sz virt size ) 614 " Boot load failed" die 615 then 616 to file-sz ( fd alloc-sz virt ) 617 swap to rd-alloc-sz ( fd virt ) 618 swap fs-close ( virt ) 619; 620 621: setup-props ( virt -- virt ) 622 dup get-type 623 setup-bootprops 624 is-archive? if 625 dup file-sz setup-ramdisk 626 then 627; 628 629: exec-file ( virt -- ) 630 is-elf? if 631 dup fix-elf-mem 632 then 633 is-archive? if >bootblk then ( virt' ) 634 " to load-base init-program" evaluate 635; 636 637: do-boot ( -- ) 638 parse-bootargs 639 halt? if 640 ." Halted with -H flag. " cr 641 exit 642 then 643 get-bootdev 644 load-pkg 645 mount-root 646 zflag? nested? invert and if 647 fs-name$ open-zfs-fs 648 then 649 load-file ( virt ) 650 setup-props 651 exec-file ( ) 652; 653 654\ Tadpole proms don't initialize my-self 6550 to my-self 656 657do-boot 658