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 233: init-targ ( -- ) 234 targ-file /buf-len erase 235 " /platform/" targ-file swap move 236; 237 238\ remove illegal file name chars (e.g., '/') 239: munge-name ( name$ -- name$' ) 240 2dup ( name$ name$ ) 241 begin dup while 242 over c@ ascii / = if 243 over ascii _ swap c! ( name$ name$' ) 244 then str++ 245 repeat 2drop ( name$ ) 246; 247 248\ if the platform exists in the FS, use it 249\ else use a default (e.g., sun4v) 250: get-arch ( -- ) 251 " device_type" root-ph get-package-property if 252 \ some older sunfires don't have device_type set 253 false ( sun4u ) 254 else ( devtype-prop$ ) 255 decode-string 2swap 2drop ( devtype$ ) 256 " sun4v" $= ( sun4v? ) 257 then ( sun4v? ) 258 if " sun4v" else " sun4u" then ( arch$ ) 259 arch-name swap move 260 " name" root-ph get-string-prop ( name$ ) 261 munge-name ( name$' ) 262 init-targ 2dup targ-file$ $append 263 targ-file$ fs-open if ( name$ fd ) 264 fs-close ( name$ ) 265 else ( name$ ) 266 2drop arch-name$ ( default$ ) 267 then ( name$ ) 268 plat-name swap move ( ) 269; 270 271\ make <pre> <file> into /platform/<pre>/<file> 272: $plat-prepend ( file$ pre$ -- file$' ) 273 init-targ 274 targ-file$ $append ( file$ ) 275 " /" targ-file$ $append 276 targ-file$ $append ( ) 277 targ-file$ ( new$ ) 278; 279 280: get-boot ( -- file$ ) 281 fflag? if 282 boot-file$ 283 else 284 " boot_archive" 285 then 286; 287 288: get-kern ( -- file$ ) 289 kern? if 290 kern-file$ 291 else 292 " kernel/sparcv9/unix" 293 then 294; 295 296\ if we're nested, load the kernel, else load the bootarchive 297: get-targ ( -- file$ ) 298 nested? if 299 get-kern 300 else 301 get-boot 302 then 303; 304 305 306: try-file ( file$ -- [ fd ] error? ) 307 diagnostic-mode? if 308 2dup ." Loading: " type cr 309 then 310 fs-open invert ( fd false | true ) 311; 312 313\ try "/platform/<plat-name>/<file>" e.g., SUNW,Sun-Blade-1000 314\ then "/platform/<arch-name>/<file>" e.g., sun4u 315: open-path ( file$ - fd ) 316 over c@ ascii / <> if 317 2dup plat-name$ $plat-prepend ( file$ file$' ) 318 try-file if ( file$ ) 319 2dup arch-name$ $plat-prepend ( file$ file$' ) 320 try-file if ( file$ ) 321 open-abort 322 then ( file$ fd ) 323 then ( file$ fd ) 324 else ( file$ ) 325 \ copy to targ-file for 'whoami' prop 326 targ-file /buf-len erase 327 2dup targ-file swap move 328 2dup try-file if ( file$ ) 329 open-abort 330 then ( file$ fd ) 331 then ( file$ fd ) 332 -rot 2drop ( fd ) 333; 334 335 336\ ZFS support 337\ -Z fsname opens specified filesystem in disk pool 338 339false value zflag? 340/buf-len buffer: fs-name 341: fs-name$ ( -- fs$ ) fs-name cscount ; 342 343[ifdef] zfs 344 345: open-zfs-fs ( fs$ -- ) 346 2dup " open-fs" fs-ih $call-method 0= if 347 open-abort 348 then 349 2drop ( ) 350; 351 352[else] 353 354: open-zfs-fs ( fs$ -- ) 355 ." -Z not supported on non-zfs root" abort 356; 357 358[then] 359 360 361\ 362\ arg parsing 363\ 364 365headerless 366: printable? ( n -- flag ) \ true if n is a printable ascii character 367 dup bl th 7f within swap th 80 th ff between or 368; 369: white-space? ( n -- flag ) \ true is n is non-printable? or a blank 370 dup printable? 0= swap bl = or 371; 372 373: skip-blanks ( adr len -- adr' len' ) 374 begin dup while ( adr' len' ) 375 over c@ white-space? 0= if exit then 376 str++ 377 repeat 378; 379 380: skip-non-blanks ( adr len -- adr' len' ) 381 begin dup while ( adr' len' ) 382 over c@ white-space? if exit then 383 str++ 384 repeat 385; 386 387headers 388\ left-parse-string w/ any white space as delimeter 389: next-str ( adr len -- adr' len' s-adr s-len ) 390 2dup skip-non-blanks ( s-adr len adr' len' ) 391 dup >r 2swap r> - ( adr' len' s-adr s-len ) 392; 393 394: next-c ( adr len -- adr' len' c ) 395 over c@ >r str++ r> 396; 397 398false value halt? 399 400: parse-bootargs ( -- ) 401 " bootargs" chosen-ph get-string-prop ( arg$ ) 402 403 \ check for explicit kernel name 404 skip-blanks dup if 405 over c@ ascii - <> if 406 next-str ( arg$ kern$ ) 407 \ use default kernel if user specific a debugger 408 2dup " kadb" $= >r ( arg$ kern$ r: kadb? ) 409 2dup " kmdb" $= r> or ( arg$ kern$ debugger? ) 410 invert if ( arg$ kern$ ) 411 kern-file swap move ( arg$ ) 412 true to kern? 413 else 2drop then ( arg$ ) 414 then 415 then 416 417 \ process args 418 begin 419 skip-blanks dup ( arg$ len ) 420 while 421 next-c ascii - = if 422 next-c case 423 ascii D of 424 \ for "boot kadb -D kernel.foo/unix" 425 skip-blanks next-str ( arg$ file$ ) 426 kern? invert if 427 ?dup if 428 kern-file swap move ( arg$ ) 429 true to kern? 430 else drop then ( arg$ ) 431 else 2drop then ( arg$ ) 432 endof 433 ascii F of 434 skip-blanks next-str ( arg$ file$ ) 435 ?dup if 436 boot-file swap move ( arg$ ) 437 true to fflag? 438 else drop then ( arg$ ) 439 endof 440 ascii H of 441 true to halt? 442 endof 443 ascii Z of 444 skip-blanks next-str ( arg$ fs-name$ ) 445 ?dup if 446 fs-name swap move ( arg$ ) 447 true to zflag? 448 else drop then ( arg$ ) 449 endof 450 endcase 451 then 452 repeat 453 2drop ( ) 454; 455 456 4570 value rd-alloc-sz 458 459: "ramdisk" ( -- dev$ ) " /ramdisk-root" ; 460 461: setup-bootprops ( -- ) 462 chosen-ph push-package 463 464 nested? invert if 465 fs-type$ encode-string " fstype" property 466 fs-ih encode-int " bootfs" property 467 fs-bootprop if property then 468 else 469 fs-type$ encode-string " archive-fstype" property 470 fs-ih encode-int " archfs" property 471 then 472 473 is-archive? if 474 "ramdisk" encode-string " bootarchive" property 475 else 476 loader-base encode-int " elfheader-address" property 477 file-sz encode-int " elfheader-length" property 478 plat-name$ encode-string " impl-arch-name" property 479 targ-file$ encode-string " whoami" property 480 fs-pkg$ encode-string " fs-package" property 481 then 482 483 pop-package 484; 485 486 487\ load ramdisk fcode and tell the driver where 488\ we put the ramdisk data 489: setup-ramdisk ( base size -- ) 490 /rd-fcode mem-alloc ( base size adr ) 491 dup /rd-fcode fs-getrd 492 493 root-ph push-package 494 new-device 495 "ramdisk" str++ device-name 496 dup 1 byte-load 497 finish-device 498 pop-package 499 500 /rd-fcode mem-free ( base size ) 501 502 "ramdisk" dev-open dup 0= if 503 "ramdisk" open-abort 504 then >r ( base size r: ih ) 505 rd-alloc-sz ( base size alloc-sz r: ih ) 506 " create" r@ $call-method ( r: ih ) 507 r> dev-close ( ) 508; 509 510 511\ 512\ ELF parsing 513\ 514 5150 value elfhdr 5160 value phdr 517 518: +elfhdr ( index -- value ) elfhdr swap ca+ ; 519: e_machine ( -- n ) h# 12 +elfhdr w@ ; 520: e_entry ( -- n ) h# 18 +elfhdr x@ ; 521: e_phoff ( -- n ) h# 20 +elfhdr x@ ; 522: e_phentsize ( -- n ) h# 36 +elfhdr w@ ; 523: e_phnum ( -- n ) h# 38 +elfhdr w@ ; 524 5251 constant pt_load 526: +phdr ( index -- value ) phdr swap ca+ ; 527: p_type ( -- n ) h# 0 +phdr l@ ; 528: p_vaddr ( -- n ) h# 10 +phdr x@ ; 529: p_memsz ( -- n ) h# 28 +phdr x@ ; 530 531: get-phdr ( filebase index -- phdr ) 532 e_phentsize * e_phoff + + ( phdr ) 533; 534 535\ alloc 4MB pages for kernel text/data 536: vmem-alloc-4mb ( size virt -- base ) 537 swap 4meg roundup swap 538 4meg (mem-alloc) 539; 540 541\ OBP doesn't allocate memory for elf 542\ programs, it assumes they'll fit 543\ under the default 10MB limit 544: fix-elf-mem ( base -- ) 545 dup to elfhdr 546 e_machine d# 43 <> if drop exit then \ 64b only 547 548 e_phnum 0 ?do 549 dup i get-phdr to phdr 550 p_type pt_load = p_vaddr h# a0.0000 > and if 551 \ allocate 4MB segs for text & data 552 p_vaddr 4meg 1- and if 553 p_memsz p_vaddr vmem-alloc drop 554 else 555 p_memsz p_vaddr vmem-alloc-4mb drop 556 then 557 then 558 loop drop ( ) 559; 560 561 562: load-file ( -- virt ) 563 get-arch 564 get-targ open-path ( fd ) 565 loader-base over get-file if ( fd alloc-sz virt size ) 566 ." Boot load failed" abort 567 then 568 to file-sz ( fd alloc-sz virt ) 569 swap to rd-alloc-sz ( fd virt ) 570 swap fs-close ( virt ) 571; 572 573: setup-props ( virt -- virt ) 574 dup get-type 575 setup-bootprops 576 is-archive? if 577 dup file-sz setup-ramdisk 578 then 579; 580 581: exec-file ( virt -- ) 582 is-elf? if 583 dup fix-elf-mem 584 then 585 is-archive? if >bootblk then ( virt' ) 586 " to load-base init-program" evaluate 587; 588 589: do-boot ( -- ) 590 parse-bootargs 591 halt? if 592 ." Halted with -H flag. " cr 593 exit 594 then 595 get-bootdev 596 load-pkg 597 mount-root 598 zflag? nested? invert and if 599 fs-name$ open-zfs-fs 600 then 601 load-file ( virt ) 602 setup-props 603 exec-file ( ) 604; 605 606\ Tadpole proms don't initialize my-self 6070 to my-self 608 609do-boot 610