xref: /titanic_44/usr/src/psm/stand/bootblks/common/boot.fth (revision 98157a7002f4f2cf7978f3084ca5577f0a1d72b2)
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\ ident	"%Z%%M%	%I%	%E% SMI"
23\ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24\ Use is subject to license terms.
25\
26
27id: %Z%%M%	%I%	%E% SMI
28purpose: boot block for OBP systems
29copyright: Copyright 2007 Sun Microsystems, Inc. All Rights Reserved
30
31
32headerless
33d# 1024 dup  *     constant  1meg
34d# 4  1meg   *     constant  4meg
35d# 32 1meg   *     constant  32meg
36
37headers
38" /"  get-package  constant  root-ph
39
400                  value     fs-ih
41false              value     nested?
420                  value     file-sz
43
44/buf-len  buffer:  boot-dev
45: boot-dev$  ( -- dev$ )  boot-dev cscount  ;
46
47: loader-base  ( -- base )
48   nested?  if
49      h# 5000.0000
50   else
51      h# 5100.0000
52   then
53;
54
55
56\
57\ methods we expect of fs reader packages
58\
59headerless
60: fs-open  ( file$ -- fd true | false )
61   " open-file" fs-ih $call-method
62;
63
64: fs-close  ( fd -- )
65   " close-file" fs-ih $call-method
66;
67
68: fs-size  ( fd -- size )
69   " size-file" fs-ih $call-method
70;
71
72: fs-read  ( adr len fd -- #read )
73   " read-file" fs-ih $call-method
74;
75
76: fs-getrd  ( adr len -- )
77   " get-rd" fs-ih $call-method
78;
79
80: fs-bootprop  ( -- propval propname true  |  false )
81   " bootprop" fs-ih $call-method
82;
83headers
84
85
86\ zfs bootblks with all headers exceeds 7.5k
87\ 'bigbootblk' allows us to load the fs reader from elsewhere
88[ifdef] bigbootblk
89
90: load-pkg  ( -- )
91   boot-dev$  2dup dev-open  ?dup 0=  if  ( dev$ )
92      open-abort
93   then  >r 2drop                         ( r: ih )
94   /fs-fcode  mem-alloc                   ( adr  r: ih )
95   dup  /fs-fcode fs-offset r@  read-disk
96   dup  1 byte-load
97   /fs-fcode  mem-free                    ( r: ih )
98   r>  dev-close
99;
100
101[else]
102
103: load-pkg  ( -- )  ;
104
105[then]
106
107
108: get-bootdev  ( -- )
109   \ first try boot archive (nested boot from ramdisk)
110   \ then try boot device (direct boot from disk)
111   " bootarchive" chosen-ph  get-package-property  if
112      " bootpath" chosen-ph  get-string-prop            ( bootpath$ )
113   else                                                 ( archiveprop$ )
114      decode-string  2swap 2drop                        ( archivepath$ )
115      true to nested?
116   then                                                 ( bootpath$ )
117   boot-dev swap  move                                  (  )
118;
119
120: mount-root  ( -- )
121   boot-dev$ fs-pkg$  $open-package to fs-ih
122   fs-ih 0=  if
123      ." Can't mount root" abort
124   then
125;
126
127\
128\ cheap entertainment for those watching
129\ boot progress
130\
131headerless
132create spin-data
133   ascii | c,  ascii / c,  ascii - c,  ascii \ c,
134
1350 instance variable spindex
136
137: spinner ( -- )
138   spindex @  3 and  spin-data +   ( c-adr )
139   c@ emit  (cr
140   1 spindex +!
141;
142
143: spin-on   ( -- )  ['] spinner  d# 1000  alarm  ;
144: spin-off  ( -- )  ['] spinner        0  alarm  ;
145
146headers
147\ allocate and return physical allocation size
148: vmem-alloc-prop  ( size virt -- alloc-size virt )
149   2dup  ['] vmem-alloc  catch  if            ( size virt ??? ??? )
150      2drop                                   ( size virt )
151      2dup  begin                             ( size virt len adr )
152         over 32meg  min  >r                  ( size virt len adr  r: alloc-sz )
153         r@ over  vmem-alloc                  ( size virt len adr adr  r: alloc-sz )
154         nip  r@ +                            ( size virt len adr'  r: alloc-sz )
155         swap r> -                            ( size virt adr len' )
156         swap over  0=                        ( size virt len adr done? )
157      until                                   ( size virt len adr )
158      2drop nip  32meg                        ( virt 32meg )
159   else                                       ( size virt virt )
160      nip nip  0                              ( virt 0 )
161   then                                       ( virt alloc-sz )
162   swap
163;
164
165\ read in file and return buffer
166\ if base==0, vmem-alloc will allocate virt
167: get-file ( base fd -- [ virt size ] failed? )
168   dup >r  fs-size                         ( base size  r: fd )
169   dup rot  vmem-alloc-prop                ( size alloc-sz virt  r: fd )
170   rot  2dup tuck  r>                      ( alloc-sz virt size size virt size fd )
171   spin-on  fs-read  spin-off              ( alloc-sz virt size size size-rd )
172   <>  if                                  ( alloc-sz virt size )
173      3drop true  exit                     ( failed )
174   then
175   false                                   ( alloc-sz virt size succeeded )
176;
177
178
179false value is-elf?
180false value is-archive?
181
182: check-elf ( base -- is-elf? )
183   l@  h# 7f454c46 ( \x7fELF )  =
184;
185
186: check-fcode ( base -- is-fcode? )
187   c@ dup  h# f0 h# f3 between  swap h# fd =  or
188;
189
190: >bootblk  ( adr -- adr' )  d# 512 +  ;
191
192\ figure out what we just loaded
193: get-type  ( adr -- )
194   dup check-elf to is-elf?
195
196   \ if not nested, check for boot archive (executable after label)
197   nested? invert  if
198      >bootblk
199      dup check-fcode           ( adr is-fcode? )
200      over check-elf            ( adr is-fcode? is-elf? )
201      or  to is-archive?
202   then
203   drop
204;
205
206
207\
208\	file name routines
209\
210
211\ boot file (-F name or boot archive)
212false     value    fflag?
213/buf-len  buffer:  boot-file
214: boot-file$  ( -- file$ )  boot-file cscount  ;
215
216\ kernel name (final name or unix)
217false     value    kern?
218/buf-len  buffer:  kern-file
219: kern-file$  ( -- file$ )  kern-file cscount  ;
220
221\ platform name
222/buf-len  buffer:  plat-name
223: plat-name$  ( -- plat$ )  plat-name cscount  ;
224
225\ arch name
226/buf-len  buffer:  arch-name
227: arch-name$  ( -- arch$ )  arch-name cscount  ;
228
229\ final name after /platform massaging
230/buf-len  buffer:  targ-file
231: targ-file$  ( -- file$ )  targ-file cscount  ;
232
233headerless
234: init-targ  ( -- )
235   targ-file /buf-len erase
236   " /platform/"  targ-file swap  move
237;
238
239\ remove illegal file name chars (e.g., '/')
240: munge-name ( name$ -- name$' )
241   2dup                           ( name$ name$ )
242   begin  dup  while
243      over c@  ascii /  =  if
244         over  ascii _  swap  c!  ( name$ name$' )
245      then  str++
246   repeat  2drop                  ( name$ )
247;
248
249headers
250\ does /platform/<name> exist?
251: try-platname  ( name$ -- name$ true | false )
252   munge-name                           ( name$' )
253   init-targ  2dup targ-file$  $append
254   targ-file$ fs-open  if               ( name$ fd )
255      fs-close  true                    ( name$ true )
256   else                                 ( name$ )
257      2drop  false                      ( false )
258   then                                 ( name$ true | false )
259;
260
261\ setup arch-name
262\  sun4v  -or-  sun4u
263: get-def-arch  ( -- )
264   " device_type"  root-ph  get-package-property  if
265      \ some older sunfires don't have device_type set
266      false                             ( sun4u )
267   else                                 ( devtype-prop$ )
268      decode-string  2swap 2drop        ( devtype$ )
269      " sun4v" $=                       ( sun4v? )
270   then                                 ( sun4v? )
271   if  " sun4v"  else  " sun4u"  then   ( arch$ )
272   arch-name swap  move
273;
274
275\ setup plat-name
276\  platform name  -or-
277\  compatible name  -or-
278\  default name
279: get-arch  ( -- )
280   get-def-arch
281
282   \ first try "name" in root
283   " name"  root-ph  get-string-prop           ( name$ )
284   try-platname  if
285      plat-name swap  move  exit               (  )
286   then                                        (  )
287
288   \ next try "compatible"
289   " compatible"  root-ph                      ( prop$ ph )
290   get-package-property  invert  if            ( compat$ )
291      begin  decode-string dup  while          ( compat$ name$ )
292         try-platname  if
293            plat-name swap  move  2drop  exit  (  )
294         then                                  ( compat$ )
295      repeat  2drop 2drop                      (  )
296   then                                        (  )
297
298   \ else use default name
299   arch-name$  plat-name swap  move
300;
301
302\ make <pre> <file> into /platform/<pre>/<file>
303: $plat-prepend  ( file$ pre$ -- file$' )
304   init-targ
305   targ-file$  $append                 ( file$ )
306   " /" targ-file$  $append
307   targ-file$  $append                 (  )
308   targ-file$                          ( new$ )
309;
310
311: get-boot  ( -- file$ )
312   fflag?  if
313      boot-file$
314   else
315      " boot_archive"
316   then
317;
318
319: get-kern  ( -- file$ )
320   kern?  if
321      kern-file$
322   else
323      " kernel/sparcv9/unix"
324   then
325;
326
327\ if we're nested, load the kernel, else load the bootarchive
328: get-targ  ( -- file$ )
329   nested?  if
330      get-kern
331   else
332      get-boot
333   then
334;
335
336
337: try-file  ( file$ -- [ fd ] error? )
338   diagnostic-mode?  if
339      2dup ." Loading: " type cr
340   then
341   fs-open  invert         ( fd false | true )
342;
343
344\  try "/platform/<plat-name>/<file>"  e.g., SUNW,Sun-Blade-1000
345\  then "/platform/<arch-name>/<file>"  e.g., sun4u
346: open-path  ( file$ - fd )
347   over c@ ascii /  <>  if
348      2dup  plat-name$  $plat-prepend      ( file$ file$' )
349      try-file  if                         ( file$ )
350         2dup  arch-name$  $plat-prepend   ( file$ file$' )
351         try-file  if                      ( file$ )
352           open-abort
353         then                              ( file$ fd )
354      then                                 ( file$ fd )
355   else                                    ( file$ )
356      \ copy to targ-file for 'whoami' prop
357      targ-file /buf-len  erase
358      2dup targ-file swap  move
359      2dup  try-file  if                   ( file$ )
360        open-abort
361      then                                 ( file$ fd )
362   then                                    ( file$ fd )
363   -rot 2drop                              ( fd )
364;
365
366
367\ ZFS support
368\ -Z fsname  opens specified filesystem in disk pool
369
370false     value    zflag?
371/buf-len  buffer:  fs-name
372: fs-name$  ( -- fs$ )  fs-name cscount  ;
373
374[ifdef] zfs
375
376: open-zfs-fs  ( fs$ -- )
377   2dup  " open-fs" fs-ih $call-method  0=  if
378      open-abort
379   then
380   2drop                     (  )
381;
382
383[else]
384
385: open-zfs-fs ( fs$ -- )
386   ." -Z not supported on non-zfs root"  abort
387;
388
389[then]
390
391
392\
393\	arg parsing
394\
395
396headerless
397: printable?  ( n -- flag ) \ true if n is a printable ascii character
398   dup bl th 7f within  swap  th 80  th ff  between  or
399;
400: white-space? ( n -- flag ) \ true is n is non-printable? or a blank
401   dup printable? 0=  swap  bl =  or
402;
403
404: skip-blanks  ( adr len -- adr' len' )
405   begin  dup  while   ( adr' len' )
406      over c@  white-space? 0=  if  exit  then
407      str++
408   repeat
409;
410
411: skip-non-blanks  ( adr len -- adr' len' )
412   begin  dup  while   ( adr' len' )
413      over c@  white-space?  if  exit  then
414      str++
415   repeat
416;
417
418headers
419\ left-parse-string w/ any white space as delimeter
420: next-str  ( adr len -- adr' len' s-adr s-len )
421   2dup  skip-non-blanks       ( s-adr len adr' len' )
422   dup >r  2swap  r> -         ( adr' len' s-adr s-len )
423;
424
425: next-c  ( adr len -- adr' len' c )
426   over c@ >r  str++  r>
427;
428
429false value halt?
430
431: parse-bootargs  ( -- )
432   " bootargs" chosen-ph  get-string-prop  ( arg$ )
433
434   \ check for explicit kernel name
435   skip-blanks  dup  if
436      over c@  ascii -  <>  if
437         next-str                          ( arg$ kern$ )
438         \ use default kernel if user specific a debugger
439         2dup  " kadb"  $=  >r             ( arg$ kern$  r: kadb? )
440         2dup  " kmdb"  $=  r>  or         ( arg$ kern$ debugger? )
441         invert  if                        ( arg$ kern$ )
442            kern-file swap  move           ( arg$ )
443            true to kern?
444         else  2drop  then                 ( arg$ )
445      then
446   then
447
448   \ process args
449   begin
450      skip-blanks  dup                     ( arg$ len )
451   while
452      next-c  ascii -  =  if
453         next-c  case
454            ascii D  of
455               \ for "boot kadb -D kernel.foo/unix"
456               skip-blanks  next-str       ( arg$ file$ )
457               kern? invert  if
458                  ?dup  if
459                     kern-file swap  move  ( arg$ )
460                     true to kern?
461                  else  drop  then         ( arg$ )
462               else  2drop  then           ( arg$ )
463            endof
464            ascii F  of
465               skip-blanks  next-str       ( arg$ file$ )
466               ?dup  if
467                  boot-file swap  move     ( arg$ )
468                  true to fflag?
469               else  drop  then            ( arg$ )
470            endof
471            ascii H  of
472               true to halt?
473            endof
474            ascii Z  of
475               skip-blanks  next-str       ( arg$ fs-name$ )
476               ?dup  if
477                  fs-name swap  move       ( arg$ )
478                  true to zflag?
479               else  drop  then            ( arg$ )
480            endof
481         endcase
482      then
483   repeat
484   2drop                                   (  )
485;
486
487
4880 value rd-alloc-sz
489
490: "ramdisk"  ( -- dev$ )  " /ramdisk-root"  ;
491
492: setup-bootprops  ( -- )
493   chosen-ph  push-package
494
495   nested? invert  if
496      fs-type$ encode-string    " fstype"             property
497      fs-ih encode-int          " bootfs"             property
498      fs-bootprop  if  property  then
499   else
500      fs-type$ encode-string    " archive-fstype"     property
501      fs-ih encode-int          " archfs"             property
502   then
503
504   is-archive?  if
505      "ramdisk" encode-string   " bootarchive"        property
506   else
507      loader-base encode-int    " elfheader-address"  property
508      file-sz encode-int        " elfheader-length"   property
509      plat-name$ encode-string  " impl-arch-name"     property
510      targ-file$ encode-string  " whoami"             property
511      fs-pkg$ encode-string     " fs-package"         property
512   then
513
514   pop-package
515;
516
517
518\ load ramdisk fcode and tell the driver where
519\ we put the ramdisk data
520: setup-ramdisk  ( base size -- )
521   /rd-fcode mem-alloc                ( base size adr )
522   dup /rd-fcode  fs-getrd
523
524   root-ph  push-package
525   new-device
526      "ramdisk" str++  device-name
527      dup 1  byte-load
528   finish-device
529   pop-package
530
531   /rd-fcode mem-free              ( base size )
532
533   "ramdisk"  dev-open  dup 0=  if
534      "ramdisk" open-abort
535   then  >r                        ( base size  r: ih )
536   rd-alloc-sz                     ( base size alloc-sz  r: ih )
537   " create"  r@ $call-method      ( r: ih )
538   r> dev-close                    (  )
539;
540
541
542\
543\	ELF parsing
544\
545
546headerless
5470 value elfhdr
5480 value phdr
549
550: +elfhdr	( index -- value )  elfhdr swap ca+ ;
551: e_machine     ( -- n )  h# 12 +elfhdr w@ ;
552: e_entry	( -- n )  h# 18 +elfhdr x@ ;
553: e_phoff	( -- n )  h# 20 +elfhdr x@ ;
554: e_phentsize	( -- n )  h# 36 +elfhdr w@ ;
555: e_phnum	( -- n )  h# 38 +elfhdr w@ ;
556
5571 constant pt_load
558: +phdr		( index -- value )  phdr swap ca+ ;
559: p_type	( -- n )  h#  0 +phdr l@ ;
560: p_vaddr	( -- n )  h# 10 +phdr x@ ;
561: p_memsz	( -- n )  h# 28 +phdr x@ ;
562
563: get-phdr ( filebase index -- phdr )
564   e_phentsize *  e_phoff +  +    ( phdr )
565;
566
567\ alloc 4MB pages for kernel text/data
568: vmem-alloc-4mb  ( size virt -- base )
569   swap  4meg roundup  swap
570   4meg (mem-alloc)
571;
572
573headers
574\ OBP doesn't allocate memory for elf
575\ programs, it assumes they'll fit
576\ under the default 10MB limit
577: fix-elf-mem  ( base -- )
578   dup to elfhdr
579   e_machine  d# 43  <>  if  drop exit  then       \ 64b only
580
581   e_phnum 0  ?do
582      dup i get-phdr  to phdr
583      p_type pt_load =  p_vaddr h# a0.0000 >  and  if
584         \ allocate 4MB segs for text & data
585         p_vaddr  4meg 1-  and  if
586            p_memsz p_vaddr  vmem-alloc  drop
587         else
588            p_memsz p_vaddr  vmem-alloc-4mb  drop
589         then
590      then
591   loop  drop                   (  )
592;
593
594
595: load-file  ( -- virt )
596   get-arch
597   get-targ  open-path              ( fd )
598   loader-base over  get-file  if   ( fd alloc-sz virt size )
599      ." Boot load failed" abort
600   then
601   to file-sz                       ( fd alloc-sz virt )
602   swap  to rd-alloc-sz             ( fd virt )
603   swap  fs-close                   ( virt )
604;
605
606: setup-props  ( virt -- virt )
607   dup get-type
608   setup-bootprops
609   is-archive?  if
610      dup file-sz  setup-ramdisk
611   then
612;
613
614: exec-file  ( virt -- )
615   is-elf?  if
616      dup  fix-elf-mem
617   then
618   is-archive?  if  >bootblk  then          ( virt' )
619   " to load-base init-program"  evaluate
620;
621
622: do-boot ( -- )
623   parse-bootargs
624   halt?  if
625      ." Halted with -H flag. " cr
626      exit
627   then
628   get-bootdev
629   load-pkg
630   mount-root
631   zflag?  nested? invert  and  if
632      fs-name$  open-zfs-fs
633   then
634   load-file                        ( virt )
635   setup-props
636   exec-file                        (  )
637;
638
639\ Tadpole proms don't initialize my-self
6400 to my-self
641
642do-boot
643