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