1\ $NetBSD: bootblk.fth,v 1.4 2002/06/12 22:18:02 eeh Exp $ 2\ 3\ IEEE 1275 Open Firmware Boot Block 4\ 5\ Parses disklabel and UFS and loads the file called `ofwboot' 6\ 7\ 8\ Copyright (c) 1998 Eduardo Horvath. 9\ All rights reserved. 10\ 11\ Redistribution and use in source and binary forms, with or without 12\ modification, are permitted provided that the following conditions 13\ are met: 14\ 1. Redistributions of source code must retain the above copyright 15\ notice, this list of conditions and the following disclaimer. 16\ 2. Redistributions in binary form must reproduce the above copyright 17\ notice, this list of conditions and the following disclaimer in the 18\ documentation and/or other materials provided with the distribution. 19\ 3. All advertising materials mentioning features or use of this software 20\ must display the following acknowledgement: 21\ This product includes software developed by Eduardo Horvath. 22\ 4. The name of the author may not be used to endorse or promote products 23\ derived from this software without specific prior written permission 24\ 25\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26\ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27\ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28\ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29\ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30\ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31\ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32\ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33\ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34\ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35\ 36 37offset16 38hex 39headers 40 41false value boot-debug? 42 43\ 44\ First some housekeeping: Open /chosen and set up vectors into 45\ client-services 46 47" /chosen" find-package 0= if ." Cannot find /chosen" 0 then 48constant chosen-phandle 49 50" /openprom/client-services" find-package 0= if 51 ." Cannot find client-services" cr abort 52then constant cif-phandle 53 54defer cif-claim ( align size virt -- base ) 55defer cif-release ( size virt -- ) 56defer cif-open ( cstr -- ihandle|0 ) 57defer cif-close ( ihandle -- ) 58defer cif-read ( len adr ihandle -- #read ) 59defer cif-seek ( low high ihandle -- -1|0|1 ) 60\ defer cif-peer ( phandle -- phandle ) 61\ defer cif-getprop ( len adr cstr phandle -- ) 62 63: find-cif-method ( method,len -- xf ) 64 cif-phandle find-method drop 65; 66 67" claim" find-cif-method to cif-claim 68" open" find-cif-method to cif-open 69" close" find-cif-method to cif-close 70" read" find-cif-method to cif-read 71" seek" find-cif-method to cif-seek 72 73: twiddle ( -- ) ." ." ; \ Need to do this right. Just spit out periods for now. 74 75\ 76\ Support routines 77\ 78 79: strcmp ( s1 l1 s2 l2 -- true:false ) 80 rot tuck <> if 3drop false exit then 81 comp 0= 82; 83 84\ Move string into buffer 85 86: strmov ( s1 l1 d -- d l1 ) 87 dup 2over swap -rot ( s1 l1 d s1 d l1 ) 88 move ( s1 l1 d ) 89 rot drop swap 90; 91 92\ Move s1 on the end of s2 and return the result 93 94: strcat ( s1 l1 s2 l2 -- d tot ) 95 2over swap ( s1 l1 s2 l2 l1 s1 ) 96 2over + rot ( s1 l1 s2 l2 s1 d l1 ) 97 move rot + ( s1 s2 len ) 98 rot drop ( s2 len ) 99; 100 101: strchr ( s1 l1 c -- s2 l2 ) 102 begin 103 dup 2over 0= if ( s1 l1 c c s1 ) 104 2drop drop exit then 105 c@ = if ( s1 l1 c ) 106 drop exit then 107 -rot /c - swap ca1+ ( c l2 s2 ) 108 swap rot 109 again 110; 111 112 113: cstr ( ptr -- str len ) 114 dup 115 begin dup c@ 0<> while + repeat 116 over - 117; 118 119\ 120\ BSD FFS parameters 121\ 122 123fload assym.fth.h 124 125sbsize buffer: sb-buf 126-1 value boot-ihandle 127dev_bsize value bsize 1280 value raid-offset \ Offset if it's a raid-frame partition 129 130: strategy ( addr size start -- nread ) 131 raid-offset + bsize * 0 " seek" boot-ihandle $call-method 132 -1 = if 133 ." strategy: Seek failed" cr 134 abort 135 then 136 " read" boot-ihandle $call-method 137; 138 139\ 140\ Cylinder group macros 141\ 142 143: cgbase ( cg fs -- cgbase ) fs_fpg l@ * ; 144: cgstart ( cg fs -- cgstart ) 145 2dup fs_cgmask l@ not and ( cg fs stuff -- ) 146 over fs_cgoffset l@ * -rot ( stuffcg fs -- ) 147 cgbase + 148; 149: cgdmin ( cg fs -- 1st-data-block ) dup fs_dblkno l@ -rot cgstart + ; 150: cgimin ( cg fs -- inode-block ) dup fs_iblkno l@ -rot cgstart + ; 151: cgsblock ( cg fs -- super-block ) dup fs_sblkno l@ -rot cgstart + ; 152: cgstod ( cg fs -- cg-block ) dup fs_cblkno l@ -rot cgstart + ; 153 154\ 155\ Block and frag position macros 156\ 157 158: blkoff ( pos fs -- off ) fs_qbmask x@ and ; 159: fragoff ( pos fs -- off ) fs_qfmask x@ and ; 160: lblktosize ( blk fs -- off ) fs_bshift l@ << ; 161: lblkno ( pos fs -- off ) fs_bshift l@ >> ; 162: numfrags ( pos fs -- off ) fs_fshift l@ >> ; 163: blkroundup ( pos fs -- off ) dup fs_bmask l@ -rot fs_qbmask x@ + and ; 164: fragroundup ( pos fs -- off ) dup fs_fmask l@ -rot fs_qfmask x@ + and ; 165\ : fragroundup ( pos fs -- off ) tuck fs_qfmask x@ + swap fs_fmask l@ and ; 166: fragstoblks ( pos fs -- off ) fs_fragshift l@ >> ; 167: blkstofrags ( blk fs -- frag ) fs_fragshift l@ << ; 168: fragnum ( fsb fs -- off ) fs_frag l@ 1- and ; 169: blknum ( fsb fs -- off ) fs_frag l@ 1- not and ; 170: dblksize ( lbn dino fs -- size ) 171 -rot ( fs lbn dino ) 172 di_size x@ ( fs lbn di_size ) 173 -rot dup 1+ ( di_size fs lbn lbn+1 ) 174 2over fs_bshift l@ ( di_size fs lbn lbn+1 di_size b_shift ) 175 rot swap << >= ( di_size fs lbn res1 ) 176 swap ndaddr >= or if ( di_size fs ) 177 swap drop fs_bsize l@ exit ( size ) 178 then tuck blkoff swap fragroundup ( size ) 179; 180 181 182: ino-to-cg ( ino fs -- cg ) fs_ipg l@ / ; 183: ino-to-fsbo ( ino fs -- fsb0 ) fs_inopb l@ mod ; 184: ino-to-fsba ( ino fs -- ba ) \ Need to remove the stupid stack diags someday 185 2dup ( ino fs ino fs ) 186 ino-to-cg ( ino fs cg ) 187 over ( ino fs cg fs ) 188 cgimin ( ino fs inode-blk ) 189 -rot ( inode-blk ino fs ) 190 tuck ( inode-blk fs ino fs ) 191 fs_ipg l@ ( inode-blk fs ino ipg ) 192 mod ( inode-blk fs mod ) 193 swap ( inode-blk mod fs ) 194 dup ( inode-blk mod fs fs ) 195 fs_inopb l@ ( inode-blk mod fs inopb ) 196 rot ( inode-blk fs inopb mod ) 197 swap ( inode-blk fs mod inopb ) 198 / ( inode-blk fs div ) 199 swap ( inode-blk div fs ) 200 blkstofrags ( inode-blk frag ) 201 + 202; 203: fsbtodb ( fsb fs -- db ) fs_fsbtodb l@ << ; 204 205\ 206\ File stuff 207\ 208 209niaddr /w* constant narraysize 210 211struct 212 8 field >f_ihandle \ device handle 213 8 field >f_seekp \ seek pointer 214 8 field >f_fs \ pointer to super block 215 dinode_SIZEOF field >f_di \ copy of on-disk inode 216 8 field >f_buf \ buffer for data block 217 4 field >f_buf_size \ size of data block 218 4 field >f_buf_blkno \ block number of data block 219constant file_SIZEOF 220 221file_SIZEOF buffer: the-file 222sb-buf the-file >f_fs x! 223 224dinode_SIZEOF buffer: cur-inode 225h# 2000 buffer: indir-block 226-1 value indir-addr 227 228\ 229\ Translate a fileblock to a disk block 230\ 231\ We only allow single indirection 232\ 233 234: block-map ( fileblock -- diskblock ) 235 \ Direct block? 236 dup ndaddr < if ( fileblock ) 237 cur-inode di_db ( arr-indx arr-start ) 238 swap la+ l@ exit ( diskblock ) 239 then ( fileblock ) 240 ndaddr - ( fileblock' ) 241 \ Now we need to check the indirect block 242 dup sb-buf fs_nindir l@ < if ( fileblock' ) 243 cur-inode di_ib l@ dup ( fileblock' indir-block indir-block ) 244 indir-addr <> if ( fileblock' indir-block ) 245 to indir-addr ( fileblock' ) 246 indir-block ( fileblock' indir-block ) 247 sb-buf dup fs_bsize l@ ( fileblock' indir-block fs fs_bsize ) 248 swap indir-addr swap ( fileblock' indir-block fs_bsize indiraddr fs ) 249 fsbtodb ( fileblock' indir-block fs_bsize db ) 250 strategy ( fileblock' nread ) 251 then ( fileblock' nread|indir-block ) 252 drop \ Really should check return value 253 indir-block swap la+ l@ exit 254 then 255 dup sb-buf fs_nindir - ( fileblock'' ) 256 \ Now try 2nd level indirect block -- just read twice 257 dup sb-buf fs_nindir l@ dup * < if ( fileblock'' ) 258 cur-inode di_ib 1 la+ l@ ( fileblock'' indir2-block ) 259 to indir-addr ( fileblock'' ) 260 \ load 1st level indir block 261 indir-block ( fileblock'' indir-block ) 262 sb-buf dup fs_bsize l@ ( fileblock'' indir-block fs fs_bsize ) 263 swap indir-addr swap ( fileblock'' indir-block fs_bsize indiraddr fs ) 264 fsbtodb ( fileblock'' indir-block fs_bsize db ) 265 strategy ( fileblock'' nread ) 266 drop ( fileblock'' ) 267 dup sb-buf fs_nindir / ( fileblock'' indir-offset ) 268 indir-block swap la+ l@ ( fileblock'' indirblock ) 269 to indir-addr ( fileblock'' ) 270 \ load 2nd level indir block 271 indir-block ( fileblock'' indir-block ) 272 sb-buf dup fs_bsize l@ ( fileblock'' indir-block fs fs_bsize ) 273 swap indir-addr swap ( fileblock'' indir-block fs_bsize indiraddr fs ) 274 fsbtodb ( fileblock'' indir-block fs_bsize db ) 275 strategy ( fileblock'' nread ) 276 drop ( fileblock'' ) 277 sb-buf fs_nindir l@ mod indir-block swap la+ l@ exit 278 then 279 ." block-map: exceeded max file size" cr 280 abort 281; 282 283\ 284\ Read file into internal buffer and return pointer and len 285\ 286 2870 value cur-block \ allocated dynamically in ufs-open 2880 value cur-blocksize \ size of cur-block 289-1 value cur-blockno 2900 value cur-offset 291 292: buf-read-file ( fs -- len buf ) 293 cur-offset swap ( seekp fs ) 294 2dup blkoff ( seekp fs off ) 295 -rot 2dup lblkno ( off seekp fs block ) 296 swap 2dup cur-inode ( off seekp block fs block fs inop ) 297 swap dblksize ( off seekp block fs size ) 298 rot dup cur-blockno ( off seekp fs size block block cur ) 299 <> if ( off seekp fs size block ) 300 block-map ( off seekp fs size diskblock ) 301 dup 0= if ( off seekp fs size diskblock ) 302 over cur-block swap 0 fill ( off seekp fs size diskblock ) 303 boot-debug? if ." buf-read-file fell off end of file" cr then 304 else 305 2dup sb-buf fsbtodb cur-block -rot strategy ( off seekp fs size diskblock nread ) 306 rot 2dup <> if " buf-read-file: short read." cr abort then 307 then ( off seekp fs diskblock nread size ) 308 nip nip ( off seekp fs size ) 309 else ( off seekp fs size block block cur ) 310 2drop ( off seekp fs size ) 311 then 312\ dup cur-offset + to cur-offset \ Set up next xfer -- not done 313 nip nip swap - ( len ) 314 cur-block 315; 316 317\ 318\ Read inode into cur-inode -- uses cur-block 319\ 320 321: read-inode ( inode fs -- ) 322 twiddle ( inode fs -- inode fs ) 323 324 cur-block ( inode fs -- inode fs buffer ) 325 326 over ( inode fs buffer -- inode fs buffer fs ) 327 fs_bsize l@ ( inode fs buffer -- inode fs buffer size ) 328 329 2over ( inode fs buffer size -- inode fs buffer size inode fs ) 330 2over ( inode fs buffer size inode fs -- inode fs buffer size inode fs buffer size ) 331 2swap tuck ( inode fs buffer size inode fs buffer size -- inode fs buffer size buffer size fs inode fs ) 332 333 ino-to-fsba ( inode fs buffer size buffer size fs inode fs -- inode fs buffer size buffer size fs fsba ) 334 swap ( inode fs buffer size buffer size fs fsba -- inode fs buffer size buffer size fsba fs ) 335 fsbtodb ( inode fs buffer size buffer size fsba fs -- inode fs buffer size buffer size db ) 336 337 dup to cur-blockno ( inode fs buffer size buffer size dstart -- inode fs buffer size buffer size dstart ) 338 strategy ( inode fs buffer size buffer size dstart -- inode fs buffer size nread ) 339 <> if ." read-inode - residual" cr abort then 340 dup 2over ( inode fs buffer -- inode fs buffer buffer inode fs ) 341 ino-to-fsbo ( inode fs buffer -- inode fs buffer buffer fsbo ) 342 dinode_SIZEOF * + ( inode fs buffer buffer fsbo -- inode fs buffer dinop ) 343 cur-inode dinode_SIZEOF move ( inode fs buffer dinop -- inode fs buffer ) 344 \ clear out the old buffers 345 drop ( inode fs buffer -- inode fs ) 346 2drop 347; 348 349\ Identify inode type 350 351: is-dir? ( dinode -- true:false ) di_mode w@ ifmt and ifdir = ; 352: is-symlink? ( dinode -- true:false ) di_mode w@ ifmt and iflnk = ; 353 354 355 356\ 357\ Hunt for directory entry: 358\ 359\ repeat 360\ load a buffer 361\ while entries do 362\ if entry == name return 363\ next entry 364\ until no buffers 365\ 366 367: search-directory ( str len -- ino|0 ) 368 0 to cur-offset 369 begin cur-offset cur-inode di_size x@ < while ( str len ) 370 sb-buf buf-read-file ( str len len buf ) 371 over 0= if ." search-directory: buf-read-file zero len" cr abort then 372 swap dup cur-offset + to cur-offset ( str len buf len ) 373 2dup + nip ( str len buf bufend ) 374 swap 2swap rot ( bufend str len buf ) 375 begin dup 4 pick < while ( bufend str len buf ) 376 dup d_ino l@ 0<> if ( bufend str len buf ) 377 boot-debug? if dup dup d_name swap d_namlen c@ type cr then 378 2dup d_namlen c@ = if ( bufend str len buf ) 379 dup d_name 2over ( bufend str len buf dname str len ) 380 comp 0= if ( bufend str len buf ) 381 \ Found it -- return inode 382 d_ino l@ nip nip nip ( dino ) 383 boot-debug? if ." Found it" cr then 384 exit ( dino ) 385 then 386 then ( bufend str len buf ) 387 then ( bufend str len buf ) 388 dup d_reclen w@ + ( bufend str len nextbuf ) 389 repeat 390 drop rot drop ( str len ) 391 repeat 392 2drop 2drop 0 ( 0 ) 393; 394 395: ffs_oldcompat ( -- ) 396\ Make sure old ffs values in sb-buf are sane 397 sb-buf fs_npsect dup l@ sb-buf fs_nsect l@ max swap l! 398 sb-buf fs_interleave dup l@ 1 max swap l! 399 sb-buf fs_postblformat l@ fs_42postblfmt = if 400 8 sb-buf fs_nrpos l! 401 then 402 sb-buf fs_inodefmt l@ fs_44inodefmt < if 403 sb-buf fs_bsize l@ 404 dup ndaddr * 1- sb-buf fs_maxfilesize x! 405 niaddr 0 ?do 406 sb-buf fs_nindir l@ * dup ( sizebp sizebp -- ) 407 sb-buf fs_maxfilesize dup x@ ( sizebp sizebp *fs_maxfilesize fs_maxfilesize -- ) 408 rot ( sizebp *fs_maxfilesize fs_maxfilesize sizebp -- ) 409 + ( sizebp *fs_maxfilesize new_fs_maxfilesize -- ) 410 swap x! ( sizebp -- ) 411 loop drop ( -- ) 412 sb-buf dup fs_bmask l@ not swap fs_qbmask x! 413 sb-buf dup fs_fmask l@ not swap fs_qfmask x! 414 then 415; 416 417: read-super ( sector -- ) 4180 " seek" boot-ihandle $call-method 419 -1 = if 420 ." Seek failed" cr 421 abort 422 then 423 sb-buf sbsize " read" boot-ihandle $call-method 424 dup sbsize <> if 425 ." Read of superblock failed" cr 426 ." requested" space sbsize . 427 ." actual" space . cr 428 abort 429 else 430 drop 431 then 432; 433 434: ufs-open ( bootpath,len -- ) 435 boot-ihandle -1 = if 436 over cif-open dup 0= if ( boot-path len ihandle? ) 437 ." Could not open device" space type cr 438 abort 439 then ( boot-path len ihandle ) 440 to boot-ihandle \ Save ihandle to boot device 441 then 2drop 442 sboff read-super 443 sb-buf fs_magic l@ fs_magic_value <> if 444 64 dup to raid-offset 445 dev_bsize * sboff + read-super 446 sb-buf fs_magic l@ fs_magic_value <> if 447 ." Invalid superblock magic" cr 448 abort 449 then 450 then 451 sb-buf fs_bsize l@ dup maxbsize > if 452 ." Superblock bsize" space . ." too large" cr 453 abort 454 then 455 dup fs_SIZEOF < if 456 ." Superblock bsize < size of superblock" cr 457 abort 458 then 459 ffs_oldcompat ( fs_bsize -- fs_bsize ) 460 dup to cur-blocksize alloc-mem to cur-block \ Allocate cur-block 461 boot-debug? if ." ufs-open complete" cr then 462; 463 464: ufs-close ( -- ) 465 boot-ihandle dup -1 <> if 466 cif-close -1 to boot-ihandle 467 then 468 cur-block 0<> if 469 cur-block cur-blocksize free-mem 470 then 471; 472 473: boot-path ( -- boot-path ) 474 " bootpath" chosen-phandle get-package-property if 475 ." Could not find bootpath in /chosen" cr 476 abort 477 else 478 decode-string 2swap 2drop 479 then 480; 481 482: boot-args ( -- boot-args ) 483 " bootargs" chosen-phandle get-package-property if 484 ." Could not find bootargs in /chosen" cr 485 abort 486 else 487 decode-string 2swap 2drop 488 then 489; 490 4912000 buffer: boot-path-str 4922000 buffer: boot-path-tmp 493 494: split-path ( path len -- right len left len ) 495\ Split a string at the `/' 496 begin 497 dup -rot ( oldlen right len left ) 498 ascii / left-parse-string ( oldlen right len left len ) 499 dup 0<> if 4 roll drop exit then 500 2drop ( oldlen right len ) 501 rot over = ( right len diff ) 502 until 503; 504 505: find-file ( load-file len -- ) 506 rootino dup sb-buf read-inode ( load-file len -- load-file len ino ) 507 -rot ( load-file len ino -- pino load-file len ) 508 \ 509 \ For each path component 510 \ 511 begin split-path dup 0<> while ( pino right len left len -- ) 512 cur-inode is-dir? not if ." Inode not directory" cr abort then 513 boot-debug? if ." Looking for" space 2dup type space ." in directory..." cr then 514 search-directory ( pino right len left len -- pino right len ino|false ) 515 dup 0= if ." Bad path" cr abort then ( pino right len cino ) 516 sb-buf read-inode ( pino right len ) 517 cur-inode is-symlink? if \ Symlink -- follow the damn thing 518 \ Save path in boot-path-tmp 519 boot-path-tmp strmov ( pino new-right len ) 520 521 \ Now deal with symlink 522 cur-inode di_size x@ ( pino right len linklen ) 523 dup sb-buf fs_maxsymlinklen l@ ( pino right len linklen linklen maxlinklen ) 524 < if \ Now join the link to the path 525 cur-inode di_shortlink l@ ( pino right len linklen linkp ) 526 swap boot-path-str strmov ( pino right len new-linkp linklen ) 527 else \ Read file for symlink -- Ugh 528 \ Read link into boot-path-str 529 boot-path-str dup sb-buf fs_bsize l@ 530 0 block-map ( pino right len linklen boot-path-str bsize blockno ) 531 strategy drop swap ( pino right len boot-path-str linklen ) 532 then ( pino right len linkp linklen ) 533 \ Concatenate the two paths 534 strcat ( pino new-right newlen ) 535 swap dup c@ ascii / = if \ go to root inode? 536 rot drop rootino -rot ( rino len right ) 537 then 538 rot dup sb-buf read-inode ( len right pino ) 539 -rot swap ( pino right len ) 540 then ( pino right len ) 541 repeat 542 2drop drop 543; 544 545: read-file ( size addr -- ) 546 \ Read x bytes from a file to buffer 547 begin over 0> while 548 cur-offset cur-inode di_size x@ > if ." read-file EOF exceeded" cr abort then 549 sb-buf buf-read-file ( size addr len buf ) 550 over 2over drop swap ( size addr len buf addr len ) 551 move ( size addr len ) 552 dup cur-offset + to cur-offset ( size len newaddr ) 553 tuck + ( size len newaddr ) 554 -rot - swap ( newaddr newsize ) 555 repeat 556 2drop 557; 558 559\ 560\ According to the 1275 addendum for SPARC processors: 561\ Default load-base is 0x4000. At least 0x8.0000 or 562\ 512KB must be available at that address. 563\ 564\ The Fcode bootblock can take up up to 8KB (O.K., 7.5KB) 565\ so load programs at 0x4000 + 0x2000=> 0x6000 566\ 567 568h# 6000 constant loader-base 569 570\ 571\ Elf support -- find the load addr 572\ 573 574: is-elf? ( hdr -- res? ) h# 7f454c46 = ; 575 576\ 577\ Finally we finish it all off 578\ 579 580: load-file-signon ( load-file len boot-path len -- load-file len boot-path len ) 581 ." Loading file" space 2over type cr ." from device" space 2dup type cr 582; 583 584: load-file-print-size ( size -- size ) 585 ." Loading" space dup . space ." bytes of file..." cr 586; 587 588: load-file ( load-file len boot-path len -- load-base ) 589 boot-debug? if load-file-signon then 590 the-file file_SIZEOF 0 fill \ Clear out file structure 591 ufs-open ( load-file len ) 592 find-file ( ) 593 594 \ 595 \ Now we've found the file we should read it in in one big hunk 596 \ 597 598 cur-inode di_size x@ ( file-len ) 599 dup " to file-size" evaluate ( file-len ) 600 boot-debug? if load-file-print-size then 601 0 to cur-offset 602 loader-base ( buf-len addr ) 603 2dup read-file ( buf-len addr ) 604 ufs-close ( buf-len addr ) 605 dup is-elf? if ." load-file: not an elf executable" cr abort then 606 607 \ Luckily the prom should be able to handle ELF executables by itself 608 609 nip ( addr ) 610; 611 612: do-boot ( bootfile -- ) 613 ." NetBSD IEEE 1275 Bootblock" cr 614 boot-path load-file ( -- load-base ) 615 dup 0<> if " to load-base init-program" evaluate then 616; 617 618 619boot-args ascii V strchr 0<> swap drop if 620 true to boot-debug? 621then 622 623boot-args ascii D strchr 0= swap drop if 624 " /ofwboot" do-boot 625then exit 626 627 628