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