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