1 ()                                                                          ()
   2 
   3 
   4 
   5  Copyright (c) 1999 Daniel C. Sobral <dcs@FreeBSD.org>    Copyright (c)
   6 2011-2015 Devin Teske <dteske@FreeBSD.org>  All   rights reserved.
   7 Redistribution and use in source and binary forms, with or without
   8 modification, are permitted provided that the following conditions  are met:
   9 1. Redistributions of source code must retain the above copyright     notice,
  10 this list of conditions and the following disclaimer.   2. Redistributions in
  11 binary form must reproduce the above copyright     notice, this list of
  12 conditions and the following disclaimer in the     documentation and/or other
  13 materials provided with the distribution.   THIS SOFTWARE IS PROVIDED BY THE
  14 AUTHOR AND CONTRIBUTORS ``AS IS'' AND  ANY EXPRESS OR IMPLIED WARRANTIES,
  15 INCLUDING, BUT NOT LIMITED TO, THE  IMPLIED WARRANTIES OF MERCHANTABILITY AND
  16 FITNESS FOR A PARTICULAR PURPOSE  ARE DISCLAIMED.  IN NO EVENT SHALL THE
  17 AUTHOR OR CONTRIBUTORS BE LIABLE  FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  18 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 PROCUREMENT OF SUBSTITUTE GOODS  OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 OR BUSINESS INTERRUPTION)  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 WHETHER IN CONTRACT, STRICT  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 OTHERWISE) ARISING IN ANY WAY  OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  23 ADVISED OF THE POSSIBILITY OF  SUCH DAMAGE.   $FreeBSD$
  24 
  25 only forth definitions
  26 
  27 s" arch-i386" environment? [if] [if]    s" loader_version" environment?  [if]
  28           11 < [if]             .( Loader version 1.1+ required) cr
  29                abort          [then]    [else]         .( Could not get loader
  30 version!) cr        abort     [then] [then] [then]
  31 
  32 include /boot/forth/support.4th include /boot/forth/color.4th include
  33 /boot/forth/delay.4th include /boot/forth/check-password.4th s" efi-version"
  34 getenv? [if]   include /boot/forth/efi.4th [then]
  35 
  36 only forth definitions
  37 
  38 : bootmsg ( -- )
  39   loader_color? dup ( -- bool bool )
  40   if 7 fg 4 bg then
  41   ." Booting..."
  42   if me then
  43   cr ;
  44 
  45 : try-menu-unset
  46    menu-unset may not be present
  47   s" beastie_disable" getenv
  48   dup -1 <> if
  49     s" YES" compare-insensitive 0= if
  50       exit
  51     then
  52   else
  53     drop
  54   then
  55   s" menu-unset"
  56   sfind if
  57     execute
  58   else
  59     drop
  60   then
  61   s" menusets-unset"
  62   sfind if
  63     execute
  64   else
  65     drop
  66   then ;
  67 
  68 only forth also support-functions also builtins definitions
  69 
  70  the boot-args was parsed to individual options while loaded  now compose
  71 boot-args, so the boot can set kernel arguments  note the command line
  72 switched for boot command will cause  environment variable boot-args to be
  73 ignored  There are 2 larger strings, acpi-user-options and existing boot-args
  74 other switches are 1 byte each, so allocate boot-args+acpi + extra bytes  for
  75 rest. Be sure to review this, if more options are to be added into
  76 environment.
  77 
  78 : set-boot-args { | addr len baddr blen aaddr alen -- }
  79   s" boot-args" getenv dup -1 <> if
  80     to blen to baddr
  81   else
  82     drop
  83   then
  84   s" acpi-user-options" getenv dup -1 <> if
  85     to alen to aaddr
  86   else
  87     drop
  88   then
  89 
  90    allocate temporary space. max is:
  91     7 kernel switches
  92     26 for acpi, so use 40 for safety
  93   blen alen 40 + + allocate abort" out of memory"
  94   to addr
  95    boot-addr may have file name before options, copy it to addr
  96   baddr 0<> if
  97     baddr c@ [char] - <> if
  98       baddr blen [char] - strchr        ( addr len )
  99       dup 0= if                     no options, copy all
 100         2drop
 101         baddr addr blen move
 102         blen to len
 103         0 to blen
 104         0 to baddr
 105       else                    ( addr len )
 106         dup blen
 107         swap -
 108         to len                ( addr len )
 109         to blen                    ( addr )
 110         baddr addr len move        ( addr )
 111         to baddr               baddr points now to first option
 112       then
 113     then
 114   then
 115    now add kernel switches
 116   len 0<> if
 117     bl addr len + c! len 1+ to len
 118   then
 119   [char] - addr len + c! len 1+ to len
 120 
 121   s" boot_single" getenv dup -1 <> if
 122      s" YES" compare-insensitive 0= if
 123        [char] s addr len + c! len 1+ to len
 124      then
 125   else
 126     drop
 127   then
 128   s" boot_verbose" getenv dup -1 <> if
 129      s" YES" compare-insensitive 0= if
 130        [char] v addr len + c! len 1+ to len
 131      then
 132   else
 133     drop
 134   then
 135   s" boot_kmdb" getenv dup -1 <> if
 136      s" YES" compare-insensitive 0= if
 137        [char] k addr len + c! len 1+ to len
 138      then
 139   else
 140     drop
 141   then
 142   s" boot_drop_into_kmdb" getenv dup -1 <> if
 143      s" YES" compare-insensitive 0= if
 144        [char] d addr len + c! len 1+ to len
 145      then
 146   else
 147     drop
 148   then
 149   s" boot_reconfigure" getenv dup -1 <>   if
 150      s" YES" compare-insensitive 0= if
 151        [char] r addr len + c! len 1+ to len
 152      then
 153   else
 154     drop
 155   then
 156   s" boot_ask" getenv dup -1 <>   if
 157      s" YES" compare-insensitive 0= if
 158        [char] a addr len + c! len 1+ to len
 159      then
 160   else
 161     drop
 162   then
 163 
 164    now add remining boot args if blen != 0.
 165    baddr[0] is '-', if baddr[1] != 'B' append to addr,
 166    otherwise add space then copy
 167   blen 0<> if
 168     baddr 1+ c@ [char] B = if
 169       addr len + 1- c@ [char] - = if      if addr[len -1] == '-'      baddr 1+
 170 to baddr  blen 1- to blen
 171       else     bl addr len + c! len 1+ to len
 172       then
 173     else
 174       baddr 1+ to baddr
 175       blen 1- to blen
 176     then
 177     baddr addr len + blen move
 178     len blen + to len
 179     0 to baddr
 180     0 to blen
 181   then
 182    last part - add acpi.
 183   alen 0<> if
 184     addr len + 1- c@ [char] - <> if
 185       bl addr len + c! len 1+ to len
 186       [char] - addr len + c! len 1+ to len
 187     then
 188     s" B acpi-user-options=" dup -rot        ( len addr len )
 189     addr len + swap move           ( len )
 190     len + to len
 191     aaddr addr len + alen move
 192     len alen + to len
 193   then
 194 
 195    check for left over '-'
 196   addr len 1- + c@ [char] - = if
 197     len 1- to len                   but now we may also have left over ' '
 198     len if ( len <> 0 )
 199       addr len 1- + c@ bl = if     len 1- to len
 200       then
 201     then
 202   then
 203 
 204    if len != 0, set boot-args
 205   len 0<> if
 206     addr len s" boot-args" setenv
 207   then
 208   addr free drop ;
 209 
 210 : boot
 211   0= if ( interpreted ) get_arguments then
 212   set-boot-args
 213 
 214    Unload only if a path was passed. Paths start with /
 215   dup if
 216     >r over r> swap
 217     c@ [char] / = if
 218       0 1 unload drop
 219     else
 220       s" kernelname" getenv? if ( a kernel has been loaded )
 221         try-menu-unset
 222         bootmsg 1 boot exit
 223       then
 224       load_kernel_and_modules
 225       ?dup if exit then
 226       try-menu-unset
 227       bootmsg 0 1 boot exit
 228     then
 229   else
 230     s" kernelname" getenv? if ( a kernel has been loaded )
 231       try-menu-unset
 232       bootmsg 1 boot exit
 233     then
 234     load_kernel_and_modules
 235     ?dup if exit then
 236     try-menu-unset
 237     bootmsg 0 1 boot exit
 238   then
 239   load_kernel_and_modules
 240   ?dup 0= if bootmsg 0 1 boot then ;
 241 
 242  ***** boot-conf    Prepares to boot as specified by loaded configuration
 243 files.
 244 
 245 : boot-conf
 246   0= if ( interpreted ) get_arguments then
 247   0 1 unload drop
 248   load_kernel_and_modules
 249   ?dup 0= if 0 1 autoboot then ;
 250 
 251 also forth definitions previous
 252 
 253 builtin: boot builtin: boot-conf
 254 
 255 only forth definitions also support-functions
 256 
 257    in case the boot-args is set, parse it and extract following options:  -a
 258 to boot_ask=YES  -s to boot_single=YES  -v to boot_verbose=YES  -k to
 259 boot_kmdb=YES  -d to boot_drop_into_kmdb=YES  -r to boot_reconfigure=YES  -B
 260 acpi-user-options=X to acpi-user-options=X    This is needed so that the menu
 261 can manage these options. Unfortunately, this  also means that boot-args will
 262 override previously set options, but we have no  way to control the processing
 263 order here. boot-args will be rebuilt at boot.     NOTE: The best way to
 264 address the order is to *not* set any above options  in boot-args.
 265 
 266 : parse-boot-args  { | baddr blen -- }
 267   s" boot-args" getenv dup -1 = if drop exit then
 268   to blen
 269   to baddr
 270 
 271   baddr blen
 272 
 273    loop over all instances of switch blocks, starting with '-'
 274   begin
 275     [char] - strchr
 276     2dup to blen to baddr
 277     dup 0<>
 278   while                  ( addr len )  points to -
 279      block for switch B. keep it on top of the stack for case
 280      the property list will get empty.
 281 
 282     over 1+ c@ [char] B = if  2dup            save "-B ...." in case options
 283 is empty  2 - swap 2 +        ( addr len len-2 addr+2 )  skip -B
 284 
 285       begin               skip spaces
 286         dup c@ bl =
 287       while
 288         1+ swap 1- swap
 289       repeat
 290 
 291                     ( addr len len' addr' )
 292        its 3 cases now: end of string, -switch, or option list
 293 
 294       over 0= if          end of string, remove trailing -B      2drop
 295                ( addr len )   swap 0 swap c!       store 0 at -B      blen
 296 swap      ( blen len )   -              ( rem )   baddr swap          ( addr
 297 rem )     dup 0= if        s" boot-args" unsetenv        2drop     exit
 298      then                      trailing space(s)  begin       over
 299                ( addr rem addr )     over + 1-         ( addr rem addr+rem-1 )
 300        c@ bl =      while       1- swap      ( rem-1 addr )        over
 301                ( rem-1 addr rem-1 )       over +       ( rem-1 addr addr+rem-1
 302 )      0 swap c!      swap    repeat    s" boot-args" setenv     recurse
 303                 restart  exit
 304       then                    ( addr len len' addr' )
 305       dup c@ [char] - = if     it is switch. set to boot-args    swap s" boot-
 306 args" setenv   2drop     recurse              restart  exit
 307       then                    ( addr len len' addr' )
 308        its options string "option1,option2,... -..."
 309        cut acpi-user-options=xxx and restart the parser
 310        or skip to next option block
 311       begin    dup c@ dup 0<> swap bl <> and  stop if space or 0
 312       while    dup 18 s" acpi-user-options=" compare 0= if   matched
 313                     ( addr len len' addr' )     addr' points to acpi options,
 314 find its end [',' or ' ' or 0 ]       set it as acpi-user-options and move
 315 remaining to addr'    2dup              ( addr len len' addr' len' addr' )
 316         skip to next option in list        loop to first , or bl or 0
 317        begin       dup c@ [char] , <> >r        dup c@ bl <> >r         dup
 318 c@ 0<> r> r> and and           while       1+ swap 1- swap        repeat
 319                     ( addr len len' addr' len" addr" )        >r >r          (
 320 addr len len' addr' R: addr" len" )       over r@ -         ( addr len len'
 321 addr' proplen R: addr" len" )        dup 5 +      ( addr len len' addr'
 322 proplen proplen+5 )        allocate abort" out of memory"
 323 
 324        0 s" set " strcat ( addr len len' addr' proplen caddr clen )     >r >r
 325 2dup r>      r> 2swap strcat      ( addr len len' addr' proplen caddr clen )      2dup +
 326 0 swap c!  terminate with 0     2dup evaluate drop free drop
 327                     ( addr len len' addr' proplen R: addr" len" )        acpi-
 328 user-options is set, now move remaining string to its place.        addr: -B,
 329 addr': acpi... addr": reminder       swap              ( addr len len' proplen
 330 addr' )     r> r>       ( addr len len' proplen addr' len" addr" )
 331        dup c@ [char] , = if        skip , and move addr" to addr'         1+
 332 swap 1-        ( addr len len' proplen addr' addr" len" )       rot   swap 1+
 333 move ( addr len len' proplen )       else     its bl or 0   ( addr len len'
 334 proplen addr' len" addr" )         for both bl and 0 we need to copy to
 335 addr'-1 to remove        comma, then reset boot-args, and recurse will clear
 336 -B        if there are no properties left.       dup c@ 0= if          2drop
 337           ( addr len len' proplen addr' )          1- 0 swap c!  ( addr len
 338 len' proplen )          else        >r >r   ( addr len len' proplen
 339 addr' R: addr" len" )          1- swap 1+ swap          r> r>           ( addr
 340 len len' proplen addr' len" addr" )           rot rot move  ( addr len len'
 341 proplen )          then    then
 342 
 343        2swap 2drop       ( len' proplen )      nip               ( proplen )
 344        baddr blen rot -    s" boot-args" setenv     recurse        exit
 345      else                     ( addr len len' addr' )     not acpi option,
 346 skip to next option in list      loop to first , or bl or 0        begin
 347          dup c@ [char] , <> >r        dup c@ bl <> >r         dup c@ 0<> r>
 348 r> and and    while       1+ swap 1- swap        repeat     if its ',',
 349 skip over        dup c@ [char] , = if       1+ swap 1- swap        then
 350      then
 351       repeat                  ( addr len len' addr' )
 352        this block is done, remove addr and len from stack
 353       2swap 2drop swap
 354     then
 355 
 356     over c@ [char] - = if     ( addr len )
 357       2dup 1- swap 1+         ( addr len len' addr' )
 358       begin               loop till ' ' or 0      dup c@ dup 0<> swap bl <>
 359 and
 360       while    dup c@ [char] s = if       s" set boot_single=YES" evaluate
 361 TRUE      else dup c@ [char] v = if       s" set boot_verbose=YES" evaluate
 362 TRUE      else dup c@ [char] k = if       s" set boot_kmdb=YES" evaluate TRUE
 363      else dup c@ [char] d = if       s" set boot_drop_into_kmdb=YES" evaluate
 364 TRUE      else dup c@ [char] r = if       s" set boot_reconfigure=YES"
 365 evaluate TRUE  else dup c@ [char] a = if       s" set boot_ask=YES" evaluate
 366 TRUE      then then then then then then      dup TRUE = if    drop      dup >r
 367           ( addr len len' addr' R: addr' )     1+ swap 1-        ( addr len
 368 addr'+1 len'-1 R: addr' )       r> swap      move      ( addr len )
 369 
 370        2drop baddr blen 1-       check if we have space after '-', if so, drop
 371 '- '        swap dup 1+ c@ bl = if            2 + swap 2 -    else
 372            swap       then      dup dup 0= swap 1 = or if    empty or only '-'
 373 is left.           2drop          s" boot-args" unsetenv        exit    else
 374          s" boot-args" setenv        then      recurse        exit    then
 375      1+ swap 1- swap
 376       repeat
 377 
 378       2swap 2drop
 379       dup c@ 0= if        end of string      2drop     exit
 380       else     swap
 381       then
 382     then
 383   repeat
 384 
 385   2drop ;
 386 
 387  ***** start        Initializes support.4th global variables, sets
 388 loader_conf_files,        processes conf files, and, if any one such file was
 389 successfully        read to the end, loads kernel and modules.
 390 
 391 : start  ( -- ) ( throws: abort & user-defined )
 392   s" /boot/defaults/loader.conf" initialize
 393   include_bootenv
 394   include_conf_files
 395   include_transient
 396    If the user defined a post-initialize hook, call it now
 397   s" post-initialize" sfind if execute else drop then
 398   parse-boot-args
 399    Will *NOT* try to load kernel and modules if no configuration file
 400    was successfully loaded!
 401   any_conf_read? if
 402     s" loader_delay" getenv -1 = if
 403       load_xen_throw
 404       load_kernel
 405       load_modules
 406     else
 407       drop
 408       ." Loading Kernel and Modules (Ctrl-C to Abort)" cr
 409       s" also support-functions" evaluate
 410       s" set delay_command='load_xen_throw load_kernel load_modules'" evaluate
 411       s" set delay_showdots" evaluate
 412       delay_execute
 413     then
 414   then ;
 415 
 416  ***** initialize   Overrides support.4th initialization word with one that
 417 does      everything start one does, short of loading the kernel and  modules.
 418 Returns a flag.
 419 
 420 : initialize ( -- flag )
 421   s" /boot/defaults/loader.conf" initialize
 422   include_bootenv
 423   include_conf_files
 424   include_transient
 425    If the user defined a post-initialize hook, call it now
 426   s" post-initialize" sfind if execute else drop then
 427   parse-boot-args
 428   any_conf_read?  ;
 429 
 430  ***** read-conf    Read a configuration file, whose name was specified on the
 431 command   line, if interpreted, or given on the stack, if compiled in.
 432 
 433 : (read-conf)  ( addr len -- )
 434   conf_files string=
 435   include_conf_files  Will recurse on new loader_conf_files definitions ;
 436 
 437 : read-conf  ( <filename> | addr len --   ) ( throws: abort & user-defined )
 438   state @ if
 439      Compiling
 440     postpone (read-conf)
 441   else
 442      Interpreting
 443     bl parse (read-conf)
 444   then ; immediate
 445 
 446  show, enable, disable, toggle module loading. They all take module from  the
 447 next word
 448 
 449 : set-module-flag ( module_addr val -- )  set and print flag
 450   over module.flag !
 451   dup module.name strtype
 452   module.flag @ if ."  will be loaded" else ."  will not be loaded" then cr ;
 453 
 454 : enable-module find-module ?dup if true set-module-flag then ;
 455 
 456 : disable-module find-module ?dup if false set-module-flag then ;
 457 
 458 : toggle-module find-module ?dup if dup module.flag @ 0= set-module-flag then
 459 ;
 460 
 461  ***** show-module  Show loading information about a module.
 462 
 463 : show-module ( <module> -- ) find-module ?dup if show-one-module then ;
 464 
 465 : set-module-path ( addr len <module> -- )
 466   find-module ?dup if
 467     module.loadname string=
 468   then ;
 469 
 470  Words to be used inside configuration files
 471 
 472 : retry false ;          For use in load error commands : ignore true ;
 473  For use in load error commands
 474 
 475  Return to strict forth vocabulary
 476 
 477 : #type
 478   over - >r
 479   type
 480   r> spaces ;
 481 
 482 : .? 2 spaces 2swap 15 #type 2 spaces type cr ;
 483 
 484 : ?
 485   ['] ? execute
 486   s" boot-conf" s" load kernel and modules, then autoboot" .?
 487   s" read-conf" s" read a configuration file" .?
 488   s" enable-module" s" enable loading of a module" .?
 489   s" disable-module" s" disable loading of a module" .?
 490   s" toggle-module" s" toggle loading of a module" .?
 491   s" show-module" s" show module load data" .?
 492   s" try-include" s" try to load/interpret files" .?
 493   s" beadm" s" list or activate Boot Environments" .?  ;
 494 
 495 : try-include ( -- )  see loader.4th(8)
 496   ['] include ( -- xt )  get the execution token of `include'
 497   catch ( xt -- exception# | 0 ) if  failed
 498     LF parse ( c -- s-addr/u ) 2drop  advance >in to EOL (drop data)
 499      ... prevents words unused by `include' from being interpreted
 500   then ; immediate  interpret immediately for access to `source' (aka tib)
 501 
 502 include /boot/forth/beadm.4th only forth definitions
 503 
 504 
 505 
 506                                 August 28, 2019                             ()