() ()
 Copyright (c) 1999 Daniel C. Sobral <dcs@FreeBSD.org>  Copyright (c) 2011-2015 Devin Teske <dteske@FreeBSD.org>  All rights reserved.  Redistribution and use in source and binary forms, with or without  modification, are permitted provided that the following conditions  are met:  1. Redistributions of source code must retain the above copyright   notice, this list of conditions and the following disclaimer.  2. Redistributions in binary form must reproduce the above copyright   notice, this list of conditions and the following disclaimer in the   documentation and/or other materials provided with the distribution.  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  SUCH DAMAGE.  $FreeBSD$

only forth definitions

s" arch-i386" environment? [if] [if] s" loader_version" environment? [if] 11 < [if] .( Loader version 1.1+ required) cr abort [then] [else] .( Could not get loader version!) cr abort [then] [then] [then]

include /boot/forth/support.4th include /boot/forth/color.4th include /boot/forth/delay.4th include /boot/forth/check-password.4th s" efi-version" getenv? [if] include /boot/forth/efi.4th [then]

only forth definitions

: bootmsg ( -- ) loader_color? dup ( -- bool bool ) if 7 fg 4 bg then ." Booting..." if me then cr ;

: try-menu-unset  menu-unset may not be present s" beastie_disable" getenv dup -1 <> if s" YES" compare-insensitive 0= if exit then else drop then s" menu-unset" sfind if execute else drop then s" menusets-unset" sfind if execute else drop then ;

only forth also support-functions also builtins definitions

 the boot-args was parsed to individual options while loaded  now compose boot-args, so the boot can set kernel arguments  note the command line switched for boot command will cause  environment variable boot-args to be ignored  There are 2 larger strings, acpi-user-options and existing boot-args  other switches are 1 byte each, so allocate boot-args+acpi + extra bytes  for rest. Be sure to review this, if more options are to be added into  environment.

: set-boot-args { | addr len baddr blen aaddr alen -- } s" boot-args" getenv dup -1 <> if to blen to baddr else drop then s" acpi-user-options" getenv dup -1 <> if to alen to aaddr else drop then

 allocate temporary space. max is:   7 kernel switches   26 for acpi, so use 40 for safety blen alen 40 + + allocate abort" out of memory" to addr  boot-addr may have file name before options, copy it to addr baddr 0<> if baddr c@ [char] - <> if baddr blen [char] - strchr ( addr len ) dup 0= if  no options, copy all 2drop baddr addr blen move blen to len 0 to blen 0 to baddr else ( addr len ) dup blen swap - to len ( addr len ) to blen ( addr ) baddr addr len move ( addr ) to baddr  baddr points now to first option then then then  now add kernel switches len 0<> if bl addr len + c! len 1+ to len then [char] - addr len + c! len 1+ to len

s" boot_single" getenv dup -1 <> if s" YES" compare-insensitive 0= if [char] s addr len + c! len 1+ to len then else drop then s" boot_verbose" getenv dup -1 <> if s" YES" compare-insensitive 0= if [char] v addr len + c! len 1+ to len then else drop then s" boot_kmdb" getenv dup -1 <> if s" YES" compare-insensitive 0= if [char] k addr len + c! len 1+ to len then else drop then s" boot_drop_into_kmdb" getenv dup -1 <> if s" YES" compare-insensitive 0= if [char] d addr len + c! len 1+ to len then else drop then s" boot_reconfigure" getenv dup -1 <> if s" YES" compare-insensitive 0= if [char] r addr len + c! len 1+ to len then else drop then s" boot_ask" getenv dup -1 <> if s" YES" compare-insensitive 0= if [char] a addr len + c! len 1+ to len then else drop then

 now add remining boot args if blen != 0.  baddr[0] is '-', if baddr[1] != 'B' append to addr,  otherwise add space then copy blen 0<> if baddr 1+ c@ [char] B = if addr len + 1- c@ [char] - = if  if addr[len -1] == '-' baddr 1+ to baddr blen 1- to blen else bl addr len + c! len 1+ to len then else baddr 1+ to baddr blen 1- to blen then baddr addr len + blen move len blen + to len 0 to baddr 0 to blen then  last part - add acpi. alen 0<> if addr len + 1- c@ [char] - <> if bl addr len + c! len 1+ to len [char] - addr len + c! len 1+ to len then s" B acpi-user-options=" dup -rot ( len addr len ) addr len + swap move ( len ) len + to len aaddr addr len + alen move len alen + to len then

 check for left over '-' addr len 1- + c@ [char] - = if len 1- to len  but now we may also have left over ' ' len if ( len <> 0 ) addr len 1- + c@ bl = if len 1- to len then then then

 if len != 0, set boot-args len 0<> if addr len s" boot-args" setenv then addr free drop ;

