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 30s" 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 42include /boot/forth/support.4th 43include /boot/forth/color.4th 44include /boot/forth/delay.4th 45include /boot/forth/check-password.4th 46efi? [if] 47 include /boot/forth/efi.4th 48[then] 49 50only 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 84only 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 \ 8 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_drop_into_kmdb" 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 s" boot_noncluster" getenv dup -1 <> if 181 s" YES" compare-insensitive 0= if 182 [char] x addr len + c! len 1+ to len 183 then 184 else 185 drop 186 then 187 188 \ now add remining boot args if blen != 0. 189 \ baddr[0] is '-', if baddr[1] != 'B' append to addr, 190 \ otherwise add space then copy 191 blen 0<> if 192 baddr 1+ c@ [char] B = if 193 addr len + 1- c@ [char] - = if \ if addr[len -1] == '-' 194 baddr 1+ to baddr 195 blen 1- to blen 196 else 197 bl addr len + c! len 1+ to len 198 then 199 else 200 baddr 1+ to baddr 201 blen 1- to blen 202 then 203 baddr addr len + blen move 204 len blen + to len 205 0 to baddr 206 0 to blen 207 then 208 \ last part - add acpi. 209 alen 0<> if 210 addr len + 1- c@ [char] - <> if 211 bl addr len + c! len 1+ to len 212 [char] - addr len + c! len 1+ to len 213 then 214 s" B acpi-user-options=" dup -rot ( len addr len ) 215 addr len + swap move ( len ) 216 len + to len 217 aaddr addr len + alen move 218 len alen + to len 219 then 220 221 \ check for left over '-' 222 addr len 1- + c@ [char] - = if 223 len 1- to len 224 \ but now we may also have left over ' ' 225 len if ( len <> 0 ) 226 addr len 1- + c@ bl = if 227 len 1- to len 228 then 229 then 230 then 231 232 \ if len != 0, set boot-args 233 len 0<> if 234 addr len s" boot-args" setenv 235 then 236 addr free drop 237; 238 239: boot 240 0= if ( interpreted ) get_arguments then 241 set-boot-args 242 243 \ Unload only if a path was passed. Paths start with / 244 dup if 245 >r over r> swap 246 c@ [char] / = if 247 0 1 unload drop 248 else 249 s" kernelname" getenv? if ( a kernel has been loaded ) 250 try-menu-unset 251 bootmsg 1 boot exit 252 then 253 load_kernel_and_modules 254 ?dup if exit then 255 try-menu-unset 256 bootmsg 0 1 boot exit 257 then 258 else 259 s" kernelname" getenv? if ( a kernel has been loaded ) 260 try-menu-unset 261 bootmsg 1 boot exit 262 then 263 load_kernel_and_modules 264 ?dup if exit then 265 try-menu-unset 266 bootmsg 0 1 boot exit 267 then 268 load_kernel_and_modules 269 ?dup 0= if bootmsg 0 1 boot then 270; 271 272\ ***** boot-conf 273\ 274\ Prepares to boot as specified by loaded configuration files. 275 276: boot-conf 277 0= if ( interpreted ) get_arguments then 278 0 1 unload drop 279 load_kernel_and_modules 280 ?dup 0= if 0 1 autoboot then 281; 282 283also forth definitions previous 284 285builtin: boot 286builtin: boot-conf 287 288only forth definitions also support-functions 289 290\ 291\ in case the boot-args is set, parse it and extract following options: 292\ -a to boot_ask=YES 293\ -s to boot_single=YES 294\ -v to boot_verbose=YES 295\ -k to boot_kmdb=YES 296\ -d to boot_drop_into_kmdb=YES 297\ -r to boot_reconfigure=YES 298\ -x to boot_noncluster=YES 299\ -B acpi-user-options=X to acpi-user-options=X 300\ 301\ This is needed so that the menu can manage these options. Unfortunately, this 302\ also means that boot-args will override previously set options, but we have no 303\ way to control the processing order here. boot-args will be rebuilt at boot. 304\ 305\ NOTE: The best way to address the order is to *not* set any above options 306\ in boot-args. 307 308: parse-boot-args { | baddr blen -- } 309 s" boot-args" getenv dup -1 = if drop exit then 310 to blen 311 to baddr 312 313 baddr blen 314 315 \ loop over all instances of switch blocks, starting with '-' 316 begin 317 [char] - strchr 318 2dup to blen to baddr 319 dup 0<> 320 while ( addr len ) \ points to - 321 \ block for switch B. keep it on top of the stack for case 322 \ the property list will get empty. 323 324 over 1+ c@ [char] B = if 325 2dup \ save "-B ...." in case options is empty 326 2 - swap 2 + ( addr len len-2 addr+2 ) \ skip -B 327 328 begin \ skip spaces 329 dup c@ bl = 330 while 331 1+ swap 1- swap 332 repeat 333 334 ( addr len len' addr' ) 335 \ its 3 cases now: end of string, -switch, or option list 336 337 over 0= if \ end of string, remove trailing -B 338 2drop ( addr len ) 339 swap 0 swap c! \ store 0 at -B 340 blen swap ( blen len ) 341 - ( rem ) 342 baddr swap ( addr rem ) 343 dup 0= if 344 s" boot-args" unsetenv 345 2drop 346 exit 347 then 348 \ trailing space(s) 349 begin 350 over ( addr rem addr ) 351 over + 1- ( addr rem addr+rem-1 ) 352 c@ bl = 353 while 354 1- swap ( rem-1 addr ) 355 over ( rem-1 addr rem-1 ) 356 over + ( rem-1 addr addr+rem-1 ) 357 0 swap c! 358 swap 359 repeat 360 s" boot-args" setenv 361 recurse \ restart 362 exit 363 then 364 ( addr len len' addr' ) 365 dup c@ [char] - = if \ it is switch. set to boot-args 366 swap s" boot-args" setenv 367 2drop 368 recurse \ restart 369 exit 370 then 371 ( addr len len' addr' ) 372 \ its options string "option1,option2,... -..." 373 \ cut acpi-user-options=xxx and restart the parser 374 \ or skip to next option block 375 begin 376 dup c@ dup 0<> swap bl <> and \ stop if space or 0 377 while 378 dup 18 s" acpi-user-options=" compare 0= if \ matched 379 ( addr len len' addr' ) 380 \ addr' points to acpi options, find its end [',' or ' ' or 0 ] 381 \ set it as acpi-user-options and move remaining to addr' 382 2dup ( addr len len' addr' len' addr' ) 383 \ skip to next option in list 384 \ loop to first , or bl or 0 385 begin 386 dup c@ [char] , <> >r 387 dup c@ bl <> >r 388 dup c@ 0<> r> r> and and 389 while 390 1+ swap 1- swap 391 repeat 392 ( addr len len' addr' len" addr" ) 393 >r >r ( addr len len' addr' R: addr" len" ) 394 over r@ - ( addr len len' addr' proplen R: addr" len" ) 395 dup 5 + ( addr len len' addr' proplen proplen+5 ) 396 allocate abort" out of memory" 397 398 0 s" set " strcat ( addr len len' addr' proplen caddr clen ) 399 >r >r 2dup r> r> 2swap strcat ( addr len len' addr' proplen caddr clen ) 400 2dup + 0 swap c! \ terminate with 0 401 2dup evaluate drop free drop 402 ( addr len len' addr' proplen R: addr" len" ) 403 \ acpi-user-options is set, now move remaining string to its place. 404 \ addr: -B, addr': acpi... addr": reminder 405 swap ( addr len len' proplen addr' ) 406 r> r> ( addr len len' proplen addr' len" addr" ) 407 dup c@ [char] , = if 408 \ skip , and move addr" to addr' 409 1+ swap 1- ( addr len len' proplen addr' addr" len" ) 410 rot swap 1+ move ( addr len len' proplen ) 411 else \ its bl or 0 ( addr len len' proplen addr' len" addr" ) 412 \ for both bl and 0 we need to copy to addr'-1 to remove 413 \ comma, then reset boot-args, and recurse will clear -B 414 \ if there are no properties left. 415 dup c@ 0= if 416 2drop ( addr len len' proplen addr' ) 417 1- 0 swap c! ( addr len len' proplen ) 418 else 419 >r >r ( addr len len' proplen addr' R: addr" len" ) 420 1- swap 1+ swap 421 r> r> ( addr len len' proplen addr' len" addr" ) 422 rot rot move ( addr len len' proplen ) 423 then 424 then 425 426 2swap 2drop ( len' proplen ) 427 nip ( proplen ) 428 baddr blen rot - 429 s" boot-args" setenv 430 recurse 431 exit 432 else 433 ( addr len len' addr' ) 434 \ not acpi option, skip to next option in list 435 \ loop to first , or bl or 0 436 begin 437 dup c@ [char] , <> >r 438 dup c@ bl <> >r 439 dup c@ 0<> r> r> and and 440 while 441 1+ swap 1- swap 442 repeat 443 \ if its ',', skip over 444 dup c@ [char] , = if 445 1+ swap 1- swap 446 then 447 then 448 repeat 449 ( addr len len' addr' ) 450 \ this block is done, remove addr and len from stack 451 2swap 2drop swap 452 then 453 454 over c@ [char] - = if ( addr len ) 455 2dup 1- swap 1+ ( addr len len' addr' ) 456 begin \ loop till ' ' or 0 457 dup c@ dup 0<> swap bl <> and 458 while 459 dup c@ [char] s = if 460 s" set boot_single=YES" evaluate TRUE 461 else dup c@ [char] v = if 462 s" set boot_verbose=YES" evaluate TRUE 463 else dup c@ [char] k = if 464 s" set boot_kmdb=YES" evaluate TRUE 465 else dup c@ [char] d = if 466 s" set boot_drop_into_kmdb=YES" evaluate TRUE 467 else dup c@ [char] r = if 468 s" set boot_reconfigure=YES" evaluate TRUE 469 else dup c@ [char] a = if 470 s" set boot_ask=YES" evaluate TRUE 471 else dup c@ [char] x = if 472 s" set boot_noncluster=YES" evaluate TRUE 473 then then then then then then then 474 dup TRUE = if 475 drop 476 dup >r ( addr len len' addr' R: addr' ) 477 1+ swap 1- ( addr len addr'+1 len'-1 R: addr' ) 478 r> swap move ( addr len ) 479 480 2drop baddr blen 1- 481 \ check if we have space after '-', if so, drop '- ' 482 swap dup 1+ c@ bl = if 483 2 + swap 2 - 484 else 485 swap 486 then 487 dup dup 0= swap 1 = or if \ empty or only '-' is left. 488 2drop 489 s" boot-args" unsetenv 490 exit 491 else 492 s" boot-args" setenv 493 then 494 recurse 495 exit 496 then 497 1+ swap 1- swap 498 repeat 499 500 2swap 2drop 501 dup c@ 0= if \ end of string 502 2drop 503 exit 504 else 505 swap 506 then 507 then 508 repeat 509 510 2drop 511; 512 513\ ***** start 514\ 515\ Initializes support.4th global variables, sets loader_conf_files, 516\ processes conf files, and, if any one such file was successfully 517\ read to the end, loads kernel and modules. 518 519: start ( -- ) ( throws: abort & user-defined ) 520 s" /boot/defaults/loader.conf" initialize 521 include_bootenv 522 include_conf_files 523 include_transient 524 \ If the user defined a post-initialize hook, call it now 525 s" post-initialize" sfind if execute else drop then 526 parse-boot-args 527 \ Will *NOT* try to load kernel and modules if no configuration file 528 \ was successfully loaded! 529 any_conf_read? if 530 s" loader_delay" getenv -1 = if 531 load_xen_throw 532 load_kernel 533 load_modules 534 else 535 drop 536 ." Loading Kernel and Modules (Ctrl-C to Abort)" cr 537 s" also support-functions" evaluate 538 s" set delay_command='load_xen_throw load_kernel load_modules'" evaluate 539 s" set delay_showdots" evaluate 540 delay_execute 541 then 542 then 543; 544 545\ ***** initialize 546\ 547\ Overrides support.4th initialization word with one that does 548\ everything start one does, short of loading the kernel and 549\ modules. Returns a flag. 550 551: initialize ( -- flag ) 552 s" /boot/defaults/loader.conf" initialize 553 include_bootenv 554 include_conf_files 555 include_transient 556 \ If the user defined a post-initialize hook, call it now 557 s" post-initialize" sfind if execute else drop then 558 parse-boot-args 559 any_conf_read? 560; 561 562\ ***** read-conf 563\ 564\ Read a configuration file, whose name was specified on the command 565\ line, if interpreted, or given on the stack, if compiled in. 566 567: (read-conf) ( addr len -- ) 568 conf_files string= 569 include_conf_files \ Will recurse on new loader_conf_files definitions 570; 571 572: read-conf ( <filename> | addr len -- ) ( throws: abort & user-defined ) 573 state @ if 574 \ Compiling 575 postpone (read-conf) 576 else 577 \ Interpreting 578 bl parse (read-conf) 579 then 580; immediate 581 582\ show, enable, disable, toggle module loading. They all take module from 583\ the next word 584 585: set-module-flag ( module_addr val -- ) \ set and print flag 586 over module.flag ! 587 dup module.name strtype 588 module.flag @ if ." will be loaded" else ." will not be loaded" then cr 589; 590 591: enable-module find-module ?dup if true set-module-flag then ; 592 593: disable-module find-module ?dup if false set-module-flag then ; 594 595: toggle-module find-module ?dup if dup module.flag @ 0= set-module-flag then ; 596 597\ ***** show-module 598\ 599\ Show loading information about a module. 600 601: show-module ( <module> -- ) find-module ?dup if show-one-module then ; 602 603: set-module-path ( addr len <module> -- ) 604 find-module ?dup if 605 module.loadname string= 606 then 607; 608 609\ Words to be used inside configuration files 610 611: retry false ; \ For use in load error commands 612: ignore true ; \ For use in load error commands 613 614\ Return to strict forth vocabulary 615 616: #type 617 over - >r 618 type 619 r> spaces 620; 621 622: .? 2 spaces 2swap 15 #type 2 spaces type cr ; 623 624: ? 625 ['] ? execute 626 s" boot-conf" s" load kernel and modules, then autoboot" .? 627 s" read-conf" s" read a configuration file" .? 628 s" enable-module" s" enable loading of a module" .? 629 s" disable-module" s" disable loading of a module" .? 630 s" toggle-module" s" toggle loading of a module" .? 631 s" show-module" s" show module load data" .? 632 s" try-include" s" try to load/interpret files" .? 633 s" beadm" s" list or activate Boot Environments" .? 634; 635 636: try-include ( -- ) \ see loader.4th(8) 637 ['] include ( -- xt ) \ get the execution token of `include' 638 catch ( xt -- exception# | 0 ) if \ failed 639 LF parse ( c -- s-addr/u ) 2drop \ advance >in to EOL (drop data) 640 \ ... prevents words unused by `include' from being interpreted 641 then 642; immediate \ interpret immediately for access to `source' (aka tib) 643 644include /boot/forth/beadm.4th 645only forth definitions 646