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 28 only forth definitions 29 30 s" 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 42 include /boot/forth/support.4th 43 include /boot/forth/color.4th 44 include /boot/forth/delay.4th 45 include /boot/forth/check-password.4th 46 s" efi-version" getenv? [if] 47 include /boot/forth/efi.4th 48 [then] 49 50 only 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 84 only 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 276 also forth definitions previous 277 278 builtin: boot 279 builtin: boot-conf 280 281 only 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 634 include /boot/forth/beadm.4th 635 only forth definitions