: boot 0= if ( interpreted ) get_arguments then set-boot-args

 Unload only if a path was passed. Paths start with / dup if >r over r> swap c@ [char] / = if 0 1 unload drop else s" kernelname" getenv? if ( a kernel has been loaded ) try-menu-unset bootmsg 1 boot exit then load_kernel_and_modules ?dup if exit then try-menu-unset bootmsg 0 1 boot exit then else s" kernelname" getenv? if ( a kernel has been loaded ) try-menu-unset bootmsg 1 boot exit then load_kernel_and_modules ?dup if exit then try-menu-unset bootmsg 0 1 boot exit then load_kernel_and_modules ?dup 0= if bootmsg 0 1 boot then ;

 ***** boot-conf Prepares to boot as specified by loaded configuration files.

: boot-conf 0= if ( interpreted ) get_arguments then 0 1 unload drop load_kernel_and_modules ?dup 0= if 0 1 autoboot then ;

also forth definitions previous

builtin: boot builtin: boot-conf

only forth definitions also support-functions

   in case the boot-args is set, parse it and extract following options:  -a to boot_ask=YES  -s to boot_single=YES  -v to boot_verbose=YES  -k to boot_kmdb=YES  -d to boot_drop_into_kmdb=YES  -r to boot_reconfigure=YES  -B acpi-user-options=X to acpi-user-options=X    This is needed so that the menu can manage these options. Unfortunately, this  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.    NOTE: The best way to address the order is to *not* set any above options  in boot-args.

: parse-boot-args { | baddr blen -- } s" boot-args" getenv dup -1 = if drop exit then to blen to baddr

baddr blen

 loop over all instances of switch blocks, starting with '-' begin [char] - strchr 2dup to blen to baddr dup 0<> while ( addr len )  points to -  block for switch B. keep it on top of the stack for case  the property list will get empty.

over 1+ c@ [char] B = if 2dup  save "-B ...." in case options is empty 2 - swap 2 + ( addr len len-2 addr+2 )  skip -B

begin  skip spaces dup c@ bl = while 1+ swap 1- swap repeat

( addr len len' addr' )  its 3 cases now: end of string, -switch, or option list

over 0= if  end of string, remove trailing -B 2drop ( addr len ) swap 0 swap c!  store 0 at -B blen swap ( blen len ) - ( rem ) baddr swap ( addr rem ) dup 0= if s" boot-args" unsetenv 2drop exit then  trailing space(s) begin over ( addr rem addr ) over + 1- ( addr rem addr+rem-1 ) c@ bl = while 1- swap ( rem-1 addr ) over ( rem-1 addr rem-1 ) over + ( rem-1 addr addr+rem-1 ) 0 swap c! swap repeat s" boot-args" setenv recurse  restart exit then ( addr len len' addr' ) dup c@ [char] - = if  it is switch. set to boot-args swap s" boot-args" setenv 2drop recurse  restart exit then ( addr len len' addr' )  its options string "option1,option2,... -..."  cut acpi-user-options=xxx and restart the parser  or skip to next option block begin dup c@ dup 0<> swap bl <> and  stop if space or 0 while dup 18 s" acpi-user-options=" compare 0= if  matched ( addr len len' addr' )  addr' points to acpi options, find its end [',' or ' ' or 0 ]  set it as acpi-user-options and move remaining to addr' 2dup ( addr len len' addr' len' addr' )  skip to next option in list  loop to first , or bl or 0 begin dup c@ [char] , <> >r dup c@ bl <> >r dup c@ 0<> r> r> and and while 1+ swap 1- swap repeat ( addr len len' addr' len" addr" ) >r >r ( addr len len' addr' R: addr" len" ) over r@ - ( addr len len' addr' proplen R: addr" len" ) dup 5 + ( addr len len' addr' proplen proplen+5 ) allocate abort" out of memory"

