bootblk.fth revision 1.10
11.10Seeh\	$NetBSD: bootblk.fth,v 1.10 2010/02/13 23:38:17 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.1Smrg\
391.1Smrg\ First some housekeeping:  Open /chosen and set up vectors into
401.1Smrg\	client-services
411.1Smrg
421.1Smrg" /chosen" find-package 0=  if ." Cannot find /chosen" 0 then
431.1Smrgconstant chosen-phandle
441.1Smrg
451.1Smrg" /openprom/client-services" find-package 0=  if 
461.1Smrg	." Cannot find client-services" cr abort
471.1Smrgthen constant cif-phandle
481.1Smrg
491.1Smrgdefer cif-claim ( align size virt -- base )
501.1Smrgdefer cif-release ( size virt -- )
511.1Smrgdefer cif-open ( cstr -- ihandle|0 )
521.1Smrgdefer cif-close ( ihandle -- )
531.1Smrgdefer cif-read ( len adr ihandle -- #read )
541.1Smrgdefer cif-seek ( low high ihandle -- -1|0|1 )
551.1Smrg\ defer cif-peer ( phandle -- phandle )
561.1Smrg\ defer cif-getprop ( len adr cstr phandle -- )
571.1Smrg
581.10Seeh: find-cif-method ( method len -- xf )
591.1Smrg   cif-phandle find-method drop 
601.1Smrg;
611.1Smrg
621.10Seeh" claim" find-cif-method  to  cif-claim
631.10Seeh" open" find-cif-method  to  cif-open
641.10Seeh" close" find-cif-method  to  cif-close
651.10Seeh" read" find-cif-method  to  cif-read
661.10Seeh" seek" find-cif-method  to  cif-seek
671.1Smrg
681.1Smrg: twiddle ( -- ) ." ." ; \ Need to do this right.  Just spit out periods for now.
691.1Smrg
701.1Smrg\
711.1Smrg\ Support routines
721.1Smrg\
731.1Smrg
741.10Seeh\ 64-bit math support
751.10Seeh
761.10Seehhere h# ffff over l! <w@ constant little-endian?
771.10Seeh: ul>d ( l -- d.lo d.hi )	0 ;
781.10Seeh: l>d ( l -- d.lo d.hi )	dup 0<  if  -1  else  0  then ;
791.10Seeh: d>l ( d.lo d.hi -- l )	drop ;
801.10Seeh: d@ ( addr -- d.lo d.hi )	dup l@ swap la1+ l@ little-endian? invert  if  swap  then ;
811.10Seeh: d! ( d.lo d.hi addr -- )
821.10Seeh   little-endian? invert  if  -rot swap rot  then  tuck la1+ l! l! ;
831.10Seeh: d-and ( d1 d2 -- d1-and-d2 )  rot and -rot and swap ;
841.10Seeh: d*u ( d1 u -- d2 )		tuck um* drop -rot um* rot + ;
851.10Seeh: d<< ( d1 n -- d1<<n )	\ Hope this works
861.10Seeh   tuck <<			( d.lo n d.hi' )
871.10Seeh   -rot 2dup <<			( d.hi' d.lo n d.lo' )
881.10Seeh   -rot d# 32 swap - >>		( d.hi' d.lo' lo.hi )
891.10Seeh   rot +
901.10Seeh;
911.10Seeh: d>> ( d1 n -- d1>>n )	\ Hope this works
921.10Seeh   rot over >>	-rot		( d.lo' d.hi n )
931.10Seeh   2dup >> -rot			( d.lo' d.hi' d.hi n )
941.10Seeh   d# 32 swap - << rot + swap
951.10Seeh;
961.10Seeh: d> ( d1 d2 -- d1>d2? )
971.10Seeh   rot swap 2dup = if
981.10Seeh      2drop > exit
991.10Seeh   then
1001.10Seeh   > nip nip
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? )	d>= invert ;
1091.10Seeh: d= ( d1 d2 -- d1=d2? )	rot = -rot = and ;
1101.10Seeh: d<> ( d1 d2 -- d1<>d2? )	d= invert ;
1111.10Seeh
1121.10Seeh
1131.10Seeh\ String support 
1141.10Seeh
1151.1Smrg: strcmp ( s1 l1 s2 l2 -- true:false )
1161.10Seeh   rot tuck <>  if  3drop false exit  then
1171.1Smrg   comp 0=
1181.1Smrg;
1191.1Smrg
1201.1Smrg\ Move string into buffer
1211.1Smrg
1221.1Smrg: strmov ( s1 l1 d -- d l1 )
1231.1Smrg   dup 2over swap -rot		( s1 l1 d s1 d l1 )
1241.1Smrg   move				( s1 l1 d )
1251.1Smrg   rot drop swap
1261.1Smrg;
1271.1Smrg
1281.1Smrg\ Move s1 on the end of s2 and return the result
1291.1Smrg
1301.1Smrg: strcat ( s1 l1 s2 l2 -- d tot )
1311.1Smrg   2over swap 				( s1 l1 s2 l2 l1 s1 )
1321.1Smrg   2over + rot				( s1 l1 s2 l2 s1 d l1 )
1331.1Smrg   move rot + 				( s1 s2 len )
1341.1Smrg   rot drop				( s2 len )
1351.1Smrg;
1361.1Smrg
1371.1Smrg: strchr ( s1 l1 c -- s2 l2 )
1381.1Smrg   begin
1391.1Smrg      dup 2over 0= if			( s1 l1 c c s1  )
1401.1Smrg         2drop drop exit then
1411.1Smrg      c@ = if				( s1 l1 c )
1421.1Smrg         drop exit then
1431.1Smrg      -rot /c - swap ca1+		( c l2 s2 )
1441.1Smrg     swap rot
1451.1Smrg  again
1461.1Smrg;
1471.1Smrg
1481.1Smrg   
1491.1Smrg: cstr ( ptr -- str len )
1501.1Smrg   dup 
1511.1Smrg   begin dup c@ 0<>  while + repeat
1521.1Smrg   over -
1531.1Smrg;
1541.1Smrg
1551.1Smrg\
1561.10Seeh\ BSD UFS parameters
1571.1Smrg\
1581.1Smrg
1591.10Seehfload	ffs.fth.h
1601.10Seehfload   lfs.fth.h
1611.1Smrg
1621.1Smrgsbsize buffer: sb-buf
1631.1Smrg-1 value boot-ihandle
1641.1Smrgdev_bsize value bsize
1651.3Seeh0 value raid-offset	\ Offset if it's a raid-frame partition
1661.1Smrg
1671.10Seeh: strategy ( addr size db.lo db.hi -- nread )
1681.10Seeh    raid-offset l>d d+			( addr size db.lo' db.hi' )
1691.10Seeh    bsize d*u				( addr size sector.lo sector.hi )
1701.10Seeh    " seek" boot-ihandle $call-method -1 = if 
1711.10Seeh	." strategy: Seek failed" cr
1721.10Seeh	abort
1731.10Seeh    then				( addr size )
1741.10Seeh    " read" boot-ihandle $call-method
1751.10Seeh;
1761.10Seeh
1771.10Seeh
1781.10Seeh\
1791.10Seeh\ Multi-FS support
1801.10Seeh\
1811.10Seeh\ XXX Maybe the different filesystems should be segregated into separate files
1821.10Seeh\ XXX that are individually fload-ed.
1831.10Seeh\
1841.10Seeh
1851.10Seehdefer fs-size
1861.10Seehdefer di-size
1871.10Seehdefer di-mode
1881.10Seehdefer /dino
1891.10Seehdefer cgstart
1901.10Seehdefer di-db@
1911.10Seehdefer di-ib@
1921.10Seehdefer ib-ib@
1931.10Seehdefer fs-bsize
1941.10Seehdefer fsbtodb
1951.10Seehdefer blksize
1961.10Seehdefer lblkno
1971.10Seehdefer blkoff
1981.10Seehdefer read-inode
1991.10Seeh\ LFS ifile
2001.10Seehdefer /ifile
2011.10Seehdefer if_daddr
2021.10Seeh
2031.10Seeh\
2041.10Seeh\ FFS Cylinder group macros
2051.10Seeh\
2061.10Seeh
2071.10Seeh: cgdmin ( cg fs -- d-1st-data-block )	dup fs_dblkno l@ l>d 2swap cgstart d+ ;
2081.10Seeh: cgimin ( cg fs -- d-inode-block )	dup fs_iblkno l@ l>d 2swap cgstart d+ ;
2091.10Seeh: cgsblock ( cg fs -- d-super-block )	dup fs_sblkno l@ l>d 2swap cgstart d+ ;
2101.10Seeh: cgstod ( cg fs -- d-cg-block )	dup fs_cblkno l@ l>d 2swap cgstart d+ ;
2111.10Seeh
2121.10Seeh\
2131.10Seeh\ FFS Block and frag position macros
2141.10Seeh\
2151.10Seeh
2161.10Seeh: ffs-blkoff ( pos.lo pos.hi fs -- off.lo off.hi )	fs_qbmask d@ d-and ;
2171.10Seeh\ : ffs-fragoff ( pos.lo pos.hi fs -- off.lo off.hi )	fs_qfmask d@ d-and ;
2181.10Seeh\ : ffs-lblktosize ( blk fs -- off.lo off.hi )		0 fs_bshift l@ d<< ;
2191.10Seeh: ffs-lblkno ( pos.lo pos.hi fs -- off.lo off.hi )	fs_bshift l@ d>> ;
2201.10Seeh: ffs-numfrags ( pos.lo pos.hi fs -- off.lo off.hi )	fs_fshift l@ d>> ;
2211.10Seeh: ffs-blkroundup ( pos.lo pos.hi fs -- off.lo off.hi )
2221.10Seeh    >r r@ fs_qbmask d@ d+ r> fs_bmask l@ l>d d-and
2231.10Seeh;
2241.10Seeh: ffs-fragroundup ( pos.lo pos.hi fs -- off.lo off.hi )
2251.10Seeh    >r r@ fs_qfmask d@ d+ r> fs_fmask l@ l>d d-and
2261.10Seeh;
2271.10Seeh: ffs-fragstoblks ( pos.lo pos.hi fs -- off.lo off.hi )	fs_fragshift l@ d>> ;
2281.10Seeh: ffs-blkstofrags ( blk fs -- frag )			fs_fragshift l@ << ;
2291.10Seeh\ : ffs-fragnum ( fsb fs -- off )			fs_frag l@ 1- and ;
2301.10Seeh\ : ffs-blknum ( fsb fs -- off )			fs_frag l@ 1- not and ;
2311.10Seeh: ffs-dblksize ( lbn.lo lbn.hi inodep fs -- size )
2321.10Seeh   >r -rot 2dup ndaddr l>d d>		( inop d-lbn >ndaddr? )
2331.10Seeh   -rot 1 0 d+				( inop >ndaddr? d-lbn+1 )
2341.10Seeh   r@ fs_bshift l@ d<<			( inop >ndaddr? d-lbn+1<<bshift )
2351.10Seeh   2swap >r di-size d@			( d-lbn+1<<bshift d-size )
2361.10Seeh   2swap 2over d< r> or  if		( d-size )
2371.10Seeh	2drop r> fs-bsize l@ exit
2381.10Seeh    then
2391.10Seeh    r@ ffs-blkoff			( size.lo size.hi )
2401.10Seeh    r> ffs-fragroundup d>l		( size )
2411.10Seeh;
2421.10Seeh
2431.10Seeh: ino-to-cg ( ino fs -- cg )		fs_ipg l@ / ;
2441.10Seeh: ino-to-fsbo ( ino fs -- fsb0 )	fs_inopb l@ mod ;
2451.10Seeh: ino-to-fsba ( ino fs -- ba.lo ba.hi )	\ Need to remove the stupid stack diags someday
2461.10Seeh   2dup 				( ino fs ino fs )
2471.10Seeh   ino-to-cg				( ino fs cg )
2481.10Seeh   over					( ino fs cg fs )
2491.10Seeh   cgimin				( ino fs inode-blk.lo inode-blk.hi )
2501.10Seeh   2swap				( d-inode-blk ino fs )
2511.10Seeh   tuck 				( d-inode-blk fs ino fs )
2521.10Seeh   fs_ipg l@ 				( d-inode-blk fs ino ipg )
2531.10Seeh   mod					( d-inode-blk fs mod )
2541.10Seeh   swap					( d-inode-blk mod fs )
2551.10Seeh   dup 					( d-inode-blk mod fs fs )
2561.10Seeh   fs_inopb l@ 				( d-inode-blk mod fs inopb )
2571.10Seeh   rot 					( d-inode-blk fs inopb mod )
2581.10Seeh   swap					( d-inode-blk fs mod inopb )
2591.10Seeh   /					( d-inode-blk fs div )
2601.10Seeh   swap					( d-inode-blk div fs )
2611.10Seeh   ffs-blkstofrags			( d-inode-blk frag )
2621.10Seeh   0 d+
2631.10Seeh;
2641.10Seeh: ffs-fsbtodb ( fsb.lo fsb.hi fs -- db.lo db.hi )
2651.10Seeh    fs_fsbtodb l@ d<<
2661.10Seeh;
2671.10Seeh
2681.10Seeh
2691.10Seeh\
2701.10Seeh\ LFS suff
2711.10Seeh\
2721.10Seeh: lfs-blkoff ( pos.lo pos.hi fs -- off.lo off.hi )	lfs_bmask d@ d-and ;
2731.10Seeh\ : lfs-fragoff ( pos.lo pos.hi fs -- off.lo off.hi )	lfs_ffmask d@ d-and ;
2741.10Seeh\ : lfs-lblktosize ( blk fs -- off.lo off.hi )		0 lfs_bshift l@ d<< ;
2751.10Seeh: lfs-lblkno ( pos.lo pos.hi fs -- off.lo off.hi )	lfs_bshift l@ d>> ;
2761.10Seeh: lfs-numfrags ( pos.lo pos.hi fs -- off.lo off.hi )	lfs_ffshift l@ d>> ;
2771.10Seeh: lfs-roundup ( pos.lo pos.hi mask.lo mask.hi )
2781.10Seeh   2swap 2over d+ 2swap			( d-pos* d-mask )
2791.10Seeh   invert swap invert swap d-and
2801.10Seeh;
2811.10Seeh: lfs-blkroundup ( pos.lo pos.hi fs -- off.lo off.hi )	lfs_bmask d@ lfs-roundup ;
2821.10Seeh: lfs-fragroundup ( pos.lo pos.hi fs -- off.lo off.hi )	lfs_ffmask d@ lfs-roundup ;
2831.10Seeh: lfs-fragstoblks ( pos.lo pos.hi fs -- off.lo off.hi )	lfs_fbshift l@ d>> ;
2841.10Seeh: lfs-dblksize ( lbn.lo lbn.hi inodep fs -- size )
2851.10Seeh   >r -rot 2dup ndaddr l>d d>		( inop d-lbn >ndaddr? )
2861.10Seeh   -rot 1 0 d+				( inop >ndaddr? d-lbn+1 )
2871.10Seeh   r@ fs_bshift l@ d<<			( inop >ndaddr? d-lbn+1<<bshift )
2881.10Seeh   2swap >r di-size d@			( d-lbn+1<<bshift d-size )
2891.10Seeh   2swap 2over d< r> or  if		( d-size )
2901.10Seeh      2drop r> fs-bsize l@ exit
2911.1Smrg   then
2921.10Seeh   r@ lfs-blkoff			( size.lo size.hi )
2931.10Seeh   r> lfs-fragroundup d>l		( size )
2941.10Seeh;
2951.10Seeh: lfs-fsbtodb ( fsb.lo fsb.hi fs -- db.lo db.hi )
2961.10Seeh    lfs_fsbtodb l@ d<<
2971.1Smrg;
2981.1Smrg
2991.10Seeh\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
3001.1Smrg\
3011.10Seeh\ The rest of the multi-filesystem stuff
3021.1Smrg\
3031.10Seeh\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
3041.1Smrg
3051.10Seeh\
3061.10Seeh\ FFS v1
3071.10Seeh\
3081.10Seeh: di-db-v1@ ( indx dinode -- db.lo db.hi )	di1_db swap la+ l@ l>d ;
3091.10Seeh: di-ib-v1@ ( indx dinode -- db.lo db.hi )	di1_ib swap la+ l@ l>d ;
3101.10Seeh: ib-ib-v1@ ( indx iblk -- db.lo db.hi )	swap la+ l@ l>d ;
3111.10Seeh
3121.10Seeh: cgbase ( cg fs -- daddr.lo daddr.hi ) fs_fpg l@ um* ;
3131.10Seeh: cgstart-ufs1 ( cg fs -- cgstart ) 
3141.10Seeh    2dup fs_old_cgmask l@ invert and		( cg fs stuff )
3151.10Seeh    over fs_old_cgoffset l@ um*			( cg fs off.lo off.hi )
3161.10Seeh    2swap cgbase d+				( off.lo off.hi )
3171.1Smrg;
3181.1Smrg
3191.1Smrg\
3201.10Seeh\ FFS v2
3211.1Smrg\
3221.1Smrg
3231.10Seeh: di-db-v2@ ( indx dinode -- db.lo db.hi )	di2_db swap 2* la+ d@ ;
3241.10Seeh: di-ib-v2@ ( indx dinode -- db.lo db.hi )	di2_ib swap 2* la+ d@ ;
3251.10Seeh: ib-ib-v2@ ( indx iblk -- db.lo db.hi )	2* la+ d@ ;
3261.1Smrg
3271.10Seeh\
3281.10Seeh\ LFS v1
3291.10Seeh\
3301.1Smrg
3311.1Smrg
3321.1Smrg\
3331.1Smrg\ File stuff
3341.1Smrg\
3351.1Smrg
3361.1Smrgniaddr /w* constant narraysize
3371.1Smrg
3381.10Seeh\ Assume UFS2 dinodes are always biger than UFS1
3391.10Seehufs2_dinode_SIZEOF buffer: cur-inode
3401.1Smrgh# 2000 buffer: indir-block
3411.10Seehcreate indir-addr -1 , -1 ,
3421.1Smrg
3431.1Smrg\
3441.1Smrg\ Translate a fileblock to a disk block
3451.1Smrg\
3461.10Seeh\ We don't do triple indirect blocks.
3471.1Smrg\
3481.1Smrg
3491.10Seeh\ Get the disk address from a single indirect block
3501.10Seeh: ib@ ( indx indir.lo indir.hi -- db.lo db.hi )
3511.10Seeh    2dup indir-addr d@ d<>  if		( indx indir.hi indir.lo )
3521.10Seeh	indir-addr d!			( indx )
3531.10Seeh	indir-block 			( indx indir-block )
3541.10Seeh	sb-buf fs-bsize l@		( indx indir-block fs fs-bsize )
3551.10Seeh	indir-addr d@ sb-buf		( indx indir-block fs-bsize indiraddr fs )
3561.10Seeh	fsbtodb 			( indx indir-block fs-bsize db.lo db.hi )
3571.10Seeh	strategy 0			( indx nread 0 ) \ Really should check return value
3581.10Seeh    then
3591.10Seeh    2drop				( indx )
3601.10Seeh    indir-block ib-ib@
3611.10Seeh;
3621.10Seeh
3631.10Seeh
3641.10Seeh: block-map ( fileblock -- diskblock.lo diskblock.hi )
3651.10Seeh    \ Direct block?
3661.10Seeh    dup ndaddr <  if			( fileblock )
3671.10Seeh	cur-inode di-db@ exit		( diskblock.lo diskblock.hi )
3681.10Seeh    then 				( fileblock )
3691.10Seeh    ndaddr -				( fileblock' )
3701.10Seeh    \ Now we need to check the indirect block
3711.10Seeh    dup sb-buf fs_nindir l@ <  if	( fileblock' )
3721.10Seeh	0 cur-inode di-ib@		( fileblock' indir.lo indir.hi )
3731.10Seeh	ib@ exit			( db.lo db.hi )
3741.1Smrg   then
3751.1Smrg   dup sb-buf fs_nindir -		( fileblock'' )
3761.1Smrg   \ Now try 2nd level indirect block -- just read twice 
3771.10Seeh   dup sb-buf fs_nindir l@ dup * >= if	( fileblock'' )
3781.10Seeh       ." block-map: exceeded max file size" cr
3791.10Seeh       abort
3801.1Smrg   then
3811.10Seeh       
3821.10Seeh   1 cur-inode di-ib@		( fileblock'' ib.lo ib.hi )
3831.10Seeh   
3841.10Seeh   \ Get 1st indirect block and find the 2nd indirect block
3851.10Seeh   rot dup sb-buf fs_nindir u/mod	( ib2.lo ib2.hi indx2 indx1 )
3861.10Seeh   2swap ib@			( indx2 ib2.lo ib2.hi )
3871.10Seeh   
3881.10Seeh   \ Get 2nd indirect block and find our diskblock
3891.10Seeh   ib@				( db.lo db.hi )
3901.1Smrg;
3911.1Smrg
3921.1Smrg\
3931.1Smrg\ Read file into internal buffer and return pointer and len
3941.1Smrg\
3951.1Smrg
3961.4Seeh0 value cur-block			\ allocated dynamically in ufs-open
3971.10Seeh0 value cur-blocksize			\ size allocated  to  cur-block
3981.10Seehcreate cur-blockno -1 l, -1 l,		\ Current disk block.
3991.10Seeh-1 value file-blockno			\ Current file block no.
4001.10Seeh0 value file-offset			\ Current file offset, max 4GB.
4011.10Seeh
4021.10Seeh: buf-read-file ( fs -- buf len )
4031.10Seeh    >r file-offset			( seek )
4041.10Seeh    dup l>d r@ lblkno drop		( seek blk )
4051.10Seeh    dup l>d cur-inode r@ blksize	( seek blk blksize )
4061.10Seeh    over file-blockno <> if		( seek blk blksize )
4071.10Seeh	over  to  file-blockno
4081.10Seeh	swap block-map			( seek blksize fsblk.lo fsblk.hi )
4091.10Seeh	2dup or 0=  if			( seek blksize fsblk.lo fsblk.hi )
4101.10Seeh	    \ Clear out curblock  XXX Why? Idunno.
4111.10Seeh	    2drop dup
4121.10Seeh	    cur-block swap erase	( seek blksize )
4131.10Seeh	    boot-debug?  if ." buf-read-file reading block 0" cr then
4141.10Seeh	    -1 l>d			\ Invalid disk block
4151.10Seeh	else
4161.10Seeh	    \ Call strategy to load the correct block.
4171.10Seeh	    r@ fsbtodb			( seek blksize dblk.lo dblk.hi )
4181.10Seeh	    rot >r cur-block r@ 2over	( seek addr size db.lo db.hi )
4191.10Seeh	    strategy r@	<>  if  ." buf-read-file: short read." cr abort  then
4201.10Seeh	    r> -rot			( seek size db.lo db.hi )
4211.10Seeh	then
4221.10Seeh	\ Save the new current disk block number
4231.10Seeh	cur-blockno d!			( seek size )
4241.10Seeh   else					
4251.10Seeh      nip				( seek size )
4261.10Seeh   then
4271.10Seeh   \ Now figure out how much we have in the buffer.
4281.10Seeh   swap l>d r> blkoff			( size off.lo off.hi )
4291.10Seeh   d>l cur-block over +			( size off buf )
4301.10Seeh   -rot -				( buf siz )
4311.1Smrg;
4321.1Smrg
4331.1Smrg\
4341.1Smrg\ Read inode into cur-inode -- uses cur-block
4351.1Smrg\ 
4361.1Smrg
4371.10Seeh: read-inode-ffs ( inode fs -- )
4381.10Seeh    twiddle
4391.10Seeh
4401.10Seeh    >r dup r@ ino-to-fsba		( ino fsblk.lo fsblck.hi )
4411.10Seeh    r@ fsbtodb				( ino dblk.lo dblk.hi )
4421.10Seeh    2dup cur-blockno d@ d<>  if		( ino dblk.lo dblk.hi )
4431.10Seeh	\ We need  to  read the block
4441.10Seeh	cur-block r@ fs-bsize l@	( ino dblk.lo dblk.hi addr size )
4451.10Seeh	>r r@ 2over strategy r> <> if	( ino dblk.lo dblk.hi )
4461.10Seeh	    ." read-inode - residual" cr abort
4471.10Seeh	then
4481.10Seeh	2dup cur-blockno d!		( ino dblk.lo dblk.hi )
4491.10Seeh    then 2drop				( ino )
4501.1Smrg
4511.10Seeh    r> ino-to-fsbo /dino *		( off )
4521.10Seeh    cur-block + cur-inode /dino move	( )
4531.10Seeh;
4541.10Seeh
4551.10Seeh: find-inode-sector ( ino fs -- d-dblkno true | false )
4561.10Seeh   >r r@ lfs_ifile l@ r@  read-inode	( ino )
4571.10Seeh
4581.10Seeh   r@ lfs_ifpb l@ u/mod			( rem q )
4591.10Seeh
4601.10Seeh   r@ lfs_cleansz l@ +
4611.10Seeh   r@ lfs_segtabsz l@ +			( rem blkno )
4621.1Smrg
4631.10Seeh   r@ fs-bsize l@ um* rot /ifile um* d+	( dseekp )
4641.1Smrg
4651.10Seeh   drop  to  file-offset r@ buf-read-file	( buf len )
4661.10Seeh
4671.10Seeh   /ifile <  if  r> 2drop false exit  then	( buf )
4681.10Seeh
4691.10Seeh   if_daddr l@ l>d r> fsbtodb		( daddr )
4701.10Seeh   2dup lfs_unused_daddr l>d d=  if  2drop false  then
4711.10Seeh   true
4721.10Seeh;
4731.10Seeh
4741.10Seeh: read-inode-lfs ( inode fs -- )
4751.10Seeh   twiddle
4761.10Seeh
4771.10Seeh   >r dup r@ lfs_ifile l@ =  if		( ino  r: fs )
4781.10Seeh      r@ lfs_idaddr l@ l>d		( ino d-idaddr )
4791.10Seeh      r@ fsbtodb			( ino d-db )
4801.10Seeh   else
4811.10Seeh      dup r@ find-inode-sector 0= abort" Could not find inode sector!"
4821.10Seeh   then					( ino d-db )
4831.10Seeh   
4841.10Seeh    2dup cur-blockno d@ d<>  if		( ino dblk.lo dblk.hi )
4851.10Seeh	\ We need to read the block
4861.10Seeh	cur-block r@ fs-bsize l@	( ino dblk.lo dblk.hi addr size )
4871.10Seeh	>r r@ 2over strategy r> <> if	( ino dblk.lo dblk.hi )
4881.10Seeh	    ." read-inode - residual" cr abort
4891.10Seeh	then
4901.10Seeh	2dup cur-blockno d!		( ino dblk.lo dblk.hi )
4911.10Seeh    then  2drop				( ino )
4921.10Seeh
4931.10Seeh    r@ lfs_inopb l@			( ino cnt )
4941.10Seeh    swap cur-block  begin		( cnt ino p )
4951.10Seeh       tuck di_inumber l@ over <>	( cnt p ino !found? )
4961.10Seeh    while				( cnt p ino )
4971.10Seeh	  rot 1- ?dup 0=  abort" Could not find inode!"
4981.10Seeh	  rot /dino + swap -rot		( cnt ino p )
4991.10Seeh    repeat  swap			( cnt ino p )
5001.10Seeh
5011.10Seeh    cur-inode /dino move		( cnt ino )
5021.10Seeh	  
5031.10Seeh    r> 3drop
5041.1Smrg;
5051.1Smrg
5061.1Smrg\ Identify inode type
5071.1Smrg
5081.10Seeh: is-dir? ( ufs1_dinode -- is-dir? )		di-mode w@ ifmt and ifdir = ;
5091.10Seeh: is-symlink? ( ufs1_dinode -- is-symlink? )	di-mode w@ ifmt and iflnk = ;
5101.10Seeh
5111.10Seeh\
5121.10Seeh\ Multi-FS initialiation.
5131.10Seeh\
5141.10Seeh\ It's way down here so all the fs-specific routines have already been defined.
5151.10Seeh\
5161.10Seeh
5171.10Seeh: init-ffs-common ( -- )
5181.10Seeh   ' fs_SIZEOF  to  fs-size 
5191.10Seeh   ' fs_bsize  to  fs-bsize
5201.10Seeh   ' ffs-dblksize  to  blksize
5211.10Seeh   ' read-inode-ffs  to  read-inode
5221.10Seeh   ' ffs-fsbtodb  to  fsbtodb
5231.10Seeh   ' ffs-lblkno  to  lblkno
5241.10Seeh   ' ffs-blkoff  to   blkoff
5251.10Seeh;   
5261.10Seeh
5271.10Seeh
5281.10Seeh: ffs-oldcompat ( -- )
5291.10Seeh   \ Make sure old ffs values in sb-buf are sane
5301.10Seeh   sb-buf fs_old_npsect dup l@ sb-buf fs_old_nsect l@ max swap l!
5311.10Seeh   sb-buf fs_old_interleave dup l@ 1 max swap l!
5321.10Seeh   sb-buf fs_old_postblformat l@ fs_42postblfmt =  if
5331.10Seeh      8 sb-buf fs_old_nrpos l!
5341.10Seeh   then
5351.10Seeh   sb-buf fs_old_inodefmt l@ fs_44inodefmt <  if
5361.10Seeh      sb-buf fs-bsize l@ 
5371.10Seeh      dup ndaddr um* 1 d- sb-buf fs_maxfilesize d!
5381.10Seeh      niaddr 0  ?do
5391.10Seeh	 sb-buf fs_nindir l@ * dup	( sizebp sizebp )
5401.10Seeh	 sb-buf fs_maxfilesize dup d@ ( sizebp sizebp *mxfs mxfs.lo mxfs.hi )
5411.10Seeh	 2over drop l>d d+ 2swap d!	( sizebp )
5421.10Seeh      loop  drop 			( )
5431.10Seeh      sb-buf dup fs_bmask l@ invert l>d rot fs_qbmask d!
5441.10Seeh      sb-buf dup fs_fmask l@ invert l>d rot fs_qfmask d!
5451.10Seeh   then
5461.10Seeh;
5471.10Seeh
5481.10Seeh
5491.10Seeh: init-ffs-v1 ( -- )
5501.10Seeh   init-ffs-common
5511.10Seeh   ' di1_size  to  di-size
5521.10Seeh   ' di1_mode  to  di-mode
5531.10Seeh   ' ufs1_dinode_SIZEOF  to  /dino
5541.10Seeh   ' cgstart-ufs1  to  cgstart
5551.10Seeh   ' di-db-v1@  to  di-db@
5561.10Seeh   ' di-ib-v1@  to  di-ib@
5571.10Seeh   ' ib-ib-v1@  to  ib-ib@
5581.10Seeh   ffs-oldcompat
5591.10Seeh;
5601.10Seeh
5611.10Seeh: init-ffs-v2 ( -- )
5621.10Seeh   init-ffs-common
5631.10Seeh   ' di2_size  to  di-size
5641.10Seeh   ' di2_mode  to  di-mode
5651.10Seeh   ' ufs2_dinode_SIZEOF  to  /dino
5661.10Seeh   ' cgbase  to  cgstart
5671.10Seeh   ' di-db-v2@  to  di-db@
5681.10Seeh   ' di-ib-v2@  to  di-ib@
5691.10Seeh   ' ib-ib-v2@  to  ib-ib@
5701.10Seeh;
5711.10Seeh
5721.10Seeh: init-lfs-common ( -- )
5731.10Seeh   ' dlfs_SIZEOF  to  fs-size 
5741.10Seeh   ' di1_size  to  di-size
5751.10Seeh   ' di1_mode  to  di-mode
5761.10Seeh   ' ufs1_dinode_SIZEOF  to  /dino
5771.10Seeh   ' cgbase  to  cgstart
5781.10Seeh   ' di-db-v1@  to  di-db@
5791.10Seeh   ' di-ib-v1@  to  di-ib@
5801.10Seeh   ' ib-ib-v1@  to  ib-ib@
5811.10Seeh   ' lfs-dblksize  to  blksize
5821.10Seeh   ' read-inode-lfs  to  read-inode
5831.10Seeh   ' lfs-fsbtodb  to  fsbtodb
5841.10Seeh   ' lfs-lblkno  to  lblkno
5851.10Seeh   ' lfs-blkoff  to  blkoff
5861.10Seeh;
5871.10Seeh
5881.10Seeh: init-lfs-v1 ( -- )
5891.10Seeh   init-lfs-common
5901.10Seeh   ' lfs_ibsize  to  fs-bsize
5911.10Seeh   ' ifile_v1_SIZEOF  to  /ifile
5921.10Seeh   ' if1_daddr  to  if_daddr
5931.10Seeh;   
5941.10Seeh
5951.10Seeh: init-lfs-v2 ( -- )
5961.10Seeh   init-lfs-common
5971.10Seeh   ' lfs_bsize  to  fs-bsize
5981.10Seeh   ' ifile_SIZEOF  to  /ifile
5991.10Seeh   ' if2_daddr  to  if_daddr
6001.10Seeh;   
6011.10Seeh
6021.10Seeh
6031.10Seeh: fs-magic? ( sb -- is-ufs? )
6041.10Seeh   \ The LFS magic is the first word in the superblock
6051.10Seeh   dup lfs_magic l@ lfs_magic_value =  if
6061.10Seeh      dup lfs_version l@  case		( sb sel )
6071.10Seeh	 1  of  init-lfs-v1 drop true exit  endof
6081.10Seeh	 2  of  init-lfs-v2 drop true exit  endof
6091.10Seeh	 ." Invalid LFS version."  \ Try FFS.
6101.10Seeh      endcase
6111.10Seeh   then					( sb )
6121.10Seeh   \ The FFS magic is at the end of the superblock
6131.10Seeh   fs_magic l@  case
6141.10Seeh      fs1_magic_value  of  init-ffs-v1 true  endof
6151.10Seeh      fs2_magic_value  of  init-ffs-v2 true  endof
6161.10Seeh      false swap	\ Return false
6171.10Seeh   endcase
6181.10Seeh;
6191.1Smrg
6201.1Smrg
6211.1Smrg
6221.1Smrg\
6231.1Smrg\ Hunt for directory entry:
6241.1Smrg\ 
6251.1Smrg\ repeat
6261.1Smrg\    load a buffer
6271.1Smrg\    while entries do
6281.1Smrg\       if entry == name return
6291.1Smrg\       next entry
6301.1Smrg\ until no buffers
6311.1Smrg\
6321.1Smrg
6331.10Seeh: search-dir-block ( str len buf len -- ino | 0 )
6341.10Seeh    2dup + nip				( str len buf bufend )
6351.10Seeh    swap 2swap rot			( bufend str len direct )
6361.10Seeh    begin  dup 4 pick <  while		( bufend str len direct )
6371.10Seeh	    dup d_ino l@ 0<>  if	( bufend str len direct )
6381.10Seeh		boot-debug?  if
6391.10Seeh		    \ Print the current file name
6401.10Seeh		    dup dup d_name swap d_namlen c@ type cr
6411.10Seeh		then
6421.10Seeh		2dup d_namlen c@ =  if	( bufend str len direct )
6431.10Seeh		    dup d_name 2over	( bufend str len direct dname str len )
6441.10Seeh		    comp 0= if		( bufend str len direct )
6451.10Seeh			\ Found it -- return inode
6461.10Seeh			d_ino l@ nip nip nip	( dino )
6471.10Seeh			boot-debug?  if  ." Found it" cr  then 
6481.10Seeh			exit 		( dino )
6491.10Seeh		    then
6501.10Seeh		then			( bufend str len direct )
6511.10Seeh	    then			( bufend str len direct )
6521.10Seeh	    dup d_reclen w@ +		( bufend str len nextdirect )
6531.10Seeh    repeat
6541.10Seeh    2drop 2drop 0
6551.10Seeh;
6561.10Seeh    
6571.10Seeh
6581.10Seeh: search-directory ( str len -- ino | 0 )
6591.10Seeh    0  to  file-offset
6601.10Seeh    begin
6611.10Seeh	file-offset cur-inode di-size d@ drop <
6621.10Seeh    while				( str len )
6631.10Seeh	    \ Read a directory block
6641.10Seeh	    sb-buf buf-read-file	( str len buf len )
6651.10Seeh	    dup 0=  if  ." search-directory: buf-read-file zero len" cr abort  then
6661.10Seeh	    dup file-offset +  to  file-offset	( str len buf len )
6671.10Seeh
6681.10Seeh	    2over 2swap search-dir-block ?dup  if
6691.10Seeh		\ Found it
6701.10Seeh		nip nip exit
6711.10Seeh	    then			( str len )
6721.10Seeh    repeat
6731.10Seeh    2drop 2drop 0			( 0 )
6741.1Smrg;
6751.1Smrg
6761.3Seeh: read-super ( sector -- )
6771.10Seeh   0 " seek" boot-ihandle $call-method -1 =  if 
6781.10Seeh      ." Seek failed" cr abort
6791.1Smrg   then
6801.1Smrg   sb-buf sbsize " read" boot-ihandle $call-method
6811.1Smrg   dup sbsize <>  if
6821.1Smrg      ." Read of superblock failed" cr
6831.1Smrg      ." requested" space sbsize .
6841.1Smrg      ." actual" space . cr
6851.1Smrg      abort
6861.1Smrg   else 
6871.1Smrg      drop
6881.1Smrg   then
6891.3Seeh;
6901.3Seeh
6911.10Seeh: ufs-open ( bootpath len -- )
6921.3Seeh   boot-ihandle -1 =  if
6931.10Seeh      2dup + 0 swap c!	\ Nul terminate.
6941.10Seeh      over cif-open dup 0=  if 	( boot-path len ihandle? )
6951.10Seeh	 ." Could not open device" space type cr 
6961.10Seeh	 abort
6971.3Seeh      then 				( boot-path len ihandle )
6981.10Seeh      to  boot-ihandle			\ Save ihandle to boot device
6991.10Seeh   then
7001.10Seeh   2drop
7011.10Seeh   
7021.10Seeh   boot-debug?  if ." Try a RAID superblock read" cr  then
7031.10Seeh   rf_protected dup  to  raid-offset 
7041.10Seeh   dev_bsize * sboff + read-super
7051.10Seeh   sb-buf fs-magic? invert  if
7061.10Seeh      boot-debug?  if ." Try a normal superblock read" cr  then
7071.10Seeh      0  to  raid-offset 
7081.8Sjdc      sboff read-super
7091.10Seeh      sb-buf fs-magic? invert  abort" Invalid superblock magic"
7101.1Smrg   then
7111.10Seeh   sb-buf fs-bsize l@ dup maxbsize >  if
7121.1Smrg      ." Superblock bsize" space . ." too large" cr
7131.1Smrg      abort
7141.1Smrg   then 
7151.10Seeh   dup fs-size <  if
7161.1Smrg      ." Superblock bsize < size of superblock" cr
7171.1Smrg      abort
7181.1Smrg   then
7191.10Seeh   dup  to  cur-blocksize alloc-mem  to  cur-block    \ Allocate cur-block
7201.10Seeh   boot-debug?  if  ." ufs-open complete" cr  then
7211.1Smrg;
7221.1Smrg
7231.1Smrg: ufs-close ( -- ) 
7241.10Seeh    boot-ihandle dup -1 <>  if
7251.10Seeh	cif-close -1  to  boot-ihandle 
7261.10Seeh    then
7271.10Seeh    cur-block 0<> if
7281.10Seeh	cur-block cur-blocksize free-mem
7291.10Seeh    then
7301.1Smrg;
7311.1Smrg
7321.1Smrg: boot-path ( -- boot-path )
7331.10Seeh    " bootpath" chosen-phandle get-package-property  if
7341.10Seeh	." Could not find bootpath in /chosen" cr
7351.10Seeh	abort
7361.10Seeh    else
7371.10Seeh	decode-string 2swap 2drop
7381.10Seeh    then
7391.1Smrg;
7401.1Smrg
7411.1Smrg: boot-args ( -- boot-args )
7421.10Seeh    " bootargs" chosen-phandle get-package-property  if
7431.10Seeh	." Could not find bootargs in /chosen" cr
7441.10Seeh	abort
7451.10Seeh    else
7461.10Seeh	decode-string 2swap 2drop
7471.10Seeh    then
7481.1Smrg;
7491.1Smrg
7501.1Smrg2000 buffer: boot-path-str
7511.1Smrg2000 buffer: boot-path-tmp
7521.1Smrg
7531.1Smrg: split-path ( path len -- right len left len )
7541.1Smrg\ Split a string at the `/'
7551.10Seeh    begin
7561.10Seeh	dup -rot				( oldlen right len left )
7571.10Seeh	ascii / left-parse-string		( oldlen right len left len )
7581.10Seeh	dup 0<>  if  4 roll drop exit  then
7591.10Seeh	2drop					( oldlen right len )
7601.10Seeh	rot over =				( right len diff )
7611.10Seeh    until
7621.1Smrg;
7631.1Smrg
7641.1Smrg: find-file ( load-file len -- )
7651.10Seeh    rootino dup sb-buf read-inode	( load-file len pino )
7661.10Seeh    -rot				( pino load-file len )
7671.10Seeh    \
7681.10Seeh    \ For each path component
7691.10Seeh    \ 
7701.10Seeh    begin  split-path dup 0<>  while	( pino right len left len )
7711.10Seeh	    cur-inode is-dir? not  if  ." Inode not directory" cr abort  then
7721.10Seeh	    boot-debug?  if  ." Looking for" space 2dup type space ." in directory..." cr  then
7731.10Seeh	    search-directory		( pino right len ino|false )
7741.10Seeh	    dup 0=  abort" Bad path" 	( pino right len cino )
7751.10Seeh	    sb-buf read-inode			( pino right len )
7761.10Seeh	    cur-inode is-symlink?  if		\ Symlink -- follow the damn thing
7771.10Seeh		\ Save path in boot-path-tmp
7781.10Seeh		boot-path-tmp strmov		( pino new-right len )
7791.10Seeh		
7801.10Seeh		\ Now deal with symlink  XXX drop high word of linklen
7811.10Seeh		cur-inode di-size d@ drop	( pino right len linklen.lo )
7821.10Seeh		dup sb-buf fs_maxsymlinklen l@	( pino right len linklen linklen maxlinklen )
7831.10Seeh		<  if				\ Now join the link to the path
7841.10Seeh		    0 cur-inode di-db@ drop	( pino right len linklen linkp )
7851.10Seeh		    swap boot-path-str strmov	( pino right len new-linkp linklen )
7861.10Seeh		else				\ Read file for symlink -- Ugh
7871.10Seeh		    \ Read link into boot-path-str
7881.10Seeh		    boot-path-str dup sb-buf fs-bsize l@
7891.10Seeh		    0 block-map			( pino right len linklen boot-path-str bsize blockno.lo blockno.hi )
7901.10Seeh		    strategy drop swap		( pino right len boot-path-str linklen )
7911.10Seeh		then 				( pino right len linkp linklen )
7921.10Seeh		\ Concatenate the two paths
7931.10Seeh		strcat				( pino new-right newlen )
7941.10Seeh		swap dup c@ ascii / =  if	\ go to root inode?
7951.10Seeh		    rot drop rootino -rot	( rino len right )
7961.10Seeh		then
7971.10Seeh		rot dup sb-buf read-inode	( len right pino )
7981.10Seeh		-rot swap			( pino right len )
7991.10Seeh	    then				( pino right len )
8001.10Seeh    repeat
8011.10Seeh    2drop drop
8021.10Seeh;
8031.10Seeh
8041.10Seeh: .read-file-msg ( addr xxx siz -- addr xxx siz )
8051.10Seeh    boot-debug? if
8061.10Seeh	." Copying " dup . ." bytes to " 3 pick . cr
8071.10Seeh    then
8081.10Seeh;
8091.10Seeh       
8101.10Seeh: read-file ( addr size -- )
8111.10Seeh    noop \ In case we need to debug this
8121.10Seeh    \ Read x bytes from a file to buffer
8131.10Seeh    begin  dup 0>  while
8141.10Seeh	    file-offset cur-inode di-size d@ drop >  if
8151.10Seeh		." read-file EOF exceeded" cr abort
8161.10Seeh	    then
8171.10Seeh	    sb-buf buf-read-file		( addr size buf len )
8181.10Seeh	    
8191.10Seeh	    .read-file-msg
8201.10Seeh	    
8211.10Seeh	    \ Copy len bytes to addr  XXX min ( len, size ) ?
8221.10Seeh	    2over drop 3dup swap move drop	( addr size buf len )
8231.10Seeh	    
8241.10Seeh	    dup file-offset +  to  file-offset	( addr size buf len )
8251.10Seeh	    
8261.10Seeh	    nip tuck - -rot + swap		( addr' size' )
8271.10Seeh    repeat
8281.10Seeh    2drop
8291.1Smrg;
8301.1Smrg
8311.10Seeh" load-base " evaluate constant loader-base
8321.1Smrg
8331.1Smrg: load-file-signon ( load-file len boot-path len -- load-file len boot-path len )
8341.1Smrg   ." Loading file" space 2over type cr ." from device" space 2dup type cr
8351.1Smrg;
8361.1Smrg
8371.1Smrg: load-file ( load-file len boot-path len -- load-base )
8381.10Seeh   boot-debug?  if  load-file-signon  then
8391.10Seeh   
8401.10Seeh   ufs-open 				( load-file len )
8411.10Seeh   find-file				( )
8421.1Smrg
8431.10Seeh    \
8441.10Seeh    \ Now we've found the file we should read it in in one big hunk
8451.10Seeh    \
8461.10Seeh    
8471.10Seeh    cur-inode di-size d@  if  ." File len >2GB!" cr abort  then
8481.10Seeh\    dup " to file-size " evaluate	( file-len ) \ Wassthis?
8491.10Seeh    boot-debug?  if
8501.10Seeh	." Loading " dup . ."  bytes of file..." cr
8511.10Seeh    then
8521.10Seeh    0  to  file-offset
8531.10Seeh    -1  to  file-blockno
8541.10Seeh    loader-base				( buf-len addr )
8551.10Seeh    tuck swap read-file			( addr )
8561.10Seeh    ufs-close				( addr )
8571.1Smrg;
8581.1Smrg
8591.1Smrg: do-boot ( bootfile -- )
8601.10Seeh    ." NetBSD IEEE 1275 Multi-FS Bootblock" cr
8611.10Seeh    boot-path load-file ( -- load-base )
8621.10Seeh    dup 0<>  if  " init-program " evaluate  then
8631.10Seeh; 
8641.1Smrg
8651.1Smrg
8661.10Seehboot-args ascii V strchr 0<> swap drop  if
8671.10Seeh    true  to  boot-debug?
8681.1Smrgthen
8691.1Smrg
8701.10Seehboot-args ascii D strchr 0= swap drop  if
8711.10Seeh    " /ofwboot" do-boot
8721.10Seehthen  exit
8731.1Smrg
8741.1Smrg
875