1088b4f5fSWarner Losh-- 272e39d71SKyle Evans-- SPDX-License-Identifier: BSD-2-Clause-FreeBSD 372e39d71SKyle Evans-- 4088b4f5fSWarner Losh-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org> 5beaafe4fSKyle Evans-- Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org> 6088b4f5fSWarner Losh-- All rights reserved. 7088b4f5fSWarner Losh-- 8088b4f5fSWarner Losh-- Redistribution and use in source and binary forms, with or without 9088b4f5fSWarner Losh-- modification, are permitted provided that the following conditions 10088b4f5fSWarner Losh-- are met: 11088b4f5fSWarner Losh-- 1. Redistributions of source code must retain the above copyright 12088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer. 13088b4f5fSWarner Losh-- 2. Redistributions in binary form must reproduce the above copyright 14088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer in the 15088b4f5fSWarner Losh-- documentation and/or other materials provided with the distribution. 16088b4f5fSWarner Losh-- 17088b4f5fSWarner Losh-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18088b4f5fSWarner Losh-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19088b4f5fSWarner Losh-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20088b4f5fSWarner Losh-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21088b4f5fSWarner Losh-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22088b4f5fSWarner Losh-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23088b4f5fSWarner Losh-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24088b4f5fSWarner Losh-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25088b4f5fSWarner Losh-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26088b4f5fSWarner Losh-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27088b4f5fSWarner Losh-- SUCH DAMAGE. 28088b4f5fSWarner Losh-- 29088b4f5fSWarner Losh-- $FreeBSD$ 30088b4f5fSWarner Losh-- 31088b4f5fSWarner Losh 32011eae6cSKyle Evanslocal config = require("config") 33fa4a2394SKyle Evans 34aedd6be5SKyle Evanslocal core = {} 35088b4f5fSWarner Losh 366d4ed94dSKyle Evanslocal compose_loader_cmd = function(cmd_name, argstr) 379f71d421SKyle Evans if argstr ~= nil then 38aedd6be5SKyle Evans cmd_name = cmd_name .. " " .. argstr 396d4ed94dSKyle Evans end 40aedd6be5SKyle Evans return cmd_name 416d4ed94dSKyle Evansend 426d4ed94dSKyle Evans 43b5746545SKyle Evans-- Module exports 44fe672a15SKyle Evans-- Commonly appearing constants 45aedd6be5SKyle Evanscore.KEY_BACKSPACE = 8 46aedd6be5SKyle Evanscore.KEY_ENTER = 13 47aedd6be5SKyle Evanscore.KEY_DELETE = 127 48fe672a15SKyle Evans 49aedd6be5SKyle Evanscore.KEYSTR_ESCAPE = "\027" 5039006570SKyle Evans 51aedd6be5SKyle Evanscore.MENU_RETURN = "return" 52aedd6be5SKyle Evanscore.MENU_ENTRY = "entry" 53aedd6be5SKyle Evanscore.MENU_SEPARATOR = "separator" 54aedd6be5SKyle Evanscore.MENU_SUBMENU = "submenu" 55aedd6be5SKyle Evanscore.MENU_CAROUSEL_ENTRY = "carousel_entry" 56a7cf0562SKyle Evans 57088b4f5fSWarner Loshfunction core.setVerbose(b) 589f71d421SKyle Evans if b == nil then 59aedd6be5SKyle Evans b = not core.verbose 60088b4f5fSWarner Losh end 61088b4f5fSWarner Losh 6249550489SKyle Evans if b then 63aedd6be5SKyle Evans loader.setenv("boot_verbose", "YES") 64088b4f5fSWarner Losh else 65aedd6be5SKyle Evans loader.unsetenv("boot_verbose") 66088b4f5fSWarner Losh end 67aedd6be5SKyle Evans core.verbose = b 68088b4f5fSWarner Loshend 69088b4f5fSWarner Losh 70088b4f5fSWarner Loshfunction core.setSingleUser(b) 719f71d421SKyle Evans if b == nil then 72aedd6be5SKyle Evans b = not core.su 73088b4f5fSWarner Losh end 74088b4f5fSWarner Losh 7549550489SKyle Evans if b then 76aedd6be5SKyle Evans loader.setenv("boot_single", "YES") 77088b4f5fSWarner Losh else 78aedd6be5SKyle Evans loader.unsetenv("boot_single") 79088b4f5fSWarner Losh end 80aedd6be5SKyle Evans core.su = b 81088b4f5fSWarner Loshend 82088b4f5fSWarner Losh 836401094fSKyle Evansfunction core.getACPIPresent(checkingSystemDefaults) 84aedd6be5SKyle Evans local c = loader.getenv("hint.acpi.0.rsdp") 856401094fSKyle Evans 869f71d421SKyle Evans if c ~= nil then 8749550489SKyle Evans if checkingSystemDefaults then 88aedd6be5SKyle Evans return true 896401094fSKyle Evans end 906401094fSKyle Evans -- Otherwise, respect disabled if it's set 91aedd6be5SKyle Evans c = loader.getenv("hint.acpi.0.disabled") 929f71d421SKyle Evans return c == nil or tonumber(c) ~= 1 936401094fSKyle Evans end 94aedd6be5SKyle Evans return false 956401094fSKyle Evansend 966401094fSKyle Evans 97088b4f5fSWarner Loshfunction core.setACPI(b) 989f71d421SKyle Evans if b == nil then 99aedd6be5SKyle Evans b = not core.acpi 100088b4f5fSWarner Losh end 101088b4f5fSWarner Losh 10249550489SKyle Evans if b then 103aedd6be5SKyle Evans loader.setenv("acpi_load", "YES") 104aedd6be5SKyle Evans loader.setenv("hint.acpi.0.disabled", "0") 105aedd6be5SKyle Evans loader.unsetenv("loader.acpi_disabled_by_user") 106088b4f5fSWarner Losh else 107aedd6be5SKyle Evans loader.unsetenv("acpi_load") 108aedd6be5SKyle Evans loader.setenv("hint.acpi.0.disabled", "1") 109aedd6be5SKyle Evans loader.setenv("loader.acpi_disabled_by_user", "1") 110088b4f5fSWarner Losh end 111aedd6be5SKyle Evans core.acpi = b 112088b4f5fSWarner Loshend 113088b4f5fSWarner Losh 114088b4f5fSWarner Loshfunction core.setSafeMode(b) 1159f71d421SKyle Evans if b == nil then 116aedd6be5SKyle Evans b = not core.sm 117088b4f5fSWarner Losh end 11849550489SKyle Evans if b then 119aedd6be5SKyle Evans loader.setenv("kern.smp.disabled", "1") 120aedd6be5SKyle Evans loader.setenv("hw.ata.ata_dma", "0") 121aedd6be5SKyle Evans loader.setenv("hw.ata.atapi_dma", "0") 122aedd6be5SKyle Evans loader.setenv("hw.ata.wc", "0") 123aedd6be5SKyle Evans loader.setenv("hw.eisa_slots", "0") 124aedd6be5SKyle Evans loader.setenv("kern.eventtimer.periodic", "1") 125aedd6be5SKyle Evans loader.setenv("kern.geom.part.check_integrity", "0") 126088b4f5fSWarner Losh else 127aedd6be5SKyle Evans loader.unsetenv("kern.smp.disabled") 128aedd6be5SKyle Evans loader.unsetenv("hw.ata.ata_dma") 129aedd6be5SKyle Evans loader.unsetenv("hw.ata.atapi_dma") 130aedd6be5SKyle Evans loader.unsetenv("hw.ata.wc") 131aedd6be5SKyle Evans loader.unsetenv("hw.eisa_slots") 132aedd6be5SKyle Evans loader.unsetenv("kern.eventtimer.periodic") 133aedd6be5SKyle Evans loader.unsetenv("kern.geom.part.check_integrity") 134088b4f5fSWarner Losh end 135aedd6be5SKyle Evans core.sm = b 136088b4f5fSWarner Loshend 137088b4f5fSWarner Losh 138088b4f5fSWarner Loshfunction core.kernelList() 139aedd6be5SKyle Evans local k = loader.getenv("kernel") 1403f4eb56bSKyle Evans local v = loader.getenv("kernels") 1413889e6cdSKyle Evans local autodetect = loader.getenv("kernels_autodetect") or "" 142088b4f5fSWarner Losh 143aedd6be5SKyle Evans local kernels = {} 144aedd6be5SKyle Evans local unique = {} 145aedd6be5SKyle Evans local i = 0 1469f71d421SKyle Evans if k ~= nil then 147aedd6be5SKyle Evans i = i + 1 148aedd6be5SKyle Evans kernels[i] = k 149aedd6be5SKyle Evans unique[k] = true 150088b4f5fSWarner Losh end 151088b4f5fSWarner Losh 1523f4eb56bSKyle Evans if v ~= nil then 153088b4f5fSWarner Losh for n in v:gmatch("([^; ]+)[; ]?") do 1549f71d421SKyle Evans if unique[n] == nil then 155aedd6be5SKyle Evans i = i + 1 156aedd6be5SKyle Evans kernels[i] = n 157aedd6be5SKyle Evans unique[n] = true 158088b4f5fSWarner Losh end 159088b4f5fSWarner Losh end 1603889e6cdSKyle Evans end 161a108046fSConrad Meyer 1623889e6cdSKyle Evans -- Base whether we autodetect kernels or not on a loader.conf(5) 1633889e6cdSKyle Evans -- setting, kernels_autodetect. If it's set to 'yes', we'll add 1643889e6cdSKyle Evans -- any kernels we detect based on the criteria described. 1653889e6cdSKyle Evans if autodetect:lower() ~= "yes" then 1663f4eb56bSKyle Evans return kernels 1673f4eb56bSKyle Evans end 1683f4eb56bSKyle Evans 169a108046fSConrad Meyer -- Automatically detect other bootable kernel directories using a 170a108046fSConrad Meyer -- heuristic. Any directory in /boot that contains an ordinary file 171a108046fSConrad Meyer -- named "kernel" is considered eligible. 172a108046fSConrad Meyer for file in lfs.dir("/boot") do 173aedd6be5SKyle Evans local fname = "/boot/" .. file 174a108046fSConrad Meyer 1759f71d421SKyle Evans if file == "." or file == ".." then 176aedd6be5SKyle Evans goto continue 177a108046fSConrad Meyer end 178a108046fSConrad Meyer 1799f71d421SKyle Evans if lfs.attributes(fname, "mode") ~= "directory" then 180aedd6be5SKyle Evans goto continue 181a108046fSConrad Meyer end 182a108046fSConrad Meyer 1839f71d421SKyle Evans if lfs.attributes(fname .. "/kernel", "mode") ~= "file" then 184aedd6be5SKyle Evans goto continue 185a108046fSConrad Meyer end 186a108046fSConrad Meyer 1879f71d421SKyle Evans if unique[file] == nil then 188aedd6be5SKyle Evans i = i + 1 189aedd6be5SKyle Evans kernels[i] = file 190aedd6be5SKyle Evans unique[file] = true 191a108046fSConrad Meyer end 192a108046fSConrad Meyer 193a108046fSConrad Meyer ::continue:: 194a108046fSConrad Meyer end 195aedd6be5SKyle Evans return kernels 196088b4f5fSWarner Loshend 197088b4f5fSWarner Losh 1987efc058fSKyle Evansfunction core.bootenvDefault() 1997efc058fSKyle Evans return loader.getenv("zfs_be_active") 2007efc058fSKyle Evansend 2017efc058fSKyle Evans 2027efc058fSKyle Evansfunction core.bootenvList() 2037efc058fSKyle Evans local bootenv_count = tonumber(loader.getenv("bootenvs_count")) 2047efc058fSKyle Evans local bootenvs = {} 2057efc058fSKyle Evans local curenv 2067efc058fSKyle Evans local envcount = 0 2077efc058fSKyle Evans local unique = {} 2087efc058fSKyle Evans 2097efc058fSKyle Evans if bootenv_count == nil or bootenv_count <= 0 then 2107efc058fSKyle Evans return bootenvs 2117efc058fSKyle Evans end 2127efc058fSKyle Evans 2137efc058fSKyle Evans -- Currently selected bootenv is always first/default 2147efc058fSKyle Evans curenv = core.bootenvDefault() 2157efc058fSKyle Evans if curenv ~= nil then 2167efc058fSKyle Evans envcount = envcount + 1 2177efc058fSKyle Evans bootenvs[envcount] = curenv 2187efc058fSKyle Evans unique[curenv] = true 2197efc058fSKyle Evans end 2207efc058fSKyle Evans 2217efc058fSKyle Evans for curenv_idx = 0, bootenv_count - 1 do 2227efc058fSKyle Evans curenv = loader.getenv("bootenvs[" .. curenv_idx .. "]") 2237efc058fSKyle Evans if curenv ~= nil and unique[curenv] == nil then 2247efc058fSKyle Evans envcount = envcount + 1 2257efc058fSKyle Evans bootenvs[envcount] = curenv 2267efc058fSKyle Evans unique[curenv] = true 2277efc058fSKyle Evans end 2287efc058fSKyle Evans end 2297efc058fSKyle Evans return bootenvs 2307efc058fSKyle Evansend 2317efc058fSKyle Evans 232088b4f5fSWarner Loshfunction core.setDefaults() 233aedd6be5SKyle Evans core.setACPI(core.getACPIPresent(true)) 234aedd6be5SKyle Evans core.setSafeMode(false) 235aedd6be5SKyle Evans core.setSingleUser(false) 236aedd6be5SKyle Evans core.setVerbose(false) 237088b4f5fSWarner Loshend 238088b4f5fSWarner Losh 2396d4ed94dSKyle Evansfunction core.autoboot(argstr) 240aedd6be5SKyle Evans config.loadelf() 241aedd6be5SKyle Evans loader.perform(compose_loader_cmd("autoboot", argstr)) 242088b4f5fSWarner Loshend 243088b4f5fSWarner Losh 2446d4ed94dSKyle Evansfunction core.boot(argstr) 245aedd6be5SKyle Evans config.loadelf() 246aedd6be5SKyle Evans loader.perform(compose_loader_cmd("boot", argstr)) 247088b4f5fSWarner Loshend 248088b4f5fSWarner Losh 249e07fc39cSKyle Evansfunction core.isSingleUserBoot() 250aedd6be5SKyle Evans local single_user = loader.getenv("boot_single") 251aedd6be5SKyle Evans return single_user ~= nil and single_user:lower() == "yes" 252e07fc39cSKyle Evansend 253e07fc39cSKyle Evans 2547efc058fSKyle Evansfunction core.isZFSBoot() 2557efc058fSKyle Evans local c = loader.getenv("currdev") 2567efc058fSKyle Evans 2577efc058fSKyle Evans if c ~= nil then 2587efc058fSKyle Evans return c:match("^zfs:") ~= nil 2597efc058fSKyle Evans end 2607efc058fSKyle Evans return false 2617efc058fSKyle Evansend 2627efc058fSKyle Evans 263b140d14bSKyle Evansfunction core.isSerialBoot() 264aedd6be5SKyle Evans local c = loader.getenv("console") 265088b4f5fSWarner Losh 2669f71d421SKyle Evans if c ~= nil then 2679f71d421SKyle Evans if c:find("comconsole") ~= nil then 268aedd6be5SKyle Evans return true 269088b4f5fSWarner Losh end 270088b4f5fSWarner Losh end 271088b4f5fSWarner Losh 272aedd6be5SKyle Evans local s = loader.getenv("boot_serial") 2739f71d421SKyle Evans if s ~= nil then 274aedd6be5SKyle Evans return true 275088b4f5fSWarner Losh end 276088b4f5fSWarner Losh 277aedd6be5SKyle Evans local m = loader.getenv("boot_multicons") 2789f71d421SKyle Evans if m ~= nil then 279aedd6be5SKyle Evans return true 280088b4f5fSWarner Losh end 281aedd6be5SKyle Evans return false 282088b4f5fSWarner Loshend 283088b4f5fSWarner Losh 284c1ab36f5SKyle Evansfunction core.isSystem386() 2859f71d421SKyle Evans return loader.machine_arch == "i386" 286c1ab36f5SKyle Evansend 287c1ab36f5SKyle Evans 2885c1b5165SKyle Evans-- This may be a better candidate for a 'utility' module. 289*ee4e69f1SKyle Evansfunction core.deepCopyTable(tbl) 290aedd6be5SKyle Evans local new_tbl = {} 2915c1b5165SKyle Evans for k, v in pairs(tbl) do 2929f71d421SKyle Evans if type(v) == "table" then 293*ee4e69f1SKyle Evans new_tbl[k] = core.deepCopyTable(v) 2945c1b5165SKyle Evans else 295aedd6be5SKyle Evans new_tbl[k] = v 2965c1b5165SKyle Evans end 2975c1b5165SKyle Evans end 298aedd6be5SKyle Evans return new_tbl 2995c1b5165SKyle Evansend 3005c1b5165SKyle Evans 3016d4ed94dSKyle Evans-- XXX This should go away if we get the table lib into shape for importing. 3026d4ed94dSKyle Evans-- As of now, it requires some 'os' functions, so we'll implement this in lua 3036d4ed94dSKyle Evans-- for our uses 3046d4ed94dSKyle Evansfunction core.popFrontTable(tbl) 3056d4ed94dSKyle Evans -- Shouldn't reasonably happen 3069f71d421SKyle Evans if #tbl == 0 then 307aedd6be5SKyle Evans return nil, nil 3089f71d421SKyle Evans elseif #tbl == 1 then 309aedd6be5SKyle Evans return tbl[1], {} 3106d4ed94dSKyle Evans end 3116d4ed94dSKyle Evans 312aedd6be5SKyle Evans local first_value = tbl[1] 313aedd6be5SKyle Evans local new_tbl = {} 3146d4ed94dSKyle Evans -- This is not a cheap operation 3156d4ed94dSKyle Evans for k, v in ipairs(tbl) do 3169f71d421SKyle Evans if k > 1 then 317aedd6be5SKyle Evans new_tbl[k - 1] = v 3186d4ed94dSKyle Evans end 3196d4ed94dSKyle Evans end 3206d4ed94dSKyle Evans 321aedd6be5SKyle Evans return first_value, new_tbl 3226d4ed94dSKyle Evansend 3236d4ed94dSKyle Evans 3246f412147SKyle Evans-- On i386, hint.acpi.0.rsdp will be set before we're loaded. On !i386, it will 3256f412147SKyle Evans-- generally be set upon execution of the kernel. Because of this, we can't (or 3266f412147SKyle Evans-- don't really want to) detect/disable ACPI on !i386 reliably. Just set it 3276f412147SKyle Evans-- enabled if we detect it and leave well enough alone if we don't. 3289f71d421SKyle Evansif core.isSystem386() and core.getACPIPresent(false) then 329aedd6be5SKyle Evans core.setACPI(true) 3306f412147SKyle Evansend 331aedd6be5SKyle Evansreturn core 332