0 s" set " strcat ( addr len len' addr' proplen caddr clen ) >r >r 2dup r> r> 2swap strcat ( addr len len' addr' proplen caddr clen ) 2dup + 0 swap c!  terminate with 0 2dup evaluate drop free drop ( addr len len' addr' proplen R: addr" len" )  acpi-user-options is set, now move remaining string to its place.  addr: -B, addr': acpi... addr": reminder swap ( addr len len' proplen addr' ) r> r> ( addr len len' proplen addr' len" addr" ) dup c@ [char] , = if  skip , and move addr" to addr' 1+ swap 1- ( addr len len' proplen addr' addr" len" ) rot swap 1+ move ( addr len len' proplen ) else  its bl or 0 ( addr len len' proplen addr' len" addr" )  for both bl and 0 we need to copy to addr'-1 to remove  comma, then reset boot-args, and recurse will clear -B  if there are no properties left. dup c@ 0= if 2drop ( addr len len' proplen addr' ) 1- 0 swap c! ( addr len len' proplen ) else >r >r ( addr len len' proplen addr' R: addr" len" ) 1- swap 1+ swap r> r> ( addr len len' proplen addr' len" addr" ) rot rot move ( addr len len' proplen ) then then

2swap 2drop ( len' proplen ) nip ( proplen ) baddr blen rot - s" boot-args" setenv recurse exit else ( addr len len' addr' )  not acpi option, skip to next option in list  loop to first , or bl or 0 begin dup c@ [char] , <> >r dup c@ bl <> >r dup c@ 0<> r> r> and and while 1+ swap 1- swap repeat  if its ',', skip over dup c@ [char] , = if 1+ swap 1- swap then then repeat ( addr len len' addr' )  this block is done, remove addr and len from stack 2swap 2drop swap then

over c@ [char] - = if ( addr len ) 2dup 1- swap 1+ ( addr len len' addr' ) begin  loop till ' ' or 0 dup c@ dup 0<> swap bl <> and while dup c@ [char] s = if s" set boot_single=YES" evaluate TRUE else dup c@ [char] v = if s" set boot_verbose=YES" evaluate TRUE else dup c@ [char] k = if s" set boot_kmdb=YES" evaluate TRUE else dup c@ [char] d = if s" set boot_drop_into_kmdb=YES" evaluate TRUE else dup c@ [char] r = if s" set boot_reconfigure=YES" evaluate TRUE else dup c@ [char] a = if s" set boot_ask=YES" evaluate TRUE then then then then then then dup TRUE = if drop dup >r ( addr len len' addr' R: addr' ) 1+ swap 1- ( addr len addr'+1 len'-1 R: addr' ) r> swap move ( addr len )

2drop baddr blen 1-  check if we have space after '-', if so, drop '- ' swap dup 1+ c@ bl = if 2 + swap 2 - else swap then dup dup 0= swap 1 = or if  empty or only '-' is left. 2drop s" boot-args" unsetenv exit else s" boot-args" setenv then recurse exit then 1+ swap 1- swap repeat

2swap 2drop dup c@ 0= if  end of string 2drop exit else swap then then repeat

2drop ;

 ***** start   Initializes support.4th global variables, sets loader_conf_files,   processes conf files, and, if any one such file was successfully   read to the end, loads kernel and modules.

: start ( -- ) ( throws: abort & user-defined ) s" /boot/defaults/loader.conf" initialize include_bootenv include_conf_files include_transient  If the user defined a post-initialize hook, call it now s" post-initialize" sfind if execute else drop then parse-boot-args  Will *NOT* try to load kernel and modules if no configuration file  was successfully loaded! any_conf_read? if s" loader_delay" getenv -1 = if load_xen_throw load_kernel load_modules else drop ." Loading Kernel and Modules (Ctrl-C to Abort)" cr s" also support-functions" evaluate s" set delay_command='load_xen_throw load_kernel load_modules'" evaluate s" set delay_showdots" evaluate delay_execute then then ;

 ***** initialize Overrides support.4th initialization word with one that does everything start one does, short of loading the kernel and modules. Returns a flag.

: initialize ( -- flag ) s" /boot/defaults/loader.conf" initialize include_bootenv include_conf_files include_transient  If the user defined a post-initialize hook, call it now s" post-initialize" sfind if execute else drop then parse-boot-args any_conf_read? ;

 ***** read-conf Read a configuration file, whose name was specified on the command line, if interpreted, or given on the stack, if compiled in.

: (read-conf) ( addr len -- ) conf_files string= include_conf_files  Will recurse on new loader_conf_files definitions ;

: read-conf ( <filename> | addr len -- ) ( throws: abort & user-defined ) state @ if  Compiling postpone (read-conf) else  Interpreting bl parse (read-conf) then ; immediate

 show, enable, disable, toggle module loading. They all take module from  the next word

: set-module-flag ( module_addr val -- )  set and print flag over module.flag ! dup module.name strtype module.flag @ if ." will be loaded" else ." will not be loaded" then cr ;

: enable-module find-module ?dup if true set-module-flag then ;

: disable-module find-module ?dup if false set-module-flag then ;

: toggle-module find-module ?dup if dup module.flag @ 0= set-module-flag then ;

 ***** show-module Show loading information about a module.

: show-module ( <module> -- ) find-module ?dup if show-one-module then ;

: set-module-path ( addr len <module> -- ) find-module ?dup if module.loadname string= then ;

 Words to be used inside configuration files

: retry false ;  For use in load error commands : ignore true ;  For use in load error commands

 Return to strict forth vocabulary

: #type over - >r type r> spaces ;

: .? 2 spaces 2swap 15 #type 2 spaces type cr ;

: ? ['] ? execute s" boot-conf" s" load kernel and modules, then autoboot" .? s" read-conf" s" read a configuration file" .? s" enable-module" s" enable loading of a module" .? s" disable-module" s" disable loading of a module" .? s" toggle-module" s" toggle loading of a module" .? s" show-module" s" show module load data" .? s" try-include" s" try to load/interpret files" .? s" beadm" s" list or activate Boot Environments" .? ;

: try-include ( -- )  see loader.4th(8) ['] include ( -- xt )  get the execution token of `include' catch ( xt -- exception# | 0 ) if  failed LF parse ( c -- s-addr/u ) 2drop  advance >in to EOL (drop data)  ... prevents words unused by `include' from being interpreted then ; immediate  interpret immediately for access to `source' (aka tib)

include /boot/forth/beadm.4th only forth definitions

August 28, 2019