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