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