xref: /illumos-gate/usr/src/boot/forth/loader.4th (revision 199767f8)
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\ 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_debug=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	then then then then then then
460	dup TRUE = if
461	  drop
462	  dup >r		( addr len len' addr' R: addr' )
463	  1+ swap 1-		( addr len addr'+1 len'-1 R: addr' )
464	  r> swap move		( addr len )
465
466	  2drop baddr blen 1-
467	  \ check if we have space after '-', if so, drop '- '
468	  swap dup 1+ c@ bl = if
469	      2 + swap 2 -
470	  else
471	      swap
472	  then
473	  dup dup 0= swap 1 = or if	\ empty or only '-' is left.
474	    2drop
475	    s" boot-args" unsetenv
476	    exit
477	  else
478	    s" boot-args" setenv
479	  then
480	  recurse
481	  exit
482	then
483	1+ swap 1- swap
484      repeat
485
486      2swap 2drop
487      dup c@ 0= if		\ end of string
488	2drop
489	exit
490      else
491	swap
492      then
493    then
494  repeat
495
496  2drop
497;
498
499\ ***** start
500\
501\       Initializes support.4th global variables, sets loader_conf_files,
502\       processes conf files, and, if any one such file was succesfully
503\       read to the end, loads kernel and modules.
504
505: start  ( -- ) ( throws: abort & user-defined )
506  s" /boot/defaults/loader.conf" initialize
507  include_bootenv
508  include_conf_files
509  include_transient
510  parse-boot-args
511  \ Will *NOT* try to load kernel and modules if no configuration file
512  \ was succesfully loaded!
513  any_conf_read? if
514    s" loader_delay" getenv -1 = if
515      load_xen_throw
516      load_kernel
517      load_modules
518    else
519      drop
520      ." Loading Kernel and Modules (Ctrl-C to Abort)" cr
521      s" also support-functions" evaluate
522      s" set delay_command='load_xen_throw load_kernel load_modules'" evaluate
523      s" set delay_showdots" evaluate
524      delay_execute
525    then
526  then
527;
528
529\ ***** initialize
530\
531\	Overrides support.4th initialization word with one that does
532\	everything start one does, short of loading the kernel and
533\	modules. Returns a flag
534
535: initialize ( -- flag )
536  s" /boot/defaults/loader.conf" initialize
537  include_bootenv
538  include_conf_files
539  include_transient
540  parse-boot-args
541  any_conf_read?
542;
543
544\ ***** read-conf
545\
546\	Read a configuration file, whose name was specified on the command
547\	line, if interpreted, or given on the stack, if compiled in.
548
549: (read-conf)  ( addr len -- )
550  conf_files string=
551  include_conf_files \ Will recurse on new loader_conf_files definitions
552;
553
554: read-conf  ( <filename> | addr len -- ) ( throws: abort & user-defined )
555  state @ if
556    \ Compiling
557    postpone (read-conf)
558  else
559    \ Interpreting
560    bl parse (read-conf)
561  then
562; immediate
563
564\ show, enable, disable, toggle module loading. They all take module from
565\ the next word
566
567: set-module-flag ( module_addr val -- ) \ set and print flag
568  over module.flag !
569  dup module.name strtype
570  module.flag @ if ."  will be loaded" else ."  will not be loaded" then cr
571;
572
573: enable-module find-module ?dup if true set-module-flag then ;
574
575: disable-module find-module ?dup if false set-module-flag then ;
576
577: toggle-module find-module ?dup if dup module.flag @ 0= set-module-flag then ;
578
579\ ***** show-module
580\
581\	Show loading information about a module.
582
583: show-module ( <module> -- ) find-module ?dup if show-one-module then ;
584
585\ Words to be used inside configuration files
586
587: retry false ;         \ For use in load error commands
588: ignore true ;         \ For use in load error commands
589
590\ Return to strict forth vocabulary
591
592: #type
593  over - >r
594  type
595  r> spaces
596;
597
598: .? 2 spaces 2swap 15 #type 2 spaces type cr ;
599
600: ?
601  ['] ? execute
602  s" boot-conf" s" load kernel and modules, then autoboot" .?
603  s" read-conf" s" read a configuration file" .?
604  s" enable-module" s" enable loading of a module" .?
605  s" disable-module" s" disable loading of a module" .?
606  s" toggle-module" s" toggle loading of a module" .?
607  s" show-module" s" show module load data" .?
608  s" try-include" s" try to load/interpret files" .?
609  s" beadm" s" list or activate Boot Environments" .?
610;
611
612: try-include ( -- ) \ see loader.4th(8)
613  ['] include ( -- xt ) \ get the execution token of `include'
614  catch ( xt -- exception# | 0 ) if \ failed
615    LF parse ( c -- s-addr/u ) 2drop \ advance >in to EOL (drop data)
616    \ ... prevents words unused by `include' from being interpreted
617  then
618; immediate \ interpret immediately for access to `source' (aka tib)
619
620include /boot/forth/beadm.4th
621only forth definitions
622