bootblk.fth revision 1.10
1\	$NetBSD: bootblk.fth,v 1.10 2010/02/13 23:38:17 eeh Exp $
2\
3\	IEEE 1275 Open Firmware Boot Block
4\
5\	Parses disklabel and UFS and loads the file called `ofwboot'
6\
7\
8\	Copyright (c) 1998-2010 Eduardo Horvath.
9\	All rights reserved.
10\
11\	Redistribution and use in source and binary forms, with or without
12\	modification, are permitted provided that the following conditions
13\	are met:
14\	1. Redistributions of source code must retain the above copyright
15\	   notice, this list of conditions and the following disclaimer.
16\	2. Redistributions in binary form must reproduce the above copyright
17\	   notice, this list of conditions and the following disclaimer in the
18\	   documentation and/or other materials provided with the distribution.
19\
20\	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21\	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22\	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23\	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24\	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25\	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26\	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27\	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28\	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29\	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30\
31
32offset16
33hex
34headers
35
36false value boot-debug?
37
38\
39\ First some housekeeping:  Open /chosen and set up vectors into
40\	client-services
41
42" /chosen" find-package 0=  if ." Cannot find /chosen" 0 then
43constant chosen-phandle
44
45" /openprom/client-services" find-package 0=  if 
46	." Cannot find client-services" cr abort
47then constant cif-phandle
48
49defer cif-claim ( align size virt -- base )
50defer cif-release ( size virt -- )
51defer cif-open ( cstr -- ihandle|0 )
52defer cif-close ( ihandle -- )
53defer cif-read ( len adr ihandle -- #read )
54defer cif-seek ( low high ihandle -- -1|0|1 )
55\ defer cif-peer ( phandle -- phandle )
56\ defer cif-getprop ( len adr cstr phandle -- )
57
58: find-cif-method ( method len -- xf )
59   cif-phandle find-method drop 
60;
61
62" claim" find-cif-method  to  cif-claim
63" open" find-cif-method  to  cif-open
64" close" find-cif-method  to  cif-close
65" read" find-cif-method  to  cif-read
66" seek" find-cif-method  to  cif-seek
67
68: twiddle ( -- ) ." ." ; \ Need to do this right.  Just spit out periods for now.
69
70\
71\ Support routines
72\
73
74\ 64-bit math support
75
76here h# ffff over l! <w@ constant little-endian?
77: ul>d ( l -- d.lo d.hi )	0 ;
78: l>d ( l -- d.lo d.hi )	dup 0<  if  -1  else  0  then ;
79: d>l ( d.lo d.hi -- l )	drop ;
80: d@ ( addr -- d.lo d.hi )	dup l@ swap la1+ l@ little-endian? invert  if  swap  then ;
81: d! ( d.lo d.hi addr -- )
82   little-endian? invert  if  -rot swap rot  then  tuck la1+ l! l! ;
83: d-and ( d1 d2 -- d1-and-d2 )  rot and -rot and swap ;
84: d*u ( d1 u -- d2 )		tuck um* drop -rot um* rot + ;
85: d<< ( d1 n -- d1<<n )	\ Hope this works
86   tuck <<			( d.lo n d.hi' )
87   -rot 2dup <<			( d.hi' d.lo n d.lo' )
88   -rot d# 32 swap - >>		( d.hi' d.lo' lo.hi )
89   rot +
90;
91: d>> ( d1 n -- d1>>n )	\ Hope this works
92   rot over >>	-rot		( d.lo' d.hi n )
93   2dup >> -rot			( d.lo' d.hi' d.hi n )
94   d# 32 swap - << rot + swap
95;
96: d> ( d1 d2 -- d1>d2? )
97   rot swap 2dup = if
98      2drop > exit
99   then
100   > nip nip
101;
102: d>= ( d1 d2 -- d1>=d2? )
103   rot swap 2dup =  if
104      2drop >= exit
105   then
106   >= nip nip
107;
108: d< ( d1 d2 -- d1<d2? )	d>= invert ;
109: d= ( d1 d2 -- d1=d2? )	rot = -rot = and ;
110: d<> ( d1 d2 -- d1<>d2? )	d= invert ;
111
112
113\ String support 
114
115: strcmp ( s1 l1 s2 l2 -- true:false )
116   rot tuck <>  if  3drop false exit  then
117   comp 0=
118;
119
120\ Move string into buffer
121
122: strmov ( s1 l1 d -- d l1 )
123   dup 2over swap -rot		( s1 l1 d s1 d l1 )
124   move				( s1 l1 d )
125   rot drop swap
126;
127
128\ Move s1 on the end of s2 and return the result
129
130: strcat ( s1 l1 s2 l2 -- d tot )
131   2over swap 				( s1 l1 s2 l2 l1 s1 )
132   2over + rot				( s1 l1 s2 l2 s1 d l1 )
133   move rot + 				( s1 s2 len )
134   rot drop				( s2 len )
135;
136
137: strchr ( s1 l1 c -- s2 l2 )
138   begin
139      dup 2over 0= if			( s1 l1 c c s1  )
140         2drop drop exit then
141      c@ = if				( s1 l1 c )
142         drop exit then
143      -rot /c - swap ca1+		( c l2 s2 )
144     swap rot
145  again
146;
147
148   
149: cstr ( ptr -- str len )
150   dup 
151   begin dup c@ 0<>  while + repeat
152   over -
153;
154
155\
156\ BSD UFS parameters
157\
158
159fload	ffs.fth.h
160fload   lfs.fth.h
161
162sbsize buffer: sb-buf
163-1 value boot-ihandle
164dev_bsize value bsize
1650 value raid-offset	\ Offset if it's a raid-frame partition
166
167: strategy ( addr size db.lo db.hi -- nread )
168    raid-offset l>d d+			( addr size db.lo' db.hi' )
169    bsize d*u				( addr size sector.lo sector.hi )
170    " seek" boot-ihandle $call-method -1 = if 
171	." strategy: Seek failed" cr
172	abort
173    then				( addr size )
174    " read" boot-ihandle $call-method
175;
176
177
178\
179\ Multi-FS support
180\
181\ XXX Maybe the different filesystems should be segregated into separate files
182\ XXX that are individually fload-ed.
183\
184
185defer fs-size
186defer di-size
187defer di-mode
188defer /dino
189defer cgstart
190defer di-db@
191defer di-ib@
192defer ib-ib@
193defer fs-bsize
194defer fsbtodb
195defer blksize
196defer lblkno
197defer blkoff
198defer read-inode
199\ LFS ifile
200defer /ifile
201defer if_daddr
202
203\
204\ FFS Cylinder group macros
205\
206
207: cgdmin ( cg fs -- d-1st-data-block )	dup fs_dblkno l@ l>d 2swap cgstart d+ ;
208: cgimin ( cg fs -- d-inode-block )	dup fs_iblkno l@ l>d 2swap cgstart d+ ;
209: cgsblock ( cg fs -- d-super-block )	dup fs_sblkno l@ l>d 2swap cgstart d+ ;
210: cgstod ( cg fs -- d-cg-block )	dup fs_cblkno l@ l>d 2swap cgstart d+ ;
211
212\
213\ FFS Block and frag position macros
214\
215
216: ffs-blkoff ( pos.lo pos.hi fs -- off.lo off.hi )	fs_qbmask d@ d-and ;
217\ : ffs-fragoff ( pos.lo pos.hi fs -- off.lo off.hi )	fs_qfmask d@ d-and ;
218\ : ffs-lblktosize ( blk fs -- off.lo off.hi )		0 fs_bshift l@ d<< ;
219: ffs-lblkno ( pos.lo pos.hi fs -- off.lo off.hi )	fs_bshift l@ d>> ;
220: ffs-numfrags ( pos.lo pos.hi fs -- off.lo off.hi )	fs_fshift l@ d>> ;
221: ffs-blkroundup ( pos.lo pos.hi fs -- off.lo off.hi )
222    >r r@ fs_qbmask d@ d+ r> fs_bmask l@ l>d d-and
223;
224: ffs-fragroundup ( pos.lo pos.hi fs -- off.lo off.hi )
225    >r r@ fs_qfmask d@ d+ r> fs_fmask l@ l>d d-and
226;
227: ffs-fragstoblks ( pos.lo pos.hi fs -- off.lo off.hi )	fs_fragshift l@ d>> ;
228: ffs-blkstofrags ( blk fs -- frag )			fs_fragshift l@ << ;
229\ : ffs-fragnum ( fsb fs -- off )			fs_frag l@ 1- and ;
230\ : ffs-blknum ( fsb fs -- off )			fs_frag l@ 1- not and ;
231: ffs-dblksize ( lbn.lo lbn.hi inodep fs -- size )
232   >r -rot 2dup ndaddr l>d d>		( inop d-lbn >ndaddr? )
233   -rot 1 0 d+				( inop >ndaddr? d-lbn+1 )
234   r@ fs_bshift l@ d<<			( inop >ndaddr? d-lbn+1<<bshift )
235   2swap >r di-size d@			( d-lbn+1<<bshift d-size )
236   2swap 2over d< r> or  if		( d-size )
237	2drop r> fs-bsize l@ exit
238    then
239    r@ ffs-blkoff			( size.lo size.hi )
240    r> ffs-fragroundup d>l		( size )
241;
242
243: ino-to-cg ( ino fs -- cg )		fs_ipg l@ / ;
244: ino-to-fsbo ( ino fs -- fsb0 )	fs_inopb l@ mod ;
245: ino-to-fsba ( ino fs -- ba.lo ba.hi )	\ Need to remove the stupid stack diags someday
246   2dup 				( ino fs ino fs )
247   ino-to-cg				( ino fs cg )
248   over					( ino fs cg fs )
249   cgimin				( ino fs inode-blk.lo inode-blk.hi )
250   2swap				( d-inode-blk ino fs )
251   tuck 				( d-inode-blk fs ino fs )
252   fs_ipg l@ 				( d-inode-blk fs ino ipg )
253   mod					( d-inode-blk fs mod )
254   swap					( d-inode-blk mod fs )
255   dup 					( d-inode-blk mod fs fs )
256   fs_inopb l@ 				( d-inode-blk mod fs inopb )
257   rot 					( d-inode-blk fs inopb mod )
258   swap					( d-inode-blk fs mod inopb )
259   /					( d-inode-blk fs div )
260   swap					( d-inode-blk div fs )
261   ffs-blkstofrags			( d-inode-blk frag )
262   0 d+
263;
264: ffs-fsbtodb ( fsb.lo fsb.hi fs -- db.lo db.hi )
265    fs_fsbtodb l@ d<<
266;
267
268
269\
270\ LFS suff
271\
272: lfs-blkoff ( pos.lo pos.hi fs -- off.lo off.hi )	lfs_bmask d@ d-and ;
273\ : lfs-fragoff ( pos.lo pos.hi fs -- off.lo off.hi )	lfs_ffmask d@ d-and ;
274\ : lfs-lblktosize ( blk fs -- off.lo off.hi )		0 lfs_bshift l@ d<< ;
275: lfs-lblkno ( pos.lo pos.hi fs -- off.lo off.hi )	lfs_bshift l@ d>> ;
276: lfs-numfrags ( pos.lo pos.hi fs -- off.lo off.hi )	lfs_ffshift l@ d>> ;
277: lfs-roundup ( pos.lo pos.hi mask.lo mask.hi )
278   2swap 2over d+ 2swap			( d-pos* d-mask )
279   invert swap invert swap d-and
280;
281: lfs-blkroundup ( pos.lo pos.hi fs -- off.lo off.hi )	lfs_bmask d@ lfs-roundup ;
282: lfs-fragroundup ( pos.lo pos.hi fs -- off.lo off.hi )	lfs_ffmask d@ lfs-roundup ;
283: lfs-fragstoblks ( pos.lo pos.hi fs -- off.lo off.hi )	lfs_fbshift l@ d>> ;
284: lfs-dblksize ( lbn.lo lbn.hi inodep fs -- size )
285   >r -rot 2dup ndaddr l>d d>		( inop d-lbn >ndaddr? )
286   -rot 1 0 d+				( inop >ndaddr? d-lbn+1 )
287   r@ fs_bshift l@ d<<			( inop >ndaddr? d-lbn+1<<bshift )
288   2swap >r di-size d@			( d-lbn+1<<bshift d-size )
289   2swap 2over d< r> or  if		( d-size )
290      2drop r> fs-bsize l@ exit
291   then
292   r@ lfs-blkoff			( size.lo size.hi )
293   r> lfs-fragroundup d>l		( size )
294;
295: lfs-fsbtodb ( fsb.lo fsb.hi fs -- db.lo db.hi )
296    lfs_fsbtodb l@ d<<
297;
298
299\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
300\
301\ The rest of the multi-filesystem stuff
302\
303\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
304
305\
306\ FFS v1
307\
308: di-db-v1@ ( indx dinode -- db.lo db.hi )	di1_db swap la+ l@ l>d ;
309: di-ib-v1@ ( indx dinode -- db.lo db.hi )	di1_ib swap la+ l@ l>d ;
310: ib-ib-v1@ ( indx iblk -- db.lo db.hi )	swap la+ l@ l>d ;
311
312: cgbase ( cg fs -- daddr.lo daddr.hi ) fs_fpg l@ um* ;
313: cgstart-ufs1 ( cg fs -- cgstart ) 
314    2dup fs_old_cgmask l@ invert and		( cg fs stuff )
315    over fs_old_cgoffset l@ um*			( cg fs off.lo off.hi )
316    2swap cgbase d+				( off.lo off.hi )
317;
318
319\
320\ FFS v2
321\
322
323: di-db-v2@ ( indx dinode -- db.lo db.hi )	di2_db swap 2* la+ d@ ;
324: di-ib-v2@ ( indx dinode -- db.lo db.hi )	di2_ib swap 2* la+ d@ ;
325: ib-ib-v2@ ( indx iblk -- db.lo db.hi )	2* la+ d@ ;
326
327\
328\ LFS v1
329\
330
331
332\
333\ File stuff
334\
335
336niaddr /w* constant narraysize
337
338\ Assume UFS2 dinodes are always biger than UFS1
339ufs2_dinode_SIZEOF buffer: cur-inode
340h# 2000 buffer: indir-block
341create indir-addr -1 , -1 ,
342
343\
344\ Translate a fileblock to a disk block
345\
346\ We don't do triple indirect blocks.
347\
348
349\ Get the disk address from a single indirect block
350: ib@ ( indx indir.lo indir.hi -- db.lo db.hi )
351    2dup indir-addr d@ d<>  if		( indx indir.hi indir.lo )
352	indir-addr d!			( indx )
353	indir-block 			( indx indir-block )
354	sb-buf fs-bsize l@		( indx indir-block fs fs-bsize )
355	indir-addr d@ sb-buf		( indx indir-block fs-bsize indiraddr fs )
356	fsbtodb 			( indx indir-block fs-bsize db.lo db.hi )
357	strategy 0			( indx nread 0 ) \ Really should check return value
358    then
359    2drop				( indx )
360    indir-block ib-ib@
361;
362
363
364: block-map ( fileblock -- diskblock.lo diskblock.hi )
365    \ Direct block?
366    dup ndaddr <  if			( fileblock )
367	cur-inode di-db@ exit		( diskblock.lo diskblock.hi )
368    then 				( fileblock )
369    ndaddr -				( fileblock' )
370    \ Now we need to check the indirect block
371    dup sb-buf fs_nindir l@ <  if	( fileblock' )
372	0 cur-inode di-ib@		( fileblock' indir.lo indir.hi )
373	ib@ exit			( db.lo db.hi )
374   then
375   dup sb-buf fs_nindir -		( fileblock'' )
376   \ Now try 2nd level indirect block -- just read twice 
377   dup sb-buf fs_nindir l@ dup * >= if	( fileblock'' )
378       ." block-map: exceeded max file size" cr
379       abort
380   then
381       
382   1 cur-inode di-ib@		( fileblock'' ib.lo ib.hi )
383   
384   \ Get 1st indirect block and find the 2nd indirect block
385   rot dup sb-buf fs_nindir u/mod	( ib2.lo ib2.hi indx2 indx1 )
386   2swap ib@			( indx2 ib2.lo ib2.hi )
387   
388   \ Get 2nd indirect block and find our diskblock
389   ib@				( db.lo db.hi )
390;
391
392\
393\ Read file into internal buffer and return pointer and len
394\
395
3960 value cur-block			\ allocated dynamically in ufs-open
3970 value cur-blocksize			\ size allocated  to  cur-block
398create cur-blockno -1 l, -1 l,		\ Current disk block.
399-1 value file-blockno			\ Current file block no.
4000 value file-offset			\ Current file offset, max 4GB.
401
402: buf-read-file ( fs -- buf len )
403    >r file-offset			( seek )
404    dup l>d r@ lblkno drop		( seek blk )
405    dup l>d cur-inode r@ blksize	( seek blk blksize )
406    over file-blockno <> if		( seek blk blksize )
407	over  to  file-blockno
408	swap block-map			( seek blksize fsblk.lo fsblk.hi )
409	2dup or 0=  if			( seek blksize fsblk.lo fsblk.hi )
410	    \ Clear out curblock  XXX Why? Idunno.
411	    2drop dup
412	    cur-block swap erase	( seek blksize )
413	    boot-debug?  if ." buf-read-file reading block 0" cr then
414	    -1 l>d			\ Invalid disk block
415	else
416	    \ Call strategy to load the correct block.
417	    r@ fsbtodb			( seek blksize dblk.lo dblk.hi )
418	    rot >r cur-block r@ 2over	( seek addr size db.lo db.hi )
419	    strategy r@	<>  if  ." buf-read-file: short read." cr abort  then
420	    r> -rot			( seek size db.lo db.hi )
421	then
422	\ Save the new current disk block number
423	cur-blockno d!			( seek size )
424   else					
425      nip				( seek size )
426   then
427   \ Now figure out how much we have in the buffer.
428   swap l>d r> blkoff			( size off.lo off.hi )
429   d>l cur-block over +			( size off buf )
430   -rot -				( buf siz )
431;
432
433\
434\ Read inode into cur-inode -- uses cur-block
435\ 
436
437: read-inode-ffs ( inode fs -- )
438    twiddle
439
440    >r dup r@ ino-to-fsba		( ino fsblk.lo fsblck.hi )
441    r@ fsbtodb				( ino dblk.lo dblk.hi )
442    2dup cur-blockno d@ d<>  if		( ino dblk.lo dblk.hi )
443	\ We need  to  read the block
444	cur-block r@ fs-bsize l@	( ino dblk.lo dblk.hi addr size )
445	>r r@ 2over strategy r> <> if	( ino dblk.lo dblk.hi )
446	    ." read-inode - residual" cr abort
447	then
448	2dup cur-blockno d!		( ino dblk.lo dblk.hi )
449    then 2drop				( ino )
450
451    r> ino-to-fsbo /dino *		( off )
452    cur-block + cur-inode /dino move	( )
453;
454
455: find-inode-sector ( ino fs -- d-dblkno true | false )
456   >r r@ lfs_ifile l@ r@  read-inode	( ino )
457
458   r@ lfs_ifpb l@ u/mod			( rem q )
459
460   r@ lfs_cleansz l@ +
461   r@ lfs_segtabsz l@ +			( rem blkno )
462
463   r@ fs-bsize l@ um* rot /ifile um* d+	( dseekp )
464
465   drop  to  file-offset r@ buf-read-file	( buf len )
466
467   /ifile <  if  r> 2drop false exit  then	( buf )
468
469   if_daddr l@ l>d r> fsbtodb		( daddr )
470   2dup lfs_unused_daddr l>d d=  if  2drop false  then
471   true
472;
473
474: read-inode-lfs ( inode fs -- )
475   twiddle
476
477   >r dup r@ lfs_ifile l@ =  if		( ino  r: fs )
478      r@ lfs_idaddr l@ l>d		( ino d-idaddr )
479      r@ fsbtodb			( ino d-db )
480   else
481      dup r@ find-inode-sector 0= abort" Could not find inode sector!"
482   then					( ino d-db )
483   
484    2dup cur-blockno d@ d<>  if		( ino dblk.lo dblk.hi )
485	\ We need to read the block
486	cur-block r@ fs-bsize l@	( ino dblk.lo dblk.hi addr size )
487	>r r@ 2over strategy r> <> if	( ino dblk.lo dblk.hi )
488	    ." read-inode - residual" cr abort
489	then
490	2dup cur-blockno d!		( ino dblk.lo dblk.hi )
491    then  2drop				( ino )
492
493    r@ lfs_inopb l@			( ino cnt )
494    swap cur-block  begin		( cnt ino p )
495       tuck di_inumber l@ over <>	( cnt p ino !found? )
496    while				( cnt p ino )
497	  rot 1- ?dup 0=  abort" Could not find inode!"
498	  rot /dino + swap -rot		( cnt ino p )
499    repeat  swap			( cnt ino p )
500
501    cur-inode /dino move		( cnt ino )
502	  
503    r> 3drop
504;
505
506\ Identify inode type
507
508: is-dir? ( ufs1_dinode -- is-dir? )		di-mode w@ ifmt and ifdir = ;
509: is-symlink? ( ufs1_dinode -- is-symlink? )	di-mode w@ ifmt and iflnk = ;
510
511\
512\ Multi-FS initialiation.
513\
514\ It's way down here so all the fs-specific routines have already been defined.
515\
516
517: init-ffs-common ( -- )
518   ' fs_SIZEOF  to  fs-size 
519   ' fs_bsize  to  fs-bsize
520   ' ffs-dblksize  to  blksize
521   ' read-inode-ffs  to  read-inode
522   ' ffs-fsbtodb  to  fsbtodb
523   ' ffs-lblkno  to  lblkno
524   ' ffs-blkoff  to   blkoff
525;   
526
527
528: ffs-oldcompat ( -- )
529   \ Make sure old ffs values in sb-buf are sane
530   sb-buf fs_old_npsect dup l@ sb-buf fs_old_nsect l@ max swap l!
531   sb-buf fs_old_interleave dup l@ 1 max swap l!
532   sb-buf fs_old_postblformat l@ fs_42postblfmt =  if
533      8 sb-buf fs_old_nrpos l!
534   then
535   sb-buf fs_old_inodefmt l@ fs_44inodefmt <  if
536      sb-buf fs-bsize l@ 
537      dup ndaddr um* 1 d- sb-buf fs_maxfilesize d!
538      niaddr 0  ?do
539	 sb-buf fs_nindir l@ * dup	( sizebp sizebp )
540	 sb-buf fs_maxfilesize dup d@ ( sizebp sizebp *mxfs mxfs.lo mxfs.hi )
541	 2over drop l>d d+ 2swap d!	( sizebp )
542      loop  drop 			( )
543      sb-buf dup fs_bmask l@ invert l>d rot fs_qbmask d!
544      sb-buf dup fs_fmask l@ invert l>d rot fs_qfmask d!
545   then
546;
547
548
549: init-ffs-v1 ( -- )
550   init-ffs-common
551   ' di1_size  to  di-size
552   ' di1_mode  to  di-mode
553   ' ufs1_dinode_SIZEOF  to  /dino
554   ' cgstart-ufs1  to  cgstart
555   ' di-db-v1@  to  di-db@
556   ' di-ib-v1@  to  di-ib@
557   ' ib-ib-v1@  to  ib-ib@
558   ffs-oldcompat
559;
560
561: init-ffs-v2 ( -- )
562   init-ffs-common
563   ' di2_size  to  di-size
564   ' di2_mode  to  di-mode
565   ' ufs2_dinode_SIZEOF  to  /dino
566   ' cgbase  to  cgstart
567   ' di-db-v2@  to  di-db@
568   ' di-ib-v2@  to  di-ib@
569   ' ib-ib-v2@  to  ib-ib@
570;
571
572: init-lfs-common ( -- )
573   ' dlfs_SIZEOF  to  fs-size 
574   ' di1_size  to  di-size
575   ' di1_mode  to  di-mode
576   ' ufs1_dinode_SIZEOF  to  /dino
577   ' cgbase  to  cgstart
578   ' di-db-v1@  to  di-db@
579   ' di-ib-v1@  to  di-ib@
580   ' ib-ib-v1@  to  ib-ib@
581   ' lfs-dblksize  to  blksize
582   ' read-inode-lfs  to  read-inode
583   ' lfs-fsbtodb  to  fsbtodb
584   ' lfs-lblkno  to  lblkno
585   ' lfs-blkoff  to  blkoff
586;
587
588: init-lfs-v1 ( -- )
589   init-lfs-common
590   ' lfs_ibsize  to  fs-bsize
591   ' ifile_v1_SIZEOF  to  /ifile
592   ' if1_daddr  to  if_daddr
593;   
594
595: init-lfs-v2 ( -- )
596   init-lfs-common
597   ' lfs_bsize  to  fs-bsize
598   ' ifile_SIZEOF  to  /ifile
599   ' if2_daddr  to  if_daddr
600;   
601
602
603: fs-magic? ( sb -- is-ufs? )
604   \ The LFS magic is the first word in the superblock
605   dup lfs_magic l@ lfs_magic_value =  if
606      dup lfs_version l@  case		( sb sel )
607	 1  of  init-lfs-v1 drop true exit  endof
608	 2  of  init-lfs-v2 drop true exit  endof
609	 ." Invalid LFS version."  \ Try FFS.
610      endcase
611   then					( sb )
612   \ The FFS magic is at the end of the superblock
613   fs_magic l@  case
614      fs1_magic_value  of  init-ffs-v1 true  endof
615      fs2_magic_value  of  init-ffs-v2 true  endof
616      false swap	\ Return false
617   endcase
618;
619
620
621
622\
623\ Hunt for directory entry:
624\ 
625\ repeat
626\    load a buffer
627\    while entries do
628\       if entry == name return
629\       next entry
630\ until no buffers
631\
632
633: search-dir-block ( str len buf len -- ino | 0 )
634    2dup + nip				( str len buf bufend )
635    swap 2swap rot			( bufend str len direct )
636    begin  dup 4 pick <  while		( bufend str len direct )
637	    dup d_ino l@ 0<>  if	( bufend str len direct )
638		boot-debug?  if
639		    \ Print the current file name
640		    dup dup d_name swap d_namlen c@ type cr
641		then
642		2dup d_namlen c@ =  if	( bufend str len direct )
643		    dup d_name 2over	( bufend str len direct dname str len )
644		    comp 0= if		( bufend str len direct )
645			\ Found it -- return inode
646			d_ino l@ nip nip nip	( dino )
647			boot-debug?  if  ." Found it" cr  then 
648			exit 		( dino )
649		    then
650		then			( bufend str len direct )
651	    then			( bufend str len direct )
652	    dup d_reclen w@ +		( bufend str len nextdirect )
653    repeat
654    2drop 2drop 0
655;
656    
657
658: search-directory ( str len -- ino | 0 )
659    0  to  file-offset
660    begin
661	file-offset cur-inode di-size d@ drop <
662    while				( str len )
663	    \ Read a directory block
664	    sb-buf buf-read-file	( str len buf len )
665	    dup 0=  if  ." search-directory: buf-read-file zero len" cr abort  then
666	    dup file-offset +  to  file-offset	( str len buf len )
667
668	    2over 2swap search-dir-block ?dup  if
669		\ Found it
670		nip nip exit
671	    then			( str len )
672    repeat
673    2drop 2drop 0			( 0 )
674;
675
676: read-super ( sector -- )
677   0 " seek" boot-ihandle $call-method -1 =  if 
678      ." Seek failed" cr abort
679   then
680   sb-buf sbsize " read" boot-ihandle $call-method
681   dup sbsize <>  if
682      ." Read of superblock failed" cr
683      ." requested" space sbsize .
684      ." actual" space . cr
685      abort
686   else 
687      drop
688   then
689;
690
691: ufs-open ( bootpath len -- )
692   boot-ihandle -1 =  if
693      2dup + 0 swap c!	\ Nul terminate.
694      over cif-open dup 0=  if 	( boot-path len ihandle? )
695	 ." Could not open device" space type cr 
696	 abort
697      then 				( boot-path len ihandle )
698      to  boot-ihandle			\ Save ihandle to boot device
699   then
700   2drop
701   
702   boot-debug?  if ." Try a RAID superblock read" cr  then
703   rf_protected dup  to  raid-offset 
704   dev_bsize * sboff + read-super
705   sb-buf fs-magic? invert  if
706      boot-debug?  if ." Try a normal superblock read" cr  then
707      0  to  raid-offset 
708      sboff read-super
709      sb-buf fs-magic? invert  abort" Invalid superblock magic"
710   then
711   sb-buf fs-bsize l@ dup maxbsize >  if
712      ." Superblock bsize" space . ." too large" cr
713      abort
714   then 
715   dup fs-size <  if
716      ." Superblock bsize < size of superblock" cr
717      abort
718   then
719   dup  to  cur-blocksize alloc-mem  to  cur-block    \ Allocate cur-block
720   boot-debug?  if  ." ufs-open complete" cr  then
721;
722
723: ufs-close ( -- ) 
724    boot-ihandle dup -1 <>  if
725	cif-close -1  to  boot-ihandle 
726    then
727    cur-block 0<> if
728	cur-block cur-blocksize free-mem
729    then
730;
731
732: boot-path ( -- boot-path )
733    " bootpath" chosen-phandle get-package-property  if
734	." Could not find bootpath in /chosen" cr
735	abort
736    else
737	decode-string 2swap 2drop
738    then
739;
740
741: boot-args ( -- boot-args )
742    " bootargs" chosen-phandle get-package-property  if
743	." Could not find bootargs in /chosen" cr
744	abort
745    else
746	decode-string 2swap 2drop
747    then
748;
749
7502000 buffer: boot-path-str
7512000 buffer: boot-path-tmp
752
753: split-path ( path len -- right len left len )
754\ Split a string at the `/'
755    begin
756	dup -rot				( oldlen right len left )
757	ascii / left-parse-string		( oldlen right len left len )
758	dup 0<>  if  4 roll drop exit  then
759	2drop					( oldlen right len )
760	rot over =				( right len diff )
761    until
762;
763
764: find-file ( load-file len -- )
765    rootino dup sb-buf read-inode	( load-file len pino )
766    -rot				( pino load-file len )
767    \
768    \ For each path component
769    \ 
770    begin  split-path dup 0<>  while	( pino right len left len )
771	    cur-inode is-dir? not  if  ." Inode not directory" cr abort  then
772	    boot-debug?  if  ." Looking for" space 2dup type space ." in directory..." cr  then
773	    search-directory		( pino right len ino|false )
774	    dup 0=  abort" Bad path" 	( pino right len cino )
775	    sb-buf read-inode			( pino right len )
776	    cur-inode is-symlink?  if		\ Symlink -- follow the damn thing
777		\ Save path in boot-path-tmp
778		boot-path-tmp strmov		( pino new-right len )
779		
780		\ Now deal with symlink  XXX drop high word of linklen
781		cur-inode di-size d@ drop	( pino right len linklen.lo )
782		dup sb-buf fs_maxsymlinklen l@	( pino right len linklen linklen maxlinklen )
783		<  if				\ Now join the link to the path
784		    0 cur-inode di-db@ drop	( pino right len linklen linkp )
785		    swap boot-path-str strmov	( pino right len new-linkp linklen )
786		else				\ Read file for symlink -- Ugh
787		    \ Read link into boot-path-str
788		    boot-path-str dup sb-buf fs-bsize l@
789		    0 block-map			( pino right len linklen boot-path-str bsize blockno.lo blockno.hi )
790		    strategy drop swap		( pino right len boot-path-str linklen )
791		then 				( pino right len linkp linklen )
792		\ Concatenate the two paths
793		strcat				( pino new-right newlen )
794		swap dup c@ ascii / =  if	\ go to root inode?
795		    rot drop rootino -rot	( rino len right )
796		then
797		rot dup sb-buf read-inode	( len right pino )
798		-rot swap			( pino right len )
799	    then				( pino right len )
800    repeat
801    2drop drop
802;
803
804: .read-file-msg ( addr xxx siz -- addr xxx siz )
805    boot-debug? if
806	." Copying " dup . ." bytes to " 3 pick . cr
807    then
808;
809       
810: read-file ( addr size -- )
811    noop \ In case we need to debug this
812    \ Read x bytes from a file to buffer
813    begin  dup 0>  while
814	    file-offset cur-inode di-size d@ drop >  if
815		." read-file EOF exceeded" cr abort
816	    then
817	    sb-buf buf-read-file		( addr size buf len )
818	    
819	    .read-file-msg
820	    
821	    \ Copy len bytes to addr  XXX min ( len, size ) ?
822	    2over drop 3dup swap move drop	( addr size buf len )
823	    
824	    dup file-offset +  to  file-offset	( addr size buf len )
825	    
826	    nip tuck - -rot + swap		( addr' size' )
827    repeat
828    2drop
829;
830
831" load-base " evaluate constant loader-base
832
833: load-file-signon ( load-file len boot-path len -- load-file len boot-path len )
834   ." Loading file" space 2over type cr ." from device" space 2dup type cr
835;
836
837: load-file ( load-file len boot-path len -- load-base )
838   boot-debug?  if  load-file-signon  then
839   
840   ufs-open 				( load-file len )
841   find-file				( )
842
843    \
844    \ Now we've found the file we should read it in in one big hunk
845    \
846    
847    cur-inode di-size d@  if  ." File len >2GB!" cr abort  then
848\    dup " to file-size " evaluate	( file-len ) \ Wassthis?
849    boot-debug?  if
850	." Loading " dup . ."  bytes of file..." cr
851    then
852    0  to  file-offset
853    -1  to  file-blockno
854    loader-base				( buf-len addr )
855    tuck swap read-file			( addr )
856    ufs-close				( addr )
857;
858
859: do-boot ( bootfile -- )
860    ." NetBSD IEEE 1275 Multi-FS Bootblock" cr
861    boot-path load-file ( -- load-base )
862    dup 0<>  if  " init-program " evaluate  then
863; 
864
865
866boot-args ascii V strchr 0<> swap drop  if
867    true  to  boot-debug?
868then
869
870boot-args ascii D strchr 0= swap drop  if
871    " /ofwboot" do-boot
872then  exit
873
874
875