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