dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / psm / stand / bootblks / common / boot.fth
blobef0fd839405faa5122acadbf90ee805740bc36ad
2 \ CDDL HEADER START
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.
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.
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]
19 \ CDDL HEADER END
22 \ Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 \ Use is subject to license terms.
26 purpose: boot block for OBP systems
27 copyright: Copyright 2009 Sun Microsystems, Inc. All Rights Reserved
30 headerless
31 d# 1024 dup  *     constant  1meg
32 d# 4  1meg   *     constant  4meg
33 d# 32 1meg   *     constant  32meg
35 headers
36 " /"  get-package  constant  root-ph
38 0                  value     fs-ih
39 false              value     nested?
40 0                  value     file-sz
42 /buf-len  buffer:  boot-dev
43 : boot-dev$  ( -- dev$ )  boot-dev cscount  ;
45 : loader-base  ( -- base )
46    nested?  if
47       h# 5000.0000
48    else
49       h# 5100.0000
50    then
55 \ methods we expect of fs reader packages
57 headerless
58 : fs-open  ( file$ -- fd true | false )
59    " open-file" fs-ih $call-method
62 : fs-close  ( fd -- )
63    " close-file" fs-ih $call-method
66 : fs-size  ( fd -- size )
67    " size-file" fs-ih $call-method
70 : fs-read  ( adr len fd -- #read )
71    " read-file" fs-ih $call-method
74 : fs-getrd  ( adr len -- )
75    " get-rd" fs-ih $call-method
78 : fs-bootprop  ( -- propval propname true  |  false )
79    " bootprop" fs-ih $call-method
81 headers
84 : check-elf ( base -- is-elf? )
85    l@  h# 7f454c46 ( \x7fELF )  =
88 : check-fcode ( base -- is-fcode? )
89    c@ dup  h# f0 h# f3 between  swap h# fd =  or
93 \ zfs bootblks with all headers exceeds 7.5k
94 \ 'bigbootblk' allows us to load the fs reader from elsewhere
95 [ifdef] bigbootblk
97 : load-pkg  ( -- )
98    boot-dev$                              ( dev$ )
99    2dup dev-open  ?dup 0=  if
100       open-abort
101    then  >r 2drop                         ( r: ih )
103    /fs-fcode  mem-alloc                   ( adr  r: ih )
104    dup  /fs-fcode fs-offset r@  read-disk
106    dup check-fcode  invert  if
107       " No fs fcode found"  die
108    then
109    dup  1 byte-load
111    /fs-fcode  mem-free                    ( r: ih )
112    r>  dev-close
115 [else]
117 : load-pkg  ( -- )  ;
119 [then]
122 : get-bootdev  ( -- )
123    \ first try boot archive (nested boot from ramdisk)
124    \ then try boot device (direct boot from disk)
125    " bootarchive" chosen-ph  get-package-property  if
126       " bootpath" chosen-ph  get-string-prop            ( bootpath$ )
127    else                                                 ( archiveprop$ )
128       decode-string  2swap 2drop                        ( archivepath$ )
129       true to nested?
130    then                                                 ( bootpath$ )
131    boot-dev swap  move                                  (  )
134 : mount-root  ( -- )
135    boot-dev$ fs-pkg$  $open-package to fs-ih
136    fs-ih 0=  if
137       " Can't mount root" die
138    then
142 \ cheap entertainment for those watching
143 \ boot progress
145 headerless
146 create spin-data
147    ascii | c,  ascii / c,  ascii - c,  ascii \ c,
149 variable spindex
151 headers
152 : spinner ( -- )
153    spindex @  3 and  spin-data +   ( c-adr )
154    c@ emit  (cr
155    1 spindex +!
158 \ allocate and return physical allocation size
159 : vmem-alloc-prop  ( size virt -- alloc-size virt )
160    2dup  ['] vmem-alloc  catch  if            ( size virt ??? ??? )
161       2drop                                   ( size virt )
162       2dup  begin                             ( size virt len adr )
163          over 32meg  min  >r                  ( size virt len adr  r: alloc-sz )
164          r@ over  vmem-alloc                  ( size virt len adr adr  r: alloc-sz )
165          nip  r@ +                            ( size virt len adr'  r: alloc-sz )
166          swap r> -                            ( size virt adr len' )
167          swap over  0=                        ( size virt len' adr done? )
168       until                                   ( size virt len' adr )
169       2drop nip  32meg                        ( virt 32meg )
170    else                                       ( size virt virt )
171       nip nip  0                              ( virt 0 )
172    then                                       ( virt alloc-sz )
173    swap
176 \ read file in chunks so we can toggle the spinner
177 : read-file  ( virt size fd -- failed? )
178    >r                             ( virt sz-left  r: fd )
179    begin  dup  while
180       spinner
181       dup  4meg min               ( virt sz-left read-sz  r: fd )
182       3dup nip  r@ fs-read        ( virt sz-left read-sz size-read  r: fd )
183       over <>  if                 ( virt sz-left read-sz  r: fd )
184          r>  2drop  2drop         (  )
185          true  exit               ( failed )
186       then
187       rot over  +                 ( sz-left read-sz virt'  r: fd )
188       -rot  -                     ( virt' sz-left'  r: fd )
189    repeat
190    r>  3drop                      (  )
191    false                          ( succeeded )
194 \ read in file and return buffer
195 \ if base==0, vmem-alloc will allocate virt
196 \ NB returned size is 8k rounded since the
197 \ memory allocator rounded it for us
198 : get-file ( base fd -- [ alloc-sz virt size ] failed? )
199    dup >r  fs-size                         ( base size  r: fd )
200    dup rot  vmem-alloc-prop                ( size alloc-sz virt  r: fd )
201    rot  2dup                               ( alloc-sz virt size virt size  r: fd )
202    r>  read-file  if                       ( alloc-sz virt size )
203       3drop true  exit                     ( failed )
204    then
205    h# 2000  roundup                        ( alloc-sz virt size' )
206    false                                   ( alloc-sz virt size' succeeded )
210 false value is-elf?
211 false value is-archive?
214 : >bootblk  ( adr -- adr' )  d# 512 +  ;
216 \ figure out what we just loaded
217 : get-type  ( adr -- )
218    dup check-elf to is-elf?
220    \ if not nested, check for boot archive (executable after label)
221    nested? invert  if
222       >bootblk
223       dup check-fcode           ( adr is-fcode? )
224       over check-elf            ( adr is-fcode? is-elf? )
225       or  to is-archive?
226    then
227    drop
232 \       file name routines
235 \ boot file (-F name or boot archive)
236 false     value    fflag?
237 /buf-len  buffer:  boot-file
238 : boot-file$  ( -- file$ )  boot-file cscount  ;
240 \ kernel name (final name or unix)
241 false     value    kern?
242 /buf-len  buffer:  kern-file
243 : kern-file$  ( -- file$ )  kern-file cscount  ;
245 \ platform name
246 /buf-len  buffer:  plat-name
247 : plat-name$  ( -- plat$ )  plat-name cscount  ;
249 \ arch name
250 /buf-len  buffer:  arch-name
251 : arch-name$  ( -- arch$ )  arch-name cscount  ;
253 \ final name after /platform massaging
254 /buf-len  buffer:  targ-file
255 : targ-file$  ( -- file$ )  targ-file cscount  ;
257 : init-targ  ( -- )
258    targ-file /buf-len erase
259    " /platform/"  targ-file swap  move
262 \ remove illegal file name chars (e.g., '/')
263 : munge-name ( name$ -- name$' )
264    2dup                           ( name$ name$ )
265    begin  dup  while
266       over c@  ascii /  =  if
267          over  ascii _  swap  c!  ( name$ name$' )
268       then  str++
269    repeat  2drop                  ( name$ )
272 \ does /platform/<name> exist?
273 : try-platname  ( name$ -- name$ true | false )
274    munge-name                           ( name$' )
275    init-targ  2dup targ-file$  $append
276    targ-file$ fs-open  if               ( name$ fd )
277       fs-close  true                    ( name$ true )
278    else                                 ( name$ )
279       2drop  false                      ( false )
280    then                                 ( name$ true | false )
283 \ setup arch-name
284 \  sun4v  -or-  sun4u
285 : get-def-arch  ( -- )
286    " device_type"  root-ph  get-package-property  if
287       \ some older sunfires don't have device_type set
288       false                             ( sun4u )
289    else                                 ( devtype-prop$ )
290       decode-string  2swap 2drop        ( devtype$ )
291       " sun4v" $=                       ( sun4v? )
292    then                                 ( sun4v? )
293    if  " sun4v"  else  " sun4u"  then   ( arch$ )
294    arch-name swap  move
297 \ setup plat-name
298 \  platform name  -or-
299 \  compatible name  -or-
300 \  default name
301 : get-arch  ( -- )
302    get-def-arch
304    \ first try "name" in root
305    " name"  root-ph  get-string-prop           ( name$ )
306    try-platname  if
307       plat-name swap  move  exit               (  )
308    then                                        (  )
310    \ next try "compatible"
311    " compatible"  root-ph                      ( prop$ ph )
312    get-package-property  invert  if            ( compat$ )
313       begin  decode-string dup  while          ( compat$ name$ )
314          try-platname  if
315             plat-name swap  move  2drop  exit  (  )
316          then                                  ( compat$ )
317       repeat  2drop 2drop                      (  )
318    then                                        (  )
320    \ else use default name
321    arch-name$  plat-name swap  move
324 \ make <pre> <file> into /platform/<pre>/<file>
325 : $plat-prepend  ( file$ pre$ -- file$' )
326    init-targ
327    targ-file$  $append                 ( file$ )
328    " /" targ-file$  $append
329    targ-file$  $append                 (  )
330    targ-file$                          ( new$ )
333 : get-boot  ( -- file$ )
334    fflag?  if
335       boot-file$
336    else
337       " boot_archive"
338    then
341 : get-kern  ( -- file$ )
342    kern?  if
343       kern-file$
344    else
345       " kernel/sparcv9/unix"
346    then
349 \ if we're nested, load the kernel, else load the bootarchive
350 : get-targ  ( -- file$ )
351    nested?  if
352       get-kern
353    else
354       get-boot
355    then
359 : try-file  ( file$ -- [ fd ] error? )
360    diagnostic-mode?  if
361       2dup ." Loading: " type cr
362    then
363    fs-open  invert         ( fd false | true )
366 \  try "/platform/<plat-name>/<file>"  e.g., SUNW,Sun-Blade-1000
367 \  then "/platform/<arch-name>/<file>"  e.g., sun4u
368 : open-path  ( file$ - fd )
369    over c@ ascii /  <>  if
370       2dup  plat-name$  $plat-prepend      ( file$ file$' )
371       try-file  if                         ( file$ )
372          2dup  arch-name$  $plat-prepend   ( file$ file$' )
373          try-file  if                      ( file$ )
374            open-abort
375          then                              ( file$ fd )
376       then                                 ( file$ fd )
377    else                                    ( file$ )
378       \ copy to targ-file for 'whoami' prop
379       targ-file /buf-len  erase
380       2dup targ-file swap  move
381       2dup  try-file  if                   ( file$ )
382         open-abort
383       then                                 ( file$ fd )
384    then                                    ( file$ fd )
385    -rot 2drop                              ( fd )
389 false  value  lflag?
391 \ ZFS support
392 \ -Z fsname  opens specified filesystem in disk pool
394 false     value    zflag?
395 /buf-len  buffer:  fs-name
396 : fs-name$  ( -- fs$ )  fs-name cscount  ;
398 [ifdef] zfs
400 : open-zfs-fs  ( fs$ -- )
401    2dup  " open-fs" fs-ih $call-method  0=  if
402       open-abort
403    then
404    2drop                     (  )
407 [else]
409 : open-zfs-fs ( fs$ -- )
410    \ ignore on -L
411    lflag? invert  if
412       " -Z not supported on non-zfs root"  die
413    then
416 [then]
420 \       arg parsing
423 headerless
424 : printable?  ( n -- flag ) \ true if n is a printable ascii character
425    dup bl th 7f within  swap  th 80  th ff  between  or
427 : white-space? ( n -- flag ) \ true is n is non-printable? or a blank
428    dup printable? 0=  swap  bl =  or
431 : skip-blanks  ( adr len -- adr' len' )
432    begin  dup  while   ( adr' len' )
433       over c@  white-space? 0=  if  exit  then
434       str++
435    repeat
438 : skip-non-blanks  ( adr len -- adr' len' )
439    begin  dup  while   ( adr' len' )
440       over c@  white-space?  if  exit  then
441       str++
442    repeat
445 headers
446 \ left-parse-string w/ any white space as delimeter
447 : next-str  ( adr len -- adr' len' s-adr s-len )
448    2dup  skip-non-blanks       ( s-adr len adr' len' )
449    dup >r  2swap  r> -         ( adr' len' s-adr s-len )
452 \ next char or 0 if eol
453 : next-c  ( adr len -- adr' len' c )
454    dup  if  over c@ >r  str++  r>  else  0  then
457 false value halt?
459 : parse-bootargs  ( -- )
460    " bootargs" chosen-ph  get-string-prop  ( arg$ )
462    \ check for explicit kernel name
463    skip-blanks  dup  if
464       over c@  ascii -  <>  if
465          next-str                          ( arg$ kern$ )
466          \ use default kernel if user specific a debugger
467          2dup  " kadb"  $=  >r             ( arg$ kern$  r: kadb? )
468          2dup  " kmdb"  $=  r>  or         ( arg$ kern$ debugger? )
469          invert  if                        ( arg$ kern$ )
470             kern-file swap  move           ( arg$ )
471             true to kern?
472          else  2drop  then                 ( arg$ )
473       then
474    then
476    \ process args
477    begin
478       skip-blanks  dup                     ( arg$ len )
479    while
480       next-c  ascii -  =  if
481          next-c  case
482             ascii D  of
483                \ for "boot kadb -D kernel.foo/unix"
484                skip-blanks  next-str       ( arg$ file$ )
485                kern? invert  if
486                   ?dup  if
487                      kern-file swap  move  ( arg$ )
488                      true to kern?
489                   else  drop  then         ( arg$ )
490                else  2drop  then           ( arg$ )
491             endof
492             ascii F  of
493                skip-blanks  next-str       ( arg$ file$ )
494                ?dup  if
495                   boot-file swap  move     ( arg$ )
496                   true to fflag?
497                else  drop  then            ( arg$ )
498             endof
499             ascii H  of
500                true to halt?
501             endof
502             ascii L  of
503                " /" fs-name swap  move
504                true to zflag?
505                " bootlst" boot-file swap  move
506                true to fflag?
507                true to lflag?
508             endof
509             ascii Z  of
510                skip-blanks  next-str       ( arg$ fs-name$ )
511                ?dup  if
512                   fs-name swap  move       ( arg$ )
513                   true to zflag?
514                else  drop  then            ( arg$ )
515             endof
516          endcase
517       then
518    repeat
519    2drop                                   (  )
523 0 value rd-alloc-sz
525 : "ramdisk"  ( -- dev$ )  " /ramdisk-root"  ;
527 : setup-bootprops  ( -- )
528    chosen-ph  push-package
530    nested? invert  if
531       fs-type$ encode-string    " fstype"             property
532       fs-ih encode-int          " bootfs"             property
533       fs-bootprop  if  property  then
534    else
535       fs-type$ encode-string    " archive-fstype"     property
536       fs-ih encode-int          " archfs"             property
537    then
539    is-archive?  if
540       "ramdisk" encode-string   " bootarchive"        property
541    else
542       loader-base encode-int    " elfheader-address"  property
543       file-sz encode-int        " elfheader-length"   property
544       plat-name$ encode-string  " impl-arch-name"     property
545       targ-file$ encode-string  " whoami"             property
546       fs-pkg$ encode-string     " fs-package"         property
547    then
549    pop-package
553 \ load ramdisk fcode and tell the driver where
554 \ we put the ramdisk data
555 : setup-ramdisk  ( base size -- )
556    /rd-fcode mem-alloc                ( base size adr )
557    dup /rd-fcode  fs-getrd
559    root-ph  push-package
560    new-device
561       "ramdisk" str++  device-name
562       dup 1  byte-load
563    finish-device
564    pop-package
565    
566    /rd-fcode mem-free              ( base size )
568    "ramdisk"  dev-open  dup 0=  if
569       "ramdisk" open-abort
570    then  >r                        ( base size  r: ih )
571    rd-alloc-sz                     ( base size alloc-sz  r: ih )
572    " create"  r@ $call-method      ( r: ih )
573    r> dev-close                    (  )
578 \       ELF parsing
581 headerless
582 0 value elfhdr
583 0 value phdr
585 : +elfhdr       ( index -- value )  elfhdr swap ca+ ;
586 : e_machine     ( -- n )  h# 12 +elfhdr w@ ;
587 : e_entry       ( -- n )  h# 18 +elfhdr x@ ;
588 : e_phoff       ( -- n )  h# 20 +elfhdr x@ ;
589 : e_phentsize   ( -- n )  h# 36 +elfhdr w@ ;
590 : e_phnum       ( -- n )  h# 38 +elfhdr w@ ;
592 1 constant pt_load
593 : +phdr         ( index -- value )  phdr swap ca+ ;
594 : p_type        ( -- n )  h#  0 +phdr l@ ;
595 : p_vaddr       ( -- n )  h# 10 +phdr x@ ;
596 : p_memsz       ( -- n )  h# 28 +phdr x@ ;
598 : get-phdr ( filebase index -- phdr )
599    e_phentsize *  e_phoff +  +    ( phdr )
602 \ alloc 4MB pages for kernel text/data
603 : vmem-alloc-4mb  ( size virt -- base )
604    swap  4meg roundup  swap
605    4meg (mem-alloc)
608 headers
609 \ OBP doesn't allocate memory for elf
610 \ programs, it assumes they'll fit
611 \ under the default 10MB limit
612 : fix-elf-mem  ( base -- )
613    dup to elfhdr
614    e_machine  d# 43  <>  if  drop exit  then       \ 64b only
616    e_phnum 0  ?do
617       dup i get-phdr  to phdr
618       p_type pt_load =  p_vaddr h# a0.0000 >  and  if
619          \ allocate 4MB segs for text & data
620          p_vaddr  4meg 1-  and  if
621             p_memsz p_vaddr  vmem-alloc  drop
622          else
623             p_memsz p_vaddr  vmem-alloc-4mb  drop
624          then
625       then
626    loop  drop                   (  )
630 : load-file  ( -- virt )
631    get-arch
632    get-targ  open-path              ( fd )
633    loader-base over  get-file  if   ( fd alloc-sz virt size )
634       " Boot load failed" die
635    then
636    to file-sz                       ( fd alloc-sz virt )
637    swap  to rd-alloc-sz             ( fd virt )
638    swap  fs-close                   ( virt )
641 : setup-props  ( virt -- virt )
642    dup get-type
643    setup-bootprops
644    is-archive?  if
645       dup file-sz  setup-ramdisk
646    then
649 : exec-file  ( virt -- )
650    is-elf?  if
651       dup  fix-elf-mem
652    then
653    is-archive?  if  >bootblk  then          ( virt' )
654    " to load-base init-program"  evaluate
657 : do-boot ( -- )
658    parse-bootargs
659    halt?  if
660       ." Halted with -H flag. " cr
661       exit
662    then
663    get-bootdev
664    load-pkg
665    mount-root
666    zflag?  nested? invert  and  if
667       fs-name$  open-zfs-fs
668    then
669    load-file                        ( virt )
670    setup-props
671    exec-file                        (  )
674 \ Tadpole proms don't initialize my-self
675 0 to my-self
677 do-boot