bootblk.fth revision 1.11
11.11Seeh\ $NetBSD: bootblk.fth,v 1.11 2010/02/17 15:49:19 eeh 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.10Seeh tuck << ( d.lo n d.hi' ) 891.10Seeh -rot 2dup << ( d.hi' d.lo n d.lo' ) 901.10Seeh -rot d# 32 swap - >> ( d.hi' d.lo' lo.hi ) 911.10Seeh rot + 921.10Seeh; 931.10Seeh: d>> ( d1 n -- d1>>n ) \ Hope this works 941.10Seeh rot over >> -rot ( d.lo' d.hi n ) 951.10Seeh 2dup >> -rot ( d.lo' d.hi' d.hi n ) 961.10Seeh d# 32 swap - << rot + swap 971.10Seeh; 981.10Seeh: d> ( d1 d2 -- d1>d2? ) 991.10Seeh rot swap 2dup = if 1001.10Seeh 2drop > exit 1011.10Seeh then 1021.10Seeh > nip nip 1031.10Seeh; 1041.10Seeh: d>= ( d1 d2 -- d1>=d2? ) 1051.10Seeh rot swap 2dup = if 1061.10Seeh 2drop >= exit 1071.10Seeh then 1081.10Seeh >= nip nip 1091.10Seeh; 1101.10Seeh: d< ( d1 d2 -- d1<d2? ) d>= invert ; 1111.10Seeh: d= ( d1 d2 -- d1=d2? ) rot = -rot = and ; 1121.10Seeh: d<> ( d1 d2 -- d1<>d2? ) d= invert ; 1131.10Seeh 1141.10Seeh 1151.10Seeh\ String support 1161.10Seeh 1171.1Smrg: strcmp ( s1 l1 s2 l2 -- true:false ) 1181.10Seeh rot tuck <> if 3drop false exit then 1191.1Smrg comp 0= 1201.1Smrg; 1211.1Smrg 1221.1Smrg\ Move string into buffer 1231.1Smrg 1241.1Smrg: strmov ( s1 l1 d -- d l1 ) 1251.1Smrg dup 2over swap -rot ( s1 l1 d s1 d l1 ) 1261.1Smrg move ( s1 l1 d ) 1271.1Smrg rot drop swap 1281.1Smrg; 1291.1Smrg 1301.1Smrg\ Move s1 on the end of s2 and return the result 1311.1Smrg 1321.1Smrg: strcat ( s1 l1 s2 l2 -- d tot ) 1331.1Smrg 2over swap ( s1 l1 s2 l2 l1 s1 ) 1341.1Smrg 2over + rot ( s1 l1 s2 l2 s1 d l1 ) 1351.1Smrg move rot + ( s1 s2 len ) 1361.1Smrg rot drop ( s2 len ) 1371.1Smrg; 1381.1Smrg 1391.1Smrg: strchr ( s1 l1 c -- s2 l2 ) 1401.1Smrg begin 1411.1Smrg dup 2over 0= if ( s1 l1 c c s1 ) 1421.1Smrg 2drop drop exit then 1431.1Smrg c@ = if ( s1 l1 c ) 1441.1Smrg drop exit then 1451.1Smrg -rot /c - swap ca1+ ( c l2 s2 ) 1461.1Smrg swap rot 1471.1Smrg again 1481.1Smrg; 1491.1Smrg 1501.1Smrg 1511.1Smrg: cstr ( ptr -- str len ) 1521.1Smrg dup 1531.1Smrg begin dup c@ 0<> while + repeat 1541.1Smrg over - 1551.1Smrg; 1561.1Smrg 1571.1Smrg\ 1581.10Seeh\ BSD UFS parameters 1591.1Smrg\ 1601.1Smrg 1611.10Seehfload ffs.fth.h 1621.10Seehfload lfs.fth.h 1631.1Smrg 1641.1Smrgsbsize buffer: sb-buf 1651.1Smrg-1 value boot-ihandle 1661.1Smrgdev_bsize value bsize 1671.3Seeh0 value raid-offset \ Offset if it's a raid-frame partition 1681.1Smrg 1691.10Seeh: strategy ( addr size db.lo db.hi -- nread ) 1701.10Seeh raid-offset l>d d+ ( addr size db.lo' db.hi' ) 1711.10Seeh bsize d*u ( addr size sector.lo sector.hi ) 1721.10Seeh " seek" boot-ihandle $call-method -1 = if 1731.10Seeh ." strategy: Seek failed" cr 1741.10Seeh abort 1751.10Seeh then ( addr size ) 1761.10Seeh " read" boot-ihandle $call-method 1771.10Seeh; 1781.10Seeh 1791.10Seeh 1801.10Seeh\ 1811.10Seeh\ Multi-FS support 1821.10Seeh\ 1831.10Seeh\ XXX Maybe the different filesystems should be segregated into separate files 1841.10Seeh\ XXX that are individually fload-ed. 1851.10Seeh\ 1861.10Seeh 1871.10Seehdefer fs-size 1881.10Seehdefer di-size 1891.10Seehdefer di-mode 1901.10Seehdefer /dino 1911.10Seehdefer cgstart 1921.10Seehdefer di-db@ 1931.10Seehdefer di-ib@ 1941.10Seehdefer ib-ib@ 1951.10Seehdefer fs-bsize 1961.10Seehdefer fsbtodb 1971.10Seehdefer blksize 1981.10Seehdefer lblkno 1991.10Seehdefer blkoff 2001.10Seehdefer read-inode 2011.10Seeh\ LFS ifile 2021.10Seehdefer /ifile 2031.10Seehdefer if_daddr 2041.10Seeh 2051.10Seeh\ 2061.10Seeh\ FFS Cylinder group macros 2071.10Seeh\ 2081.10Seeh 2091.10Seeh: cgdmin ( cg fs -- d-1st-data-block ) dup fs_dblkno l@ l>d 2swap cgstart d+ ; 2101.10Seeh: cgimin ( cg fs -- d-inode-block ) dup fs_iblkno l@ l>d 2swap cgstart d+ ; 2111.10Seeh: cgsblock ( cg fs -- d-super-block ) dup fs_sblkno l@ l>d 2swap cgstart d+ ; 2121.10Seeh: cgstod ( cg fs -- d-cg-block ) dup fs_cblkno l@ l>d 2swap cgstart d+ ; 2131.10Seeh 2141.10Seeh\ 2151.10Seeh\ FFS Block and frag position macros 2161.10Seeh\ 2171.10Seeh 2181.10Seeh: ffs-blkoff ( pos.lo pos.hi fs -- off.lo off.hi ) fs_qbmask d@ d-and ; 2191.10Seeh\ : ffs-fragoff ( pos.lo pos.hi fs -- off.lo off.hi ) fs_qfmask d@ d-and ; 2201.10Seeh\ : ffs-lblktosize ( blk fs -- off.lo off.hi ) 0 fs_bshift l@ d<< ; 2211.10Seeh: ffs-lblkno ( pos.lo pos.hi fs -- off.lo off.hi ) fs_bshift l@ d>> ; 2221.10Seeh: ffs-numfrags ( pos.lo pos.hi fs -- off.lo off.hi ) fs_fshift l@ d>> ; 2231.10Seeh: ffs-blkroundup ( pos.lo pos.hi fs -- off.lo off.hi ) 2241.10Seeh >r r@ fs_qbmask d@ d+ r> fs_bmask l@ l>d d-and 2251.10Seeh; 2261.10Seeh: ffs-fragroundup ( pos.lo pos.hi fs -- off.lo off.hi ) 2271.10Seeh >r r@ fs_qfmask d@ d+ r> fs_fmask l@ l>d d-and 2281.10Seeh; 2291.10Seeh: ffs-fragstoblks ( pos.lo pos.hi fs -- off.lo off.hi ) fs_fragshift l@ d>> ; 2301.10Seeh: ffs-blkstofrags ( blk fs -- frag ) fs_fragshift l@ << ; 2311.10Seeh\ : ffs-fragnum ( fsb fs -- off ) fs_frag l@ 1- and ; 2321.10Seeh\ : ffs-blknum ( fsb fs -- off ) fs_frag l@ 1- not and ; 2331.10Seeh: ffs-dblksize ( lbn.lo lbn.hi inodep fs -- size ) 2341.10Seeh >r -rot 2dup ndaddr l>d d> ( inop d-lbn >ndaddr? ) 2351.10Seeh -rot 1 0 d+ ( inop >ndaddr? d-lbn+1 ) 2361.10Seeh r@ fs_bshift l@ d<< ( inop >ndaddr? d-lbn+1<<bshift ) 2371.10Seeh 2swap >r di-size d@ ( d-lbn+1<<bshift d-size ) 2381.10Seeh 2swap 2over d< r> or if ( d-size ) 2391.10Seeh 2drop r> fs-bsize l@ exit 2401.10Seeh then 2411.10Seeh r@ ffs-blkoff ( size.lo size.hi ) 2421.10Seeh r> ffs-fragroundup d>l ( size ) 2431.10Seeh; 2441.10Seeh 2451.10Seeh: ino-to-cg ( ino fs -- cg ) fs_ipg l@ / ; 2461.10Seeh: ino-to-fsbo ( ino fs -- fsb0 ) fs_inopb l@ mod ; 2471.10Seeh: ino-to-fsba ( ino fs -- ba.lo ba.hi ) \ Need to remove the stupid stack diags someday 2481.10Seeh 2dup ( ino fs ino fs ) 2491.10Seeh ino-to-cg ( ino fs cg ) 2501.10Seeh over ( ino fs cg fs ) 2511.10Seeh cgimin ( ino fs inode-blk.lo inode-blk.hi ) 2521.10Seeh 2swap ( d-inode-blk ino fs ) 2531.10Seeh tuck ( d-inode-blk fs ino fs ) 2541.10Seeh fs_ipg l@ ( d-inode-blk fs ino ipg ) 2551.10Seeh mod ( d-inode-blk fs mod ) 2561.10Seeh swap ( d-inode-blk mod fs ) 2571.10Seeh dup ( d-inode-blk mod fs fs ) 2581.10Seeh fs_inopb l@ ( d-inode-blk mod fs inopb ) 2591.10Seeh rot ( d-inode-blk fs inopb mod ) 2601.10Seeh swap ( d-inode-blk fs mod inopb ) 2611.10Seeh / ( d-inode-blk fs div ) 2621.10Seeh swap ( d-inode-blk div fs ) 2631.10Seeh ffs-blkstofrags ( d-inode-blk frag ) 2641.10Seeh 0 d+ 2651.10Seeh; 2661.10Seeh: ffs-fsbtodb ( fsb.lo fsb.hi fs -- db.lo db.hi ) 2671.10Seeh fs_fsbtodb l@ d<< 2681.10Seeh; 2691.10Seeh 2701.10Seeh 2711.10Seeh\ 2721.10Seeh\ LFS suff 2731.10Seeh\ 2741.10Seeh: lfs-blkoff ( pos.lo pos.hi fs -- off.lo off.hi ) lfs_bmask d@ d-and ; 2751.10Seeh\ : lfs-fragoff ( pos.lo pos.hi fs -- off.lo off.hi ) lfs_ffmask d@ d-and ; 2761.10Seeh\ : lfs-lblktosize ( blk fs -- off.lo off.hi ) 0 lfs_bshift l@ d<< ; 2771.10Seeh: lfs-lblkno ( pos.lo pos.hi fs -- off.lo off.hi ) lfs_bshift l@ d>> ; 2781.10Seeh: lfs-numfrags ( pos.lo pos.hi fs -- off.lo off.hi ) lfs_ffshift l@ d>> ; 2791.10Seeh: lfs-roundup ( pos.lo pos.hi mask.lo mask.hi ) 2801.10Seeh 2swap 2over d+ 2swap ( d-pos* d-mask ) 2811.10Seeh invert swap invert swap d-and 2821.10Seeh; 2831.10Seeh: lfs-blkroundup ( pos.lo pos.hi fs -- off.lo off.hi ) lfs_bmask d@ lfs-roundup ; 2841.10Seeh: lfs-fragroundup ( pos.lo pos.hi fs -- off.lo off.hi ) lfs_ffmask d@ lfs-roundup ; 2851.10Seeh: lfs-fragstoblks ( pos.lo pos.hi fs -- off.lo off.hi ) lfs_fbshift l@ d>> ; 2861.10Seeh: lfs-dblksize ( lbn.lo lbn.hi inodep fs -- size ) 2871.10Seeh >r -rot 2dup ndaddr l>d d> ( inop d-lbn >ndaddr? ) 2881.10Seeh -rot 1 0 d+ ( inop >ndaddr? d-lbn+1 ) 2891.10Seeh r@ fs_bshift l@ d<< ( inop >ndaddr? d-lbn+1<<bshift ) 2901.10Seeh 2swap >r di-size d@ ( d-lbn+1<<bshift d-size ) 2911.10Seeh 2swap 2over d< r> or if ( d-size ) 2921.10Seeh 2drop r> fs-bsize l@ exit 2931.1Smrg then 2941.10Seeh r@ lfs-blkoff ( size.lo size.hi ) 2951.10Seeh r> lfs-fragroundup d>l ( size ) 2961.10Seeh; 2971.10Seeh: lfs-fsbtodb ( fsb.lo fsb.hi fs -- db.lo db.hi ) 2981.10Seeh lfs_fsbtodb l@ d<< 2991.1Smrg; 3001.1Smrg 3011.10Seeh\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 3021.1Smrg\ 3031.10Seeh\ The rest of the multi-filesystem stuff 3041.1Smrg\ 3051.10Seeh\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 3061.1Smrg 3071.10Seeh\ 3081.10Seeh\ FFS v1 3091.10Seeh\ 3101.10Seeh: di-db-v1@ ( indx dinode -- db.lo db.hi ) di1_db swap la+ l@ l>d ; 3111.10Seeh: di-ib-v1@ ( indx dinode -- db.lo db.hi ) di1_ib swap la+ l@ l>d ; 3121.10Seeh: ib-ib-v1@ ( indx iblk -- db.lo db.hi ) swap la+ l@ l>d ; 3131.10Seeh 3141.10Seeh: cgbase ( cg fs -- daddr.lo daddr.hi ) fs_fpg l@ um* ; 3151.10Seeh: cgstart-ufs1 ( cg fs -- cgstart ) 3161.10Seeh 2dup fs_old_cgmask l@ invert and ( cg fs stuff ) 3171.10Seeh over fs_old_cgoffset l@ um* ( cg fs off.lo off.hi ) 3181.10Seeh 2swap cgbase d+ ( off.lo off.hi ) 3191.1Smrg; 3201.1Smrg 3211.1Smrg\ 3221.10Seeh\ FFS v2 3231.1Smrg\ 3241.1Smrg 3251.10Seeh: di-db-v2@ ( indx dinode -- db.lo db.hi ) di2_db swap 2* la+ d@ ; 3261.10Seeh: di-ib-v2@ ( indx dinode -- db.lo db.hi ) di2_ib swap 2* la+ d@ ; 3271.10Seeh: ib-ib-v2@ ( indx iblk -- db.lo db.hi ) 2* la+ d@ ; 3281.1Smrg 3291.10Seeh\ 3301.10Seeh\ LFS v1 3311.10Seeh\ 3321.1Smrg 3331.1Smrg 3341.1Smrg\ 3351.1Smrg\ File stuff 3361.1Smrg\ 3371.1Smrg 3381.1Smrgniaddr /w* constant narraysize 3391.1Smrg 3401.10Seeh\ Assume UFS2 dinodes are always biger than UFS1 3411.10Seehufs2_dinode_SIZEOF buffer: cur-inode 3421.1Smrgh# 2000 buffer: indir-block 3431.10Seehcreate indir-addr -1 , -1 , 3441.1Smrg 3451.1Smrg\ 3461.1Smrg\ Translate a fileblock to a disk block 3471.1Smrg\ 3481.10Seeh\ We don't do triple indirect blocks. 3491.1Smrg\ 3501.1Smrg 3511.10Seeh\ Get the disk address from a single indirect block 3521.10Seeh: ib@ ( indx indir.lo indir.hi -- db.lo db.hi ) 3531.10Seeh 2dup indir-addr d@ d<> if ( indx indir.hi indir.lo ) 3541.10Seeh indir-addr d! ( indx ) 3551.10Seeh indir-block ( indx indir-block ) 3561.10Seeh sb-buf fs-bsize l@ ( indx indir-block fs fs-bsize ) 3571.10Seeh indir-addr d@ sb-buf ( indx indir-block fs-bsize indiraddr fs ) 3581.10Seeh fsbtodb ( indx indir-block fs-bsize db.lo db.hi ) 3591.10Seeh strategy 0 ( indx nread 0 ) \ Really should check return value 3601.10Seeh then 3611.10Seeh 2drop ( indx ) 3621.10Seeh indir-block ib-ib@ 3631.10Seeh; 3641.10Seeh 3651.10Seeh 3661.10Seeh: block-map ( fileblock -- diskblock.lo diskblock.hi ) 3671.10Seeh \ Direct block? 3681.10Seeh dup ndaddr < if ( fileblock ) 3691.10Seeh cur-inode di-db@ exit ( diskblock.lo diskblock.hi ) 3701.10Seeh then ( fileblock ) 3711.10Seeh ndaddr - ( fileblock' ) 3721.10Seeh \ Now we need to check the indirect block 3731.10Seeh dup sb-buf fs_nindir l@ < if ( fileblock' ) 3741.10Seeh 0 cur-inode di-ib@ ( fileblock' indir.lo indir.hi ) 3751.10Seeh ib@ exit ( db.lo db.hi ) 3761.1Smrg then 3771.1Smrg dup sb-buf fs_nindir - ( fileblock'' ) 3781.1Smrg \ Now try 2nd level indirect block -- just read twice 3791.10Seeh dup sb-buf fs_nindir l@ dup * >= if ( fileblock'' ) 3801.10Seeh ." block-map: exceeded max file size" cr 3811.10Seeh abort 3821.1Smrg then 3831.10Seeh 3841.10Seeh 1 cur-inode di-ib@ ( fileblock'' ib.lo ib.hi ) 3851.10Seeh 3861.10Seeh \ Get 1st indirect block and find the 2nd indirect block 3871.10Seeh rot dup sb-buf fs_nindir u/mod ( ib2.lo ib2.hi indx2 indx1 ) 3881.10Seeh 2swap ib@ ( indx2 ib2.lo ib2.hi ) 3891.10Seeh 3901.10Seeh \ Get 2nd indirect block and find our diskblock 3911.10Seeh ib@ ( db.lo db.hi ) 3921.1Smrg; 3931.1Smrg 3941.1Smrg\ 3951.1Smrg\ Read file into internal buffer and return pointer and len 3961.1Smrg\ 3971.1Smrg 3981.4Seeh0 value cur-block \ allocated dynamically in ufs-open 3991.10Seeh0 value cur-blocksize \ size allocated to cur-block 4001.10Seehcreate cur-blockno -1 l, -1 l, \ Current disk block. 4011.10Seeh-1 value file-blockno \ Current file block no. 4021.10Seeh0 value file-offset \ Current file offset, max 4GB. 4031.10Seeh 4041.10Seeh: buf-read-file ( fs -- buf len ) 4051.10Seeh >r file-offset ( seek ) 4061.10Seeh dup l>d r@ lblkno drop ( seek blk ) 4071.10Seeh dup l>d cur-inode r@ blksize ( seek blk blksize ) 4081.10Seeh over file-blockno <> if ( seek blk blksize ) 4091.10Seeh over to file-blockno 4101.10Seeh swap block-map ( seek blksize fsblk.lo fsblk.hi ) 4111.10Seeh 2dup or 0= if ( seek blksize fsblk.lo fsblk.hi ) 4121.10Seeh \ Clear out curblock XXX Why? Idunno. 4131.10Seeh 2drop dup 4141.10Seeh cur-block swap erase ( seek blksize ) 4151.10Seeh boot-debug? if ." buf-read-file reading block 0" cr then 4161.10Seeh -1 l>d \ Invalid disk block 4171.10Seeh else 4181.10Seeh \ Call strategy to load the correct block. 4191.10Seeh r@ fsbtodb ( seek blksize dblk.lo dblk.hi ) 4201.10Seeh rot >r cur-block r@ 2over ( seek addr size db.lo db.hi ) 4211.10Seeh strategy r@ <> if ." buf-read-file: short read." cr abort then 4221.10Seeh r> -rot ( seek size db.lo db.hi ) 4231.10Seeh then 4241.10Seeh \ Save the new current disk block number 4251.10Seeh cur-blockno d! ( seek size ) 4261.10Seeh else 4271.10Seeh nip ( seek size ) 4281.10Seeh then 4291.10Seeh \ Now figure out how much we have in the buffer. 4301.10Seeh swap l>d r> blkoff ( size off.lo off.hi ) 4311.10Seeh d>l cur-block over + ( size off buf ) 4321.10Seeh -rot - ( buf siz ) 4331.1Smrg; 4341.1Smrg 4351.1Smrg\ 4361.1Smrg\ Read inode into cur-inode -- uses cur-block 4371.1Smrg\ 4381.1Smrg 4391.10Seeh: read-inode-ffs ( inode fs -- ) 4401.10Seeh twiddle 4411.10Seeh 4421.10Seeh >r dup r@ ino-to-fsba ( ino fsblk.lo fsblck.hi ) 4431.10Seeh r@ fsbtodb ( ino dblk.lo dblk.hi ) 4441.10Seeh 2dup cur-blockno d@ d<> if ( ino dblk.lo dblk.hi ) 4451.10Seeh \ We need to read the block 4461.10Seeh cur-block r@ fs-bsize l@ ( ino dblk.lo dblk.hi addr size ) 4471.10Seeh >r r@ 2over strategy r> <> if ( ino dblk.lo dblk.hi ) 4481.10Seeh ." read-inode - residual" cr abort 4491.10Seeh then 4501.10Seeh 2dup cur-blockno d! ( ino dblk.lo dblk.hi ) 4511.10Seeh then 2drop ( ino ) 4521.1Smrg 4531.10Seeh r> ino-to-fsbo /dino * ( off ) 4541.10Seeh cur-block + cur-inode /dino move ( ) 4551.10Seeh; 4561.10Seeh 4571.10Seeh: find-inode-sector ( ino fs -- d-dblkno true | false ) 4581.10Seeh >r r@ lfs_ifile l@ r@ read-inode ( ino ) 4591.10Seeh 4601.10Seeh r@ lfs_ifpb l@ u/mod ( rem q ) 4611.10Seeh 4621.10Seeh r@ lfs_cleansz l@ + 4631.10Seeh r@ lfs_segtabsz l@ + ( rem blkno ) 4641.1Smrg 4651.10Seeh r@ fs-bsize l@ um* rot /ifile um* d+ ( dseekp ) 4661.1Smrg 4671.10Seeh drop to file-offset r@ buf-read-file ( buf len ) 4681.10Seeh 4691.10Seeh /ifile < if r> 2drop false exit then ( buf ) 4701.10Seeh 4711.10Seeh if_daddr l@ l>d r> fsbtodb ( daddr ) 4721.10Seeh 2dup lfs_unused_daddr l>d d= if 2drop false then 4731.10Seeh true 4741.10Seeh; 4751.10Seeh 4761.10Seeh: read-inode-lfs ( inode fs -- ) 4771.10Seeh twiddle 4781.10Seeh 4791.10Seeh >r dup r@ lfs_ifile l@ = if ( ino r: fs ) 4801.10Seeh r@ lfs_idaddr l@ l>d ( ino d-idaddr ) 4811.10Seeh r@ fsbtodb ( ino d-db ) 4821.10Seeh else 4831.10Seeh dup r@ find-inode-sector 0= abort" Could not find inode sector!" 4841.10Seeh then ( ino d-db ) 4851.10Seeh 4861.10Seeh 2dup cur-blockno d@ d<> if ( ino dblk.lo dblk.hi ) 4871.10Seeh \ We need to read the block 4881.10Seeh cur-block r@ fs-bsize l@ ( ino dblk.lo dblk.hi addr size ) 4891.10Seeh >r r@ 2over strategy r> <> if ( ino dblk.lo dblk.hi ) 4901.10Seeh ." read-inode - residual" cr abort 4911.10Seeh then 4921.10Seeh 2dup cur-blockno d! ( ino dblk.lo dblk.hi ) 4931.10Seeh then 2drop ( ino ) 4941.10Seeh 4951.10Seeh r@ lfs_inopb l@ ( ino cnt ) 4961.10Seeh swap cur-block begin ( cnt ino p ) 4971.10Seeh tuck di_inumber l@ over <> ( cnt p ino !found? ) 4981.10Seeh while ( cnt p ino ) 4991.10Seeh rot 1- ?dup 0= abort" Could not find inode!" 5001.10Seeh rot /dino + swap -rot ( cnt ino p ) 5011.10Seeh repeat swap ( cnt ino p ) 5021.10Seeh 5031.10Seeh cur-inode /dino move ( cnt ino ) 5041.10Seeh 5051.10Seeh r> 3drop 5061.1Smrg; 5071.1Smrg 5081.1Smrg\ Identify inode type 5091.1Smrg 5101.10Seeh: is-dir? ( ufs1_dinode -- is-dir? ) di-mode w@ ifmt and ifdir = ; 5111.10Seeh: is-symlink? ( ufs1_dinode -- is-symlink? ) di-mode w@ ifmt and iflnk = ; 5121.10Seeh 5131.10Seeh\ 5141.10Seeh\ Multi-FS initialiation. 5151.10Seeh\ 5161.10Seeh\ It's way down here so all the fs-specific routines have already been defined. 5171.10Seeh\ 5181.10Seeh 5191.10Seeh: init-ffs-common ( -- ) 5201.10Seeh ' fs_SIZEOF to fs-size 5211.10Seeh ' fs_bsize to fs-bsize 5221.10Seeh ' ffs-dblksize to blksize 5231.10Seeh ' read-inode-ffs to read-inode 5241.10Seeh ' ffs-fsbtodb to fsbtodb 5251.10Seeh ' ffs-lblkno to lblkno 5261.10Seeh ' ffs-blkoff to blkoff 5271.10Seeh; 5281.10Seeh 5291.10Seeh 5301.10Seeh: ffs-oldcompat ( -- ) 5311.10Seeh \ Make sure old ffs values in sb-buf are sane 5321.10Seeh sb-buf fs_old_npsect dup l@ sb-buf fs_old_nsect l@ max swap l! 5331.10Seeh sb-buf fs_old_interleave dup l@ 1 max swap l! 5341.10Seeh sb-buf fs_old_postblformat l@ fs_42postblfmt = if 5351.10Seeh 8 sb-buf fs_old_nrpos l! 5361.10Seeh then 5371.10Seeh sb-buf fs_old_inodefmt l@ fs_44inodefmt < if 5381.10Seeh sb-buf fs-bsize l@ 5391.10Seeh dup ndaddr um* 1 d- sb-buf fs_maxfilesize d! 5401.10Seeh niaddr 0 ?do 5411.10Seeh sb-buf fs_nindir l@ * dup ( sizebp sizebp ) 5421.10Seeh sb-buf fs_maxfilesize dup d@ ( sizebp sizebp *mxfs mxfs.lo mxfs.hi ) 5431.10Seeh 2over drop l>d d+ 2swap d! ( sizebp ) 5441.10Seeh loop drop ( ) 5451.10Seeh sb-buf dup fs_bmask l@ invert l>d rot fs_qbmask d! 5461.10Seeh sb-buf dup fs_fmask l@ invert l>d rot fs_qfmask d! 5471.10Seeh then 5481.10Seeh; 5491.10Seeh 5501.10Seeh 5511.10Seeh: init-ffs-v1 ( -- ) 5521.10Seeh init-ffs-common 5531.10Seeh ' di1_size to di-size 5541.10Seeh ' di1_mode to di-mode 5551.10Seeh ' ufs1_dinode_SIZEOF to /dino 5561.10Seeh ' cgstart-ufs1 to cgstart 5571.10Seeh ' di-db-v1@ to di-db@ 5581.10Seeh ' di-ib-v1@ to di-ib@ 5591.10Seeh ' ib-ib-v1@ to ib-ib@ 5601.10Seeh ffs-oldcompat 5611.10Seeh; 5621.10Seeh 5631.10Seeh: init-ffs-v2 ( -- ) 5641.10Seeh init-ffs-common 5651.10Seeh ' di2_size to di-size 5661.10Seeh ' di2_mode to di-mode 5671.10Seeh ' ufs2_dinode_SIZEOF to /dino 5681.10Seeh ' cgbase to cgstart 5691.10Seeh ' di-db-v2@ to di-db@ 5701.10Seeh ' di-ib-v2@ to di-ib@ 5711.10Seeh ' ib-ib-v2@ to ib-ib@ 5721.10Seeh; 5731.10Seeh 5741.10Seeh: init-lfs-common ( -- ) 5751.10Seeh ' dlfs_SIZEOF to fs-size 5761.10Seeh ' di1_size to di-size 5771.10Seeh ' di1_mode to di-mode 5781.10Seeh ' ufs1_dinode_SIZEOF to /dino 5791.10Seeh ' cgbase to cgstart 5801.10Seeh ' di-db-v1@ to di-db@ 5811.10Seeh ' di-ib-v1@ to di-ib@ 5821.10Seeh ' ib-ib-v1@ to ib-ib@ 5831.10Seeh ' lfs-dblksize to blksize 5841.10Seeh ' read-inode-lfs to read-inode 5851.10Seeh ' lfs-fsbtodb to fsbtodb 5861.10Seeh ' lfs-lblkno to lblkno 5871.10Seeh ' lfs-blkoff to blkoff 5881.10Seeh; 5891.10Seeh 5901.10Seeh: init-lfs-v1 ( -- ) 5911.10Seeh init-lfs-common 5921.10Seeh ' lfs_ibsize to fs-bsize 5931.10Seeh ' ifile_v1_SIZEOF to /ifile 5941.10Seeh ' if1_daddr to if_daddr 5951.10Seeh; 5961.10Seeh 5971.10Seeh: init-lfs-v2 ( -- ) 5981.10Seeh init-lfs-common 5991.10Seeh ' lfs_bsize to fs-bsize 6001.10Seeh ' ifile_SIZEOF to /ifile 6011.10Seeh ' if2_daddr to if_daddr 6021.10Seeh; 6031.10Seeh 6041.10Seeh 6051.10Seeh: fs-magic? ( sb -- is-ufs? ) 6061.10Seeh \ The LFS magic is the first word in the superblock 6071.10Seeh dup lfs_magic l@ lfs_magic_value = if 6081.10Seeh dup lfs_version l@ case ( sb sel ) 6091.10Seeh 1 of init-lfs-v1 drop true exit endof 6101.10Seeh 2 of init-lfs-v2 drop true exit endof 6111.10Seeh ." Invalid LFS version." \ Try FFS. 6121.10Seeh endcase 6131.10Seeh then ( sb ) 6141.10Seeh \ The FFS magic is at the end of the superblock 6151.11Seeh \ XXX we should check to make sure this is not an alternate SB. 6161.10Seeh fs_magic l@ case 6171.10Seeh fs1_magic_value of init-ffs-v1 true endof 6181.10Seeh fs2_magic_value of init-ffs-v2 true endof 6191.10Seeh false swap \ Return false 6201.10Seeh endcase 6211.10Seeh; 6221.1Smrg 6231.1Smrg 6241.1Smrg 6251.1Smrg\ 6261.1Smrg\ Hunt for directory entry: 6271.1Smrg\ 6281.1Smrg\ repeat 6291.1Smrg\ load a buffer 6301.1Smrg\ while entries do 6311.1Smrg\ if entry == name return 6321.1Smrg\ next entry 6331.1Smrg\ until no buffers 6341.1Smrg\ 6351.1Smrg 6361.10Seeh: search-dir-block ( str len buf len -- ino | 0 ) 6371.10Seeh 2dup + nip ( str len buf bufend ) 6381.10Seeh swap 2swap rot ( bufend str len direct ) 6391.10Seeh begin dup 4 pick < while ( bufend str len direct ) 6401.10Seeh dup d_ino l@ 0<> if ( bufend str len direct ) 6411.10Seeh boot-debug? if 6421.10Seeh \ Print the current file name 6431.10Seeh dup dup d_name swap d_namlen c@ type cr 6441.10Seeh then 6451.10Seeh 2dup d_namlen c@ = if ( bufend str len direct ) 6461.10Seeh dup d_name 2over ( bufend str len direct dname str len ) 6471.10Seeh comp 0= if ( bufend str len direct ) 6481.10Seeh \ Found it -- return inode 6491.10Seeh d_ino l@ nip nip nip ( dino ) 6501.10Seeh boot-debug? if ." Found it" cr then 6511.10Seeh exit ( dino ) 6521.10Seeh then 6531.10Seeh then ( bufend str len direct ) 6541.10Seeh then ( bufend str len direct ) 6551.10Seeh dup d_reclen w@ + ( bufend str len nextdirect ) 6561.10Seeh repeat 6571.10Seeh 2drop 2drop 0 6581.10Seeh; 6591.10Seeh 6601.10Seeh 6611.10Seeh: search-directory ( str len -- ino | 0 ) 6621.10Seeh 0 to file-offset 6631.10Seeh begin 6641.10Seeh file-offset cur-inode di-size d@ drop < 6651.10Seeh while ( str len ) 6661.10Seeh \ Read a directory block 6671.10Seeh sb-buf buf-read-file ( str len buf len ) 6681.10Seeh dup 0= if ." search-directory: buf-read-file zero len" cr abort then 6691.10Seeh dup file-offset + to file-offset ( str len buf len ) 6701.10Seeh 6711.10Seeh 2over 2swap search-dir-block ?dup if 6721.10Seeh \ Found it 6731.10Seeh nip nip exit 6741.10Seeh then ( str len ) 6751.10Seeh repeat 6761.10Seeh 2drop 2drop 0 ( 0 ) 6771.1Smrg; 6781.1Smrg 6791.3Seeh: read-super ( sector -- ) 6801.10Seeh 0 " seek" boot-ihandle $call-method -1 = if 6811.10Seeh ." Seek failed" cr abort 6821.1Smrg then 6831.1Smrg sb-buf sbsize " read" boot-ihandle $call-method 6841.1Smrg dup sbsize <> if 6851.1Smrg ." Read of superblock failed" cr 6861.1Smrg ." requested" space sbsize . 6871.1Smrg ." actual" space . cr 6881.1Smrg abort 6891.1Smrg else 6901.1Smrg drop 6911.1Smrg then 6921.3Seeh; 6931.3Seeh 6941.11Seeh: check-supers ( -- found? ) 6951.11Seeh \ Superblocks used to be 8KB into the partition, but ffsv2 changed that. 6961.11Seeh \ See comments in src/sys/ufs/ffs/fs.h 6971.11Seeh \ Put a list of offets to check on the stack, ending with -1 6981.11Seeh -1 6991.11Seeh 0 7001.11Seeh d# 128 KB 7011.11Seeh d# 64 KB 7021.11Seeh 8 KB 7031.11Seeh 7041.11Seeh begin dup -1 <> while ( -1 .. off ) 7051.11Seeh raid-offset dev_bsize * + read-super ( -1 .. ) 7061.11Seeh sb-buf fs-magic? if ( -1 .. ) 7071.11Seeh begin -1 = until \ Clean out extra stuff from stack 7081.11Seeh true exit 7091.11Seeh then 7101.11Seeh repeat 7111.11Seeh drop false 7121.11Seeh; 7131.11Seeh 7141.10Seeh: ufs-open ( bootpath len -- ) 7151.3Seeh boot-ihandle -1 = if 7161.10Seeh 2dup + 0 swap c! \ Nul terminate. 7171.10Seeh over cif-open dup 0= if ( boot-path len ihandle? ) 7181.10Seeh ." Could not open device" space type cr 7191.10Seeh abort 7201.3Seeh then ( boot-path len ihandle ) 7211.10Seeh to boot-ihandle \ Save ihandle to boot device 7221.10Seeh then 7231.10Seeh 2drop 7241.10Seeh 7251.10Seeh boot-debug? if ." Try a RAID superblock read" cr then 7261.11Seeh \ RAIDFRAME skips 64 sectors. 7271.11Seeh d# 64 to raid-offset 7281.11Seeh check-supers invert if 7291.10Seeh boot-debug? if ." Try a normal superblock read" cr then 7301.10Seeh 0 to raid-offset 7311.11Seeh check-supers 0= abort" Invalid superblock magic" 7321.1Smrg then 7331.10Seeh sb-buf fs-bsize l@ dup maxbsize > if 7341.1Smrg ." Superblock bsize" space . ." too large" cr 7351.1Smrg abort 7361.1Smrg then 7371.10Seeh dup fs-size < if 7381.1Smrg ." Superblock bsize < size of superblock" cr 7391.1Smrg abort 7401.1Smrg then 7411.10Seeh dup to cur-blocksize alloc-mem to cur-block \ Allocate cur-block 7421.10Seeh boot-debug? if ." ufs-open complete" cr then 7431.1Smrg; 7441.1Smrg 7451.1Smrg: ufs-close ( -- ) 7461.10Seeh boot-ihandle dup -1 <> if 7471.10Seeh cif-close -1 to boot-ihandle 7481.10Seeh then 7491.10Seeh cur-block 0<> if 7501.10Seeh cur-block cur-blocksize free-mem 7511.10Seeh then 7521.1Smrg; 7531.1Smrg 7541.1Smrg: boot-path ( -- boot-path ) 7551.10Seeh " bootpath" chosen-phandle get-package-property if 7561.10Seeh ." Could not find bootpath in /chosen" cr 7571.10Seeh abort 7581.10Seeh else 7591.10Seeh decode-string 2swap 2drop 7601.10Seeh then 7611.1Smrg; 7621.1Smrg 7631.1Smrg: boot-args ( -- boot-args ) 7641.10Seeh " bootargs" chosen-phandle get-package-property if 7651.10Seeh ." Could not find bootargs in /chosen" cr 7661.10Seeh abort 7671.10Seeh else 7681.10Seeh decode-string 2swap 2drop 7691.10Seeh then 7701.1Smrg; 7711.1Smrg 7721.1Smrg2000 buffer: boot-path-str 7731.1Smrg2000 buffer: boot-path-tmp 7741.1Smrg 7751.1Smrg: split-path ( path len -- right len left len ) 7761.1Smrg\ Split a string at the `/' 7771.10Seeh begin 7781.10Seeh dup -rot ( oldlen right len left ) 7791.10Seeh ascii / left-parse-string ( oldlen right len left len ) 7801.10Seeh dup 0<> if 4 roll drop exit then 7811.10Seeh 2drop ( oldlen right len ) 7821.10Seeh rot over = ( right len diff ) 7831.10Seeh until 7841.1Smrg; 7851.1Smrg 7861.1Smrg: find-file ( load-file len -- ) 7871.10Seeh rootino dup sb-buf read-inode ( load-file len pino ) 7881.10Seeh -rot ( pino load-file len ) 7891.10Seeh \ 7901.10Seeh \ For each path component 7911.10Seeh \ 7921.10Seeh begin split-path dup 0<> while ( pino right len left len ) 7931.10Seeh cur-inode is-dir? not if ." Inode not directory" cr abort then 7941.10Seeh boot-debug? if ." Looking for" space 2dup type space ." in directory..." cr then 7951.10Seeh search-directory ( pino right len ino|false ) 7961.10Seeh dup 0= abort" Bad path" ( pino right len cino ) 7971.10Seeh sb-buf read-inode ( pino right len ) 7981.10Seeh cur-inode is-symlink? if \ Symlink -- follow the damn thing 7991.10Seeh \ Save path in boot-path-tmp 8001.10Seeh boot-path-tmp strmov ( pino new-right len ) 8011.10Seeh 8021.10Seeh \ Now deal with symlink XXX drop high word of linklen 8031.10Seeh cur-inode di-size d@ drop ( pino right len linklen.lo ) 8041.10Seeh dup sb-buf fs_maxsymlinklen l@ ( pino right len linklen linklen maxlinklen ) 8051.10Seeh < if \ Now join the link to the path 8061.10Seeh 0 cur-inode di-db@ drop ( pino right len linklen linkp ) 8071.10Seeh swap boot-path-str strmov ( pino right len new-linkp linklen ) 8081.10Seeh else \ Read file for symlink -- Ugh 8091.10Seeh \ Read link into boot-path-str 8101.10Seeh boot-path-str dup sb-buf fs-bsize l@ 8111.10Seeh 0 block-map ( pino right len linklen boot-path-str bsize blockno.lo blockno.hi ) 8121.10Seeh strategy drop swap ( pino right len boot-path-str linklen ) 8131.10Seeh then ( pino right len linkp linklen ) 8141.10Seeh \ Concatenate the two paths 8151.10Seeh strcat ( pino new-right newlen ) 8161.10Seeh swap dup c@ ascii / = if \ go to root inode? 8171.10Seeh rot drop rootino -rot ( rino len right ) 8181.10Seeh then 8191.10Seeh rot dup sb-buf read-inode ( len right pino ) 8201.10Seeh -rot swap ( pino right len ) 8211.10Seeh then ( pino right len ) 8221.10Seeh repeat 8231.10Seeh 2drop drop 8241.10Seeh; 8251.10Seeh 8261.10Seeh: .read-file-msg ( addr xxx siz -- addr xxx siz ) 8271.10Seeh boot-debug? if 8281.10Seeh ." Copying " dup . ." bytes to " 3 pick . cr 8291.10Seeh then 8301.10Seeh; 8311.10Seeh 8321.10Seeh: read-file ( addr size -- ) 8331.10Seeh noop \ In case we need to debug this 8341.10Seeh \ Read x bytes from a file to buffer 8351.10Seeh begin dup 0> while 8361.10Seeh file-offset cur-inode di-size d@ drop > if 8371.10Seeh ." read-file EOF exceeded" cr abort 8381.10Seeh then 8391.10Seeh sb-buf buf-read-file ( addr size buf len ) 8401.10Seeh 8411.10Seeh .read-file-msg 8421.10Seeh 8431.10Seeh \ Copy len bytes to addr XXX min ( len, size ) ? 8441.10Seeh 2over drop 3dup swap move drop ( addr size buf len ) 8451.10Seeh 8461.10Seeh dup file-offset + to file-offset ( addr size buf len ) 8471.10Seeh 8481.10Seeh nip tuck - -rot + swap ( addr' size' ) 8491.10Seeh repeat 8501.10Seeh 2drop 8511.1Smrg; 8521.1Smrg 8531.10Seeh" load-base " evaluate constant loader-base 8541.1Smrg 8551.1Smrg: load-file-signon ( load-file len boot-path len -- load-file len boot-path len ) 8561.1Smrg ." Loading file" space 2over type cr ." from device" space 2dup type cr 8571.1Smrg; 8581.1Smrg 8591.1Smrg: load-file ( load-file len boot-path len -- load-base ) 8601.10Seeh boot-debug? if load-file-signon then 8611.10Seeh 8621.10Seeh ufs-open ( load-file len ) 8631.10Seeh find-file ( ) 8641.1Smrg 8651.10Seeh \ 8661.10Seeh \ Now we've found the file we should read it in in one big hunk 8671.10Seeh \ 8681.10Seeh 8691.10Seeh cur-inode di-size d@ if ." File len >2GB!" cr abort then 8701.10Seeh\ dup " to file-size " evaluate ( file-len ) \ Wassthis? 8711.10Seeh boot-debug? if 8721.10Seeh ." Loading " dup . ." bytes of file..." cr 8731.10Seeh then 8741.10Seeh 0 to file-offset 8751.10Seeh -1 to file-blockno 8761.10Seeh loader-base ( buf-len addr ) 8771.10Seeh tuck swap read-file ( addr ) 8781.10Seeh ufs-close ( addr ) 8791.1Smrg; 8801.1Smrg 8811.1Smrg: do-boot ( bootfile -- ) 8821.11Seeh ." NetBSD IEEE 1275 Multi-FS Bootblock" cr 8831.11Seeh ." Version $NetBSD: bootblk.fth,v 1.11 2010/02/17 15:49:19 eeh Exp $" cr 8841.11Seeh boot-path load-file ( -- load-base ) 8851.11Seeh dup 0<> if " init-program " evaluate then 8861.10Seeh; 8871.1Smrg 8881.1Smrg 8891.10Seehboot-args ascii V strchr 0<> swap drop if 8901.10Seeh true to boot-debug? 8911.1Smrgthen 8921.1Smrg 8931.10Seehboot-args ascii D strchr 0= swap drop if 8941.10Seeh " /ofwboot" do-boot 8951.10Seehthen exit 8961.1Smrg 8971.1Smrg 898