xref: /illumos-gate/usr/src/boot/forth/loader.4th (revision 64439ec0071c576648f76b4466ad6ee7a580ed33)
1\ Copyright (c) 1999 Daniel C. Sobral <dcs@FreeBSD.org>
2\ Copyright (c) 2011-2015 Devin Teske <dteske@FreeBSD.org>
3\ All rights reserved.
4\
5\ Redistribution and use in source and binary forms, with or without
6\ modification, are permitted provided that the following conditions
7\ are met:
8\ 1. Redistributions of source code must retain the above copyright
9\    notice, this list of conditions and the following disclaimer.
10\ 2. Redistributions in binary form must reproduce the above copyright
11\    notice, this list of conditions and the following disclaimer in the
12\    documentation and/or other materials provided with the distribution.
13\
14\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17\ ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24\ SUCH DAMAGE.
25\
26\ $FreeBSD$
27
28only forth definitions
29
30s" arch-i386" environment? [if] [if]
31	s" loader_version" environment?  [if]
32		11 < [if]
33			.( Loader version 1.1+ required) cr
34			abort
35		[then]
36	[else]
37		.( Could not get loader version!) cr
38		abort
39	[then]
40[then] [then]
41
42include /boot/forth/support.4th
43include /boot/forth/color.4th
44include /boot/forth/delay.4th
45include /boot/forth/check-password.4th
46efi? [if]
47	include /boot/forth/efi.4th
48[then]
49
50only forth definitions
51
52: bootmsg ( -- )
53  loader_color? dup ( -- bool bool )
54  if 7 fg 4 bg then
55  ." Booting..."
56  if me then
57  cr
58;
59
60: try-menu-unset
61  \ menu-unset may not be present
62  s" beastie_disable" getenv
63  dup -1 <> if
64    s" YES" compare-insensitive 0= if
65      exit
66    then
67  else
68    drop
69  then
70  s" menu-unset"
71  sfind if
72    execute
73  else
74    drop
75  then
76  s" menusets-unset"
77  sfind if
78    execute
79  else
80    drop
81  then
82;
83
84only forth also support-functions also builtins definitions
85
86\ the boot-args was parsed to individual options while loaded
87\ now compose boot-args, so the boot can set kernel arguments
88\ note the command line switched for boot command will cause
89\ environment variable boot-args to be ignored
90\ There are 2 larger strings, acpi-user-options and existing boot-args
91\ other switches are 1 byte each, so allocate boot-args+acpi + extra bytes
92\ for rest. Be sure to review this, if more options are to be added into
93\ environment.
94
95: set-boot-args { | addr len baddr blen aaddr alen -- }
96  s" boot-args" getenv dup -1 <> if
97    to blen to baddr
98  else
99    drop
100  then
101  s" acpi-user-options" getenv dup -1 <> if
102    to alen to aaddr
103  else
104    drop
105  then
106
107  \ allocate temporary space. max is:
108  \  8 kernel switches
109  \  26 for acpi, so use 40 for safety
110  blen alen 40 + + allocate abort" out of memory"
111  to addr
112  \ boot-addr may have file name before options, copy it to addr
113  baddr 0<> if
114    baddr c@ [char] - <> if
115      baddr blen [char] - strchr		( addr len )
116      dup 0= if				\ no options, copy all
117        2drop
118        baddr addr blen move
119        blen to len
120        0 to blen
121        0 to baddr
122      else				( addr len )
123        dup blen
124        swap -
125        to len				( addr len )
126        to blen				( addr )
127        baddr addr len move		( addr )
128        to baddr			\ baddr points now to first option
129      then
130    then
131  then
132  \ now add kernel switches
133  len 0<> if
134    bl addr len + c! len 1+ to len
135  then
136  [char] - addr len + c! len 1+ to len
137
138  s" boot_single" getenv dup -1 <> if
139     s" YES" compare-insensitive 0= if
140       [char] s addr len + c! len 1+ to len
141     then
142  else
143    drop
144  then
145  s" boot_verbose" getenv dup -1 <> if
146     s" YES" compare-insensitive 0= if
147       [char] v addr len + c! len 1+ to len
148     then
149  else
150    drop
151  then
152  s" boot_kmdb" getenv dup -1 <> if
153     s" YES" compare-insensitive 0= if
154       [char] k addr len + c! len 1+ to len
155     then
156  else
157    drop
158  then
159  s" boot_drop_into_kmdb" getenv dup -1 <> if
160     s" YES" compare-insensitive 0= if
161       [char] d addr len + c! len 1+ to len
162     then
163  else
164    drop
165  then
166  s" boot_reconfigure" getenv dup -1 <> if
167     s" YES" compare-insensitive 0= if
168       [char] r addr len + c! len 1+ to len
169     then
170  else
171    drop
172  then
173  s" boot_ask" getenv dup -1 <> if
174     s" YES" compare-insensitive 0= if
175       [char] a addr len + c! len 1+ to len
176     then
177  else
178    drop
179  then
180  s" boot_noncluster" getenv dup -1 <> if
181     s" YES" compare-insensitive 0= if
182       [char] x addr len + c! len 1+ to len
183     then
184  else
185    drop
186  then
187
188  \ now add remining boot args if blen != 0.
189  \ baddr[0] is '-', if baddr[1] != 'B' append to addr,
190  \ otherwise add space then copy
191  blen 0<> if
192    baddr 1+ c@ [char] B = if
193      addr len + 1- c@ [char] - = if	 \ if addr[len -1] == '-'
194	baddr 1+ to baddr
195	blen 1- to blen
196      else
197	bl addr len + c! len 1+ to len
198      then
199    else
200      baddr 1+ to baddr
201      blen 1- to blen
202    then
203    baddr addr len + blen move
204    len blen + to len
205    0 to baddr
206    0 to blen
207  then
208  \ last part - add acpi.
209  alen 0<> if
210    addr len + 1- c@ [char] - <> if
211      bl addr len + c! len 1+ to len
212      [char] - addr len + c! len 1+ to len
213    then
214    s" B acpi-user-options=" dup -rot		( len addr len )
215    addr len + swap move			( len )
216    len + to len
217    aaddr addr len + alen move
218    len alen + to len
219  then
220
221  \ check for left over '-'
222  addr len 1- + c@ [char] - = if
223    len 1- to len
224				\ but now we may also have left over ' '
225    len if ( len <> 0 )
226      addr len 1- + c@ bl = if
227	len 1- to len
228      then
229    then
230  then
231
232  \ if len != 0, set boot-args
233  len 0<> if
234    addr len s" boot-args" setenv
235  then
236  addr free drop
237;
238
239: boot
240  0= if ( interpreted ) get_arguments then
241  set-boot-args
242
243  \ Unload only if a path was passed. Paths start with /
244  dup if
245    >r over r> swap
246    c@ [char] / = if
247      0 1 unload drop
248    else
249      s" kernelname" getenv? if ( a kernel has been loaded )
250        try-menu-unset
251        bootmsg 1 boot exit
252      then
253      load_kernel_and_modules
254      ?dup if exit then
255      try-menu-unset
256      bootmsg 0 1 boot exit
257    then
258  else
259    s" kernelname" getenv? if ( a kernel has been loaded )
260      try-menu-unset
261      bootmsg 1 boot exit
262    then
263    load_kernel_and_modules
264    ?dup if exit then
265    try-menu-unset
266    bootmsg 0 1 boot exit
267  then
268  load_kernel_and_modules
269  ?dup 0= if bootmsg 0 1 boot then
270;
271
272\ ***** boot-conf
273\
274\	Prepares to boot as specified by loaded configuration files.
275
276: boot-conf
277  0= if ( interpreted ) get_arguments then
278  0 1 unload drop
279  load_kernel_and_modules
280  ?dup 0= if 0 1 autoboot then
281;
282
283also forth definitions previous
284
285builtin: boot
286builtin: boot-conf
287
288only forth definitions also support-functions
289
290\
291\ in case the boot-args is set, parse it and extract following options:
292\ -a to boot_ask=YES
293\ -s to boot_single=YES
294\ -v to boot_verbose=YES
295\ -k to boot_kmdb=YES
296\ -d to boot_drop_into_kmdb=YES
297\ -r to boot_reconfigure=YES
298\ -x to boot_noncluster=YES
299\ -B acpi-user-options=X to acpi-user-options=X
300\
301\ This is needed so that the menu can manage these options. Unfortunately, this
302\ also means that boot-args will override previously set options, but we have no
303\ way to control the processing order here. boot-args will be rebuilt at boot.
304\
305\ NOTE: The best way to address the order is to *not* set any above options
306\ in boot-args.
307
308: parse-boot-args  { | baddr blen -- }
309  s" boot-args" getenv dup -1 = if drop exit then
310  to blen
311  to baddr
312
313  baddr blen
314
315  \ loop over all instances of switch blocks, starting with '-'
316  begin
317    [char] - strchr
318    2dup to blen to baddr
319    dup 0<>
320  while				( addr len ) \ points to -
321    \ block for switch B. keep it on top of the stack for case
322    \ the property list will get empty.
323
324    over 1+ c@ [char] B = if
325	2dup			\ save "-B ...." in case options is empty
326	2 - swap 2 +		( addr len len-2 addr+2 ) \ skip -B
327
328      begin			\ skip spaces
329        dup c@ bl =
330      while
331        1+ swap 1- swap
332      repeat
333
334				( addr len len' addr' )
335      \ its 3 cases now: end of string, -switch, or option list
336
337      over 0= if		\ end of string, remove trailing -B
338	2drop			( addr len )
339	swap 0 swap c!		\ store 0 at -B
340	blen swap		( blen len )
341	-			( rem )
342	baddr swap		( addr rem )
343	dup 0= if
344	  s" boot-args" unsetenv
345	  2drop
346	  exit
347	then
348				\ trailing space(s)
349	begin
350	  over			( addr rem addr )
351	  over + 1-		( addr rem addr+rem-1 )
352	  c@ bl =
353	while
354	  1- swap		( rem-1 addr )
355	  over			( rem-1 addr rem-1 )
356	  over +		( rem-1 addr addr+rem-1 )
357	  0 swap c!
358	  swap
359	repeat
360	s" boot-args" setenv
361	recurse			\ restart
362	exit
363      then
364				( addr len len' addr' )
365      dup c@ [char] - = if	\ it is switch. set to boot-args
366	swap s" boot-args" setenv
367	2drop
368	recurse			\ restart
369	exit
370      then
371				( addr len len' addr' )
372      \ its options string "option1,option2,... -..."
373      \ cut acpi-user-options=xxx and restart the parser
374      \ or skip to next option block
375      begin
376	dup c@ dup 0<> swap bl <> and \ stop if space or 0
377      while
378	dup 18 s" acpi-user-options=" compare 0= if	\ matched
379				( addr len len' addr' )
380	  \ addr' points to acpi options, find its end [',' or ' ' or 0 ]
381	  \ set it as acpi-user-options and move remaining to addr'
382	  2dup			( addr len len' addr' len' addr' )
383	  \ skip to next option in list
384	  \ loop to first , or bl or 0
385	  begin
386	    dup c@ [char] , <> >r
387	    dup c@ bl <> >r
388	    dup c@ 0<> r> r> and and
389	  while
390	    1+ swap 1- swap
391	  repeat
392				( addr len len' addr' len" addr" )
393	  >r >r			( addr len len' addr' R: addr" len" )
394	  over r@ -		( addr len len' addr' proplen R: addr" len" )
395	  dup 5 +		( addr len len' addr' proplen proplen+5 )
396	  allocate abort" out of memory"
397
398	  0 s" set " strcat	( addr len len' addr' proplen caddr clen )
399	  >r >r 2dup r> r> 2swap strcat ( addr len len' addr' proplen caddr clen )
400	  2dup + 0 swap c!	\ terminate with 0
401	  2dup evaluate drop free drop
402				( addr len len' addr' proplen R: addr" len" )
403	  \ acpi-user-options is set, now move remaining string to its place.
404	  \ addr: -B, addr': acpi... addr": reminder
405	  swap			( addr len len' proplen addr' )
406	  r> r>			( addr len len' proplen addr' len" addr" )
407	  dup c@ [char] , = if
408	    \ skip , and move addr" to addr'
409	    1+ swap 1-		( addr len len' proplen addr' addr" len" )
410	    rot	swap 1+ move	( addr len len' proplen )
411	  else	\ its bl or 0	( addr len len' proplen addr' len" addr" )
412	    \ for both bl and 0 we need to copy to addr'-1 to remove
413	    \ comma, then reset boot-args, and recurse will clear -B
414	    \ if there are no properties left.
415	    dup c@ 0= if
416	      2drop		( addr len len' proplen addr' )
417	      1- 0 swap c!	( addr len len' proplen )
418	    else
419	      >r >r		( addr len len' proplen addr' R: addr" len" )
420	      1- swap 1+ swap
421	      r> r>		( addr len len' proplen addr' len" addr" )
422	      rot rot move	( addr len len' proplen )
423	    then
424	  then
425
426	  2swap 2drop		( len' proplen )
427	  nip			( proplen )
428	  baddr blen rot -
429	  s" boot-args" setenv
430	  recurse
431	  exit
432	else
433				( addr len len' addr' )
434	  \ not acpi option, skip to next option in list
435	  \ loop to first , or bl or 0
436	  begin
437	    dup c@ [char] , <> >r
438	    dup c@ bl <> >r
439	    dup c@ 0<> r> r> and and
440	  while
441	    1+ swap 1- swap
442	  repeat
443	  \ if its ',', skip over
444	  dup c@ [char] , = if
445	    1+ swap 1- swap
446	  then
447	then
448      repeat
449				( addr len len' addr' )
450      \ this block is done, remove addr and len from stack
451      2swap 2drop swap
452    then
453
454    over c@ [char] - = if	( addr len )
455      2dup 1- swap 1+		( addr len len' addr' )
456      begin			\ loop till ' ' or 0
457	dup c@ dup 0<> swap bl <> and
458      while
459	dup c@ [char] s = if
460	  s" set boot_single=YES" evaluate TRUE
461	else dup c@ [char] v = if
462	  s" set boot_verbose=YES" evaluate TRUE
463	else dup c@ [char] k = if
464	  s" set boot_kmdb=YES" evaluate TRUE
465	else dup c@ [char] d = if
466	  s" set boot_drop_into_kmdb=YES" evaluate TRUE
467	else dup c@ [char] r = if
468	  s" set boot_reconfigure=YES" evaluate TRUE
469	else dup c@ [char] a = if
470	  s" set boot_ask=YES" evaluate TRUE
471	else dup c@ [char] x = if
472	  s" set boot_noncluster=YES" evaluate TRUE
473	then then then then then then then
474	dup TRUE = if
475	  drop
476	  dup >r		( addr len len' addr' R: addr' )
477	  1+ swap 1-		( addr len addr'+1 len'-1 R: addr' )
478	  r> swap move		( addr len )
479
480	  2drop baddr blen 1-
481	  \ check if we have space after '-', if so, drop '- '
482	  swap dup 1+ c@ bl = if
483	      2 + swap 2 -
484	  else
485	      swap
486	  then
487	  dup dup 0= swap 1 = or if	\ empty or only '-' is left.
488	    2drop
489	    s" boot-args" unsetenv
490	    exit
491	  else
492	    s" boot-args" setenv
493	  then
494	  recurse
495	  exit
496	then
497	1+ swap 1- swap
498      repeat
499
500      2swap 2drop
501      dup c@ 0= if		\ end of string
502	2drop
503	exit
504      else
505	swap
506      then
507    then
508  repeat
509
510  2drop
511;
512
513\ ***** start
514\
515\       Initializes support.4th global variables, sets loader_conf_files,
516\       processes conf files, and, if any one such file was successfully
517\       read to the end, loads kernel and modules.
518
519: start  ( -- ) ( throws: abort & user-defined )
520  s" /boot/defaults/loader.conf" initialize
521  include_bootenv
522  include_conf_files
523  include_transient
524  \ If the user defined a post-initialize hook, call it now
525  s" post-initialize" sfind if execute else drop then
526  parse-boot-args
527  \ Will *NOT* try to load kernel and modules if no configuration file
528  \ was successfully loaded!
529  any_conf_read? if
530    s" loader_delay" getenv -1 = if
531      load_xen_throw
532      load_kernel
533      load_modules
534    else
535      drop
536      ." Loading Kernel and Modules (Ctrl-C to Abort)" cr
537      s" also support-functions" evaluate
538      s" set delay_command='load_xen_throw load_kernel load_modules'" evaluate
539      s" set delay_showdots" evaluate
540      delay_execute
541    then
542  then
543;
544
545\ ***** initialize
546\
547\	Overrides support.4th initialization word with one that does
548\	everything start one does, short of loading the kernel and
549\	modules. Returns a flag.
550
551: initialize ( -- flag )
552  s" /boot/defaults/loader.conf" initialize
553  include_bootenv
554  include_conf_files
555  include_transient
556  \ If the user defined a post-initialize hook, call it now
557  s" post-initialize" sfind if execute else drop then
558  parse-boot-args
559  any_conf_read?
560;
561
562\ ***** read-conf
563\
564\	Read a configuration file, whose name was specified on the command
565\	line, if interpreted, or given on the stack, if compiled in.
566
567: (read-conf)  ( addr len -- )
568  conf_files string=
569  include_conf_files \ Will recurse on new loader_conf_files definitions
570;
571
572: read-conf  ( <filename> | addr len -- ) ( throws: abort & user-defined )
573  state @ if
574    \ Compiling
575    postpone (read-conf)
576  else
577    \ Interpreting
578    bl parse (read-conf)
579  then
580; immediate
581
582\ show, enable, disable, toggle module loading. They all take module from
583\ the next word
584
585: set-module-flag ( module_addr val -- ) \ set and print flag
586  over module.flag !
587  dup module.name strtype
588  module.flag @ if ."  will be loaded" else ."  will not be loaded" then cr
589;
590
591: enable-module find-module ?dup if true set-module-flag then ;
592
593: disable-module find-module ?dup if false set-module-flag then ;
594
595: toggle-module find-module ?dup if dup module.flag @ 0= set-module-flag then ;
596
597\ ***** show-module
598\
599\	Show loading information about a module.
600
601: show-module ( <module> -- ) find-module ?dup if show-one-module then ;
602
603: set-module-path ( addr len <module> -- )
604  find-module ?dup if
605    module.loadname string=
606  then
607;
608
609\ Words to be used inside configuration files
610
611: retry false ;         \ For use in load error commands
612: ignore true ;         \ For use in load error commands
613
614\ Return to strict forth vocabulary
615
616: #type
617  over - >r
618  type
619  r> spaces
620;
621
622: .? 2 spaces 2swap 15 #type 2 spaces type cr ;
623
624: ?
625  ['] ? execute
626  s" boot-conf" s" load kernel and modules, then autoboot" .?
627  s" read-conf" s" read a configuration file" .?
628  s" enable-module" s" enable loading of a module" .?
629  s" disable-module" s" disable loading of a module" .?
630  s" toggle-module" s" toggle loading of a module" .?
631  s" show-module" s" show module load data" .?
632  s" try-include" s" try to load/interpret files" .?
633  s" beadm" s" list or activate Boot Environments" .?
634;
635
636: try-include ( -- ) \ see loader.4th(8)
637  ['] include ( -- xt ) \ get the execution token of `include'
638  catch ( xt -- exception# | 0 ) if \ failed
639    LF parse ( c -- s-addr/u ) 2drop \ advance >in to EOL (drop data)
640    \ ... prevents words unused by `include' from being interpreted
641  then
642; immediate \ interpret immediately for access to `source' (aka tib)
643
644include /boot/forth/beadm.4th
645only forth definitions
646