xref: /netbsd/sys/arch/sparc/stand/bootblk/bootblk.fth (revision c4a72b64)
1\	$NetBSD: bootblk.fth,v 1.4 2002/06/12 22:18:02 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
2870 value cur-block			\ allocated dynamically in ufs-open
2880 value cur-blocksize			\ size of cur-block
289-1 value cur-blockno
2900 value cur-offset
291
292: buf-read-file ( fs -- len buf )
293   cur-offset swap			( seekp fs )
294   2dup blkoff				( seekp fs off )
295   -rot 2dup lblkno			( off seekp fs block )
296   swap 2dup cur-inode			( off seekp block fs block fs inop )
297   swap dblksize			( off seekp block fs size )
298   rot dup cur-blockno			( off seekp fs size block block cur )
299   <>  if 				( off seekp fs size block )
300      block-map				( off seekp fs size diskblock )
301      dup 0=  if			( off seekp fs size diskblock )
302         over cur-block swap 0 fill	( off seekp fs size diskblock )
303         boot-debug?  if ." buf-read-file fell off end of file" cr then
304      else
305         2dup sb-buf fsbtodb cur-block -rot strategy	( off seekp fs size diskblock nread )
306         rot 2dup <>  if " buf-read-file: short read." cr abort then
307      then				( off seekp fs diskblock nread size )
308      nip nip				( off seekp fs size )
309   else					( off seekp fs size block block cur )
310      2drop				( off seekp fs size )
311   then
312\   dup cur-offset + to cur-offset	\ Set up next xfer -- not done
313   nip nip swap -			( len )
314   cur-block
315;
316
317\
318\ Read inode into cur-inode -- uses cur-block
319\
320
321: read-inode ( inode fs -- )
322   twiddle				( inode fs -- inode fs )
323
324   cur-block				( inode fs -- inode fs buffer )
325
326   over					( inode fs buffer -- inode fs buffer fs )
327   fs_bsize l@				( inode fs buffer -- inode fs buffer size )
328
329   2over				( inode fs buffer size -- inode fs buffer size inode fs )
330   2over				( inode fs buffer size inode fs -- inode fs buffer size inode fs buffer size )
331   2swap tuck				( inode fs buffer size inode fs buffer size -- inode fs buffer size buffer size fs inode fs )
332
333   ino-to-fsba 				( inode fs buffer size buffer size fs inode fs -- inode fs buffer size buffer size fs fsba )
334   swap					( inode fs buffer size buffer size fs fsba -- inode fs buffer size buffer size fsba fs )
335   fsbtodb				( inode fs buffer size buffer size fsba fs -- inode fs buffer size buffer size db )
336
337   dup to cur-blockno			( inode fs buffer size buffer size dstart -- inode fs buffer size buffer size dstart )
338   strategy				( inode fs buffer size buffer size dstart -- inode fs buffer size nread )
339   <>  if ." read-inode - residual" cr abort then
340   dup 2over				( inode fs buffer -- inode fs buffer buffer inode fs )
341   ino-to-fsbo				( inode fs buffer -- inode fs buffer buffer fsbo )
342   dinode_SIZEOF * +			( inode fs buffer buffer fsbo -- inode fs buffer dinop )
343   cur-inode dinode_SIZEOF move 	( inode fs buffer dinop -- inode fs buffer )
344	\ clear out the old buffers
345   drop					( inode fs buffer -- inode fs )
346   2drop
347;
348
349\ Identify inode type
350
351: is-dir? ( dinode -- true:false ) di_mode w@ ifmt and ifdir = ;
352: is-symlink? ( dinode -- true:false ) di_mode w@ ifmt and iflnk = ;
353
354
355
356\
357\ Hunt for directory entry:
358\
359\ repeat
360\    load a buffer
361\    while entries do
362\       if entry == name return
363\       next entry
364\ until no buffers
365\
366
367: search-directory ( str len -- ino|0 )
368   0 to cur-offset
369   begin cur-offset cur-inode di_size x@ < while	( str len )
370      sb-buf buf-read-file		( str len len buf )
371      over 0=  if ." search-directory: buf-read-file zero len" cr abort then
372      swap dup cur-offset + to cur-offset	( str len buf len )
373      2dup + nip			( str len buf bufend )
374      swap 2swap rot			( bufend str len buf )
375      begin dup 4 pick < while		( bufend str len buf )
376         dup d_ino l@ 0<>  if 		( bufend str len buf )
377            boot-debug?  if dup dup d_name swap d_namlen c@ type cr then
378            2dup d_namlen c@ =  if	( bufend str len buf )
379               dup d_name 2over		( bufend str len buf dname str len )
380               comp 0= if		( bufend str len buf )
381                  \ Found it -- return inode
382                  d_ino l@ nip nip nip	( dino )
383                  boot-debug?  if ." Found it" cr then
384                  exit 			( dino )
385               then
386            then			( bufend str len buf )
387         then				( bufend str len buf )
388         dup d_reclen w@ +		( bufend str len nextbuf )
389      repeat
390      drop rot drop			( str len )
391   repeat
392   2drop 2drop 0			( 0 )
393;
394
395: ffs_oldcompat ( -- )
396\ Make sure old ffs values in sb-buf are sane
397   sb-buf fs_npsect dup l@ sb-buf fs_nsect l@ max swap l!
398   sb-buf fs_interleave dup l@ 1 max swap l!
399   sb-buf fs_postblformat l@ fs_42postblfmt =  if
400      8 sb-buf fs_nrpos l!
401   then
402   sb-buf fs_inodefmt l@ fs_44inodefmt <  if
403      sb-buf fs_bsize l@
404      dup ndaddr * 1- sb-buf fs_maxfilesize x!
405      niaddr 0 ?do
406	sb-buf fs_nindir l@ * dup	( sizebp sizebp -- )
407	sb-buf fs_maxfilesize dup x@	( sizebp sizebp *fs_maxfilesize fs_maxfilesize -- )
408	rot 				( sizebp *fs_maxfilesize fs_maxfilesize sizebp -- )
409	+ 				( sizebp *fs_maxfilesize new_fs_maxfilesize  -- )
410        swap x! 			( sizebp -- )
411      loop drop 			( -- )
412      sb-buf dup fs_bmask l@ not swap fs_qbmask x!
413      sb-buf dup fs_fmask l@ not swap fs_qfmask x!
414   then
415;
416
417: read-super ( sector -- )
4180 " seek" boot-ihandle $call-method
419   -1 = if
420      ." Seek failed" cr
421      abort
422   then
423   sb-buf sbsize " read" boot-ihandle $call-method
424   dup sbsize <>  if
425      ." Read of superblock failed" cr
426      ." requested" space sbsize .
427      ." actual" space . cr
428      abort
429   else
430      drop
431   then
432;
433
434: ufs-open ( bootpath,len -- )
435   boot-ihandle -1 =  if
436      over cif-open dup 0=  if 		( boot-path len ihandle? )
437         ." Could not open device" space type cr
438         abort
439      then 				( boot-path len ihandle )
440      to boot-ihandle			\ Save ihandle to boot device
441   then 2drop
442   sboff read-super
443   sb-buf fs_magic l@ fs_magic_value <>  if
444      64 dup to raid-offset
445      dev_bsize * sboff + read-super
446      sb-buf fs_magic l@ fs_magic_value <>  if
447         ." Invalid superblock magic" cr
448         abort
449      then
450   then
451   sb-buf fs_bsize l@ dup maxbsize >  if
452      ." Superblock bsize" space . ." too large" cr
453      abort
454   then
455   dup fs_SIZEOF <  if
456      ." Superblock bsize < size of superblock" cr
457      abort
458   then
459   ffs_oldcompat	( fs_bsize -- fs_bsize )
460   dup to cur-blocksize alloc-mem to cur-block    \ Allocate cur-block
461   boot-debug?  if ." ufs-open complete" cr then
462;
463
464: ufs-close ( -- )
465   boot-ihandle dup -1 <>  if
466      cif-close -1 to boot-ihandle
467   then
468   cur-block 0<> if
469      cur-block cur-blocksize free-mem
470   then
471;
472
473: boot-path ( -- boot-path )
474   " bootpath" chosen-phandle get-package-property  if
475      ." Could not find bootpath in /chosen" cr
476      abort
477   else
478      decode-string 2swap 2drop
479   then
480;
481
482: boot-args ( -- boot-args )
483   " bootargs" chosen-phandle get-package-property  if
484      ." Could not find bootargs in /chosen" cr
485      abort
486   else
487      decode-string 2swap 2drop
488   then
489;
490
4912000 buffer: boot-path-str
4922000 buffer: boot-path-tmp
493
494: split-path ( path len -- right len left len )
495\ Split a string at the `/'
496   begin
497      dup -rot				( oldlen right len left )
498      ascii / left-parse-string		( oldlen right len left len )
499      dup 0<>  if 4 roll drop exit then
500      2drop				( oldlen right len )
501      rot over =			( right len diff )
502   until
503;
504
505: find-file ( load-file len -- )
506   rootino dup sb-buf read-inode	( load-file len -- load-file len ino )
507   -rot					( load-file len ino -- pino load-file len )
508   \
509   \ For each path component
510   \
511   begin split-path dup 0<> while	( pino right len left len -- )
512      cur-inode is-dir? not  if ." Inode not directory" cr abort then
513      boot-debug?  if ." Looking for" space 2dup type space ." in directory..." cr then
514      search-directory			( pino right len left len -- pino right len ino|false )
515      dup 0=  if ." Bad path" cr abort then	( pino right len cino )
516      sb-buf read-inode			( pino right len )
517      cur-inode is-symlink?  if		\ Symlink -- follow the damn thing
518         \ Save path in boot-path-tmp
519         boot-path-tmp strmov		( pino new-right len )
520
521         \ Now deal with symlink
522         cur-inode di_size x@		( pino right len linklen )
523         dup sb-buf fs_maxsymlinklen l@	( pino right len linklen linklen maxlinklen )
524         <  if				\ Now join the link to the path
525            cur-inode di_shortlink l@	( pino right len linklen linkp )
526            swap boot-path-str strmov	( pino right len new-linkp linklen )
527         else				\ Read file for symlink -- Ugh
528            \ Read link into boot-path-str
529            boot-path-str dup sb-buf fs_bsize l@
530            0 block-map			( pino right len linklen boot-path-str bsize blockno )
531            strategy drop swap		( pino right len boot-path-str linklen )
532         then 				( pino right len linkp linklen )
533         \ Concatenate the two paths
534         strcat				( pino new-right newlen )
535         swap dup c@ ascii / =  if	\ go to root inode?
536            rot drop rootino -rot	( rino len right )
537         then
538         rot dup sb-buf read-inode	( len right pino )
539         -rot swap			( pino right len )
540      then				( pino right len )
541   repeat
542   2drop drop
543;
544
545: read-file ( size addr -- )
546   \ Read x bytes from a file to buffer
547   begin over 0> while
548      cur-offset cur-inode di_size x@ >  if ." read-file EOF exceeded" cr abort then
549      sb-buf buf-read-file		( size addr len buf )
550      over 2over drop swap		( size addr len buf addr len )
551      move				( size addr len )
552      dup cur-offset + to cur-offset	( size len newaddr )
553      tuck +				( size len newaddr )
554      -rot - swap			( newaddr newsize )
555   repeat
556   2drop
557;
558
559\
560\ According to the 1275 addendum for SPARC processors:
561\ Default load-base is 0x4000.  At least 0x8.0000 or
562\ 512KB must be available at that address.
563\
564\ The Fcode bootblock can take up up to 8KB (O.K., 7.5KB)
565\ so load programs at 0x4000 + 0x2000=> 0x6000
566\
567
568h# 6000 constant loader-base
569
570\
571\ Elf support -- find the load addr
572\
573
574: is-elf? ( hdr -- res? ) h# 7f454c46 = ;
575
576\
577\ Finally we finish it all off
578\
579
580: load-file-signon ( load-file len boot-path len -- load-file len boot-path len )
581   ." Loading file" space 2over type cr ." from device" space 2dup type cr
582;
583
584: load-file-print-size ( size -- size )
585   ." Loading" space dup . space ." bytes of file..." cr
586;
587
588: load-file ( load-file len boot-path len -- load-base )
589   boot-debug?  if load-file-signon then
590   the-file file_SIZEOF 0 fill		\ Clear out file structure
591   ufs-open 				( load-file len )
592   find-file				( )
593
594   \
595   \ Now we've found the file we should read it in in one big hunk
596   \
597
598   cur-inode di_size x@			( file-len )
599   dup " to file-size" evaluate		( file-len )
600   boot-debug?  if load-file-print-size then
601   0 to cur-offset
602   loader-base				( buf-len addr )
603   2dup read-file			( buf-len addr )
604   ufs-close				( buf-len addr )
605   dup is-elf?  if ." load-file: not an elf executable" cr abort then
606
607   \ Luckily the prom should be able to handle ELF executables by itself
608
609   nip					( addr )
610;
611
612: do-boot ( bootfile -- )
613   ." NetBSD IEEE 1275 Bootblock" cr
614   boot-path load-file ( -- load-base )
615   dup 0<> if  " to load-base init-program" evaluate then
616;
617
618
619boot-args ascii V strchr 0<> swap drop if
620 true to boot-debug?
621then
622
623boot-args ascii D strchr 0= swap drop if
624  " /ofwboot" do-boot
625then exit
626
627
628