\ Copyright (c) 1999 Daniel C. Sobral \ Copyright (c) 2011-2015 Devin Teske \ 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 efi? [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: \ 8 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 s" boot_noncluster" getenv dup -1 <> if s" YES" compare-insensitive 0= if [char] x 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 \ -x to boot_noncluster=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 else dup c@ [char] x = if s" set boot_noncluster=YES" evaluate TRUE then 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 ( | 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 ( -- ) find-module ?dup if show-one-module then ; : set-module-path ( addr len -- ) 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