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