xref: /illumos-gate/usr/src/boot/forth/loader.4th (revision 15f90b02bdacbf0ae47fa105944f15b6596f9748)
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  \  7 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
181  \ now add remining boot args if blen != 0.
182  \ baddr[0] is '-', if baddr[1] != 'B' append to addr,
183  \ otherwise add space then copy
184  blen 0<> if
185    baddr 1+ c@ [char] B = if
186      addr len + 1- c@ [char] - = if	 \ if addr[len -1] == '-'
187	baddr 1+ to baddr
188	blen 1- to blen
189      else
190	bl addr len + c! len 1+ to len
191      then
192    else
193      baddr 1+ to baddr
194      blen 1- to blen
195    then
196    baddr addr len + blen move
197    len blen + to len
198    0 to baddr
199    0 to blen
200  then
201  \ last part - add acpi.
202  alen 0<> if
203    addr len + 1- c@ [char] - <> if
204      bl addr len + c! len 1+ to len
205      [char] - addr len + c! len 1+ to len
206    then
207    s" B acpi-user-options=" dup -rot		( len addr len )
208    addr len + swap move			( len )
209    len + to len
210    aaddr addr len + alen move
211    len alen + to len
212  then
213
214  \ check for left over '-'
215  addr len 1- + c@ [char] - = if
216    len 1- to len
217				\ but now we may also have left over ' '
218    len if ( len <> 0 )
219      addr len 1- + c@ bl = if
220	len 1- to len
221      then
222    then
223  then
224
225  \ if len != 0, set boot-args
226  len 0<> if
227    addr len s" boot-args" setenv
228  then
229  addr free drop
230;
231
232: boot
233  0= if ( interpreted ) get_arguments then
234  set-boot-args
235
236  \ Unload only if a path was passed. Paths start with /
237  dup if
238    >r over r> swap
239    c@ [char] / = if
240      0 1 unload drop
241    else
242      s" kernelname" getenv? if ( a kernel has been loaded )
243        try-menu-unset
244        bootmsg 1 boot exit
245      then
246      load_kernel_and_modules
247      ?dup if exit then
248      try-menu-unset
249      bootmsg 0 1 boot exit
250    then
251  else
252    s" kernelname" getenv? if ( a kernel has been loaded )
253      try-menu-unset
254      bootmsg 1 boot exit
255    then
256    load_kernel_and_modules
257    ?dup if exit then
258    try-menu-unset
259    bootmsg 0 1 boot exit
260  then
261  load_kernel_and_modules
262  ?dup 0= if bootmsg 0 1 boot then
263;
264
265\ ***** boot-conf
266\
267\	Prepares to boot as specified by loaded configuration files.
268
269: boot-conf
270  0= if ( interpreted ) get_arguments then
271  0 1 unload drop
272  load_kernel_and_modules
273  ?dup 0= if 0 1 autoboot then
274;
275
276also forth definitions previous
277
278builtin: boot
279builtin: boot-conf
280
281only forth definitions also support-functions
282
283\
284\ in case the boot-args is set, parse it and extract following options:
285\ -a to boot_ask=YES
286\ -s to boot_single=YES
287\ -v to boot_verbose=YES
288\ -k to boot_kmdb=YES
289\ -d to boot_drop_into_kmdb=YES
290\ -r to boot_reconfigure=YES
291\ -B acpi-user-options=X to acpi-user-options=X
292\
293\ This is needed so that the menu can manage these options. Unfortunately, this
294\ also means that boot-args will override previously set options, but we have no
295\ way to control the processing order here. boot-args will be rebuilt at boot.
296\
297\ NOTE: The best way to address the order is to *not* set any above options
298\ in boot-args.
299
300: parse-boot-args  { | baddr blen -- }
301  s" boot-args" getenv dup -1 = if drop exit then
302  to blen
303  to baddr
304
305  baddr blen
306
307  \ loop over all instances of switch blocks, starting with '-'
308  begin
309    [char] - strchr
310    2dup to blen to baddr
311    dup 0<>
312  while				( addr len ) \ points to -
313    \ block for switch B. keep it on top of the stack for case
314    \ the property list will get empty.
315
316    over 1+ c@ [char] B = if
317	2dup			\ save "-B ...." in case options is empty
318	2 - swap 2 +		( addr len len-2 addr+2 ) \ skip -B
319
320      begin			\ skip spaces
321        dup c@ bl =
322      while
323        1+ swap 1- swap
324      repeat
325
326				( addr len len' addr' )
327      \ its 3 cases now: end of string, -switch, or option list
328
329      over 0= if		\ end of string, remove trailing -B
330	2drop			( addr len )
331	swap 0 swap c!		\ store 0 at -B
332	blen swap		( blen len )
333	-			( rem )
334	baddr swap		( addr rem )
335	dup 0= if
336	  s" boot-args" unsetenv
337	  2drop
338	  exit
339	then
340				\ trailing space(s)
341	begin
342	  over			( addr rem addr )
343	  over + 1-		( addr rem addr+rem-1 )
344	  c@ bl =
345	while
346	  1- swap		( rem-1 addr )
347	  over			( rem-1 addr rem-1 )
348	  over +		( rem-1 addr addr+rem-1 )
349	  0 swap c!
350	  swap
351	repeat
352	s" boot-args" setenv
353	recurse			\ restart
354	exit
355      then
356				( addr len len' addr' )
357      dup c@ [char] - = if	\ it is switch. set to boot-args
358	swap s" boot-args" setenv
359	2drop
360	recurse			\ restart
361	exit
362      then
363				( addr len len' addr' )
364      \ its options string "option1,option2,... -..."
365      \ cut acpi-user-options=xxx and restart the parser
366      \ or skip to next option block
367      begin
368	dup c@ dup 0<> swap bl <> and \ stop if space or 0
369      while
370	dup 18 s" acpi-user-options=" compare 0= if	\ matched
371				( addr len len' addr' )
372	  \ addr' points to acpi options, find its end [',' or ' ' or 0 ]
373	  \ set it as acpi-user-options and move remaining to addr'
374	  2dup			( addr len len' addr' len' addr' )
375	  \ skip to next option in list
376	  \ loop to first , or bl or 0
377	  begin
378	    dup c@ [char] , <> >r
379	    dup c@ bl <> >r
380	    dup c@ 0<> r> r> and and
381	  while
382	    1+ swap 1- swap
383	  repeat
384				( addr len len' addr' len" addr" )
385	  >r >r			( addr len len' addr' R: addr" len" )
386	  over r@ -		( addr len len' addr' proplen R: addr" len" )
387	  dup 5 +		( addr len len' addr' proplen proplen+5 )
388	  allocate abort" out of memory"
389
390	  0 s" set " strcat	( addr len len' addr' proplen caddr clen )
391	  >r >r 2dup r> r> 2swap strcat ( addr len len' addr' proplen caddr clen )
392	  2dup + 0 swap c!	\ terminate with 0
393	  2dup evaluate drop free drop
394				( addr len len' addr' proplen R: addr" len" )
395	  \ acpi-user-options is set, now move remaining string to its place.
396	  \ addr: -B, addr': acpi... addr": reminder
397	  swap			( addr len len' proplen addr' )
398	  r> r>			( addr len len' proplen addr' len" addr" )
399	  dup c@ [char] , = if
400	    \ skip , and move addr" to addr'
401	    1+ swap 1-		( addr len len' proplen addr' addr" len" )
402	    rot	swap 1+ move	( addr len len' proplen )
403	  else	\ its bl or 0	( addr len len' proplen addr' len" addr" )
404	    \ for both bl and 0 we need to copy to addr'-1 to remove
405	    \ comma, then reset boot-args, and recurse will clear -B
406	    \ if there are no properties left.
407	    dup c@ 0= if
408	      2drop		( addr len len' proplen addr' )
409	      1- 0 swap c!	( addr len len' proplen )
410	    else
411	      >r >r		( addr len len' proplen addr' R: addr" len" )
412	      1- swap 1+ swap
413	      r> r>		( addr len len' proplen addr' len" addr" )
414	      rot rot move	( addr len len' proplen )
415	    then
416	  then
417
418	  2swap 2drop		( len' proplen )
419	  nip			( proplen )
420	  baddr blen rot -
421	  s" boot-args" setenv
422	  recurse
423	  exit
424	else
425				( addr len len' addr' )
426	  \ not acpi option, skip to next option in list
427	  \ loop to first , or bl or 0
428	  begin
429	    dup c@ [char] , <> >r
430	    dup c@ bl <> >r
431	    dup c@ 0<> r> r> and and
432	  while
433	    1+ swap 1- swap
434	  repeat
435	  \ if its ',', skip over
436	  dup c@ [char] , = if
437	    1+ swap 1- swap
438	  then
439	then
440      repeat
441				( addr len len' addr' )
442      \ this block is done, remove addr and len from stack
443      2swap 2drop swap
444    then
445
446    over c@ [char] - = if	( addr len )
447      2dup 1- swap 1+		( addr len len' addr' )
448      begin			\ loop till ' ' or 0
449	dup c@ dup 0<> swap bl <> and
450      while
451	dup c@ [char] s = if
452	  s" set boot_single=YES" evaluate TRUE
453	else dup c@ [char] v = if
454	  s" set boot_verbose=YES" evaluate TRUE
455	else dup c@ [char] k = if
456	  s" set boot_kmdb=YES" evaluate TRUE
457	else dup c@ [char] d = if
458	  s" set boot_drop_into_kmdb=YES" evaluate TRUE
459	else dup c@ [char] r = if
460	  s" set boot_reconfigure=YES" evaluate TRUE
461	else dup c@ [char] a = if
462	  s" set boot_ask=YES" evaluate TRUE
463	then then then then then then
464	dup TRUE = if
465	  drop
466	  dup >r		( addr len len' addr' R: addr' )
467	  1+ swap 1-		( addr len addr'+1 len'-1 R: addr' )
468	  r> swap move		( addr len )
469
470	  2drop baddr blen 1-
471	  \ check if we have space after '-', if so, drop '- '
472	  swap dup 1+ c@ bl = if
473	      2 + swap 2 -
474	  else
475	      swap
476	  then
477	  dup dup 0= swap 1 = or if	\ empty or only '-' is left.
478	    2drop
479	    s" boot-args" unsetenv
480	    exit
481	  else
482	    s" boot-args" setenv
483	  then
484	  recurse
485	  exit
486	then
487	1+ swap 1- swap
488      repeat
489
490      2swap 2drop
491      dup c@ 0= if		\ end of string
492	2drop
493	exit
494      else
495	swap
496      then
497    then
498  repeat
499
500  2drop
501;
502
503\ ***** start
504\
505\       Initializes support.4th global variables, sets loader_conf_files,
506\       processes conf files, and, if any one such file was successfully
507\       read to the end, loads kernel and modules.
508
509: start  ( -- ) ( throws: abort & user-defined )
510  s" /boot/defaults/loader.conf" initialize
511  include_bootenv
512  include_conf_files
513  include_transient
514  \ If the user defined a post-initialize hook, call it now
515  s" post-initialize" sfind if execute else drop then
516  parse-boot-args
517  \ Will *NOT* try to load kernel and modules if no configuration file
518  \ was successfully loaded!
519  any_conf_read? if
520    s" loader_delay" getenv -1 = if
521      load_xen_throw
522      load_kernel
523      load_modules
524    else
525      drop
526      ." Loading Kernel and Modules (Ctrl-C to Abort)" cr
527      s" also support-functions" evaluate
528      s" set delay_command='load_xen_throw load_kernel load_modules'" evaluate
529      s" set delay_showdots" evaluate
530      delay_execute
531    then
532  then
533;
534
535\ ***** initialize
536\
537\	Overrides support.4th initialization word with one that does
538\	everything start one does, short of loading the kernel and
539\	modules. Returns a flag.
540
541: initialize ( -- flag )
542  s" /boot/defaults/loader.conf" initialize
543  include_bootenv
544  include_conf_files
545  include_transient
546  \ If the user defined a post-initialize hook, call it now
547  s" post-initialize" sfind if execute else drop then
548  parse-boot-args
549  any_conf_read?
550;
551
552\ ***** read-conf
553\
554\	Read a configuration file, whose name was specified on the command
555\	line, if interpreted, or given on the stack, if compiled in.
556
557: (read-conf)  ( addr len -- )
558  conf_files string=
559  include_conf_files \ Will recurse on new loader_conf_files definitions
560;
561
562: read-conf  ( <filename> | addr len -- ) ( throws: abort & user-defined )
563  state @ if
564    \ Compiling
565    postpone (read-conf)
566  else
567    \ Interpreting
568    bl parse (read-conf)
569  then
570; immediate
571
572\ show, enable, disable, toggle module loading. They all take module from
573\ the next word
574
575: set-module-flag ( module_addr val -- ) \ set and print flag
576  over module.flag !
577  dup module.name strtype
578  module.flag @ if ."  will be loaded" else ."  will not be loaded" then cr
579;
580
581: enable-module find-module ?dup if true set-module-flag then ;
582
583: disable-module find-module ?dup if false set-module-flag then ;
584
585: toggle-module find-module ?dup if dup module.flag @ 0= set-module-flag then ;
586
587\ ***** show-module
588\
589\	Show loading information about a module.
590
591: show-module ( <module> -- ) find-module ?dup if show-one-module then ;
592
593: set-module-path ( addr len <module> -- )
594  find-module ?dup if
595    module.loadname string=
596  then
597;
598
599\ Words to be used inside configuration files
600
601: retry false ;         \ For use in load error commands
602: ignore true ;         \ For use in load error commands
603
604\ Return to strict forth vocabulary
605
606: #type
607  over - >r
608  type
609  r> spaces
610;
611
612: .? 2 spaces 2swap 15 #type 2 spaces type cr ;
613
614: ?
615  ['] ? execute
616  s" boot-conf" s" load kernel and modules, then autoboot" .?
617  s" read-conf" s" read a configuration file" .?
618  s" enable-module" s" enable loading of a module" .?
619  s" disable-module" s" disable loading of a module" .?
620  s" toggle-module" s" toggle loading of a module" .?
621  s" show-module" s" show module load data" .?
622  s" try-include" s" try to load/interpret files" .?
623  s" beadm" s" list or activate Boot Environments" .?
624;
625
626: try-include ( -- ) \ see loader.4th(8)
627  ['] include ( -- xt ) \ get the execution token of `include'
628  catch ( xt -- exception# | 0 ) if \ failed
629    LF parse ( c -- s-addr/u ) 2drop \ advance >in to EOL (drop data)
630    \ ... prevents words unused by `include' from being interpreted
631  then
632; immediate \ interpret immediately for access to `source' (aka tib)
633
634include /boot/forth/beadm.4th
635only forth definitions
636