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