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