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