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
26purpose: boot block for OBP systems
27copyright: Copyright 2009 Sun Microsystems, Inc. All Rights Reserved
28
29
30headerless
31d# 1024 dup  *     constant  1meg
32d# 4  1meg   *     constant  4meg
33d# 32 1meg   *     constant  32meg
34
35headers
36" /"  get-package  constant  root-ph
37
380                  value     fs-ih
39false              value     nested?
400                  value     file-sz
41
42/buf-len  buffer:  boot-dev
43: boot-dev$  ( -- dev$ )  boot-dev cscount  ;
44
45: loader-base  ( -- base )
46   nested?  if
47      h# 5000.0000
48   else
49      h# 5100.0000
50   then
51;
52
53
54\
55\ methods we expect of fs reader packages
56\
57headerless
58: fs-open  ( file$ -- fd true | false )
59   " open-file" fs-ih $call-method
60;
61
62: fs-close  ( fd -- )
63   " close-file" fs-ih $call-method
64;
65
66: fs-size  ( fd -- size )
67   " size-file" fs-ih $call-method
68;
69
70: fs-read  ( adr len fd -- #read )
71   " read-file" fs-ih $call-method
72;
73
74: fs-getrd  ( adr len -- )
75   " get-rd" fs-ih $call-method
76;
77
78: fs-bootprop  ( -- propval propname true  |  false )
79   " bootprop" fs-ih $call-method
80;
81headers
82
83
84: check-elf ( base -- is-elf? )
85   l@  h# 7f454c46 ( \x7fELF )  =
86;
87
88: check-fcode ( base -- is-fcode? )
89   c@ dup  h# f0 h# f3 between  swap h# fd =  or
90;
91
92
93\ zfs bootblks with all headers exceeds 7.5k
94\ 'bigbootblk' allows us to load the fs reader from elsewhere
95[ifdef] bigbootblk
96
97: load-pkg  ( -- )
98   boot-dev$                              ( dev$ )
99   2dup dev-open  ?dup 0=  if
100      open-abort
101   then  >r 2drop                         ( r: ih )
102
103   /fs-fcode  mem-alloc                   ( adr  r: ih )
104   dup  /fs-fcode fs-offset r@  read-disk
105
106   dup check-fcode  invert  if
107      " No fs fcode found"  die
108   then
109   dup  1 byte-load
110
111   /fs-fcode  mem-free                    ( r: ih )
112   r>  dev-close
113;
114
115[else]
116
117: load-pkg  ( -- )  ;
118
119[then]
120
121
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                                  (  )
132;
133
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
139;
140
141\
142\ cheap entertainment for those watching
143\ boot progress
144\
145headerless
146create spin-data
147   ascii | c,  ascii / c,  ascii - c,  ascii \ c,
148
149variable spindex
150
151headers
152: spinner ( -- )
153   spindex @  3 and  spin-data +   ( c-adr )
154   c@ emit  (cr
155   1 spindex +!
156;
157
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
174;
175
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 )
192;
193
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 )
207;
208
209
210false value is-elf?
211false value is-archive?
212
213
214: >bootblk  ( adr -- adr' )  d# 512 +  ;
215
216\ figure out what we just loaded
217: get-type  ( adr -- )
218   dup check-elf to is-elf?
219
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
228;
229
230
231\
232\	file name routines
233\
234
235\ boot file (-F name or boot archive)
236false     value    fflag?
237/buf-len  buffer:  boot-file
238: boot-file$  ( -- file$ )  boot-file cscount  ;
239
240\ kernel name (final name or unix)
241false     value    kern?
242/buf-len  buffer:  kern-file
243: kern-file$  ( -- file$ )  kern-file cscount  ;
244
245\ platform name
246/buf-len  buffer:  plat-name
247: plat-name$  ( -- plat$ )  plat-name cscount  ;
248
249\ arch name
250/buf-len  buffer:  arch-name
251: arch-name$  ( -- arch$ )  arch-name cscount  ;
252
253\ final name after /platform massaging
254/buf-len  buffer:  targ-file
255: targ-file$  ( -- file$ )  targ-file cscount  ;
256
257: init-targ  ( -- )
258   targ-file /buf-len erase
259   " /platform/"  targ-file swap  move
260;
261
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$ )
270;
271
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 )
281;
282
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
295;
296
297\ setup plat-name
298\  platform name  -or-
299\  compatible name  -or-
300\  default name
301: get-arch  ( -- )
302   get-def-arch
303
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                                        (  )
309
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                                        (  )
319
320   \ else use default name
321   arch-name$  plat-name swap  move
322;
323
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$ )
331;
332
333: get-boot  ( -- file$ )
334   fflag?  if
335      boot-file$
336   else
337      " boot_archive"
338   then
339;
340
341: get-kern  ( -- file$ )
342   kern?  if
343      kern-file$
344   else
345      " kernel/sparcv9/unix"
346   then
347;
348
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
356;
357
358
359: try-file  ( file$ -- [ fd ] error? )
360   diagnostic-mode?  if
361      2dup ." Loading: " type cr
362   then
363   fs-open  invert         ( fd false | true )
364;
365
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 )
386;
387
388
389false  value  lflag?
390
391\ ZFS support
392\ -Z fsname  opens specified filesystem in disk pool
393
394false     value    zflag?
395/buf-len  buffer:  fs-name
396: fs-name$  ( -- fs$ )  fs-name cscount  ;
397
398[ifdef] zfs
399
400: open-zfs-fs  ( fs$ -- )
401   2dup  " open-fs" fs-ih $call-method  0=  if
402      open-abort
403   then
404   2drop                     (  )
405;
406
407[else]
408
409: open-zfs-fs ( fs$ -- )
410   \ ignore on -L
411   lflag? invert  if
412      " -Z not supported on non-zfs root"  die
413   then
414;
415
416[then]
417
418
419\
420\	arg parsing
421\
422
423headerless
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
426;
427: white-space? ( n -- flag ) \ true is n is non-printable? or a blank
428   dup printable? 0=  swap  bl =  or
429;
430
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
436;
437
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
443;
444
445headers
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 )
450;
451
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
455;
456
457false value halt?
458
459: parse-bootargs  ( -- )
460   " bootargs" chosen-ph  get-string-prop  ( arg$ )
461
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
475
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                                   (  )
520;
521
522
5230 value rd-alloc-sz
524
525: "ramdisk"  ( -- dev$ )  " /ramdisk-root"  ;
526
527: setup-bootprops  ( -- )
528   chosen-ph  push-package
529
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
538
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
548
549   pop-package
550;
551
552
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
558
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 )
567
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                    (  )
574;
575
576
577\
578\	ELF parsing
579\
580
581headerless
5820 value elfhdr
5830 value phdr
584
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@ ;
591
5921 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@ ;
597
598: get-phdr ( filebase index -- phdr )
599   e_phentsize *  e_phoff +  +    ( phdr )
600;
601
602\ alloc 4MB pages for kernel text/data
603: vmem-alloc-4mb  ( size virt -- base )
604   swap  4meg roundup  swap
605   4meg (mem-alloc)
606;
607
608headers
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
615
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                   (  )
627;
628
629
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 )
639;
640
641: setup-props  ( virt -- virt )
642   dup get-type
643   setup-bootprops
644   is-archive?  if
645      dup file-sz  setup-ramdisk
646   then
647;
648
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
655;
656
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                        (  )
672;
673
674\ Tadpole proms don't initialize my-self
6750 to my-self
676
677do-boot
678