1 \ Copyright (c) 2006-2015 Devin Teske <dteske@FreeBSD.org>
   2 \ All rights reserved.
   3 \
   4 \ Redistribution and use in source and binary forms, with or without
   5 \ modification, are permitted provided that the following conditions
   6 \ are met:
   7 \ 1. Redistributions of source code must retain the above copyright
   8 \    notice, this list of conditions and the following disclaimer.
   9 \ 2. Redistributions in binary form must reproduce the above copyright
  10 \    notice, this list of conditions and the following disclaimer in the
  11 \    documentation and/or other materials provided with the distribution.
  12 \
  13 \ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  14 \ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15 \ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16 \ ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  17 \ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18 \ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  19 \ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  20 \ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21 \ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22 \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  23 \ SUCH DAMAGE.
  24 \
  25 \ Copyright 2015 Toomas Soome <tsoome@me.com>
  26 \ Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
  27 
  28 marker task-menu-commands.4th
  29 
  30 include /boot/forth/menusets.4th
  31 
  32 only forth definitions
  33 
  34 variable osconsole_state
  35 variable acpi_state
  36 variable kernel_state
  37 variable root_state
  38 variable kmdb_state
  39 variable debug_state
  40 0 kmdb_state !
  41 0 debug_state !
  42 0 osconsole_state !
  43 0 acpi_state !
  44 0 kernel_state !
  45 0 root_state !
  46 
  47 also menu-namespace also menu-command-helpers
  48 
  49 \
  50 \ Boot
  51 \
  52 
  53 : init_boot ( N -- N )
  54         dup
  55         s" smartos" getenv? if
  56                 s" set menu_keycode[N]=98" \ base command to execute
  57         else
  58                 s" boot_single" getenv -1 <> if
  59                         drop ( n n c-addr -- n n ) \ unused
  60                         toggle_menuitem ( n n -- n n )
  61                         s" set menu_keycode[N]=115" \ base command to execute
  62                 else
  63                         s" set menu_keycode[N]=98" \ base command to execute
  64                 then
  65         then
  66         17 +c! \ replace 'N' with ASCII numeral
  67         evaluate
  68 ;
  69 
  70 \
  71 \ Alternate Boot
  72 \
  73 
  74 : init_altboot ( N -- N )
  75         dup
  76         s" smartos" getenv? if
  77                 s" set menu_keycode[N]=114" \ base command to execute
  78         else
  79                 s" boot_single" getenv -1 <> if
  80                         drop ( n c-addr -- n ) \ unused
  81                         toggle_menuitem ( n -- n )
  82                         s" set menu_keycode[N]=109" \ base command to execute
  83                 else
  84                         s" set menu_keycode[N]=115" \ base command to execute
  85                 then
  86         then
  87         17 +c! \ replace 'N' with ASCII numeral
  88         evaluate
  89 ;
  90 
  91 : altboot ( N -- NOTREACHED )
  92         s" smartos" getenv? if
  93                 s" alt-boot-args" getenv dup -1 <> if
  94                         s" boot-args" setenv ( c-addr/u -- )
  95                 then
  96                 ." NoInstall/Recovery mode boot. login/pw: root/root" cr
  97         else
  98                 s" boot_single" 2dup getenv -1 <> if
  99                         drop ( c-addr/u c-addr -- c-addr/u ) \ unused
 100                         unsetenv ( c-addr/u -- )
 101                 else
 102                         2drop ( c-addr/u -- ) \ unused
 103                         s" set boot_single=YES" evaluate
 104                 then
 105         then
 106         0 boot ( state -- )
 107 ;
 108 
 109 \
 110 \ Single User Mode
 111 \
 112 
 113 : singleuser_enabled? ( -- flag )
 114         s" boot_single" getenv -1 <> dup if
 115                 swap drop ( c-addr flag -- flag )
 116         then
 117 ;
 118 
 119 : singleuser_enable ( -- )
 120         s" set boot_single=YES" evaluate
 121 ;
 122 
 123 : singleuser_disable ( -- )
 124         s" boot_single" unsetenv
 125 ;
 126 
 127 : init_singleuser ( N -- N )
 128         singleuser_enabled? if
 129                 toggle_menuitem ( n -- n )
 130         then
 131 ;
 132 
 133 : toggle_singleuser ( N -- N TRUE )
 134         toggle_menuitem
 135         menu-redraw
 136 
 137         \ Now we're going to make the change effective
 138 
 139         dup toggle_stateN @ 0= if
 140                 singleuser_disable
 141         else
 142                 singleuser_enable
 143         then
 144 
 145         TRUE \ loop menu again
 146 ;
 147 
 148 \
 149 \ Verbose Boot
 150 \
 151 
 152 : verbose_enabled? ( -- flag )
 153         s" boot_verbose" getenv -1 <> dup if
 154                 swap drop ( c-addr flag -- flag )
 155         then
 156 ;
 157 
 158 : verbose_enable ( -- )
 159         s" set boot_verbose=YES" evaluate
 160 ;
 161 
 162 : verbose_disable ( -- )
 163         s" boot_verbose" unsetenv
 164 ;
 165 
 166 : init_verbose ( N -- N )
 167         verbose_enabled? if
 168                 toggle_menuitem ( n -- n )
 169         then
 170 ;
 171 
 172 : toggle_verbose ( N -- N TRUE )
 173         toggle_menuitem
 174         menu-redraw
 175 
 176         \ Now we're going to make the change effective
 177 
 178         dup toggle_stateN @ 0= if
 179                 verbose_disable
 180         else
 181                 verbose_enable
 182         then
 183 
 184         TRUE \ loop menu again
 185 ;
 186 
 187 \
 188 \ kmdb
 189 \
 190 
 191 : kmdb_enabled? ( -- flag )
 192         s" boot_kmdb" getenv -1 <> dup if
 193                 swap drop ( c-addr flag -- flag )
 194         then
 195 ;
 196 
 197 : kmdb_enable ( -- )
 198         s" set boot_kmdb=YES" evaluate
 199 ;
 200 
 201 : kmdb_disable ( -- )
 202         s" boot_kmdb" unsetenv
 203         s" boot_debug" unsetenv
 204 ;
 205 
 206 : init_kmdb ( N -- N )
 207         dup kmdb_state !                \ store entry number for kmdb+debug
 208         kmdb_enabled? if
 209                 toggle_menuitem ( n -- n )
 210         then
 211 ;
 212 
 213 : toggle_kmdb ( N -- N TRUE )
 214         toggle_menuitem
 215         dup toggle_stateN @ 0= if ( kmdb is not set )
 216                 debug_state @ if ( debug is set? )
 217                         debug_state @ toggle_stateN @ if ( debug is enabled? )
 218                                 debug_state @ toggle_menuitem drop
 219                         then
 220                 then
 221         then
 222         menu-redraw
 223 
 224         \ Now we're going to make the change effective
 225 
 226         dup toggle_stateN @ 0= if
 227                 kmdb_disable
 228         else
 229                 kmdb_enable
 230         then
 231 
 232         TRUE \ loop menu again
 233 ;
 234 
 235 \
 236 \ kmdb + debug
 237 \
 238 
 239 : debug_disable ( -- )
 240         s" boot_debug" unsetenv
 241 ;
 242 
 243 : debug_enabled? ( -- flag )
 244         \ -d is only allowed with -k
 245         s" boot_debug" getenv -1 <> kmdb_enabled? and dup if
 246                 swap drop ( c-addr flag -- flag )
 247         else
 248                 debug_disable           \ make sure env is not set
 249         then
 250 ;
 251 
 252 : debug_enable ( -- )
 253         kmdb_enable
 254         s" set boot_debug=YES" evaluate
 255 ;
 256 
 257 : init_debug ( N -- N )
 258         dup debug_state !               \ store entry number for kmdb
 259         kmdb_enabled? debug_enabled? and if
 260                 toggle_menuitem ( n -- n )
 261         then
 262 ;
 263 
 264 : toggle_debug ( N -- N TRUE )
 265         toggle_menuitem
 266         kmdb_enabled? 0= if
 267                 kmdb_state @ toggle_menuitem drop
 268         then
 269         menu-redraw
 270 
 271         \ Now we're going to make the change effective
 272 
 273         dup toggle_stateN @ 0= if
 274                 debug_disable
 275         else
 276                 debug_enable
 277         then
 278 
 279         TRUE \ loop menu again
 280 ;
 281 
 282 \
 283 \ Reconfiguration boot
 284 \
 285 
 286 : reconfigure_enabled? ( -- flag )
 287         s" boot_reconfigure" getenv -1 <> dup if
 288                 swap drop ( c-addr flag -- flag )
 289         then
 290 ;
 291 
 292 : reconfigure_enable ( -- )
 293         s" set boot_reconfigure=YES" evaluate
 294 ;
 295 
 296 : reconfigure_disable ( -- )
 297         s" boot_reconfigure" unsetenv
 298 ;
 299 
 300 : init_reconfigure ( N -- N )
 301         reconfigure_enabled? if
 302                 toggle_menuitem ( n -- n )
 303         then
 304 ;
 305 
 306 : toggle_reconfigure ( N -- N TRUE )
 307         toggle_menuitem
 308         menu-redraw
 309 
 310         \ Now we're going to make the change effective
 311 
 312         dup toggle_stateN @ 0= if
 313                 reconfigure_disable
 314         else
 315                 reconfigure_enable
 316         then
 317 
 318         TRUE \ loop menu again
 319 ;
 320 
 321 \
 322 \ Escape to Prompt
 323 \
 324 
 325 : goto_prompt ( N -- N FALSE )
 326 
 327         s" set autoboot_delay=NO" evaluate
 328 
 329         cr
 330         ." To get back to the menu, type `menu' and press ENTER" cr
 331         ." or type `boot' and press ENTER to start illumos." cr
 332         cr
 333 
 334         FALSE \ exit the menu
 335 ;
 336 
 337 \
 338 \ Cyclestate (used by osconsole/acpi/kernel/root below)
 339 \
 340 
 341 : init_cyclestate ( N K -- N )
 342         over cycle_stateN ( n k -- n k addr )
 343         begin
 344                 tuck @  ( n k addr -- n addr k c )
 345                 over <> ( n addr k c -- n addr k 0|-1 )
 346         while
 347                 rot ( n addr k -- addr k n )
 348                 cycle_menuitem
 349                 swap rot ( addr k n -- n k addr )
 350         repeat
 351         2drop ( n k addr -- n )
 352 ;
 353 
 354 \
 355 \ OS Console
 356 \ getenv os_console, if not set getenv console, if not set, default to "text"
 357 \ allowed serial consoles: ttya .. ttyd
 358 \ if new console will be added (graphics?), this section needs to be updated
 359 \
 360 : init_osconsole ( N -- N )
 361         s" os_console" getenv dup -1 = if
 362                 drop
 363                 s" console" getenv dup -1 = if
 364                         drop 0          \ default to text
 365                 then
 366         then                            ( n c-addr/u | n 0 )
 367 
 368         dup 0<> if                        ( n c-addr/u )
 369                 2dup s" ttyd" compare 0= if
 370                         2drop 4
 371                 else 2dup s" ttyc" compare 0= if
 372                         2drop 3
 373                 else 2dup s" ttyb" compare 0= if
 374                         2drop 2
 375                 else 2dup s" ttya" compare 0= if
 376                         2drop 1
 377                 else
 378                         2drop 0         \ anything else defaults to text
 379                 then then then then
 380         then
 381         osconsole_state !
 382 ;
 383 
 384 : activate_osconsole ( N -- N )
 385         dup cycle_stateN @      ( n -- n n2 )
 386         dup osconsole_state !   ( n n2 -- n n2 )  \ copy for re-initialization
 387 
 388         case
 389         0 of s" text" endof
 390         1 of s" ttya" endof
 391         2 of s" ttyb" endof
 392         3 of s" ttyc" endof
 393         4 of s" ttyd" endof
 394         dup s" unknown state: " type . cr
 395         endcase
 396         s" os_console" setenv
 397 ;
 398 
 399 : cycle_osconsole ( N -- N TRUE )
 400         cycle_menuitem  \ cycle cycle_stateN to next value
 401         activate_osconsole      \ apply current cycle_stateN
 402         menu-redraw     \ redraw menu
 403         TRUE            \ loop menu again
 404 ;
 405 
 406 \
 407 \ ACPI
 408 \
 409 : init_acpi ( N -- N )
 410         s" acpi-user-options" getenv dup -1 <> if
 411                 evaluate                \ use ?number parse step
 412 
 413                 \ translate option to cycle state
 414                 case
 415                 1 of 1 acpi_state ! endof
 416                 2 of 2 acpi_state ! endof
 417                 4 of 3 acpi_state ! endof
 418                 8 of 4 acpi_state ! endof
 419                 0 acpi_state !
 420                 endcase
 421         else
 422                 drop
 423         then
 424 ;
 425 
 426 : activate_acpi ( N -- N )
 427         dup cycle_stateN @      ( n -- n n2 )
 428         dup acpi_state !        ( n n2 -- n n2 )  \ copy for re-initialization
 429 
 430         \ if N == 0, it's default, just unset env.
 431         dup 0= if
 432                 drop
 433                 s" acpi-user-options" unsetenv
 434         else
 435                 case
 436                 1 of s" 1" endof
 437                 2 of s" 2" endof
 438                 3 of s" 4" endof
 439                 4 of s" 8" endof
 440                 endcase
 441                 s" acpi-user-options" setenv
 442         then
 443 ;
 444 
 445 : cycle_acpi ( N -- N TRUE )
 446         cycle_menuitem  \ cycle cycle_stateN to next value
 447         activate_acpi   \ apply current cycle_stateN
 448         menu-redraw     \ redraw menu
 449         TRUE            \ loop menu again
 450 ;
 451 
 452 \
 453 \ Kernel
 454 \
 455 
 456 : init_kernel ( N -- N )
 457         kernel_state @  ( n -- n k )
 458         init_cyclestate ( n k -- n )
 459 ;
 460 
 461 : activate_kernel ( N -- N )
 462         dup cycle_stateN @      ( n -- n n2 )
 463         dup kernel_state !      ( n n2 -- n n2 )  \ copy for re-initialization
 464         48 +                    ( n n2 -- n n2' ) \ kernel_state to ASCII num
 465 
 466         s" set kernel=${kernel_prefix}${kernel[N]}${kernel_suffix}"
 467         36 +c!          ( n n2 c-addr/u -- n c-addr/u ) \ 'N' to ASCII num
 468         evaluate        ( n c-addr/u -- n ) \ sets $kernel to full kernel-path
 469 ;
 470 
 471 : cycle_kernel ( N -- N TRUE )
 472         cycle_menuitem  \ cycle cycle_stateN to next value
 473         activate_kernel \ apply current cycle_stateN
 474         menu-redraw     \ redraw menu
 475         TRUE            \ loop menu again
 476 ;
 477 
 478 \
 479 \ Root
 480 \
 481 
 482 : init_root ( N -- N )
 483         root_state @    ( n -- n k )
 484         init_cyclestate ( n k -- n )
 485 ;
 486 
 487 : activate_root ( N -- N )
 488         dup cycle_stateN @      ( n -- n n2 )
 489         dup root_state !        ( n n2 -- n n2 )  \ copy for re-initialization
 490         48 +                    ( n n2 -- n n2' ) \ root_state to ASCII num
 491 
 492         s" set root=${root_prefix}${root[N]}${root_suffix}"
 493         30 +c!          ( n n2 c-addr/u -- n c-addr/u ) \ 'N' to ASCII num
 494         evaluate        ( n c-addr/u -- n ) \ sets $root to full kernel-path
 495 ;
 496 
 497 : cycle_root ( N -- N TRUE )
 498         cycle_menuitem  \ cycle cycle_stateN to next value
 499         activate_root   \ apply current cycle_stateN
 500         menu-redraw     \ redraw menu
 501         TRUE            \ loop menu again
 502 ;
 503 
 504 \
 505 \ Menusets
 506 \
 507 
 508 : goto_menu ( N M -- N TRUE )
 509         menu-unset
 510         menuset-loadsetnum ( n m -- n )
 511         menu-redraw
 512         TRUE \ Loop menu again
 513 ;
 514 
 515 \
 516 \ Defaults
 517 \
 518 
 519 : unset_boot_options
 520         0 acpi_state !
 521         s" acpi-user-options" unsetenv
 522         s" boot-args" unsetenv
 523         s" boot_ask" unsetenv
 524         singleuser_disable
 525         verbose_disable
 526         kmdb_disable            \ disables debug as well
 527         reconfigure_disable
 528 ;
 529 
 530 : set_default_boot_options ( N -- N TRUE )
 531         unset_boot_options
 532         2 goto_menu
 533 ;
 534 
 535 \
 536 \ Set boot environment defaults
 537 \
 538 
 539 
 540 : init_bootenv ( -- )
 541         s" set menu_caption[1]=${bemenu_current}${zfs_be_active}" evaluate
 542         s" set ansi_caption[1]=${beansi_current}${zfs_be_active}" evaluate
 543         s" set menu_caption[2]=${bemenu_bootfs}${currdev}" evaluate
 544         s" set ansi_caption[2]=${beansi_bootfs}${currdev}" evaluate
 545         s" set menu_caption[3]=${bemenu_page}${zfs_be_currpage}${bemenu_pageof}${zfs_be_pages}" evaluate
 546         s" set ansi_caption[3]=${beansi_page}${zfs_be_currpage}${bemenu_pageof}${zfs_be_pages}" evaluate
 547 ;
 548 
 549 \
 550 \ Redraw the entire screen. A long BE name can corrupt the menu
 551 \
 552 
 553 : be_draw_screen
 554         clear           \ Clear the screen (in screen.4th)
 555         print_version   \ print version string (bottom-right; see version.4th)
 556         draw-beastie    \ Draw FreeBSD logo at right (in beastie.4th)
 557         draw-brand      \ Draw brand.4th logo at top (in brand.4th)
 558         menu-init       \ Initialize menu and draw bounding box (in menu.4th)
 559 ;
 560 
 561 \
 562 \ Select a boot environment
 563 \
 564 
 565 : set_bootenv ( N -- N TRUE )
 566         dup s" bootenv_root[E]" 13 +c! getenv
 567         s" currdev" getenv compare 0= if
 568                 s" zfs_be_active" getenv type ."  is already active"
 569         else
 570                 dup s" set currdev=${bootenv_root[E]}" 27 +c! evaluate
 571                 dup s" bootenvmenu_caption[E]" 20 +c! getenv
 572                 s" zfs_be_active" setenv
 573                 ." Activating " s" currdev" getenv type cr
 574                 s" unload" evaluate
 575                 free-module-options
 576                 unset_boot_options
 577                 s" /boot/defaults/loader.conf" read-conf
 578                 s" /boot/loader.conf" read-conf
 579                 s" /boot/loader.conf.local" read-conf
 580                 init_bootenv
 581 
 582                 s" 1" s" zfs_be_currpage" setenv
 583                 s" be-set-page" evaluate
 584         then
 585 
 586         500 ms                  \ sleep so user can see the message
 587         be_draw_screen
 588         menu-redraw
 589         TRUE
 590 ;
 591 
 592 \
 593 \ Chainload this entry. Normally we do not return, in case of error
 594 \ from chain load, we continue with normal menu code.
 595 \
 596 
 597 : set_be_chain ( N -- no return | N TRUE )
 598         dup s" chain ${bootenv_root[E]}" 21 +c! evaluate catch drop
 599 
 600         menu-redraw
 601         TRUE
 602 ;
 603 
 604 \
 605 \ Switch to the next page of boot environments
 606 \
 607 
 608 : set_be_page ( N -- N TRUE )
 609         s" zfs_be_currpage" getenv dup -1 = if
 610                 drop s" 1"
 611         else
 612                 s2n
 613                 1+              \ increment the page number
 614                 dup
 615                 s" zfs_be_pages" getenv
 616                 s2n
 617                 > if drop 1 then
 618                 n2s
 619         then
 620 
 621         s" zfs_be_currpage" setenv
 622         s" be-set-page" evaluate
 623         3 goto_menu
 624 ;
 625 
 626 only forth definitions