xref: /titanic_41/usr/src/psm/stand/bootblks/hsfs/common/hsfs.fth (revision 391647d5ee9b25dc5307abb55f583388e08b2dd7)
1
2\ ident	"%Z%%M%	%I%	%E% SMI"
3\ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
4\ Use is subject to license terms.
5\
6\ CDDL HEADER START
7\
8\ The contents of this file are subject to the terms of the
9\ Common Development and Distribution License (the "License").
10\ You may not use this file except in compliance with the License.
11\
12\ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
13\ or http://www.opensolaris.org/os/licensing.
14\ See the License for the specific language governing permissions
15\ and limitations under the License.
16\
17\ When distributing Covered Code, include this CDDL HEADER in each
18\ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
19\ If applicable, add the following below this CDDL HEADER, with the
20\ fields enclosed by brackets "[]" replaced with your own identifying
21\ information: Portions Copyright [yyyy] [name of copyright owner]
22\
23\ CDDL HEADER END
24\
25\
26
27id: %Z%%M%	%I%	%E% SMI
28purpose: HSFS file system support package for NewBoot
29copyright: Copyright 2006 Sun Microsystems, Inc. All Rights Reserved
30
31\ High Sierra, Rock Ridge (CD-ROM) file system reader and boot block
32
33headers
34" /packages" get-package  push-package
35
36new-device
37   fs-pkg$  device-name  diag-cr?
38
39   \
40   \	HSFS variables
41   \
42   0 instance value dev-ih
43   0 instance value vol-desc
44   0 instance value dir-buf
45   0 instance value sua-buf
46   0 instance value ce-buf
47
48   \
49   \	HSFS volume descriptor routines
50   \
51
52   \ unaligned load of 2-byte item
53   : xw@  ( adr -- n )
54      dup c@ swap char+   ( c0 adr+1 )
55      c@                  ( c0 c1 )
56      bwjoin
57   ;
58
59   \ unaligned store of 2-byte item
60   : xw!  ( n adr -- )
61      swap wbsplit swap 2 pick c! swap char+ c!
62   ;
63
64   \ unaligned load of 4-byte item
65   : xl@  ( adr -- n )
66      dup xw@ swap wa1+   ( w0 adr+2 )
67      xw@                 ( w0 w1 )
68      wljoin
69   ;
70   \ unaligned store of 4-byte item
71   : xl!  ( n adr -- )
72      swap lwsplit swap 2 pick xw! swap wa1+ xw!
73   ;
74
75   d# 2048 constant /sector
76   d# 16 constant vol-desc-sector#  ( -- n )
77
78   : +vd  ( index -- adr )
79      vol-desc 0= if
80         ." invalid access of +vd" cr abort
81      then
82      vol-desc +
83   ;
84
85   : root-dir  ( -- n )  d# 156 +vd  ;
86   : /block    ( -- n )  d# 128 +vd xw@  ;
87   : byte>blkoff  ( byte-off -- block-off )  /block mod  ;
88
89   : get-vol-desc  ( -- )
90      vol-desc  /sector  vol-desc-sector# /sector *  dev-ih  read-disk
91   ;
92
93   : read-fs-blocks  ( adr len fs-blk# -- )  /block *  dev-ih  read-disk  ;
94
95   \
96   \	HSFS directory routines
97   \
98
99   \ Current directory variables.
100   instance variable cdir-blk		\ Current directory device block ptr.
101   instance variable cdir-blk0          \ Current directory block0.
102   instance variable cdir-offset	\ Current directory logical offset.
103   instance variable cdir-size		\ Current directory logical size.
104   instance variable cdir-ptr		\ Current directory entry pointer.
105   false instance value cdir-rescan     \ Rescan current directory for symlink.
106
107   \ Access of current directory entry.
108   : +dr  ( n -- adr )  cdir-ptr @ +  ;
109
110   : dir-entrylen    ( -- n )    d# 0  +dr c@  ;
111   : dir-block0      ( -- n )    d# 2  +dr xl@  ;
112   : dir-filesize    ( -- n )    d# 10 +dr xl@  ;
113   : dir-flags       ( -- n )    d# 25 +dr c@  ;
114   : dir-filenamelen ( -- n )    d# 32 +dr c@  ;
115   : dir-filename    ( -- adr )  d# 33 +dr  ;
116
117   : dir-isdir?      ( -- flag )  dir-flags  h# 02  and  0<>  ;
118   : dir-file$       ( -- adr len )  dir-filename  dir-filenamelen  ;
119   : dir-sualen      ( -- len )  dir-entrylen  d# 33 -  dir-filenamelen -  ;
120
121   \ ISO name, including dot & dot-dot check
122   : dir-iso$        ( -- adr len )
123      dir-filenamelen 1  =  if
124         dir-filename c@             ( name[0] )
125         dup 0=  if
126            drop " ."  exit          ( dot )
127         then
128         1 =  if                     (  )
129            " .."  exit              ( dot-dot )
130         then
131      then
132      dir-file$                      ( name$ )
133   ;
134
135   false instance value symlink?
136
137   : get-dirblk  ( -- )
138      dir-buf /block  cdir-blk @  read-fs-blocks
139      1 cdir-blk +!
140   ;
141
142   : froot  ( -- )  root-dir cdir-ptr !  ;
143
144   \
145   \ SUAs - System Use Area in directory entry (Rock Ridge
146   \  Extensions to High Sierra/ISO 9660 Format).
147   \  Immediately follows directory entry name rounded up to
148   \  a half-word boundary.
149   \
150   0 instance value sua-ptr
151   0 instance value sua-len
152
153   : +suf           ( n -- adr )    sua-ptr +  ;
154   : suf-sig        ( -- adr len )  sua-ptr 2  ;
155   : suf-len        ( -- len )      2 +suf c@  ;
156   : suf-dat        ( -- data )     5 +suf  ;
157   : suf-ce-lbn     ( -- lbn )      4 +suf xl@ ;
158   : suf-ce-offset  ( -- offset )   d# 12 +suf xl@ ;
159   : suf-ce-len     ( -- len )      d# 20 +suf xl@ ;
160
161   : init-sua     ( -- )
162      dir-file$ +  /w roundup  to sua-ptr
163      dir-sualen               to sua-len
164   ;
165
166   : next-suf  ( -- )
167      sua-len suf-len -  to sua-len
168      suf-len +suf       to sua-ptr
169   ;
170
171   : end-sua  ( -- end? )
172      sua-len 4 <
173   ;
174
175   : suf-nm$  ( -- adr len )  suf-dat  suf-len 5 -  ;
176
177   \ Continuation suffix handling.  When a 'CE' suffix is seen,
178   \ record the CE parameters (logical block#, offset and length
179   \ of continuation).  We process the CE continuation only after
180   \ we've finished processing the current SUA area.
181   instance variable ce-lbn
182   instance variable ce-offset
183   instance variable ce-len
184   : suf-ce-set  ( -- )
185      suf-ce-lbn ce-lbn !
186      suf-ce-offset ce-offset !
187      suf-ce-len ce-len !
188   ;
189
190   : suf-ce-process  ( -- error? )
191      ce-lbn @ 0= if
192         true
193      else
194         sua-buf ce-len @ ce-lbn @  read-fs-blocks
195         sua-buf   to sua-ptr
196         ce-len @  to sua-len
197         0 ce-len ! 0 ce-lbn ! 0 ce-offset !
198         false
199      then
200   ;
201
202   /buf-len  instance buffer: suf-sl-buf
203   false     instance value   symlink-need-sep
204
205   \ Format of Rock Ridge symlinks needs to be munged to unix-style
206   \ name.  Format is:  <flag><nbytes>file-name<flag><nbytes>filename...
207   \ where \ <flag> is flag byte (0=filename, 2=current dir, 4=parent
208   \ dir, 8=root dir) and <nbytes> is one-byte byte count (zero for
209   \ !filename).
210   : suf-copy-to-symlinkbuf  ( name$  -- )
211       false to symlink-need-sep
212       suf-sl-buf -rot bounds do           ( dst )
213          symlink-need-sep if
214             ascii / over c! char+
215          then
216          true to symlink-need-sep
217          i c@ dup 2 = if                   ( dst 2 )
218             \ CURRENT (".")
219             drop ascii . over c! char+ 2   ( dst' inc )
220          else  dup 4 =  if                 ( dst 4 )
221             \ PARENT ("..")
222             drop " .." 2 pick swap move    ( dst )
223             wa1+ 2                         ( dst' inc )
224          else  dup 8 =  if                 ( dst 8 )
225             \ ROOT ("/")
226             drop ascii / over c! char+ 2   ( dst' inc )
227             false to symlink-need-sep
228          else  dup 0<> if
229             ." unknown SL flag: " .x cr abort
230          else                              ( dst c )
231             drop                           ( dst )
232             i char+ dup c@ >r              ( dst src+1  R:nbytes )
233             char+ over r@ move             ( dst R:nbytes )
234             r@ +                           ( dst' R:nbytes )
235             r> wa1+                        ( dst' inc )
236          then then then then
237       +loop                                ( dst )
238       0 swap c!
239    ;
240
241   \ Saved 'NM' prefix buffer.
242   /buf-len  instance buffer: suf-nm-buf
243   0 instance value suf-nm-size
244
245   \ Return the Rock Ridge file name associated with the current
246   \ dirent ('NM' suffix).  Otherwise returns standard iso filename.
247   \ Marks whether returned filename is a symbolic link ('SL' suffix)
248   \ and also processes continuations ('CE' suffix).
249   : rr-file$ ( -- adr len )
250      false to symlink?
251      0 to suf-nm-size
252
253      \ select start of sua, record sua offset
254      init-sua
255      begin
256         end-sua  if
257            suf-ce-process if
258               suf-nm-size if
259                  suf-nm-buf suf-nm-size       ( NM$ )
260               else
261                  dir-iso$                     ( iso$ )
262               then                            ( file$ )
263               exit
264            then
265         then
266         suf-sig                               ( sig-adr sig-len )
267         2dup " NM"  $=  if
268            suf-nm$ to suf-nm-size             ( sig-adr sig-len suf-nm-adr )
269            suf-nm-buf suf-nm-size move
270         then                                  ( sig-adr sig-len )
271         2dup " SL"  $=  if
272            true to symlink?
273            suf-nm$ suf-copy-to-symlinkbuf
274         then
275         2dup " CE"  $=  if
276            suf-ce-set
277         then                                  ( sig-adr sig-len )
278         2drop  next-suf                       (  )
279      again
280   ;
281
282   \
283   \	HSFS high-level routines
284   \
285
286   \ Used for rescanning current directory for symbolic links.
287
288   \ Initializes current directory settings from current directory
289   \ entry pointer or for rescan.  If it's not a rescan, we have
290   \ access to the actual directory entry, so we can check whether
291   \ it's a directory or not here.
292   : init-dent  ( -- error? )
293      cdir-rescan if
294         false to cdir-rescan
295         cdir-blk0 @ cdir-blk !
296      else
297         dir-isdir? 0= if
298            true exit
299         then
300         dir-block0 dup cdir-blk ! cdir-blk0 !
301         dir-filesize cdir-size !
302      then                                    ( blk0 size )
303      0 cdir-offset !
304      false
305   ;
306
307   : get-dent ( -- error? )
308      begin
309         \ Check for end of directory, return true if we're past the EOF.
310         cdir-offset @  cdir-size @  >=  if
311            true  exit
312         then
313
314         \ If we're at a block boundary, get the next block.  Otherwise
315         \ increment the directory pointer.
316         cdir-offset @ byte>blkoff  0=  if
317            get-dirblk
318            dir-buf cdir-ptr !
319         else
320            dir-entrylen cdir-ptr +!
321         then
322
323         \ If dir-entrylen is not zero, increment the current directory
324         \ file offset.  Otherwise, a dir-entrylen of zero indicates
325         \ the end of a dir block, so round up cdir-offset to fetch the
326         \ next one
327         dir-entrylen ?dup if
328            cdir-offset +!  true
329         else
330            cdir-offset @  /block  roundup  cdir-offset !
331            false
332         then
333      until  false
334   ;
335
336   \ Look through current directory for file name 'file$'.
337   \ Will leave current directory entry (cdir-ptr) pointing
338   \ to matched entry on success.
339   : dirlook  ( file$ -- error? )
340      init-dent if
341         true exit
342      then
343      begin  get-dent 0=  while      ( file$ )
344         2dup rr-file$ $=  if        ( file$ )
345            2drop false  exit        ( succeeded )
346         then                        ( file$ )
347      repeat 2drop true              ( failed )
348   ;
349
350   /buf-len  instance buffer: symlink-buf
351   : symlink-buf$  ( -- path$ )  symlink-buf cscount  ;
352
353   : follow-symlink  ( tail$ -- tail$' )
354
355      \ copy symlink value (plus null) to buf
356      suf-sl-buf cscount 1+  symlink-buf swap  move
357      false to symlink?
358
359      \ append to current path
360      ?dup  if                                              ( tail$ )
361	 " /" symlink-buf$  $append                         ( tail$ )
362	 symlink-buf$  $append                              (  )
363      else  drop  then                                      (  )
364      symlink-buf$                                          ( path$ )
365      over c@  ascii /  =  if                               ( path$ )
366	 froot  str++                                       ( path$' )
367      else
368         true to cdir-rescan
369      then                                                  ( path$ )
370   ;
371
372   : lookup  ( path$ -- error? )
373      over c@  ascii /  =  if
374	 froot  str++                            ( path$' )
375      then                                       ( path$ )
376      begin                                      ( path$ )
377         ascii / left-parse-string               ( path$ file$ )
378      dup  while                                 ( path$ file$ )
379         dirlook  if
380            2drop true  exit                     ( failed )
381         then                                    ( path$ )
382         symlink?  if
383            follow-symlink                       ( path$' )
384         then                                    ( path$ )
385      repeat                                     ( path$ file$ )
386      2drop 2drop  false                         ( succeeded )
387   ;
388
389
390   \
391   \	HSFS installation routines
392   \
393
394   \ Allocate memory for necessary data structures.  Need to
395   \ read volume desriptor sector in order to get /block value.
396   : initialize  ( -- error? )
397      /sector  mem-alloc to vol-desc
398      get-vol-desc
399      /block   mem-alloc to dir-buf
400      /block   mem-alloc to sua-buf
401      /block   mem-alloc to ce-buf
402   ;
403
404   : release-buffers  ( -- )
405      ce-buf      /block  mem-free
406      sua-buf	  /block  mem-free
407      dir-buf     /block  mem-free
408      vol-desc    /sector mem-free
409      0 to vol-desc
410   ;
411
412
413   \ HSFS file interface
414   struct
415      /x     field >filesize
416      /x     field >offset
417      /x     field >block0
418   constant /file-record
419
420   d# 10                  constant #opens
421   #opens /file-record *  constant /file-records
422
423   /file-records  instance buffer: file-records
424
425   -1 instance value current-fd
426
427   : fd>record  ( fd -- record )  /file-record *  file-records +  ;
428
429   : set-fd  ( fd -- error? )
430      dup 0 #opens 1 - between 0= if
431         drop true exit
432      then
433      dup fd>record  >block0 x@ 0= if
434         drop true exit
435      then
436      to current-fd false
437   ;
438
439   : file-offset@  ( -- off )
440      current-fd fd>record >offset x@
441   ;
442
443   : file-offset!  ( off -- )
444      current-fd fd>record >offset x!
445   ;
446
447   : file-size@  ( -- size )
448      current-fd fd>record >filesize x@
449   ;
450
451   : file-size!  ( size -- )
452      current-fd fd>record >filesize x!
453   ;
454
455   : file-block0@  ( -- block0 )
456      current-fd fd>record >block0 x@
457   ;
458
459   : file-block0!  ( block0 -- )
460      current-fd fd>record >block0 x!
461   ;
462
463   : get-slot  ( -- fd false | true )
464      #opens 0  do
465         i fd>record >block0 x@  0=  if
466            i false  unloop exit
467         then
468      loop  true
469   ;
470
471   : free-slot  ( fd -- )
472      set-fd 0= if
473         0 file-offset!
474         0 file-size!
475         0 file-block0!
476      then
477   ;
478
479   \ initializes the open structure with information from
480   \ the inode (on UFS) or directory entry (from HSFS).
481   : init-fd  ( fd -- )
482      to current-fd
483      dir-block0 file-block0!
484      dir-filesize file-size!
485      0 file-offset!
486   ;
487
488   external
489
490   : open ( -- okay? )
491      my-args dev-open  dup 0=  if       ( 0 )
492         exit                            ( failed )
493      then  to dev-ih
494
495      initialize  froot
496      file-records /file-records  erase
497      true                               ( succeeded )
498   ;
499
500   : close  ( -- )
501      dev-ih dev-close
502      release-buffers
503   ;
504
505   : open-file  ( path$ -- fd true | false )
506      get-slot  if
507	 2drop false  exit            ( failed )
508      then  -rot                      ( fd path$ )
509
510      lookup  if                      ( fd )
511	 drop false  exit             ( failed )
512      then
513
514      dup init-fd true                ( fd success )
515   ;
516
517   : close-file  ( fd -- )
518      free-slot   (  )
519   ;
520
521   : read-file   ( adr len fd -- #read )
522
523      \ Check if fd is valid, if it is set current-fd.
524      set-fd if
525         2drop 0 exit
526      then                                   ( adr len )
527
528      \ Adjust len if less than len bytes remain.
529      file-size@ file-offset@ - min          ( adr len' )
530
531      \ Check for invalid length read.
532      dup 0<=  if  2drop 0 exit  then
533
534      \ Compute physical device byte offset.
535      tuck                                   ( len adr len )
536      file-block0@ /block * file-offset@ +   ( len adr len off )
537      dev-ih read-disk                       ( #read )
538   ;
539
540   : seek-file  ( off fd -- error? )
541      set-fd  if                ( off )
542         drop false  exit       ( failed )
543      then                      ( off )
544
545      dup file-size@ >  if      ( off )
546         drop false  exit       ( failed )
547      then                      ( off )
548      dup  file-offset!  true   ( off succeeded )
549   ;
550
551   : size-file  ( fd -- size )
552      set-fd if
553         0
554      else
555         file-size@
556      then
557   ;
558
559   \ we don't support compression (yet)
560   : cinfo-file  ( fd -- bsize fsize comp? )
561      set-fd  if  0 0 0  else  /block file-size@ 0  then
562   ;
563
564   \ read ramdisk fcode at rd-offset
565   : get-rd   ( adr len -- )
566      rd-offset dev-ih  read-disk
567   ;
568
569   \ no additional props needed for hsfs
570   : bootprop  ( -- )  false  ;
571
572   \ debug words
573   : chdir  ( path$ -- )
574      2dup lookup if
575         type ."  Not found" cr
576      else
577         dir-isdir? 0= if
578            type ."  Not a directory" cr
579         else
580            type
581	    ."  blk0 "
582            cdir-blk0 @ .x
583            ."  size "
584            cdir-size @ .x
585            cr
586         then
587      then
588   ;
589
590   : dir  ( -- )
591      init-dent
592      begin  get-dent 0=  while
593         rr-file$ type
594         ."  flags " dir-flags .x
595         ." blk0 " dir-block0 .x
596         ." size " dir-filesize .x
597         cr
598      repeat
599      true to cdir-rescan
600   ;
601
602
603finish-device
604pop-package
605
606