bootblk.fth revision 1.2
1\ $NetBSD: bootblk.fth,v 1.2 2001/06/13 10:46:02 wiz 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 128 129: strategy ( addr size start -- nread ) 130 bsize * 0 " seek" boot-ihandle $call-method 131 -1 = if 132 ." strategy: Seek failed" cr 133 abort 134 then 135 " read" boot-ihandle $call-method 136; 137 138\ 139\ Cylinder group macros 140\ 141 142: cgbase ( cg fs -- cgbase ) fs_fpg l@ * ; 143: cgstart ( cg fs -- cgstart ) 144 2dup fs_cgmask l@ not and ( cg fs stuff -- ) 145 over fs_cgoffset l@ * -rot ( stuffcg fs -- ) 146 cgbase + 147; 148: cgdmin ( cg fs -- 1st-data-block ) dup fs_dblkno l@ -rot cgstart + ; 149: cgimin ( cg fs -- inode-block ) dup fs_iblkno l@ -rot cgstart + ; 150: cgsblock ( cg fs -- super-block ) dup fs_sblkno l@ -rot cgstart + ; 151: cgstod ( cg fs -- cg-block ) dup fs_cblkno l@ -rot cgstart + ; 152 153\ 154\ Block and frag position macros 155\ 156 157: blkoff ( pos fs -- off ) fs_qbmask x@ and ; 158: fragoff ( pos fs -- off ) fs_qfmask x@ and ; 159: lblktosize ( blk fs -- off ) fs_bshift l@ << ; 160: lblkno ( pos fs -- off ) fs_bshift l@ >> ; 161: numfrags ( pos fs -- off ) fs_fshift l@ >> ; 162: blkroundup ( pos fs -- off ) dup fs_bmask l@ -rot fs_qbmask x@ + and ; 163: fragroundup ( pos fs -- off ) dup fs_fmask l@ -rot fs_qfmask x@ + and ; 164\ : fragroundup ( pos fs -- off ) tuck fs_qfmask x@ + swap fs_fmask l@ and ; 165: fragstoblks ( pos fs -- off ) fs_fragshift l@ >> ; 166: blkstofrags ( blk fs -- frag ) fs_fragshift l@ << ; 167: fragnum ( fsb fs -- off ) fs_frag l@ 1- and ; 168: blknum ( fsb fs -- off ) fs_frag l@ 1- not and ; 169: dblksize ( lbn dino fs -- size ) 170 -rot ( fs lbn dino ) 171 di_size x@ ( fs lbn di_size ) 172 -rot dup 1+ ( di_size fs lbn lbn+1 ) 173 2over fs_bshift l@ ( di_size fs lbn lbn+1 di_size b_shift ) 174 rot swap << >= ( di_size fs lbn res1 ) 175 swap ndaddr >= or if ( di_size fs ) 176 swap drop fs_bsize l@ exit ( size ) 177 then tuck blkoff swap fragroundup ( size ) 178; 179 180 181: ino-to-cg ( ino fs -- cg ) fs_ipg l@ / ; 182: ino-to-fsbo ( ino fs -- fsb0 ) fs_inopb l@ mod ; 183: ino-to-fsba ( ino fs -- ba ) \ Need to remove the stupid stack diags someday 184 2dup ( ino fs ino fs ) 185 ino-to-cg ( ino fs cg ) 186 over ( ino fs cg fs ) 187 cgimin ( ino fs inode-blk ) 188 -rot ( inode-blk ino fs ) 189 tuck ( inode-blk fs ino fs ) 190 fs_ipg l@ ( inode-blk fs ino ipg ) 191 mod ( inode-blk fs mod ) 192 swap ( inode-blk mod fs ) 193 dup ( inode-blk mod fs fs ) 194 fs_inopb l@ ( inode-blk mod fs inopb ) 195 rot ( inode-blk fs inopb mod ) 196 swap ( inode-blk fs mod inopb ) 197 / ( inode-blk fs div ) 198 swap ( inode-blk div fs ) 199 blkstofrags ( inode-blk frag ) 200 + 201; 202: fsbtodb ( fsb fs -- db ) fs_fsbtodb l@ << ; 203 204\ 205\ File stuff 206\ 207 208niaddr /w* constant narraysize 209 210struct 211 8 field >f_ihandle \ device handle 212 8 field >f_seekp \ seek pointer 213 8 field >f_fs \ pointer to super block 214 dinode_SIZEOF field >f_di \ copy of on-disk inode 215 8 field >f_buf \ buffer for data block 216 4 field >f_buf_size \ size of data block 217 4 field >f_buf_blkno \ block number of data block 218constant file_SIZEOF 219 220file_SIZEOF buffer: the-file 221sb-buf the-file >f_fs x! 222 223dinode_SIZEOF buffer: cur-inode 224h# 2000 buffer: indir-block 225-1 value indir-addr 226 227\ 228\ Translate a fileblock to a disk block 229\ 230\ We only allow single indirection 231\ 232 233: block-map ( fileblock -- diskblock ) 234 \ Direct block? 235 dup ndaddr < if ( fileblock ) 236 cur-inode di_db ( arr-indx arr-start ) 237 swap la+ l@ exit ( diskblock ) 238 then ( fileblock ) 239 ndaddr - ( fileblock' ) 240 \ Now we need to check the indirect block 241 dup sb-buf fs_nindir l@ < if ( fileblock' ) 242 cur-inode di_ib l@ dup ( fileblock' indir-block indir-block ) 243 indir-addr <> if ( fileblock' indir-block ) 244 to indir-addr ( fileblock' ) 245 indir-block ( fileblock' indir-block ) 246 sb-buf dup fs_bsize l@ ( fileblock' indir-block fs fs_bsize ) 247 swap indir-addr swap ( fileblock' indir-block fs_bsize indiraddr fs ) 248 fsbtodb ( fileblock' indir-block fs_bsize db ) 249 strategy ( fileblock' nread ) 250 then ( fileblock' nread|indir-block ) 251 drop \ Really should check return value 252 indir-block swap la+ l@ exit 253 then 254 dup sb-buf fs_nindir - ( fileblock'' ) 255 \ Now try 2nd level indirect block -- just read twice 256 dup sb-buf fs_nindir l@ dup * < if ( fileblock'' ) 257 cur-inode di_ib 1 la+ l@ ( fileblock'' indir2-block ) 258 to indir-addr ( fileblock'' ) 259 \ load 1st level indir block 260 indir-block ( fileblock'' indir-block ) 261 sb-buf dup fs_bsize l@ ( fileblock'' indir-block fs fs_bsize ) 262 swap indir-addr swap ( fileblock'' indir-block fs_bsize indiraddr fs ) 263 fsbtodb ( fileblock'' indir-block fs_bsize db ) 264 strategy ( fileblock'' nread ) 265 drop ( fileblock'' ) 266 dup sb-buf fs_nindir / ( fileblock'' indir-offset ) 267 indir-block swap la+ l@ ( fileblock'' indirblock ) 268 to indir-addr ( fileblock'' ) 269 \ load 2nd level indir block 270 indir-block ( fileblock'' indir-block ) 271 sb-buf dup fs_bsize l@ ( fileblock'' indir-block fs fs_bsize ) 272 swap indir-addr swap ( fileblock'' indir-block fs_bsize indiraddr fs ) 273 fsbtodb ( fileblock'' indir-block fs_bsize db ) 274 strategy ( fileblock'' nread ) 275 drop ( fileblock'' ) 276 sb-buf fs_nindir l@ mod indir-block swap la+ l@ exit 277 then 278 ." block-map: exceeded max file size" cr 279 abort 280; 281 282\ 283\ Read file into internal buffer and return pointer and len 284\ 285 2862000 buffer: cur-block \ Why do dynamic allocation? 287-1 value cur-blockno 2880 value cur-offset 289 290: buf-read-file ( fs -- len buf ) 291 cur-offset swap ( seekp fs ) 292 2dup blkoff ( seekp fs off ) 293 -rot 2dup lblkno ( off seekp fs block ) 294 swap 2dup cur-inode ( off seekp block fs block fs inop ) 295 swap dblksize ( off seekp block fs size ) 296 rot dup cur-blockno ( off seekp fs size block block cur ) 297 <> if ( off seekp fs size block ) 298 block-map ( off seekp fs size diskblock ) 299 dup 0= if ( off seekp fs size diskblock ) 300 over cur-block swap 0 fill ( off seekp fs size diskblock ) 301 boot-debug? if ." buf-read-file fell off end of file" cr then 302 else 303 2dup sb-buf fsbtodb cur-block -rot strategy ( off seekp fs size diskblock nread ) 304 rot 2dup <> if " buf-read-file: short read." cr abort then 305 then ( off seekp fs diskblock nread size ) 306 nip nip ( off seekp fs size ) 307 else ( off seekp fs size block block cur ) 308 2drop ( off seekp fs size ) 309 then 310\ dup cur-offset + to cur-offset \ Set up next xfer -- not done 311 nip nip swap - ( len ) 312 cur-block 313; 314 315\ 316\ Read inode into cur-inode -- uses cur-block 317\ 318 319: read-inode ( inode fs -- ) 320 twiddle ( inode fs -- inode fs ) 321 322 cur-block ( inode fs -- inode fs buffer ) 323 324 over ( inode fs buffer -- inode fs buffer fs ) 325 fs_bsize l@ ( inode fs buffer -- inode fs buffer size ) 326 327 2over ( inode fs buffer size -- inode fs buffer size inode fs ) 328 2over ( inode fs buffer size inode fs -- inode fs buffer size inode fs buffer size ) 329 2swap tuck ( inode fs buffer size inode fs buffer size -- inode fs buffer size buffer size fs inode fs ) 330 331 ino-to-fsba ( inode fs buffer size buffer size fs inode fs -- inode fs buffer size buffer size fs fsba ) 332 swap ( inode fs buffer size buffer size fs fsba -- inode fs buffer size buffer size fsba fs ) 333 fsbtodb ( inode fs buffer size buffer size fsba fs -- inode fs buffer size buffer size db ) 334 335 dup to cur-blockno ( inode fs buffer size buffer size dstart -- inode fs buffer size buffer size dstart ) 336 strategy ( inode fs buffer size buffer size dstart -- inode fs buffer size nread ) 337 <> if ." read-inode - residual" cr abort then 338 dup 2over ( inode fs buffer -- inode fs buffer buffer inode fs ) 339 ino-to-fsbo ( inode fs buffer -- inode fs buffer buffer fsbo ) 340 dinode_SIZEOF * + ( inode fs buffer buffer fsbo -- inode fs buffer dinop ) 341 cur-inode dinode_SIZEOF move ( inode fs buffer dinop -- inode fs buffer ) 342 \ clear out the old buffers 343 drop ( inode fs buffer -- inode fs ) 344 2drop 345; 346 347\ Identify inode type 348 349: is-dir? ( dinode -- true:false ) di_mode w@ ifmt and ifdir = ; 350: is-symlink? ( dinode -- true:false ) di_mode w@ ifmt and iflnk = ; 351 352 353 354\ 355\ Hunt for directory entry: 356\ 357\ repeat 358\ load a buffer 359\ while entries do 360\ if entry == name return 361\ next entry 362\ until no buffers 363\ 364 365: search-directory ( str len -- ino|0 ) 366 0 to cur-offset 367 begin cur-offset cur-inode di_size x@ < while ( str len ) 368 sb-buf buf-read-file ( str len len buf ) 369 over 0= if ." search-directory: buf-read-file zero len" cr abort then 370 swap dup cur-offset + to cur-offset ( str len buf len ) 371 2dup + nip ( str len buf bufend ) 372 swap 2swap rot ( bufend str len buf ) 373 begin dup 4 pick < while ( bufend str len buf ) 374 dup d_ino l@ 0<> if ( bufend str len buf ) 375 boot-debug? if dup dup d_name swap d_namlen c@ type cr then 376 2dup d_namlen c@ = if ( bufend str len buf ) 377 dup d_name 2over ( bufend str len buf dname str len ) 378 comp 0= if ( bufend str len buf ) 379 \ Found it -- return inode 380 d_ino l@ nip nip nip ( dino ) 381 boot-debug? if ." Found it" cr then 382 exit ( dino ) 383 then 384 then ( bufend str len buf ) 385 then ( bufend str len buf ) 386 dup d_reclen w@ + ( bufend str len nextbuf ) 387 repeat 388 drop rot drop ( str len ) 389 repeat 390 2drop 2drop 0 ( 0 ) 391; 392 393: ffs_oldcompat ( -- ) 394\ Make sure old ffs values in sb-buf are sane 395 sb-buf fs_npsect dup l@ sb-buf fs_nsect l@ max swap l! 396 sb-buf fs_interleave dup l@ 1 max swap l! 397 sb-buf fs_postblformat l@ fs_42postblfmt = if 398 8 sb-buf fs_nrpos l! 399 then 400 sb-buf fs_inodefmt l@ fs_44inodefmt < if 401 sb-buf fs_bsize l@ 402 dup ndaddr * 1- sb-buf fs_maxfilesize x! 403 niaddr 0 ?do 404 sb-buf fs_nindir l@ * dup ( sizebp sizebp -- ) 405 sb-buf fs_maxfilesize dup x@ ( sizebp sizebp *fs_maxfilesize fs_maxfilesize -- ) 406 rot ( sizebp *fs_maxfilesize fs_maxfilesize sizebp -- ) 407 + ( sizebp *fs_maxfilesize new_fs_maxfilesize -- ) swap x! ( sizebp -- ) 408 loop drop ( -- ) 409 sb-buf dup fs_bmask l@ not swap fs_qbmask x! 410 sb-buf dup fs_fmask l@ not swap fs_qfmask x! 411 then 412; 413 414: ufs-open ( bootpath,len -- ) 415 boot-ihandle -1 = if 416 over cif-open dup 0= if ( boot-path len ihandle? ) 417 ." Could not open device" space type cr 418 abort 419 then ( boot-path len ihandle ) 420 to boot-ihandle \ Save ihandle to boot device 421 then 2drop 422 sboff 0 " seek" boot-ihandle $call-method 423 -1 = if 424 ." Seek failed" cr 425 abort 426 then 427 sb-buf sbsize " read" boot-ihandle $call-method 428 dup sbsize <> if 429 ." Read of superblock failed" cr 430 ." requested" space sbsize . 431 ." actual" space . cr 432 abort 433 else 434 drop 435 then 436 sb-buf fs_magic l@ fs_magic_value <> if 437 ." Invalid superblock magic" cr 438 abort 439 then 440 sb-buf fs_bsize l@ dup maxbsize > if 441 ." Superblock bsize" space . ." too large" cr 442 abort 443 then 444 fs_SIZEOF < if 445 ." Superblock bsize < size of superblock" cr 446 abort 447 then 448 ffs_oldcompat 449 boot-debug? if ." ufs-open complete" cr then 450; 451 452: ufs-close ( -- ) 453 boot-ihandle dup -1 <> if 454 cif-close -1 to boot-ihandle 455 then 456; 457 458: boot-path ( -- boot-path ) 459 " bootpath" chosen-phandle get-package-property if 460 ." Could not find bootpath in /chosen" cr 461 abort 462 else 463 decode-string 2swap 2drop 464 then 465; 466 467: boot-args ( -- boot-args ) 468 " bootargs" chosen-phandle get-package-property if 469 ." Could not find bootargs in /chosen" cr 470 abort 471 else 472 decode-string 2swap 2drop 473 then 474; 475 4762000 buffer: boot-path-str 4772000 buffer: boot-path-tmp 478 479: split-path ( path len -- right len left len ) 480\ Split a string at the `/' 481 begin 482 dup -rot ( oldlen right len left ) 483 ascii / left-parse-string ( oldlen right len left len ) 484 dup 0<> if 4 roll drop exit then 485 2drop ( oldlen right len ) 486 rot over = ( right len diff ) 487 until 488; 489 490: find-file ( load-file len -- ) 491 rootino dup sb-buf read-inode ( load-file len -- load-file len ino ) 492 -rot ( load-file len ino -- pino load-file len ) 493 \ 494 \ For each path component 495 \ 496 begin split-path dup 0<> while ( pino right len left len -- ) 497 cur-inode is-dir? not if ." Inode not directory" cr abort then 498 boot-debug? if ." Looking for" space 2dup type space ." in directory..." cr then 499 search-directory ( pino right len left len -- pino right len ino|false ) 500 dup 0= if ." Bad path" cr abort then ( pino right len cino ) 501 sb-buf read-inode ( pino right len ) 502 cur-inode is-symlink? if \ Symlink -- follow the damn thing 503 \ Save path in boot-path-tmp 504 boot-path-tmp strmov ( pino new-right len ) 505 506 \ Now deal with symlink 507 cur-inode di_size x@ ( pino right len linklen ) 508 dup sb-buf fs_maxsymlinklen l@ ( pino right len linklen linklen maxlinklen ) 509 < if \ Now join the link to the path 510 cur-inode di_shortlink l@ ( pino right len linklen linkp ) 511 swap boot-path-str strmov ( pino right len new-linkp linklen ) 512 else \ Read file for symlink -- Ugh 513 \ Read link into boot-path-str 514 boot-path-str dup sb-buf fs_bsize l@ 515 0 block-map ( pino right len linklen boot-path-str bsize blockno ) 516 strategy drop swap ( pino right len boot-path-str linklen ) 517 then ( pino right len linkp linklen ) 518 \ Concatenate the two paths 519 strcat ( pino new-right newlen ) 520 swap dup c@ ascii / = if \ go to root inode? 521 rot drop rootino -rot ( rino len right ) 522 then 523 rot dup sb-buf read-inode ( len right pino ) 524 -rot swap ( pino right len ) 525 then ( pino right len ) 526 repeat 527 2drop drop 528; 529 530: read-file ( size addr -- ) 531 \ Read x bytes from a file to buffer 532 begin over 0> while 533 cur-offset cur-inode di_size x@ > if ." read-file EOF exceeded" cr abort then 534 sb-buf buf-read-file ( size addr len buf ) 535 over 2over drop swap ( size addr len buf addr len ) 536 move ( size addr len ) 537 dup cur-offset + to cur-offset ( size len newaddr ) 538 tuck + ( size len newaddr ) 539 -rot - swap ( newaddr newsize ) 540 repeat 541 2drop 542; 543 544h# 5000 constant loader-base 545 546\ 547\ Elf support -- find the load addr 548\ 549 550: is-elf? ( hdr -- res? ) h# 7f454c46 = ; 551 552\ 553\ Finally we finish it all off 554\ 555 556: load-file-signon ( load-file len boot-path len -- load-file len boot-path len ) 557 ." Loading file" space 2over type cr ." from device" space 2dup type cr 558; 559 560: load-file-print-size ( size -- size ) 561 ." Loading" space dup . space ." bytes of file..." cr 562; 563 564: load-file ( load-file len boot-path len -- load-base ) 565 boot-debug? if load-file-signon then 566 the-file file_SIZEOF 0 fill \ Clear out file structure 567 ufs-open ( load-file len ) 568 find-file ( ) 569 570 \ 571 \ Now we've found the file we should read it in in one big hunk 572 \ 573 574 cur-inode di_size x@ ( file-len ) 575 dup " to file-size" evaluate ( file-len ) 576 boot-debug? if load-file-print-size then 577 0 to cur-offset 578 loader-base ( buf-len addr ) 579 2dup read-file ( buf-len addr ) 580 ufs-close ( buf-len addr ) 581 dup is-elf? if ." load-file: not an elf executable" cr abort then 582 583 \ Luckily the prom should be able to handle ELF executables by itself 584 585 nip ( addr ) 586; 587 588: do-boot ( bootfile -- ) 589 ." NetBSD IEEE 1275 Bootblock" cr 590 boot-path load-file ( -- load-base ) 591 dup 0<> if " to load-base init-program" evaluate then 592; 593 594 595boot-args ascii V strchr 0<> swap drop if 596 true to boot-debug? 597then 598 599boot-args ascii D strchr 0= swap drop if 600 " /ofwboot" do-boot 601then exit 602 603 604