xref: /netbsd/sys/arch/sparc/stand/bootblk/bootblk.fth (revision bf9ec67e)
1\	$NetBSD: bootblk.fth,v 1.3 2001/08/15 20:10:24 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 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\	3. All advertising materials mentioning features or use of this software
20\	   must display the following acknowledgement:
21\	     This product includes software developed by Eduardo Horvath.
22\	4. The name of the author may not be used to endorse or promote products
23\	   derived from this software without specific prior written permission
24\
25\	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26\	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27\	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28\	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29\	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30\	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31\	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32\	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33\	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34\	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35\
36
37offset16
38hex
39headers
40
41false value boot-debug?
42
43\
44\ First some housekeeping:  Open /chosen and set up vectors into
45\	client-services
46
47" /chosen" find-package 0=  if ." Cannot find /chosen" 0 then
48constant chosen-phandle
49
50" /openprom/client-services" find-package 0=  if
51	." Cannot find client-services" cr abort
52then constant cif-phandle
53
54defer cif-claim ( align size virt -- base )
55defer cif-release ( size virt -- )
56defer cif-open ( cstr -- ihandle|0 )
57defer cif-close ( ihandle -- )
58defer cif-read ( len adr ihandle -- #read )
59defer cif-seek ( low high ihandle -- -1|0|1 )
60\ defer cif-peer ( phandle -- phandle )
61\ defer cif-getprop ( len adr cstr phandle -- )
62
63: find-cif-method ( method,len -- xf )
64   cif-phandle find-method drop
65;
66
67" claim" find-cif-method to cif-claim
68" open" find-cif-method to cif-open
69" close" find-cif-method to cif-close
70" read" find-cif-method to cif-read
71" seek" find-cif-method to cif-seek
72
73: twiddle ( -- ) ." ." ; \ Need to do this right.  Just spit out periods for now.
74
75\
76\ Support routines
77\
78
79: strcmp ( s1 l1 s2 l2 -- true:false )
80   rot tuck <> if  3drop false exit then
81   comp 0=
82;
83
84\ Move string into buffer
85
86: strmov ( s1 l1 d -- d l1 )
87   dup 2over swap -rot		( s1 l1 d s1 d l1 )
88   move				( s1 l1 d )
89   rot drop swap
90;
91
92\ Move s1 on the end of s2 and return the result
93
94: strcat ( s1 l1 s2 l2 -- d tot )
95   2over swap 				( s1 l1 s2 l2 l1 s1 )
96   2over + rot				( s1 l1 s2 l2 s1 d l1 )
97   move rot + 				( s1 s2 len )
98   rot drop				( s2 len )
99;
100
101: strchr ( s1 l1 c -- s2 l2 )
102   begin
103      dup 2over 0= if			( s1 l1 c c s1  )
104         2drop drop exit then
105      c@ = if				( s1 l1 c )
106         drop exit then
107      -rot /c - swap ca1+		( c l2 s2 )
108     swap rot
109  again
110;
111
112
113: cstr ( ptr -- str len )
114   dup
115   begin dup c@ 0<>  while + repeat
116   over -
117;
118
119\
120\ BSD FFS parameters
121\
122
123fload	assym.fth.h
124
125sbsize buffer: sb-buf
126-1 value boot-ihandle
127dev_bsize value bsize
1280 value raid-offset	\ Offset if it's a raid-frame partition
129
130: strategy ( addr size start -- nread )
131   raid-offset + bsize * 0 " seek" boot-ihandle $call-method
132   -1 = if
133      ." strategy: Seek failed" cr
134      abort
135   then
136   " read" boot-ihandle $call-method
137;
138
139\
140\ Cylinder group macros
141\
142
143: cgbase ( cg fs -- cgbase ) fs_fpg l@ * ;
144: cgstart ( cg fs -- cgstart )
145   2dup fs_cgmask l@ not and		( cg fs stuff -- )
146   over fs_cgoffset l@ * -rot		( stuffcg fs -- )
147   cgbase +
148;
149: cgdmin ( cg fs -- 1st-data-block ) dup fs_dblkno l@ -rot cgstart + ;
150: cgimin ( cg fs -- inode-block ) dup fs_iblkno l@ -rot cgstart + ;
151: cgsblock ( cg fs -- super-block ) dup fs_sblkno l@ -rot cgstart + ;
152: cgstod ( cg fs -- cg-block ) dup fs_cblkno l@ -rot cgstart + ;
153
154\
155\ Block and frag position macros
156\
157
158: blkoff ( pos fs -- off ) fs_qbmask x@ and ;
159: fragoff ( pos fs -- off ) fs_qfmask x@ and ;
160: lblktosize ( blk fs -- off ) fs_bshift l@ << ;
161: lblkno ( pos fs -- off ) fs_bshift l@ >> ;
162: numfrags ( pos fs -- off ) fs_fshift l@ >> ;
163: blkroundup ( pos fs -- off ) dup fs_bmask l@ -rot fs_qbmask x@ + and ;
164: fragroundup ( pos fs -- off ) dup fs_fmask l@ -rot fs_qfmask x@ + and ;
165\ : fragroundup ( pos fs -- off ) tuck fs_qfmask x@ + swap fs_fmask l@ and ;
166: fragstoblks ( pos fs -- off ) fs_fragshift l@ >> ;
167: blkstofrags ( blk fs -- frag ) fs_fragshift l@ << ;
168: fragnum ( fsb fs -- off ) fs_frag l@ 1- and ;
169: blknum ( fsb fs -- off ) fs_frag l@ 1- not and ;
170: dblksize ( lbn dino fs -- size )
171   -rot 				( fs lbn dino )
172   di_size x@				( fs lbn di_size )
173   -rot dup 1+				( di_size fs lbn lbn+1 )
174   2over fs_bshift l@			( di_size fs lbn lbn+1 di_size b_shift )
175   rot swap <<	>=			( di_size fs lbn res1 )
176   swap ndaddr >= or if			( di_size fs )
177      swap drop fs_bsize l@ exit	( size )
178   then	tuck blkoff swap fragroundup	( size )
179;
180
181
182: ino-to-cg ( ino fs -- cg ) fs_ipg l@ / ;
183: ino-to-fsbo ( ino fs -- fsb0 ) fs_inopb l@ mod ;
184: ino-to-fsba ( ino fs -- ba )	\ Need to remove the stupid stack diags someday
185   2dup 				( ino fs ino fs )
186   ino-to-cg				( ino fs cg )
187   over					( ino fs cg fs )
188   cgimin				( ino fs inode-blk )
189   -rot					( inode-blk ino fs )
190   tuck 				( inode-blk fs ino fs )
191   fs_ipg l@ 				( inode-blk fs ino ipg )
192   mod					( inode-blk fs mod )
193   swap					( inode-blk mod fs )
194   dup 					( inode-blk mod fs fs )
195   fs_inopb l@ 				( inode-blk mod fs inopb )
196   rot 					( inode-blk fs inopb mod )
197   swap					( inode-blk fs mod inopb )
198   /					( inode-blk fs div )
199   swap					( inode-blk div fs )
200   blkstofrags				( inode-blk frag )
201   +
202;
203: fsbtodb ( fsb fs -- db ) fs_fsbtodb l@ << ;
204
205\
206\ File stuff
207\
208
209niaddr /w* constant narraysize
210
211struct
212   8		field	>f_ihandle	\ device handle
213   8 		field 	>f_seekp	\ seek pointer
214   8 		field 	>f_fs		\ pointer to super block
215   dinode_SIZEOF 	field 	>f_di	\ copy of on-disk inode
216   8		field	>f_buf		\ buffer for data block
217   4		field 	>f_buf_size	\ size of data block
218   4		field	>f_buf_blkno	\ block number of data block
219constant file_SIZEOF
220
221file_SIZEOF buffer: the-file
222sb-buf the-file >f_fs x!
223
224dinode_SIZEOF buffer: cur-inode
225h# 2000 buffer: indir-block
226-1 value indir-addr
227
228\
229\ Translate a fileblock to a disk block
230\
231\ We only allow single indirection
232\
233
234: block-map ( fileblock -- diskblock )
235   \ Direct block?
236   dup ndaddr <  if 			( fileblock )
237      cur-inode di_db			( arr-indx arr-start )
238      swap la+ l@ exit			( diskblock )
239   then 				( fileblock )
240   ndaddr -				( fileblock' )
241   \ Now we need to check the indirect block
242   dup sb-buf fs_nindir l@ <  if	( fileblock' )
243      cur-inode di_ib l@ dup		( fileblock' indir-block indir-block )
244      indir-addr <>  if 		( fileblock' indir-block )
245         to indir-addr			( fileblock' )
246         indir-block 			( fileblock' indir-block )
247         sb-buf dup fs_bsize l@		( fileblock' indir-block fs fs_bsize )
248         swap indir-addr swap		( fileblock' indir-block fs_bsize indiraddr fs )
249         fsbtodb 			( fileblock' indir-block fs_bsize db )
250         strategy			( fileblock' nread )
251      then				( fileblock' nread|indir-block )
252      drop \ Really should check return value
253      indir-block swap la+ l@ exit
254   then
255   dup sb-buf fs_nindir -		( fileblock'' )
256   \ Now try 2nd level indirect block -- just read twice
257   dup sb-buf fs_nindir l@ dup * < if	( fileblock'' )
258      cur-inode di_ib 1 la+ l@		( fileblock'' indir2-block )
259      to indir-addr			( fileblock'' )
260      \ load 1st level indir block
261      indir-block 			( fileblock'' indir-block )
262      sb-buf dup fs_bsize l@		( fileblock'' indir-block fs fs_bsize )
263      swap indir-addr swap		( fileblock'' indir-block fs_bsize indiraddr fs )
264      fsbtodb 				( fileblock'' indir-block fs_bsize db )
265      strategy				( fileblock'' nread )
266      drop				( fileblock'' )
267      dup sb-buf fs_nindir /		( fileblock'' indir-offset )
268      indir-block swap la+ l@		( fileblock'' indirblock )
269      to indir-addr			( fileblock'' )
270      \ load 2nd level indir block
271      indir-block 			( fileblock'' indir-block )
272      sb-buf dup fs_bsize l@		( fileblock'' indir-block fs fs_bsize )
273      swap indir-addr swap		( fileblock'' indir-block fs_bsize indiraddr fs )
274      fsbtodb 				( fileblock'' indir-block fs_bsize db )
275      strategy				( fileblock'' nread )
276      drop				( fileblock'' )
277      sb-buf fs_nindir l@ mod indir-block swap la+ l@ exit
278   then
279   ." block-map: exceeded max file size" cr
280   abort
281;
282
283\
284\ Read file into internal buffer and return pointer and len
285\
286
2872000 buffer: cur-block		\ Why do dynamic allocation?
288-1 value cur-blockno
2890 value cur-offset
290
291: buf-read-file ( fs -- len buf )
292   cur-offset swap			( seekp fs )
293   2dup blkoff				( seekp fs off )
294   -rot 2dup lblkno			( off seekp fs block )
295   swap 2dup cur-inode			( off seekp block fs block fs inop )
296   swap dblksize			( off seekp block fs size )
297   rot dup cur-blockno			( off seekp fs size block block cur )
298   <>  if 				( off seekp fs size block )
299      block-map				( off seekp fs size diskblock )
300      dup 0=  if			( off seekp fs size diskblock )
301         over cur-block swap 0 fill	( off seekp fs size diskblock )
302         boot-debug?  if ." buf-read-file fell off end of file" cr then
303      else
304         2dup sb-buf fsbtodb cur-block -rot strategy	( off seekp fs size diskblock nread )
305         rot 2dup <>  if " buf-read-file: short read." cr abort then
306      then				( off seekp fs diskblock nread size )
307      nip nip				( off seekp fs size )
308   else					( off seekp fs size block block cur )
309      2drop				( off seekp fs size )
310   then
311\   dup cur-offset + to cur-offset	\ Set up next xfer -- not done
312   nip nip swap -			( len )
313   cur-block
314;
315
316\
317\ Read inode into cur-inode -- uses cur-block
318\
319
320: read-inode ( inode fs -- )
321   twiddle				( inode fs -- inode fs )
322
323   cur-block				( inode fs -- inode fs buffer )
324
325   over					( inode fs buffer -- inode fs buffer fs )
326   fs_bsize l@				( inode fs buffer -- inode fs buffer size )
327
328   2over				( inode fs buffer size -- inode fs buffer size inode fs )
329   2over				( inode fs buffer size inode fs -- inode fs buffer size inode fs buffer size )
330   2swap tuck				( inode fs buffer size inode fs buffer size -- inode fs buffer size buffer size fs inode fs )
331
332   ino-to-fsba 				( inode fs buffer size buffer size fs inode fs -- inode fs buffer size buffer size fs fsba )
333   swap					( inode fs buffer size buffer size fs fsba -- inode fs buffer size buffer size fsba fs )
334   fsbtodb				( inode fs buffer size buffer size fsba fs -- inode fs buffer size buffer size db )
335
336   dup to cur-blockno			( inode fs buffer size buffer size dstart -- inode fs buffer size buffer size dstart )
337   strategy				( inode fs buffer size buffer size dstart -- inode fs buffer size nread )
338   <>  if ." read-inode - residual" cr abort then
339   dup 2over				( inode fs buffer -- inode fs buffer buffer inode fs )
340   ino-to-fsbo				( inode fs buffer -- inode fs buffer buffer fsbo )
341   dinode_SIZEOF * +			( inode fs buffer buffer fsbo -- inode fs buffer dinop )
342   cur-inode dinode_SIZEOF move 	( inode fs buffer dinop -- inode fs buffer )
343	\ clear out the old buffers
344   drop					( inode fs buffer -- inode fs )
345   2drop
346;
347
348\ Identify inode type
349
350: is-dir? ( dinode -- true:false ) di_mode w@ ifmt and ifdir = ;
351: is-symlink? ( dinode -- true:false ) di_mode w@ ifmt and iflnk = ;
352
353
354
355\
356\ Hunt for directory entry:
357\
358\ repeat
359\    load a buffer
360\    while entries do
361\       if entry == name return
362\       next entry
363\ until no buffers
364\
365
366: search-directory ( str len -- ino|0 )
367   0 to cur-offset
368   begin cur-offset cur-inode di_size x@ < while	( str len )
369      sb-buf buf-read-file		( str len len buf )
370      over 0=  if ." search-directory: buf-read-file zero len" cr abort then
371      swap dup cur-offset + to cur-offset	( str len buf len )
372      2dup + nip			( str len buf bufend )
373      swap 2swap rot			( bufend str len buf )
374      begin dup 4 pick < while		( bufend str len buf )
375         dup d_ino l@ 0<>  if 		( bufend str len buf )
376            boot-debug?  if dup dup d_name swap d_namlen c@ type cr then
377            2dup d_namlen c@ =  if	( bufend str len buf )
378               dup d_name 2over		( bufend str len buf dname str len )
379               comp 0= if		( bufend str len buf )
380                  \ Found it -- return inode
381                  d_ino l@ nip nip nip	( dino )
382                  boot-debug?  if ." Found it" cr then
383                  exit 			( dino )
384               then
385            then			( bufend str len buf )
386         then				( bufend str len buf )
387         dup d_reclen w@ +		( bufend str len nextbuf )
388      repeat
389      drop rot drop			( str len )
390   repeat
391   2drop 2drop 0			( 0 )
392;
393
394: ffs_oldcompat ( -- )
395\ Make sure old ffs values in sb-buf are sane
396   sb-buf fs_npsect dup l@ sb-buf fs_nsect l@ max swap l!
397   sb-buf fs_interleave dup l@ 1 max swap l!
398   sb-buf fs_postblformat l@ fs_42postblfmt =  if
399      8 sb-buf fs_nrpos l!
400   then
401   sb-buf fs_inodefmt l@ fs_44inodefmt <  if
402      sb-buf fs_bsize l@
403      dup ndaddr * 1- sb-buf fs_maxfilesize x!
404      niaddr 0 ?do
405	sb-buf fs_nindir l@ * dup	( sizebp sizebp -- )
406	sb-buf fs_maxfilesize dup x@	( sizebp sizebp *fs_maxfilesize fs_maxfilesize -- )
407	rot ( sizebp *fs_maxfilesize fs_maxfilesize sizebp -- )
408	+ ( sizebp *fs_maxfilesize new_fs_maxfilesize  -- ) swap x! ( sizebp -- )
409      loop drop ( -- )
410      sb-buf dup fs_bmask l@ not swap fs_qbmask x!
411      sb-buf dup fs_fmask l@ not swap fs_qfmask x!
412   then
413;
414
415: read-super ( sector -- )
4160 " seek" boot-ihandle $call-method
417   -1 = if
418      ." Seek failed" cr
419      abort
420   then
421   sb-buf sbsize " read" boot-ihandle $call-method
422   dup sbsize <>  if
423      ." Read of superblock failed" cr
424      ." requested" space sbsize .
425      ." actual" space . cr
426      abort
427   else
428      drop
429   then
430;
431
432: ufs-open ( bootpath,len -- )
433   boot-ihandle -1 =  if
434      over cif-open dup 0=  if 		( boot-path len ihandle? )
435         ." Could not open device" space type cr
436         abort
437      then 				( boot-path len ihandle )
438      to boot-ihandle			\ Save ihandle to boot device
439   then 2drop
440   sboff read-super
441   sb-buf fs_magic l@ fs_magic_value <>  if
442      64 dup to raid-offset
443      dev_bsize * sboff + read-super
444      sb-buf fs_magic l@ fs_magic_value <>  if
445         ." Invalid superblock magic" cr
446         abort
447      then
448   then
449   sb-buf fs_bsize l@ dup maxbsize >  if
450      ." Superblock bsize" space . ." too large" cr
451      abort
452   then
453   fs_SIZEOF <  if
454      ." Superblock bsize < size of superblock" cr
455      abort
456   then
457   ffs_oldcompat
458   boot-debug?  if ." ufs-open complete" cr then
459;
460
461: ufs-close ( -- )
462   boot-ihandle dup -1 <>  if
463      cif-close -1 to boot-ihandle
464   then
465;
466
467: boot-path ( -- boot-path )
468   " bootpath" chosen-phandle get-package-property  if
469      ." Could not find bootpath in /chosen" cr
470      abort
471   else
472      decode-string 2swap 2drop
473   then
474;
475
476: boot-args ( -- boot-args )
477   " bootargs" chosen-phandle get-package-property  if
478      ." Could not find bootargs in /chosen" cr
479      abort
480   else
481      decode-string 2swap 2drop
482   then
483;
484
4852000 buffer: boot-path-str
4862000 buffer: boot-path-tmp
487
488: split-path ( path len -- right len left len )
489\ Split a string at the `/'
490   begin
491      dup -rot				( oldlen right len left )
492      ascii / left-parse-string		( oldlen right len left len )
493      dup 0<>  if 4 roll drop exit then
494      2drop				( oldlen right len )
495      rot over =			( right len diff )
496   until
497;
498
499: find-file ( load-file len -- )
500   rootino dup sb-buf read-inode	( load-file len -- load-file len ino )
501   -rot					( load-file len ino -- pino load-file len )
502   \
503   \ For each path component
504   \
505   begin split-path dup 0<> while	( pino right len left len -- )
506      cur-inode is-dir? not  if ." Inode not directory" cr abort then
507      boot-debug?  if ." Looking for" space 2dup type space ." in directory..." cr then
508      search-directory			( pino right len left len -- pino right len ino|false )
509      dup 0=  if ." Bad path" cr abort then	( pino right len cino )
510      sb-buf read-inode			( pino right len )
511      cur-inode is-symlink?  if		\ Symlink -- follow the damn thing
512         \ Save path in boot-path-tmp
513         boot-path-tmp strmov		( pino new-right len )
514
515         \ Now deal with symlink
516         cur-inode di_size x@		( pino right len linklen )
517         dup sb-buf fs_maxsymlinklen l@	( pino right len linklen linklen maxlinklen )
518         <  if				\ Now join the link to the path
519            cur-inode di_shortlink l@	( pino right len linklen linkp )
520            swap boot-path-str strmov	( pino right len new-linkp linklen )
521         else				\ Read file for symlink -- Ugh
522            \ Read link into boot-path-str
523            boot-path-str dup sb-buf fs_bsize l@
524            0 block-map			( pino right len linklen boot-path-str bsize blockno )
525            strategy drop swap		( pino right len boot-path-str linklen )
526         then 				( pino right len linkp linklen )
527         \ Concatenate the two paths
528         strcat				( pino new-right newlen )
529         swap dup c@ ascii / =  if	\ go to root inode?
530            rot drop rootino -rot	( rino len right )
531         then
532         rot dup sb-buf read-inode	( len right pino )
533         -rot swap			( pino right len )
534      then				( pino right len )
535   repeat
536   2drop drop
537;
538
539: read-file ( size addr -- )
540   \ Read x bytes from a file to buffer
541   begin over 0> while
542      cur-offset cur-inode di_size x@ >  if ." read-file EOF exceeded" cr abort then
543      sb-buf buf-read-file		( size addr len buf )
544      over 2over drop swap		( size addr len buf addr len )
545      move				( size addr len )
546      dup cur-offset + to cur-offset	( size len newaddr )
547      tuck +				( size len newaddr )
548      -rot - swap			( newaddr newsize )
549   repeat
550   2drop
551;
552
553h# 5000 constant loader-base
554
555\
556\ Elf support -- find the load addr
557\
558
559: is-elf? ( hdr -- res? ) h# 7f454c46 = ;
560
561\
562\ Finally we finish it all off
563\
564
565: load-file-signon ( load-file len boot-path len -- load-file len boot-path len )
566   ." Loading file" space 2over type cr ." from device" space 2dup type cr
567;
568
569: load-file-print-size ( size -- size )
570   ." Loading" space dup . space ." bytes of file..." cr
571;
572
573: load-file ( load-file len boot-path len -- load-base )
574   boot-debug?  if load-file-signon then
575   the-file file_SIZEOF 0 fill		\ Clear out file structure
576   ufs-open 				( load-file len )
577   find-file				( )
578
579   \
580   \ Now we've found the file we should read it in in one big hunk
581   \
582
583   cur-inode di_size x@			( file-len )
584   dup " to file-size" evaluate		( file-len )
585   boot-debug?  if load-file-print-size then
586   0 to cur-offset
587   loader-base				( buf-len addr )
588   2dup read-file			( buf-len addr )
589   ufs-close				( buf-len addr )
590   dup is-elf?  if ." load-file: not an elf executable" cr abort then
591
592   \ Luckily the prom should be able to handle ELF executables by itself
593
594   nip					( addr )
595;
596
597: do-boot ( bootfile -- )
598   ." NetBSD IEEE 1275 Bootblock" cr
599   boot-path load-file ( -- load-base )
600   dup 0<> if  " to load-base init-program" evaluate then
601;
602
603
604boot-args ascii V strchr 0<> swap drop if
605 true to boot-debug?
606then
607
608boot-args ascii D strchr 0= swap drop if
609  " /ofwboot" do-boot
610then exit
611
612
613