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 30include /boot/forth/support.4th 31include /boot/forth/color.4th 32include /boot/forth/delay.4th 33include /boot/forth/check-password.4th 34efi? [if] 35 include /boot/forth/efi.4th 36[then] 37 38only forth definitions 39 40: bootmsg ( -- ) 41 loader_color? dup ( -- bool bool ) 42 if 7 fg 4 bg then 43 ." Booting..." 44 if me then 45 cr 46; 47 48: try-menu-unset 49 \ menu-unset may not be present 50 s" beastie_disable" getenv 51 dup -1 <> if 52 s" YES" compare-insensitive 0= if 53 exit 54 then 55 else 56 drop 57 then 58 s" menu-unset" 59 sfind if 60 execute 61 else 62 drop 63 then 64 s" menusets-unset" 65 sfind if 66 execute 67 else 68 drop 69 then 70; 71 72only forth also support-functions also builtins definitions 73 74\ the boot-args was parsed to individual options while loaded 75\ now compose boot-args, so the boot can set kernel arguments 76\ note the command line switched for boot command will cause 77\ environment variable boot-args to be ignored 78\ There are 2 larger strings, acpi-user-options and existing boot-args 79\ other switches are 1 byte each, so allocate boot-args+acpi + extra bytes 80\ for rest. Be sure to review this, if more options are to be added into 81\ environment. 82 83: set-boot-args { | addr len baddr blen aaddr alen -- } 84 s" boot-args" getenv dup -1 <> if 85 to blen to baddr 86 else 87 drop 88 then 89 s" acpi-user-options" getenv dup -1 <> if 90 to alen to aaddr 91 else 92 drop 93 then 94 95 \ allocate temporary space. max is: 96 \ 8 kernel switches 97 \ 26 for acpi, so use 40 for safety 98 blen alen 40 + + allocate abort" out of memory" 99 to addr 100 \ boot-addr may have file name before options, copy it to addr 101 baddr 0<> if 102 baddr c@ [char] - <> if 103 baddr blen [char] - strchr ( addr len ) 104 dup 0= if \ no options, copy all 105 2drop 106 baddr addr blen move 107 blen to len 108 0 to blen 109 0 to baddr 110 else ( addr len ) 111 dup blen 112 swap - 113 to len ( addr len ) 114 to blen ( addr ) 115 baddr addr len move ( addr ) 116 to baddr \ baddr points now to first option 117 then 118 then 119 then 120 \ now add kernel switches 121 len 0<> if 122 bl addr len + c! len 1+ to len 123 then 124 [char] - addr len + c! len 1+ to len 125 126 s" boot_single" getenv dup -1 <> if 127 s" YES" compare-insensitive 0= if 128 [char] s addr len + c! len 1+ to len 129 then 130 else 131 drop 132 then 133 s" boot_verbose" getenv dup -1 <> if 134 s" YES" compare-insensitive 0= if 135 [char] v addr len + c! len 1+ to len 136 then 137 else 138 drop 139 then 140 s" boot_kmdb" getenv dup -1 <> if 141 s" YES" compare-insensitive 0= if 142 [char] k addr len + c! len 1+ to len 143 then 144 else 145 drop 146 then 147 s" boot_drop_into_kmdb" getenv dup -1 <> if 148 s" YES" compare-insensitive 0= if 149 [char] d addr len + c! len 1+ to len 150 then 151 else 152 drop 153 then 154 s" boot_reconfigure" getenv dup -1 <> if 155 s" YES" compare-insensitive 0= if 156 [char] r addr len + c! len 1+ to len 157 then 158 else 159 drop 160 then 161 s" boot_ask" getenv dup -1 <> if 162 s" YES" compare-insensitive 0= if 163 [char] a addr len + c! len 1+ to len 164 then 165 else 166 drop 167 then 168 s" boot_noncluster" getenv dup -1 <> if 169 s" YES" compare-insensitive 0= if 170 [char] x addr len + c! len 1+ to len 171 then 172 else 173 drop 174 then 175 176 \ now add remining boot args if blen != 0. 177 \ baddr[0] is '-', if baddr[1] != 'B' append to addr, 178 \ otherwise add space then copy 179 blen 0<> if 180 baddr 1+ c@ [char] B = if 181 addr len + 1- c@ [char] - = if \ if addr[len -1] == '-' 182 baddr 1+ to baddr 183 blen 1- to blen 184 else 185 bl addr len + c! len 1+ to len 186 then 187 else 188 baddr 1+ to baddr 189 blen 1- to blen 190 then 191 baddr addr len + blen move 192 len blen + to len 193 0 to baddr 194 0 to blen 195 then 196 \ last part - add acpi. 197 alen 0<> if 198 addr len + 1- c@ [char] - <> if 199 bl addr len + c! len 1+ to len 200 [char] - addr len + c! len 1+ to len 201 then 202 s" B acpi-user-options=" dup -rot ( len addr len ) 203 addr len + swap move ( len ) 204 len + to len 205 aaddr addr len + alen move 206 len alen + to len 207 then 208 209 \ check for left over '-' 210 addr len 1- + c@ [char] - = if 211 len 1- to len 212 \ but now we may also have left over ' ' 213 len if ( len <> 0 ) 214 addr len 1- + c@ bl = if 215 len 1- to len 216 then 217 then 218 then 219 220 \ if len != 0, set boot-args 221 len 0<> if 222 addr len s" boot-args" setenv 223 then 224 addr free drop 225; 226 227: boot 228 0= if ( interpreted ) get_arguments then 229 set-boot-args 230 231 \ Unload only if a path was passed. Paths start with / 232 dup if 233 >r over r> swap 234 c@ [char] / = if 235 0 1 unload drop 236 else 237 s" kernelname" getenv? if ( a kernel has been loaded ) 238 try-menu-unset 239 bootmsg 1 boot exit 240 then 241 load_kernel_and_modules 242 ?dup if exit then 243 try-menu-unset 244 bootmsg 0 1 boot exit 245 then 246 else 247 s" kernelname" getenv? if ( a kernel has been loaded ) 248 try-menu-unset 249 bootmsg 1 boot exit 250 then 251 load_kernel_and_modules 252 ?dup if exit then 253 try-menu-unset 254 bootmsg 0 1 boot exit 255 then 256 load_kernel_and_modules 257 ?dup 0= if bootmsg 0 1 boot then 258; 259 260\ ***** boot-conf 261\ 262\ Prepares to boot as specified by loaded configuration files. 263 264: boot-conf 265 0= if ( interpreted ) get_arguments then 266 0 1 unload drop 267 load_kernel_and_modules 268 ?dup 0= if 0 1 autoboot then 269; 270 271also forth definitions previous 272 273builtin: boot 274builtin: boot-conf 275 276only forth definitions also support-functions 277 278\ 279\ in case the boot-args is set, parse it and extract following options: 280\ -a to boot_ask=YES 281\ -s to boot_single=YES 282\ -v to boot_verbose=YES 283\ -k to boot_kmdb=YES 284\ -d to boot_drop_into_kmdb=YES 285\ -r to boot_reconfigure=YES 286\ -x to boot_noncluster=YES 287\ -B acpi-user-options=X to acpi-user-options=X 288\ 289\ This is needed so that the menu can manage these options. Unfortunately, this 290\ also means that boot-args will override previously set options, but we have no 291\ 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_drop_into_kmdb=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 else dup c@ [char] x = if 460 s" set boot_noncluster=YES" evaluate TRUE 461 then then then then then then then 462 dup TRUE = if 463 drop 464 dup >r ( addr len len' addr' R: addr' ) 465 1+ swap 1- ( addr len addr'+1 len'-1 R: addr' ) 466 r> swap move ( addr len ) 467 468 2drop baddr blen 1- 469 \ check if we have space after '-', if so, drop '- ' 470 swap dup 1+ c@ bl = if 471 2 + swap 2 - 472 else 473 swap 474 then 475 dup dup 0= swap 1 = or if \ empty or only '-' is left. 476 2drop 477 s" boot-args" unsetenv 478 exit 479 else 480 s" boot-args" setenv 481 then 482 recurse 483 exit 484 then 485 1+ swap 1- swap 486 repeat 487 488 2swap 2drop 489 dup c@ 0= if \ end of string 490 2drop 491 exit 492 else 493 swap 494 then 495 then 496 repeat 497 498 2drop 499; 500 501\ ***** start 502\ 503\ Initializes support.4th global variables, sets loader_conf_files, 504\ processes conf files, and, if any one such file was successfully 505\ read to the end, loads kernel and modules. 506 507: start ( -- ) ( throws: abort & user-defined ) 508 s" /boot/defaults/loader.conf" initialize 509 include_bootenv 510 include_conf_files 511 include_transient 512 \ If the user defined a post-initialize hook, call it now 513 s" post-initialize" sfind if execute else drop then 514 parse-boot-args 515 \ Will *NOT* try to load kernel and modules if no configuration file 516 \ was successfully loaded! 517 any_conf_read? if 518 s" loader_delay" getenv -1 = if 519 load_xen_throw 520 load_kernel 521 load_modules 522 else 523 drop 524 ." Loading Kernel and Modules (Ctrl-C to Abort)" cr 525 s" also support-functions" evaluate 526 s" set delay_command='load_xen_throw load_kernel load_modules'" evaluate 527 s" set delay_showdots" evaluate 528 delay_execute 529 then 530 then 531; 532 533\ ***** initialize 534\ 535\ Overrides support.4th initialization word with one that does 536\ everything start one does, short of loading the kernel and 537\ modules. Returns a flag. 538 539: initialize ( -- flag ) 540 s" /boot/defaults/loader.conf" initialize 541 include_bootenv 542 include_conf_files 543 include_transient 544 \ If the user defined a post-initialize hook, call it now 545 s" post-initialize" sfind if execute else drop then 546 parse-boot-args 547 any_conf_read? 548; 549 550\ ***** read-conf 551\ 552\ Read a configuration file, whose name was specified on the command 553\ line, if interpreted, or given on the stack, if compiled in. 554 555: (read-conf) ( addr len -- ) 556 conf_files string= 557 include_conf_files \ Will recurse on new loader_conf_files definitions 558; 559 560: read-conf ( <filename> | addr len -- ) ( throws: abort & user-defined ) 561 state @ if 562 \ Compiling 563 postpone (read-conf) 564 else 565 \ Interpreting 566 bl parse (read-conf) 567 then 568; immediate 569 570\ show, enable, disable, toggle module loading. They all take module from 571\ the next word 572 573: set-module-flag ( module_addr val -- ) \ set and print flag 574 over module.flag ! 575 dup module.name strtype 576 module.flag @ if ." will be loaded" else ." will not be loaded" then cr 577; 578 579: enable-module find-module ?dup if true set-module-flag then ; 580 581: disable-module find-module ?dup if false set-module-flag then ; 582 583: toggle-module find-module ?dup if dup module.flag @ 0= set-module-flag then ; 584 585\ ***** show-module 586\ 587\ Show loading information about a module. 588 589: show-module ( <module> -- ) find-module ?dup if show-one-module then ; 590 591: set-module-path ( addr len <module> -- ) 592 find-module ?dup if 593 module.loadname string= 594 then 595; 596 597\ Words to be used inside configuration files 598 599: retry false ; \ For use in load error commands 600: ignore true ; \ For use in load error commands 601 602\ Return to strict forth vocabulary 603 604: #type 605 over - >r 606 type 607 r> spaces 608; 609 610: .? 2 spaces 2swap 15 #type 2 spaces type cr ; 611 612: ? 613 ['] ? execute 614 s" boot-conf" s" load kernel and modules, then autoboot" .? 615 s" read-conf" s" read a configuration file" .? 616 s" enable-module" s" enable loading of a module" .? 617 s" disable-module" s" disable loading of a module" .? 618 s" toggle-module" s" toggle loading of a module" .? 619 s" show-module" s" show module load data" .? 620 s" try-include" s" try to load/interpret files" .? 621 s" beadm" s" list or activate Boot Environments" .? 622; 623 624: try-include ( -- ) \ see loader.4th(8) 625 ['] include ( -- xt ) \ get the execution token of `include' 626 catch ( xt -- exception# | 0 ) if \ failed 627 LF parse ( c -- s-addr/u ) 2drop \ advance >in to EOL (drop data) 628 \ ... prevents words unused by `include' from being interpreted 629 then 630; immediate \ interpret immediately for access to `source' (aka tib) 631 632include /boot/forth/beadm.4th 633only forth definitions 634