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