xref: /titanic_41/usr/src/psm/stand/bootblks/ufs/common/ufs.fth (revision b7d3956b92a285d8dac2c7f5f7e28d2ef5347ef8)
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
27
28id: %Z%%M%	%I%	%E% SMI
29purpose: UFS file system support package
30copyright: Copyright 1995 Sun Microsystems, Inc. All Rights Reserved
31
32headers
33" /packages" get-package  push-package
34
35new-device
36   fs-pkg$  device-name  diag-cr?
37
38   \
39   \	UFS low-level block routines
40   \
41
42   h# 2000  constant  /max-bsize
43   d# 512   constant  /disk-block
44
45   0 instance value dev-ih
46   0 instance value temp-block
47
48   : blk>byte ( block# -- byte# )  /disk-block *  ;
49
50   : read-disk-blocks  ( adr len dev-block# -- )
51      blk>byte dev-ih  read-disk
52   ;
53
54
55   \
56   \	UFS superblock routines
57   \
58
59   d# 512 constant /super-block
60   d#  16 constant super-block#
61   0 instance value super-block
62
63   : +sb  ( index -- value )  super-block  swap la+ l@  ;
64   : iblkno    ( -- n )  d# 04 +sb  ;
65   : cgoffset  ( -- n )  d# 06 +sb  ;
66   : cgmask    ( -- n )  d# 07 +sb  ;
67   : bsize     ( -- n )  d# 12 +sb  ;
68   : fragshift ( -- n )  d# 24 +sb  ;
69   : fsbtodbc  ( -- n )  d# 25 +sb  ;
70   : inopb     ( -- n )  d# 30 +sb  ;
71   : ipg       ( -- n )  d# 46 +sb  ;
72   : fpg       ( -- n )  d# 47 +sb  ;
73
74   : /frag  ( -- fragsize )  bsize fragshift rshift ;
75
76   : get-super-block  ( -- )
77      super-block /super-block super-block#  read-disk-blocks
78   ;
79
80   : cgstart   ( cg -- block# )
81      dup cgmask invert and  cgoffset *   swap fpg *  +
82   ;
83   : cgimin       ( cg -- block# )  cgstart  iblkno +  ;
84   : blkstofrags  ( #blocks -- #frags )  fragshift lshift  ;
85   : lblkno       ( byte-off -- lblk# )  bsize /  ;
86   : blkoff       ( byte-off -- blk-off )  bsize mod  ;
87   : fsbtodb      ( fs-blk# -- dev-blk# )  fsbtodbc lshift  ;
88
89   : read-fs-blocks  ( adr len fs-blk# -- )  fsbtodb read-disk-blocks  ;
90
91
92   \
93   \	UFS inode routines
94   \
95
96   h# 80 constant /inode
97   0 instance value inode
98   0 instance value iptr
99
100   : itoo  ( i# -- offset )  inopb mod  ;
101   : itog  ( i# -- group )  ipg /  ;
102   : itod  ( i# -- block# )
103      dup itog cgimin  swap ipg mod  inopb /  blkstofrags  +
104   ;
105
106   : +i  ( n -- adr )  iptr +  ;
107
108   : ftype ( -- n )  0 +i  w@  h# f000 and  ;
109   : dir?      ( -- flag )  ftype h# 4000 =  ;
110   : symlink?  ( -- flag )  ftype h# a000 =  ;
111   : regular?  ( -- flag )  ftype h# 8000 =  ;
112
113   : file-size  ( -- n )        8 +i x@  ;
114   : direct0    ( -- adr )  d# 40 +i  ;
115   : indirect0  ( -- adr )  d# 88 +i  ;
116   : indirect1  ( -- adr )  d# 92 +i  ;
117   : indirect2  ( -- adr )  d# 96 +i  ;
118   : comp?      ( -- flag ) d# 100 +i l@  4 and  0<> ;
119
120   0 instance value current-file
121   : iget  ( i# -- )
122      dup temp-block bsize  rot  itod        ( i# adr len blk# )
123      read-fs-blocks
124      dup itoo  /inode *  temp-block +  inode /inode  move
125      inode to iptr
126      to current-file                        (  )
127   ;
128
129   : l@++  ( ptr -- value )  dup @ l@  /l rot +!  ;
130
131   d# 12 constant #direct
132   : #blk-addr/blk  bsize /l /  ;
133   : #sgl-addr      #blk-addr/blk  ;
134   : #dbl-addr      #sgl-addr #blk-addr/blk *  ;
135\  : #tri-addr      #dbl-addr #blk-addr/blk *  ;
136
137   : >1-idx ( blk# -- idx )  #blk-addr/blk mod  ;
138   : >2-idx ( blk# -- idx )  #sgl-addr /  >1-idx  ;
139\  : >3-idx ( blk# -- idx )  #dbl-addr /  >1-idx  ;
140
141   \
142   \ indirect block cache
143   \ we assume reads will mostly be sequential, and only
144   \ cache the current indirect block tree
145   \
146   : get-indir  ( fs-blk# var adr -- adr )
147      -rot  dup >r   @ over  =  if             ( adr fs-blk#  r: var )
148         r> 2drop  exit                        ( adr )
149      then                                     ( adr fs-blk#  r: var )
150      2dup  bsize swap  read-fs-blocks         ( adr fs-blk#  r: var )
151      r> !                                     ( adr )
152   ;
153
154   0 instance value indir0-adr
155   instance variable cur-indir0
156   : get-indir0  ( fs-blk# -- adr )
157      cur-indir0 indir0-adr  get-indir
158   ;
159
160   0 instance value indir1-adr
161   instance variable cur-indir1
162   : get-indir1  ( fs-blk# -- adr )
163      cur-indir1 indir1-adr  get-indir
164   ;
165
166   \
167   \ blkptr and blklim point to an array of blk#s,
168   \ whether in the inode direct block array or in
169   \ an indirect block
170   \
171   instance variable blkptr
172   instance variable blklim
173
174   : (bmap)  ( lblk# -- )
175      dup  #direct <  if                           ( lblk# )
176         direct0 swap la+  blkptr  !               (  )
177         direct0 #direct la+  blklim  !
178         exit
179      then                                         ( lblk# )
180
181      #direct -                                    ( lblk#' )
182      dup  #sgl-addr <  if
183         indirect0 l@  get-indir0                  ( lblk# adr )
184         tuck  swap >1-idx la+  blkptr  !          ( adr )
185         #blk-addr/blk la+  blklim  !
186         exit
187      then                                         ( lblk# )
188
189      #sgl-addr -                                  ( lblk#' )
190      dup  #dbl-addr <  if
191         indirect1 l@  get-indir0                  ( lblk# adr )
192         over >2-idx la+ l@  get-indir1            ( lblk# adr' )
193         tuck  swap >1-idx la+  blkptr  !          ( adr )
194         #blk-addr/blk la+  blklim  !              (  )
195         exit
196      then                                         ( lblk# )
197
198\     #dbl-addr -                                  ( lblk#' )
199\     dup  #tri-addr <  if
200\        indirect2 l@  get-indir0                  ( lblk# adr )
201\        over >3-idx la+ l@  get-indir1            ( lblk# adr' )
202\        over >2-idx la+ l@  get-indir2            ( lblk# adr' )
203\        tuck  swap >1-idx la+  blkptr  !          ( adr )
204\        #blk-addr/blk la+  blklim  !              (  )
205\        exit
206\     then                                         ( lblk# )
207      ." file too large" cr  drop true             ( failed )
208   ;
209
210   0 instance value cur-blk
211   : bmap  ( lblk# -- fs-blk# )
212      dup cur-blk <>  blkptr @  blklim @ =  or  if       ( lblk# )
213         dup (bmap)                                      ( lblk# )
214      then                                               ( lblk# )
215      1+ to cur-blk                                      (  )
216      blkptr l@++                                        ( fs-blk# )
217   ;
218
219   : read-one-block ( adr block# -- )
220      bmap  ?dup  if
221         bsize swap  read-fs-blocks
222      else
223         bsize  erase
224      then
225   ;
226
227   : read-partial-block ( adr len off block# -- )
228      bmap  ?dup  if
229         fsbtodb  blk>byte +                        ( adr len byte# )
230         dev-ih  read-disk
231      else
232         drop  erase
233      then
234   ;
235
236   \
237   \	UFS directory routines
238   \
239
240   instance variable dir-blk
241   instance variable totoff
242   instance variable dirptr
243   0 instance value dir-buf
244
245   : get-dirblk  ( -- )
246      dir-buf bsize  dir-blk @  bmap    ( adr len fs-blk# )
247      read-fs-blocks                    ( )
248      1 dir-blk +!
249   ;
250
251   2 constant rootino
252
253   : +d  ( n -- adr ) dirptr @  +  ;
254
255   : dir-ino    ( -- adr ) 0 +d  l@  ;
256   : reclen     ( -- adr ) 4 +d  w@  ;
257   : namelen    ( -- adr ) 6 +d  w@  ;
258   : dir-name   ( -- adr ) 8 +d  ;
259   : dir-name$  ( -- file$ ) dir-name namelen  ;
260
261
262   \
263   \	UFS high-level routines
264   \
265   \       After this point, the code should be independent of the disk format!
266
267   0 instance value search-dir
268   : init-dent
269      0 totoff !  0 dir-blk !
270      current-file to search-dir
271   ;
272
273   : get-dent ( -- end-of-dir? )
274      begin
275         totoff @  file-size >=  if
276            true  exit
277         then
278         totoff @  blkoff  0=  if
279            get-dirblk
280            dir-buf dirptr !
281         else
282            reclen dirptr +!
283         then
284         reclen totoff +!
285         dir-ino  0<>
286      until  false
287   ;
288
289   : dirlook  ( file$ -- not-found? )
290      init-dent
291      begin  get-dent 0=  while      ( file$ )
292         2dup  dir-name$  $=  if     ( file$ )
293            dir-ino iget             ( file$ )
294            2drop  false exit        ( found )
295         then                        ( file$ )
296      repeat  2drop true             ( not-found )
297   ;
298
299   h# 200 constant /fpath-buf
300   /fpath-buf instance buffer: fpath-buf
301   : clr-fpath-buf  ( -- )  fpath-buf /fpath-buf  erase  ;
302   : fpath-buf$  ( -- path$ )  fpath-buf cscount  ;
303
304   : follow-symlink  ( tail$ -- tail$' )
305      clr-fpath-buf                                         ( tail$ )
306      fpath-buf file-size  0 0  read-partial-block          ( tail$ )
307      ?dup  if                                              ( tail$ )
308	 " /" fpath-buf$  $append                           ( tail$ )
309	 fpath-buf$  $append                                (  )
310      else  drop  then                                      (  )
311      fpath-buf$                                            ( path$ )
312      over c@  ascii /  =  if                               ( path$ )
313	 str++  rootino                                     ( path$' i# )
314      else                                                  ( path$ )
315	 search-dir                                         ( path$ i# )
316      then                                                  ( path$ i# )
317      iget                                                  ( path$ )
318   ;
319
320   : lookup  ( path$ -- not-found? )
321      over c@  ascii /  =  if
322         str++  rootino                           ( path$' i# )
323      else
324         current-file                             ( path$ i# )
325      then                                        ( path$ i# )
326      iget                                        ( path$ )
327      begin                                       ( path$ )
328         ascii / left-parse-string                ( path$ file$ )
329      dup  while
330         dir? 0=  if  2drop true  exit  then
331         dirlook  if  2drop true  exit  then      ( path$ )
332         symlink?  if
333            follow-symlink                        ( path$' )
334         then                                     ( path$ )
335      repeat                                      ( path$ file$ )
336      2drop 2drop  false                          ( succeeded )
337   ;
338
339   : i#>name ( i# -- name$ )
340      init-dent                      ( i# )
341      begin  get-dent 0=  while      ( i# )
342         dup dir-ino  =  if          ( i# )
343            drop dir-name$  exit     ( name$ )
344         then                        ( i# )
345      repeat  drop " ???"            ( name$ )
346   ;
347
348
349   \
350   \	UFS installation routines
351   \
352
353   /max-bsize  4 *
354   /super-block    +
355   /inode          +
356   constant alloc-size
357
358   \ **** Allocate memory for necessary data structures
359   : allocate-buffers  ( -- )
360      alloc-size mem-alloc  dup 0=  if
361         ." no memory"  abort
362      then                                ( adr )
363      dup to temp-block   /max-bsize   +  ( adr )
364      dup to dir-buf      /max-bsize   +  ( adr )
365      dup to indir0-adr   /max-bsize   +  ( adr )
366      dup to indir1-adr   /max-bsize   +  ( adr )
367      dup to super-block  /super-block +  ( adr )
368          to inode                        (  )
369   ;
370
371   : release-buffers  ( -- )
372      temp-block  alloc-size  mem-free
373   ;
374
375   \ UFS file interface
376
377   struct
378      /x     field >busy
379      /x     field >offset
380      /inode field >inode
381   constant /file-record
382
383   d# 10                  constant #opens
384   #opens /file-record *  constant /file-records
385
386   /file-records  instance buffer: file-records
387
388   -1 instance value current-fd
389   : fd>record  ( fd -- record )  /file-record *  file-records +  ;
390
391
392   : file-offset@  ( -- off )
393      current-fd fd>record >offset  x@
394   ;
395
396   : file-offset!  ( off -- )
397      current-fd fd>record >offset  x!
398   ;
399
400   : get-slot  ( -- fd false | true )
401      #opens 0  do
402         i fd>record >busy x@  0=  if
403            i false  unloop exit
404         then
405      loop  true
406   ;
407
408   : free-slot  ( fd -- )
409      0 swap  fd>record >busy  x!
410   ;
411
412   : init-fd  ( fd -- )
413      fd>record                ( rec )
414      dup  >busy  1 swap  x!
415      dup  >inode  inode swap  /inode  move
416      >offset  0 swap  x!
417   ;
418
419   : set-fd  ( fd -- error? )
420      dup fd>record  dup >busy x@  0=  if   ( fd rec )
421         2drop true  exit                   ( failed )
422      then
423      >inode to iptr                        ( fd )
424      to current-fd  false                  ( succeeded )
425   ;
426
427
428   \ get current lblk# and offset within it
429   : file-blk+off ( -- off block# )
430      file-offset@ dup  blkoff  swap lblkno
431   ;
432
433   \ advance file io stack by n
434   : fio+  ( # adr len n -- #+n adr+n len-n )
435      dup file-offset@ +  file-offset!
436      dup >r  -  -rot   ( len' # adr  r: n )
437      r@  +  -rot       ( adr' len' #  r: n )
438      r>  +  -rot       ( #' adr' len' )
439   ;
440
441   : (cwd)  ( i# -- )  tokenizer[ reveal ]tokenizer
442      dup rootino  <>  if
443         \ open parent, find current name
444         " .." lookup  drop
445         i#>name                ( name$ )
446         \ recurse to print path components above
447         current-file (cwd)     ( name$ )
448         \ and print this component
449         type                   (  )
450      else  drop  then          (  )
451      \ slash is both root name and separator
452      ." /"
453   ;
454
455   external
456
457   : open ( -- okay? )
458      my-args dev-open  dup 0=  if       ( 0 )
459         exit                            ( failed )
460      then  to dev-ih
461
462      allocate-buffers
463      get-super-block
464      file-records /file-records  erase
465      true                               ( succeeded )
466   ;
467
468   : close  ( -- )
469      dev-ih dev-close
470      0 to dev-ih
471      release-buffers
472   ;
473
474   : open-file  ( path$ -- fd true | false )
475      get-slot  if
476         2drop false  exit         ( failed )
477      then  -rot                   ( fd path$ )
478
479      lookup  if                   ( fd )
480         drop false  exit          ( failed )
481      then
482
483      dup init-fd  true            ( fd succeeded )
484   ;
485
486   : close-file  ( fd -- )
487      free-slot   (  )
488   ;
489
490   : size-file  ( fd -- size )
491      set-fd  if  0  else  file-size  then
492   ;
493
494   : seek-file  ( off fd -- off true | false )
495      set-fd  if                ( off )
496         drop false  exit       ( failed )
497      then                      ( off )
498
499      dup file-size >  if       ( off )
500         drop false  exit       ( failed )
501      then                      ( off )
502      dup  file-offset!  true   ( off succeeded )
503   ;
504
505   : read-file  ( adr len fd -- #read )
506      set-fd  if                   ( adr len )
507         2drop 0  exit             ( 0 )
508      then                         ( adr len )
509
510      regular? 0=  if  2drop 0  exit  then
511
512      \ adjust len if reading past eof
513      dup  file-offset@ +  file-size  >  if
514         dup  file-offset@ +  file-size -  -
515      then
516      dup 0=  if  nip exit  then
517
518      0 -rot                              ( #read adr len )
519
520      \ initial partial block
521      file-offset@ blkoff  ?dup  if       ( #read adr len off )
522         bsize swap -  over  min          ( #read adr len len' )
523         3dup nip  file-blk+off           ( #read adr len len' adr len' off lblk# )
524         read-partial-block               ( #read adr len len )
525         fio+                             ( #read' adr' len' )
526      then                                ( #read adr len )
527
528      dup lblkno  0  ?do                  ( #read adr len )
529         over  file-blk+off nip           ( #read adr len adr lblk# )
530         read-one-block                   ( #read adr len )
531         bsize fio+                       ( #read' adr' len' )
532      loop                                ( #read adr len )
533
534      \ final partial block
535      dup  if                             ( #read adr len )
536         2dup  file-blk+off               ( #read adr len adr len off lblk# )
537         read-partial-block               ( #read adr len )
538         dup fio+                         ( #read' adr' 0 )
539      then  2drop                         ( #read )
540   ;
541
542   : cinfo-file  ( fd -- bsize fsize comp? )
543      set-fd  if  0 0 0  else  bsize file-size comp?  then
544   ;
545
546   \ read ramdisk fcode at rd-offset
547   : get-rd   ( adr len -- )
548      rd-offset dev-ih  read-disk
549   ;
550
551   \ no additional props needed for ufs
552   : bootprop  ( -- )  false  ;
553
554   \ debug words
555   headers
556
557   : chdir  ( dir$ -- )
558      current-file -rot            ( i# dir$ )
559      lookup  if                   ( i# )
560         to current-file           (  )
561         ." no such dir" cr  exit
562      then                         ( i# )
563      dir? 0=  if                  ( i# )
564         to current-file           (  )
565         ." not a dir" cr  exit
566      then  drop                   (  )
567   ;
568
569   : dir  ( -- )
570      current-file iget
571      init-dent
572      begin  get-dent 0=  while
573         dir-name$ type  cr
574      repeat
575   ;
576
577   : cwd  ( -- )
578      current-file        ( i# )
579      dup (cwd)  cr       ( i# )
580      iget                (  )
581   ;
582
583finish-device
584pop-package
585