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
28 only forth definitions
29
30 s" 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
42 include /boot/forth/support.4th
43 include /boot/forth/color.4th
44 include /boot/forth/delay.4th
45 include /boot/forth/check-password.4th
46 s" efi-version" getenv? [if]
47 include /boot/forth/efi.4th
48 [then]
49
50 only 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
84 only 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_debug" 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
276 also forth definitions previous
277
278 builtin: boot
279 builtin: boot-conf
280
281 only 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_debug=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_debug=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
634 include /boot/forth/beadm.4th
635 only forth definitions