11.18Sandvar\ $NetBSD: bootblk.fth,v 1.18 2025/02/28 09:07:12 andvar Exp $ 21.1Smrg\ 31.1Smrg\ IEEE 1275 Open Firmware Boot Block 41.1Smrg\ 51.1Smrg\ Parses disklabel and UFS and loads the file called `ofwboot' 61.1Smrg\ 71.1Smrg\ 81.10Seeh\ Copyright (c) 1998-2010 Eduardo Horvath. 91.1Smrg\ All rights reserved. 101.1Smrg\ 111.1Smrg\ Redistribution and use in source and binary forms, with or without 121.1Smrg\ modification, are permitted provided that the following conditions 131.1Smrg\ are met: 141.1Smrg\ 1. Redistributions of source code must retain the above copyright 151.1Smrg\ notice, this list of conditions and the following disclaimer. 161.1Smrg\ 2. Redistributions in binary form must reproduce the above copyright 171.1Smrg\ notice, this list of conditions and the following disclaimer in the 181.1Smrg\ documentation and/or other materials provided with the distribution. 191.1Smrg\ 201.1Smrg\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 211.1Smrg\ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 221.1Smrg\ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 231.1Smrg\ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 241.1Smrg\ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 251.1Smrg\ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 261.1Smrg\ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 271.1Smrg\ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 281.1Smrg\ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 291.1Smrg\ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 301.1Smrg\ 311.1Smrg 321.1Smrgoffset16 331.1Smrghex 341.1Smrgheaders 351.1Smrg 361.1Smrgfalse value boot-debug? 371.1Smrg 381.11Seeh: KB d# 1024 * ; 391.11Seeh 401.1Smrg\ 411.1Smrg\ First some housekeeping: Open /chosen and set up vectors into 421.1Smrg\ client-services 431.1Smrg 441.1Smrg" /chosen" find-package 0= if ." Cannot find /chosen" 0 then 451.1Smrgconstant chosen-phandle 461.1Smrg 471.1Smrg" /openprom/client-services" find-package 0= if 481.1Smrg ." Cannot find client-services" cr abort 491.1Smrgthen constant cif-phandle 501.1Smrg 511.1Smrgdefer cif-claim ( align size virt -- base ) 521.1Smrgdefer cif-release ( size virt -- ) 531.1Smrgdefer cif-open ( cstr -- ihandle|0 ) 541.1Smrgdefer cif-close ( ihandle -- ) 551.1Smrgdefer cif-read ( len adr ihandle -- #read ) 561.1Smrgdefer cif-seek ( low high ihandle -- -1|0|1 ) 571.1Smrg\ defer cif-peer ( phandle -- phandle ) 581.1Smrg\ defer cif-getprop ( len adr cstr phandle -- ) 591.1Smrg 601.10Seeh: find-cif-method ( method len -- xf ) 611.1Smrg cif-phandle find-method drop 621.1Smrg; 631.1Smrg 641.10Seeh" claim" find-cif-method to cif-claim 651.10Seeh" open" find-cif-method to cif-open 661.10Seeh" close" find-cif-method to cif-close 671.10Seeh" read" find-cif-method to cif-read 681.10Seeh" seek" find-cif-method to cif-seek 691.1Smrg 701.1Smrg: twiddle ( -- ) ." ." ; \ Need to do this right. Just spit out periods for now. 711.1Smrg 721.1Smrg\ 731.1Smrg\ Support routines 741.1Smrg\ 751.1Smrg 761.10Seeh\ 64-bit math support 771.10Seeh 781.10Seehhere h# ffff over l! <w@ constant little-endian? 791.10Seeh: ul>d ( l -- d.lo d.hi ) 0 ; 801.10Seeh: l>d ( l -- d.lo d.hi ) dup 0< if -1 else 0 then ; 811.10Seeh: d>l ( d.lo d.hi -- l ) drop ; 821.10Seeh: d@ ( addr -- d.lo d.hi ) dup l@ swap la1+ l@ little-endian? invert if swap then ; 831.10Seeh: d! ( d.lo d.hi addr -- ) 841.10Seeh little-endian? invert if -rot swap rot then tuck la1+ l! l! ; 851.10Seeh: d-and ( d1 d2 -- d1-and-d2 ) rot and -rot and swap ; 861.10Seeh: d*u ( d1 u -- d2 ) tuck um* drop -rot um* rot + ; 871.10Seeh: d<< ( d1 n -- d1<<n ) \ Hope this works 881.12Seeh ?dup if \ Shifting by 0 doesn't appear to work properly. 891.12Seeh tuck << ( d.lo n d.hi' ) 901.12Seeh -rot 2dup << ( d.hi' d.lo n d.lo' ) 911.12Seeh -rot d# 32 swap - >> ( d.hi' d.lo' lo.hi ) 921.12Seeh rot + 931.12Seeh then 941.10Seeh; 951.10Seeh: d>> ( d1 n -- d1>>n ) \ Hope this works 961.12Seeh ?dup if \ Shifting by 0 doesn't appear to work properly. 971.12Seeh rot over >> -rot ( d.lo' d.hi n ) 981.12Seeh 2dup >> -rot ( d.lo' d.hi' d.hi n ) 991.12Seeh d# 32 swap - << rot + swap 1001.12Seeh then 1011.10Seeh; 1021.10Seeh: d> ( d1 d2 -- d1>d2? ) 1031.10Seeh rot swap 2dup = if 1041.10Seeh 2drop > exit 1051.10Seeh then 1061.10Seeh > nip nip 1071.10Seeh; 1081.10Seeh: d>= ( d1 d2 -- d1>=d2? ) 1091.10Seeh rot swap 2dup = if 1101.10Seeh 2drop >= exit 1111.10Seeh then 1121.10Seeh >= nip nip 1131.10Seeh; 1141.10Seeh: d< ( d1 d2 -- d1<d2? ) d>= invert ; 1151.10Seeh: d= ( d1 d2 -- d1=d2? ) rot = -rot = and ; 1161.10Seeh: d<> ( d1 d2 -- d1<>d2? ) d= invert ; 1171.10Seeh 1181.10Seeh 1191.10Seeh\ String support 1201.10Seeh 1211.1Smrg: strcmp ( s1 l1 s2 l2 -- true:false ) 1221.10Seeh rot tuck <> if 3drop false exit then 1231.1Smrg comp 0= 1241.1Smrg; 1251.1Smrg 1261.1Smrg\ Move string into buffer 1271.1Smrg 1281.1Smrg: strmov ( s1 l1 d -- d l1 ) 1291.1Smrg dup 2over swap -rot ( s1 l1 d s1 d l1 ) 1301.1Smrg move ( s1 l1 d ) 1311.1Smrg rot drop swap 1321.1Smrg; 1331.1Smrg 1341.1Smrg\ Move s1 on the end of s2 and return the result 1351.1Smrg 1361.1Smrg: strcat ( s1 l1 s2 l2 -- d tot ) 1371.1Smrg 2over swap ( s1 l1 s2 l2 l1 s1 ) 1381.1Smrg 2over + rot ( s1 l1 s2 l2 s1 d l1 ) 1391.1Smrg move rot + ( s1 s2 len ) 1401.1Smrg rot drop ( s2 len ) 1411.1Smrg; 1421.1Smrg 1431.1Smrg: strchr ( s1 l1 c -- s2 l2 ) 1441.1Smrg begin 1451.1Smrg dup 2over 0= if ( s1 l1 c c s1 ) 1461.1Smrg 2drop drop exit then 1471.1Smrg c@ = if ( s1 l1 c ) 1481.1Smrg drop exit then 1491.1Smrg -rot /c - swap ca1+ ( c l2 s2 ) 1501.1Smrg swap rot 1511.1Smrg again 1521.1Smrg; 1531.1Smrg 1541.1Smrg 1551.1Smrg: cstr ( ptr -- str len ) 1561.1Smrg dup 1571.1Smrg begin dup c@ 0<> while + repeat 1581.1Smrg over - 1591.1Smrg; 1601.1Smrg 1611.1Smrg\ 1621.10Seeh\ BSD UFS parameters 1631.1Smrg\ 1641.1Smrg 1651.10Seehfload ffs.fth.h 1661.10Seehfload lfs.fth.h 1671.1Smrg 1681.1Smrgsbsize buffer: sb-buf 1691.1Smrg-1 value boot-ihandle 1701.1Smrgdev_bsize value bsize 1711.3Seeh0 value raid-offset \ Offset if it's a raid-frame partition 1721.1Smrg 1731.10Seeh: strategy ( addr size db.lo db.hi -- nread ) 1741.10Seeh raid-offset l>d d+ ( addr size db.lo' db.hi' ) 1751.10Seeh bsize d*u ( addr size sector.lo sector.hi ) 1761.10Seeh " seek" boot-ihandle $call-method -1 = if 1771.10Seeh ." strategy: Seek failed" cr 1781.10Seeh abort 1791.10Seeh then ( addr size ) 1801.10Seeh " read" boot-ihandle $call-method 1811.10Seeh; 1821.10Seeh 1831.10Seeh 1841.10Seeh\ 1851.10Seeh\ Multi-FS support 1861.10Seeh\ 1871.10Seeh\ XXX Maybe the different filesystems should be segregated into separate files 1881.10Seeh\ XXX that are individually fload-ed. 1891.10Seeh\ 1901.10Seeh 1911.10Seehdefer fs-size 1921.10Seehdefer di-size 1931.10Seehdefer di-mode 1941.10Seehdefer /dino 1951.10Seehdefer cgstart 1961.10Seehdefer di-db@ 1971.10Seehdefer di-ib@ 1981.10Seehdefer ib-ib@ 1991.10Seehdefer fs-bsize 2001.10Seehdefer fsbtodb 2011.10Seehdefer blksize 2021.10Seehdefer lblkno 2031.10Seehdefer blkoff 2041.10Seehdefer read-inode 2051.10Seeh\ LFS ifile 2061.10Seehdefer /ifile 2071.10Seehdefer if_daddr 2081.10Seeh 2091.10Seeh\ 2101.10Seeh\ FFS Cylinder group macros 2111.10Seeh\ 2121.10Seeh 2131.10Seeh: cgdmin ( cg fs -- d-1st-data-block ) dup fs_dblkno l@ l>d 2swap cgstart d+ ; 2141.10Seeh: cgimin ( cg fs -- d-inode-block ) dup fs_iblkno l@ l>d 2swap cgstart d+ ; 2151.10Seeh: cgsblock ( cg fs -- d-super-block ) dup fs_sblkno l@ l>d 2swap cgstart d+ ; 2161.10Seeh: cgstod ( cg fs -- d-cg-block ) dup fs_cblkno l@ l>d 2swap cgstart d+ ; 2171.10Seeh 2181.10Seeh\ 2191.10Seeh\ FFS Block and frag position macros 2201.10Seeh\ 2211.10Seeh 2221.10Seeh: ffs-blkoff ( pos.lo pos.hi fs -- off.lo off.hi ) fs_qbmask d@ d-and ; 2231.10Seeh\ : ffs-fragoff ( pos.lo pos.hi fs -- off.lo off.hi ) fs_qfmask d@ d-and ; 2241.10Seeh\ : ffs-lblktosize ( blk fs -- off.lo off.hi ) 0 fs_bshift l@ d<< ; 2251.10Seeh: ffs-lblkno ( pos.lo pos.hi fs -- off.lo off.hi ) fs_bshift l@ d>> ; 2261.10Seeh: ffs-numfrags ( pos.lo pos.hi fs -- off.lo off.hi ) fs_fshift l@ d>> ; 2271.10Seeh: ffs-blkroundup ( pos.lo pos.hi fs -- off.lo off.hi ) 2281.10Seeh >r r@ fs_qbmask d@ d+ r> fs_bmask l@ l>d d-and 2291.10Seeh; 2301.10Seeh: ffs-fragroundup ( pos.lo pos.hi fs -- off.lo off.hi ) 2311.10Seeh >r r@ fs_qfmask d@ d+ r> fs_fmask l@ l>d d-and 2321.10Seeh; 2331.10Seeh: ffs-fragstoblks ( pos.lo pos.hi fs -- off.lo off.hi ) fs_fragshift l@ d>> ; 2341.10Seeh: ffs-blkstofrags ( blk fs -- frag ) fs_fragshift l@ << ; 2351.10Seeh\ : ffs-fragnum ( fsb fs -- off ) fs_frag l@ 1- and ; 2361.10Seeh\ : ffs-blknum ( fsb fs -- off ) fs_frag l@ 1- not and ; 2371.10Seeh: ffs-dblksize ( lbn.lo lbn.hi inodep fs -- size ) 2381.10Seeh >r -rot 2dup ndaddr l>d d> ( inop d-lbn >ndaddr? ) 2391.10Seeh -rot 1 0 d+ ( inop >ndaddr? d-lbn+1 ) 2401.10Seeh r@ fs_bshift l@ d<< ( inop >ndaddr? d-lbn+1<<bshift ) 2411.10Seeh 2swap >r di-size d@ ( d-lbn+1<<bshift d-size ) 2421.10Seeh 2swap 2over d< r> or if ( d-size ) 2431.10Seeh 2drop r> fs-bsize l@ exit 2441.10Seeh then 2451.10Seeh r@ ffs-blkoff ( size.lo size.hi ) 2461.10Seeh r> ffs-fragroundup d>l ( size ) 2471.10Seeh; 2481.10Seeh 2491.10Seeh: ino-to-cg ( ino fs -- cg ) fs_ipg l@ / ; 2501.10Seeh: ino-to-fsbo ( ino fs -- fsb0 ) fs_inopb l@ mod ; 2511.10Seeh: ino-to-fsba ( ino fs -- ba.lo ba.hi ) \ Need to remove the stupid stack diags someday 2521.10Seeh 2dup ( ino fs ino fs ) 2531.10Seeh ino-to-cg ( ino fs cg ) 2541.10Seeh over ( ino fs cg fs ) 2551.10Seeh cgimin ( ino fs inode-blk.lo inode-blk.hi ) 2561.10Seeh 2swap ( d-inode-blk ino fs ) 2571.10Seeh tuck ( d-inode-blk fs ino fs ) 2581.10Seeh fs_ipg l@ ( d-inode-blk fs ino ipg ) 2591.10Seeh mod ( d-inode-blk fs mod ) 2601.10Seeh swap ( d-inode-blk mod fs ) 2611.10Seeh dup ( d-inode-blk mod fs fs ) 2621.10Seeh fs_inopb l@ ( d-inode-blk mod fs inopb ) 2631.10Seeh rot ( d-inode-blk fs inopb mod ) 2641.10Seeh swap ( d-inode-blk fs mod inopb ) 2651.10Seeh / ( d-inode-blk fs div ) 2661.10Seeh swap ( d-inode-blk div fs ) 2671.10Seeh ffs-blkstofrags ( d-inode-blk frag ) 2681.10Seeh 0 d+ 2691.10Seeh; 2701.10Seeh: ffs-fsbtodb ( fsb.lo fsb.hi fs -- db.lo db.hi ) 2711.10Seeh fs_fsbtodb l@ d<< 2721.10Seeh; 2731.10Seeh 2741.10Seeh 2751.10Seeh\ 2761.10Seeh\ LFS suff 2771.10Seeh\ 2781.10Seeh: lfs-blkoff ( pos.lo pos.hi fs -- off.lo off.hi ) lfs_bmask d@ d-and ; 2791.10Seeh\ : lfs-fragoff ( pos.lo pos.hi fs -- off.lo off.hi ) lfs_ffmask d@ d-and ; 2801.10Seeh\ : lfs-lblktosize ( blk fs -- off.lo off.hi ) 0 lfs_bshift l@ d<< ; 2811.10Seeh: lfs-lblkno ( pos.lo pos.hi fs -- off.lo off.hi ) lfs_bshift l@ d>> ; 2821.10Seeh: lfs-numfrags ( pos.lo pos.hi fs -- off.lo off.hi ) lfs_ffshift l@ d>> ; 2831.10Seeh: lfs-roundup ( pos.lo pos.hi mask.lo mask.hi ) 2841.10Seeh 2swap 2over d+ 2swap ( d-pos* d-mask ) 2851.10Seeh invert swap invert swap d-and 2861.10Seeh; 2871.10Seeh: lfs-blkroundup ( pos.lo pos.hi fs -- off.lo off.hi ) lfs_bmask d@ lfs-roundup ; 2881.10Seeh: lfs-fragroundup ( pos.lo pos.hi fs -- off.lo off.hi ) lfs_ffmask d@ lfs-roundup ; 2891.10Seeh: lfs-fragstoblks ( pos.lo pos.hi fs -- off.lo off.hi ) lfs_fbshift l@ d>> ; 2901.10Seeh: lfs-dblksize ( lbn.lo lbn.hi inodep fs -- size ) 2911.10Seeh >r -rot 2dup ndaddr l>d d> ( inop d-lbn >ndaddr? ) 2921.10Seeh -rot 1 0 d+ ( inop >ndaddr? d-lbn+1 ) 2931.10Seeh r@ fs_bshift l@ d<< ( inop >ndaddr? d-lbn+1<<bshift ) 2941.10Seeh 2swap >r di-size d@ ( d-lbn+1<<bshift d-size ) 2951.10Seeh 2swap 2over d< r> or if ( d-size ) 2961.10Seeh 2drop r> fs-bsize l@ exit 2971.1Smrg then 2981.10Seeh r@ lfs-blkoff ( size.lo size.hi ) 2991.10Seeh r> lfs-fragroundup d>l ( size ) 3001.10Seeh; 3011.10Seeh: lfs-fsbtodb ( fsb.lo fsb.hi fs -- db.lo db.hi ) 3021.10Seeh lfs_fsbtodb l@ d<< 3031.1Smrg; 3041.1Smrg 3051.10Seeh\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 3061.1Smrg\ 3071.10Seeh\ The rest of the multi-filesystem stuff 3081.1Smrg\ 3091.10Seeh\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 3101.1Smrg 3111.10Seeh\ 3121.10Seeh\ FFS v1 3131.10Seeh\ 3141.10Seeh: di-db-v1@ ( indx dinode -- db.lo db.hi ) di1_db swap la+ l@ l>d ; 3151.10Seeh: di-ib-v1@ ( indx dinode -- db.lo db.hi ) di1_ib swap la+ l@ l>d ; 3161.10Seeh: ib-ib-v1@ ( indx iblk -- db.lo db.hi ) swap la+ l@ l>d ; 3171.10Seeh 3181.10Seeh: cgbase ( cg fs -- daddr.lo daddr.hi ) fs_fpg l@ um* ; 3191.10Seeh: cgstart-ufs1 ( cg fs -- cgstart ) 3201.10Seeh 2dup fs_old_cgmask l@ invert and ( cg fs stuff ) 3211.10Seeh over fs_old_cgoffset l@ um* ( cg fs off.lo off.hi ) 3221.10Seeh 2swap cgbase d+ ( off.lo off.hi ) 3231.1Smrg; 3241.1Smrg 3251.1Smrg\ 3261.10Seeh\ FFS v2 3271.1Smrg\ 3281.1Smrg 3291.10Seeh: di-db-v2@ ( indx dinode -- db.lo db.hi ) di2_db swap 2* la+ d@ ; 3301.10Seeh: di-ib-v2@ ( indx dinode -- db.lo db.hi ) di2_ib swap 2* la+ d@ ; 3311.10Seeh: ib-ib-v2@ ( indx iblk -- db.lo db.hi ) 2* la+ d@ ; 3321.1Smrg 3331.10Seeh\ 3341.10Seeh\ LFS v1 3351.10Seeh\ 3361.1Smrg 3371.1Smrg 3381.1Smrg\ 3391.1Smrg\ File stuff 3401.1Smrg\ 3411.1Smrg 3421.1Smrgniaddr /w* constant narraysize 3431.1Smrg 3441.16Sandvar\ Assume UFS2 dinodes are always bigger than UFS1 3451.10Seehufs2_dinode_SIZEOF buffer: cur-inode 3461.13Seeh0 value indir-block 3471.10Seehcreate indir-addr -1 , -1 , 3481.1Smrg 3491.1Smrg\ 3501.1Smrg\ Translate a fileblock to a disk block 3511.1Smrg\ 3521.10Seeh\ We don't do triple indirect blocks. 3531.1Smrg\ 3541.1Smrg 3551.10Seeh\ Get the disk address from a single indirect block 3561.10Seeh: ib@ ( indx indir.lo indir.hi -- db.lo db.hi ) 3571.10Seeh 2dup indir-addr d@ d<> if ( indx indir.hi indir.lo ) 3581.10Seeh indir-addr d! ( indx ) 3591.10Seeh indir-block ( indx indir-block ) 3601.10Seeh sb-buf fs-bsize l@ ( indx indir-block fs fs-bsize ) 3611.10Seeh indir-addr d@ sb-buf ( indx indir-block fs-bsize indiraddr fs ) 3621.10Seeh fsbtodb ( indx indir-block fs-bsize db.lo db.hi ) 3631.10Seeh strategy 0 ( indx nread 0 ) \ Really should check return value 3641.10Seeh then 3651.10Seeh 2drop ( indx ) 3661.10Seeh indir-block ib-ib@ 3671.10Seeh; 3681.10Seeh 3691.10Seeh 3701.10Seeh: block-map ( fileblock -- diskblock.lo diskblock.hi ) 3711.10Seeh \ Direct block? 3721.10Seeh dup ndaddr < if ( fileblock ) 3731.10Seeh cur-inode di-db@ exit ( diskblock.lo diskblock.hi ) 3741.10Seeh then ( fileblock ) 3751.10Seeh ndaddr - ( fileblock' ) 3761.10Seeh \ Now we need to check the indirect block 3771.10Seeh dup sb-buf fs_nindir l@ < if ( fileblock' ) 3781.10Seeh 0 cur-inode di-ib@ ( fileblock' indir.lo indir.hi ) 3791.10Seeh ib@ exit ( db.lo db.hi ) 3801.1Smrg then 3811.1Smrg dup sb-buf fs_nindir - ( fileblock'' ) 3821.1Smrg \ Now try 2nd level indirect block -- just read twice 3831.10Seeh dup sb-buf fs_nindir l@ dup * >= if ( fileblock'' ) 3841.10Seeh ." block-map: exceeded max file size" cr 3851.10Seeh abort 3861.1Smrg then 3871.10Seeh 3881.10Seeh 1 cur-inode di-ib@ ( fileblock'' ib.lo ib.hi ) 3891.10Seeh 3901.10Seeh \ Get 1st indirect block and find the 2nd indirect block 3911.10Seeh rot dup sb-buf fs_nindir u/mod ( ib2.lo ib2.hi indx2 indx1 ) 3921.10Seeh 2swap ib@ ( indx2 ib2.lo ib2.hi ) 3931.10Seeh 3941.10Seeh \ Get 2nd indirect block and find our diskblock 3951.10Seeh ib@ ( db.lo db.hi ) 3961.1Smrg; 3971.1Smrg 3981.1Smrg\ 3991.1Smrg\ Read file into internal buffer and return pointer and len 4001.1Smrg\ 4011.1Smrg 4021.4Seeh0 value cur-block \ allocated dynamically in ufs-open 4031.10Seeh0 value cur-blocksize \ size allocated to cur-block 4041.10Seehcreate cur-blockno -1 l, -1 l, \ Current disk block. 4051.10Seeh-1 value file-blockno \ Current file block no. 4061.10Seeh0 value file-offset \ Current file offset, max 4GB. 4071.10Seeh 4081.10Seeh: buf-read-file ( fs -- buf len ) 4091.10Seeh >r file-offset ( seek ) 4101.10Seeh dup l>d r@ lblkno drop ( seek blk ) 4111.10Seeh dup l>d cur-inode r@ blksize ( seek blk blksize ) 4121.10Seeh over file-blockno <> if ( seek blk blksize ) 4131.10Seeh over to file-blockno 4141.10Seeh swap block-map ( seek blksize fsblk.lo fsblk.hi ) 4151.10Seeh 2dup or 0= if ( seek blksize fsblk.lo fsblk.hi ) 4161.10Seeh \ Clear out curblock XXX Why? Idunno. 4171.10Seeh 2drop dup 4181.10Seeh cur-block swap erase ( seek blksize ) 4191.10Seeh boot-debug? if ." buf-read-file reading block 0" cr then 4201.10Seeh -1 l>d \ Invalid disk block 4211.10Seeh else 4221.10Seeh \ Call strategy to load the correct block. 4231.10Seeh r@ fsbtodb ( seek blksize dblk.lo dblk.hi ) 4241.10Seeh rot >r cur-block r@ 2over ( seek addr size db.lo db.hi ) 4251.10Seeh strategy r@ <> if ." buf-read-file: short read." cr abort then 4261.10Seeh r> -rot ( seek size db.lo db.hi ) 4271.10Seeh then 4281.10Seeh \ Save the new current disk block number 4291.10Seeh cur-blockno d! ( seek size ) 4301.10Seeh else 4311.10Seeh nip ( seek size ) 4321.10Seeh then 4331.10Seeh \ Now figure out how much we have in the buffer. 4341.10Seeh swap l>d r> blkoff ( size off.lo off.hi ) 4351.10Seeh d>l cur-block over + ( size off buf ) 4361.10Seeh -rot - ( buf siz ) 4371.1Smrg; 4381.1Smrg 4391.1Smrg\ 4401.1Smrg\ Read inode into cur-inode -- uses cur-block 4411.1Smrg\ 4421.1Smrg 4431.10Seeh: read-inode-ffs ( inode fs -- ) 4441.10Seeh twiddle 4451.10Seeh 4461.10Seeh >r dup r@ ino-to-fsba ( ino fsblk.lo fsblck.hi ) 4471.10Seeh r@ fsbtodb ( ino dblk.lo dblk.hi ) 4481.10Seeh 2dup cur-blockno d@ d<> if ( ino dblk.lo dblk.hi ) 4491.10Seeh \ We need to read the block 4501.10Seeh cur-block r@ fs-bsize l@ ( ino dblk.lo dblk.hi addr size ) 4511.10Seeh >r r@ 2over strategy r> <> if ( ino dblk.lo dblk.hi ) 4521.10Seeh ." read-inode - residual" cr abort 4531.10Seeh then 4541.10Seeh 2dup cur-blockno d! ( ino dblk.lo dblk.hi ) 4551.10Seeh then 2drop ( ino ) 4561.1Smrg 4571.10Seeh r> ino-to-fsbo /dino * ( off ) 4581.10Seeh cur-block + cur-inode /dino move ( ) 4591.10Seeh; 4601.10Seeh 4611.10Seeh: find-inode-sector ( ino fs -- d-dblkno true | false ) 4621.10Seeh >r r@ lfs_ifile l@ r@ read-inode ( ino ) 4631.10Seeh 4641.10Seeh r@ lfs_ifpb l@ u/mod ( rem q ) 4651.10Seeh 4661.10Seeh r@ lfs_cleansz l@ + 4671.10Seeh r@ lfs_segtabsz l@ + ( rem blkno ) 4681.1Smrg 4691.10Seeh r@ fs-bsize l@ um* rot /ifile um* d+ ( dseekp ) 4701.1Smrg 4711.10Seeh drop to file-offset r@ buf-read-file ( buf len ) 4721.10Seeh 4731.10Seeh /ifile < if r> 2drop false exit then ( buf ) 4741.10Seeh 4751.10Seeh if_daddr l@ l>d r> fsbtodb ( daddr ) 4761.10Seeh 2dup lfs_unused_daddr l>d d= if 2drop false then 4771.10Seeh true 4781.10Seeh; 4791.10Seeh 4801.10Seeh: read-inode-lfs ( inode fs -- ) 4811.10Seeh twiddle 4821.10Seeh 4831.10Seeh >r dup r@ lfs_ifile l@ = if ( ino r: fs ) 4841.10Seeh r@ lfs_idaddr l@ l>d ( ino d-idaddr ) 4851.10Seeh r@ fsbtodb ( ino d-db ) 4861.10Seeh else 4871.10Seeh dup r@ find-inode-sector 0= abort" Could not find inode sector!" 4881.10Seeh then ( ino d-db ) 4891.10Seeh 4901.10Seeh 2dup cur-blockno d@ d<> if ( ino dblk.lo dblk.hi ) 4911.10Seeh \ We need to read the block 4921.10Seeh cur-block r@ fs-bsize l@ ( ino dblk.lo dblk.hi addr size ) 4931.10Seeh >r r@ 2over strategy r> <> if ( ino dblk.lo dblk.hi ) 4941.10Seeh ." read-inode - residual" cr abort 4951.10Seeh then 4961.10Seeh 2dup cur-blockno d! ( ino dblk.lo dblk.hi ) 4971.10Seeh then 2drop ( ino ) 4981.10Seeh 4991.10Seeh r@ lfs_inopb l@ ( ino cnt ) 5001.10Seeh swap cur-block begin ( cnt ino p ) 5011.10Seeh tuck di_inumber l@ over <> ( cnt p ino !found? ) 5021.10Seeh while ( cnt p ino ) 5031.10Seeh rot 1- ?dup 0= abort" Could not find inode!" 5041.10Seeh rot /dino + swap -rot ( cnt ino p ) 5051.10Seeh repeat swap ( cnt ino p ) 5061.10Seeh 5071.10Seeh cur-inode /dino move ( cnt ino ) 5081.10Seeh 5091.10Seeh r> 3drop 5101.1Smrg; 5111.1Smrg 5121.1Smrg\ Identify inode type 5131.1Smrg 5141.10Seeh: is-dir? ( ufs1_dinode -- is-dir? ) di-mode w@ ifmt and ifdir = ; 5151.10Seeh: is-symlink? ( ufs1_dinode -- is-symlink? ) di-mode w@ ifmt and iflnk = ; 5161.10Seeh 5171.10Seeh\ 5181.10Seeh\ Multi-FS initialiation. 5191.10Seeh\ 5201.10Seeh\ It's way down here so all the fs-specific routines have already been defined. 5211.10Seeh\ 5221.10Seeh 5231.10Seeh: init-ffs-common ( -- ) 5241.10Seeh ' fs_SIZEOF to fs-size 5251.10Seeh ' fs_bsize to fs-bsize 5261.10Seeh ' ffs-dblksize to blksize 5271.10Seeh ' read-inode-ffs to read-inode 5281.10Seeh ' ffs-fsbtodb to fsbtodb 5291.10Seeh ' ffs-lblkno to lblkno 5301.10Seeh ' ffs-blkoff to blkoff 5311.10Seeh; 5321.10Seeh 5331.10Seeh 5341.10Seeh: ffs-oldcompat ( -- ) 5351.10Seeh \ Make sure old ffs values in sb-buf are sane 5361.10Seeh sb-buf fs_old_npsect dup l@ sb-buf fs_old_nsect l@ max swap l! 5371.10Seeh sb-buf fs_old_interleave dup l@ 1 max swap l! 5381.10Seeh sb-buf fs_old_postblformat l@ fs_42postblfmt = if 5391.10Seeh 8 sb-buf fs_old_nrpos l! 5401.10Seeh then 5411.10Seeh sb-buf fs_old_inodefmt l@ fs_44inodefmt < if 5421.10Seeh sb-buf fs-bsize l@ 5431.10Seeh dup ndaddr um* 1 d- sb-buf fs_maxfilesize d! 5441.10Seeh niaddr 0 ?do 5451.10Seeh sb-buf fs_nindir l@ * dup ( sizebp sizebp ) 5461.10Seeh sb-buf fs_maxfilesize dup d@ ( sizebp sizebp *mxfs mxfs.lo mxfs.hi ) 5471.10Seeh 2over drop l>d d+ 2swap d! ( sizebp ) 5481.10Seeh loop drop ( ) 5491.10Seeh sb-buf dup fs_bmask l@ invert l>d rot fs_qbmask d! 5501.10Seeh sb-buf dup fs_fmask l@ invert l>d rot fs_qfmask d! 5511.10Seeh then 5521.10Seeh; 5531.10Seeh 5541.10Seeh 5551.10Seeh: init-ffs-v1 ( -- ) 5561.12Seeh boot-debug? if ." FFS v1" cr then 5571.10Seeh init-ffs-common 5581.10Seeh ' di1_size to di-size 5591.10Seeh ' di1_mode to di-mode 5601.10Seeh ' ufs1_dinode_SIZEOF to /dino 5611.10Seeh ' cgstart-ufs1 to cgstart 5621.10Seeh ' di-db-v1@ to di-db@ 5631.10Seeh ' di-ib-v1@ to di-ib@ 5641.10Seeh ' ib-ib-v1@ to ib-ib@ 5651.10Seeh ffs-oldcompat 5661.10Seeh; 5671.10Seeh 5681.10Seeh: init-ffs-v2 ( -- ) 5691.12Seeh boot-debug? if ." FFS v2" cr then 5701.10Seeh init-ffs-common 5711.10Seeh ' di2_size to di-size 5721.10Seeh ' di2_mode to di-mode 5731.10Seeh ' ufs2_dinode_SIZEOF to /dino 5741.10Seeh ' cgbase to cgstart 5751.10Seeh ' di-db-v2@ to di-db@ 5761.10Seeh ' di-ib-v2@ to di-ib@ 5771.10Seeh ' ib-ib-v2@ to ib-ib@ 5781.10Seeh; 5791.10Seeh 5801.10Seeh: init-lfs-common ( -- ) 5811.10Seeh ' dlfs_SIZEOF to fs-size 5821.10Seeh ' di1_size to di-size 5831.10Seeh ' di1_mode to di-mode 5841.15Sdholland ' lfs32_dinode_SIZEOF to /dino 5851.10Seeh ' cgbase to cgstart 5861.10Seeh ' di-db-v1@ to di-db@ 5871.10Seeh ' di-ib-v1@ to di-ib@ 5881.10Seeh ' ib-ib-v1@ to ib-ib@ 5891.10Seeh ' lfs-dblksize to blksize 5901.10Seeh ' read-inode-lfs to read-inode 5911.10Seeh ' lfs-fsbtodb to fsbtodb 5921.10Seeh ' lfs-lblkno to lblkno 5931.10Seeh ' lfs-blkoff to blkoff 5941.10Seeh; 5951.10Seeh 5961.10Seeh: init-lfs-v1 ( -- ) 5971.12Seeh boot-debug? if ." LFS v1" cr then 5981.10Seeh init-lfs-common 5991.10Seeh ' lfs_ibsize to fs-bsize 6001.10Seeh ' ifile_v1_SIZEOF to /ifile 6011.10Seeh ' if1_daddr to if_daddr 6021.10Seeh; 6031.10Seeh 6041.10Seeh: init-lfs-v2 ( -- ) 6051.12Seeh boot-debug? if ." LFS v2" cr then 6061.10Seeh init-lfs-common 6071.10Seeh ' lfs_bsize to fs-bsize 6081.14Sjdc ' ifile32_SIZEOF to /ifile 6091.10Seeh ' if2_daddr to if_daddr 6101.10Seeh; 6111.10Seeh 6121.10Seeh 6131.10Seeh: fs-magic? ( sb -- is-ufs? ) 6141.10Seeh \ The LFS magic is the first word in the superblock 6151.10Seeh dup lfs_magic l@ lfs_magic_value = if 6161.10Seeh dup lfs_version l@ case ( sb sel ) 6171.10Seeh 1 of init-lfs-v1 drop true exit endof 6181.10Seeh 2 of init-lfs-v2 drop true exit endof 6191.10Seeh ." Invalid LFS version." \ Try FFS. 6201.10Seeh endcase 6211.10Seeh then ( sb ) 6221.10Seeh \ The FFS magic is at the end of the superblock 6231.11Seeh \ XXX we should check to make sure this is not an alternate SB. 6241.10Seeh fs_magic l@ case 6251.10Seeh fs1_magic_value of init-ffs-v1 true endof 6261.10Seeh fs2_magic_value of init-ffs-v2 true endof 6271.17Schs fs2ea_magic_value of init-ffs-v2 true endof 6281.10Seeh false swap \ Return false 6291.10Seeh endcase 6301.10Seeh; 6311.1Smrg 6321.1Smrg 6331.1Smrg 6341.1Smrg\ 6351.1Smrg\ Hunt for directory entry: 6361.1Smrg\ 6371.1Smrg\ repeat 6381.1Smrg\ load a buffer 6391.1Smrg\ while entries do 6401.1Smrg\ if entry == name return 6411.1Smrg\ next entry 6421.1Smrg\ until no buffers 6431.1Smrg\ 6441.1Smrg 6451.10Seeh: search-dir-block ( str len buf len -- ino | 0 ) 6461.10Seeh 2dup + nip ( str len buf bufend ) 6471.10Seeh swap 2swap rot ( bufend str len direct ) 6481.10Seeh begin dup 4 pick < while ( bufend str len direct ) 6491.10Seeh dup d_ino l@ 0<> if ( bufend str len direct ) 6501.10Seeh boot-debug? if 6511.10Seeh \ Print the current file name 6521.10Seeh dup dup d_name swap d_namlen c@ type cr 6531.10Seeh then 6541.10Seeh 2dup d_namlen c@ = if ( bufend str len direct ) 6551.10Seeh dup d_name 2over ( bufend str len direct dname str len ) 6561.10Seeh comp 0= if ( bufend str len direct ) 6571.10Seeh \ Found it -- return inode 6581.10Seeh d_ino l@ nip nip nip ( dino ) 6591.10Seeh boot-debug? if ." Found it" cr then 6601.10Seeh exit ( dino ) 6611.10Seeh then 6621.10Seeh then ( bufend str len direct ) 6631.10Seeh then ( bufend str len direct ) 6641.10Seeh dup d_reclen w@ + ( bufend str len nextdirect ) 6651.10Seeh repeat 6661.10Seeh 2drop 2drop 0 6671.10Seeh; 6681.10Seeh 6691.10Seeh 6701.10Seeh: search-directory ( str len -- ino | 0 ) 6711.10Seeh 0 to file-offset 6721.10Seeh begin 6731.10Seeh file-offset cur-inode di-size d@ drop < 6741.10Seeh while ( str len ) 6751.10Seeh \ Read a directory block 6761.10Seeh sb-buf buf-read-file ( str len buf len ) 6771.10Seeh dup 0= if ." search-directory: buf-read-file zero len" cr abort then 6781.10Seeh dup file-offset + to file-offset ( str len buf len ) 6791.10Seeh 6801.10Seeh 2over 2swap search-dir-block ?dup if 6811.10Seeh \ Found it 6821.10Seeh nip nip exit 6831.10Seeh then ( str len ) 6841.10Seeh repeat 6851.10Seeh 2drop 2drop 0 ( 0 ) 6861.1Smrg; 6871.1Smrg 6881.3Seeh: read-super ( sector -- ) 6891.10Seeh 0 " seek" boot-ihandle $call-method -1 = if 6901.10Seeh ." Seek failed" cr abort 6911.1Smrg then 6921.1Smrg sb-buf sbsize " read" boot-ihandle $call-method 6931.1Smrg dup sbsize <> if 6941.1Smrg ." Read of superblock failed" cr 6951.1Smrg ." requested" space sbsize . 6961.1Smrg ." actual" space . cr 6971.1Smrg abort 6981.1Smrg else 6991.1Smrg drop 7001.1Smrg then 7011.3Seeh; 7021.3Seeh 7031.11Seeh: check-supers ( -- found? ) 7041.11Seeh \ Superblocks used to be 8KB into the partition, but ffsv2 changed that. 7051.11Seeh \ See comments in src/sys/ufs/ffs/fs.h 7061.18Sandvar \ Put a list of offsets to check on the stack, ending with -1 7071.11Seeh -1 7081.11Seeh 0 7091.11Seeh d# 128 KB 7101.11Seeh d# 64 KB 7111.11Seeh 8 KB 7121.11Seeh 7131.11Seeh begin dup -1 <> while ( -1 .. off ) 7141.11Seeh raid-offset dev_bsize * + read-super ( -1 .. ) 7151.11Seeh sb-buf fs-magic? if ( -1 .. ) 7161.11Seeh begin -1 = until \ Clean out extra stuff from stack 7171.11Seeh true exit 7181.11Seeh then 7191.11Seeh repeat 7201.11Seeh drop false 7211.11Seeh; 7221.11Seeh 7231.10Seeh: ufs-open ( bootpath len -- ) 7241.3Seeh boot-ihandle -1 = if 7251.10Seeh 2dup + 0 swap c! \ Nul terminate. 7261.10Seeh over cif-open dup 0= if ( boot-path len ihandle? ) 7271.10Seeh ." Could not open device" space type cr 7281.10Seeh abort 7291.3Seeh then ( boot-path len ihandle ) 7301.10Seeh to boot-ihandle \ Save ihandle to boot device 7311.10Seeh then 7321.10Seeh 2drop 7331.10Seeh 7341.10Seeh boot-debug? if ." Try a RAID superblock read" cr then 7351.11Seeh \ RAIDFRAME skips 64 sectors. 7361.11Seeh d# 64 to raid-offset 7371.11Seeh check-supers invert if 7381.10Seeh boot-debug? if ." Try a normal superblock read" cr then 7391.10Seeh 0 to raid-offset 7401.11Seeh check-supers 0= abort" Invalid superblock magic" 7411.1Smrg then 7421.10Seeh sb-buf fs-bsize l@ dup maxbsize > if 7431.1Smrg ." Superblock bsize" space . ." too large" cr 7441.1Smrg abort 7451.1Smrg then 7461.10Seeh dup fs-size < if 7471.1Smrg ." Superblock bsize < size of superblock" cr 7481.1Smrg abort 7491.1Smrg then 7501.10Seeh dup to cur-blocksize alloc-mem to cur-block \ Allocate cur-block 7511.13Seeh cur-blocksize alloc-mem to indir-block 7521.10Seeh boot-debug? if ." ufs-open complete" cr then 7531.1Smrg; 7541.1Smrg 7551.1Smrg: ufs-close ( -- ) 7561.10Seeh boot-ihandle dup -1 <> if 7571.10Seeh cif-close -1 to boot-ihandle 7581.10Seeh then 7591.10Seeh cur-block 0<> if 7601.13Seeh cur-block cur-blocksize free-mem 7611.13Seeh indir-block cur-blocksize free-mem 7621.10Seeh then 7631.1Smrg; 7641.1Smrg 7651.1Smrg: boot-path ( -- boot-path ) 7661.10Seeh " bootpath" chosen-phandle get-package-property if 7671.10Seeh ." Could not find bootpath in /chosen" cr 7681.10Seeh abort 7691.10Seeh else 7701.10Seeh decode-string 2swap 2drop 7711.10Seeh then 7721.1Smrg; 7731.1Smrg 7741.1Smrg: boot-args ( -- boot-args ) 7751.10Seeh " bootargs" chosen-phandle get-package-property if 7761.10Seeh ." Could not find bootargs in /chosen" cr 7771.10Seeh abort 7781.10Seeh else 7791.10Seeh decode-string 2swap 2drop 7801.10Seeh then 7811.1Smrg; 7821.1Smrg 7831.1Smrg2000 buffer: boot-path-str 7841.1Smrg2000 buffer: boot-path-tmp 7851.1Smrg 7861.1Smrg: split-path ( path len -- right len left len ) 7871.1Smrg\ Split a string at the `/' 7881.10Seeh begin 7891.10Seeh dup -rot ( oldlen right len left ) 7901.10Seeh ascii / left-parse-string ( oldlen right len left len ) 7911.10Seeh dup 0<> if 4 roll drop exit then 7921.10Seeh 2drop ( oldlen right len ) 7931.10Seeh rot over = ( right len diff ) 7941.10Seeh until 7951.1Smrg; 7961.1Smrg 7971.1Smrg: find-file ( load-file len -- ) 7981.10Seeh rootino dup sb-buf read-inode ( load-file len pino ) 7991.10Seeh -rot ( pino load-file len ) 8001.10Seeh \ 8011.10Seeh \ For each path component 8021.10Seeh \ 8031.10Seeh begin split-path dup 0<> while ( pino right len left len ) 8041.10Seeh cur-inode is-dir? not if ." Inode not directory" cr abort then 8051.10Seeh boot-debug? if ." Looking for" space 2dup type space ." in directory..." cr then 8061.10Seeh search-directory ( pino right len ino|false ) 8071.10Seeh dup 0= abort" Bad path" ( pino right len cino ) 8081.10Seeh sb-buf read-inode ( pino right len ) 8091.10Seeh cur-inode is-symlink? if \ Symlink -- follow the damn thing 8101.10Seeh \ Save path in boot-path-tmp 8111.10Seeh boot-path-tmp strmov ( pino new-right len ) 8121.10Seeh 8131.10Seeh \ Now deal with symlink XXX drop high word of linklen 8141.10Seeh cur-inode di-size d@ drop ( pino right len linklen.lo ) 8151.10Seeh dup sb-buf fs_maxsymlinklen l@ ( pino right len linklen linklen maxlinklen ) 8161.10Seeh < if \ Now join the link to the path 8171.10Seeh 0 cur-inode di-db@ drop ( pino right len linklen linkp ) 8181.10Seeh swap boot-path-str strmov ( pino right len new-linkp linklen ) 8191.10Seeh else \ Read file for symlink -- Ugh 8201.10Seeh \ Read link into boot-path-str 8211.10Seeh boot-path-str dup sb-buf fs-bsize l@ 8221.10Seeh 0 block-map ( pino right len linklen boot-path-str bsize blockno.lo blockno.hi ) 8231.10Seeh strategy drop swap ( pino right len boot-path-str linklen ) 8241.10Seeh then ( pino right len linkp linklen ) 8251.10Seeh \ Concatenate the two paths 8261.10Seeh strcat ( pino new-right newlen ) 8271.10Seeh swap dup c@ ascii / = if \ go to root inode? 8281.10Seeh rot drop rootino -rot ( rino len right ) 8291.10Seeh then 8301.10Seeh rot dup sb-buf read-inode ( len right pino ) 8311.10Seeh -rot swap ( pino right len ) 8321.10Seeh then ( pino right len ) 8331.10Seeh repeat 8341.10Seeh 2drop drop 8351.10Seeh; 8361.10Seeh 8371.10Seeh: .read-file-msg ( addr xxx siz -- addr xxx siz ) 8381.10Seeh boot-debug? if 8391.10Seeh ." Copying " dup . ." bytes to " 3 pick . cr 8401.10Seeh then 8411.10Seeh; 8421.10Seeh 8431.10Seeh: read-file ( addr size -- ) 8441.10Seeh noop \ In case we need to debug this 8451.10Seeh \ Read x bytes from a file to buffer 8461.10Seeh begin dup 0> while 8471.10Seeh file-offset cur-inode di-size d@ drop > if 8481.10Seeh ." read-file EOF exceeded" cr abort 8491.10Seeh then 8501.10Seeh sb-buf buf-read-file ( addr size buf len ) 8511.10Seeh 8521.10Seeh .read-file-msg 8531.10Seeh 8541.10Seeh \ Copy len bytes to addr XXX min ( len, size ) ? 8551.10Seeh 2over drop 3dup swap move drop ( addr size buf len ) 8561.10Seeh 8571.10Seeh dup file-offset + to file-offset ( addr size buf len ) 8581.10Seeh 8591.10Seeh nip tuck - -rot + swap ( addr' size' ) 8601.10Seeh repeat 8611.10Seeh 2drop 8621.1Smrg; 8631.1Smrg 8641.10Seeh" load-base " evaluate constant loader-base 8651.1Smrg 8661.1Smrg: load-file-signon ( load-file len boot-path len -- load-file len boot-path len ) 8671.1Smrg ." Loading file" space 2over type cr ." from device" space 2dup type cr 8681.1Smrg; 8691.1Smrg 8701.1Smrg: load-file ( load-file len boot-path len -- load-base ) 8711.10Seeh boot-debug? if load-file-signon then 8721.10Seeh 8731.10Seeh ufs-open ( load-file len ) 8741.10Seeh find-file ( ) 8751.1Smrg 8761.10Seeh \ 8771.10Seeh \ Now we've found the file we should read it in in one big hunk 8781.10Seeh \ 8791.10Seeh 8801.10Seeh cur-inode di-size d@ if ." File len >2GB!" cr abort then 8811.10Seeh\ dup " to file-size " evaluate ( file-len ) \ Wassthis? 8821.10Seeh boot-debug? if 8831.10Seeh ." Loading " dup . ." bytes of file..." cr 8841.10Seeh then 8851.10Seeh 0 to file-offset 8861.10Seeh -1 to file-blockno 8871.10Seeh loader-base ( buf-len addr ) 8881.10Seeh tuck swap read-file ( addr ) 8891.10Seeh ufs-close ( addr ) 8901.1Smrg; 8911.1Smrg 8921.1Smrg: do-boot ( bootfile -- ) 8931.11Seeh ." NetBSD IEEE 1275 Multi-FS Bootblock" cr 8941.18Sandvar ." Version $NetBSD: bootblk.fth,v 1.18 2025/02/28 09:07:12 andvar Exp $" cr 8951.11Seeh boot-path load-file ( -- load-base ) 8961.11Seeh dup 0<> if " init-program " evaluate then 8971.10Seeh; 8981.1Smrg 8991.1Smrg 9001.10Seehboot-args ascii V strchr 0<> swap drop if 9011.10Seeh true to boot-debug? 9021.1Smrgthen 9031.1Smrg 9041.10Seehboot-args ascii D strchr 0= swap drop if 9051.10Seeh " /ofwboot" do-boot 9061.10Seehthen exit 9071.1Smrg 9081.1Smrg 909