1088b4f5fSWarner Losh-- 2*72e39d71SKyle Evans-- SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*72e39d71SKyle Evans-- 4088b4f5fSWarner Losh-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org> 5088b4f5fSWarner Losh-- All rights reserved. 6088b4f5fSWarner Losh-- 7088b4f5fSWarner Losh-- Redistribution and use in source and binary forms, with or without 8088b4f5fSWarner Losh-- modification, are permitted provided that the following conditions 9088b4f5fSWarner Losh-- are met: 10088b4f5fSWarner Losh-- 1. Redistributions of source code must retain the above copyright 11088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer. 12088b4f5fSWarner Losh-- 2. Redistributions in binary form must reproduce the above copyright 13088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer in the 14088b4f5fSWarner Losh-- documentation and/or other materials provided with the distribution. 15088b4f5fSWarner Losh-- 16088b4f5fSWarner Losh-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17088b4f5fSWarner Losh-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18088b4f5fSWarner Losh-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19088b4f5fSWarner Losh-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20088b4f5fSWarner Losh-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21088b4f5fSWarner Losh-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22088b4f5fSWarner Losh-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23088b4f5fSWarner Losh-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24088b4f5fSWarner Losh-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25088b4f5fSWarner Losh-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26088b4f5fSWarner Losh-- SUCH DAMAGE. 27088b4f5fSWarner Losh-- 28088b4f5fSWarner Losh-- $FreeBSD$ 29088b4f5fSWarner Losh-- 30088b4f5fSWarner Losh 31011eae6cSKyle Evanslocal config = require("config") 32fa4a2394SKyle Evans 33aedd6be5SKyle Evanslocal core = {} 34088b4f5fSWarner Losh 356d4ed94dSKyle Evanslocal compose_loader_cmd = function(cmd_name, argstr) 369f71d421SKyle Evans if argstr ~= nil then 37aedd6be5SKyle Evans cmd_name = cmd_name .. " " .. argstr 386d4ed94dSKyle Evans end 39aedd6be5SKyle Evans return cmd_name 406d4ed94dSKyle Evansend 416d4ed94dSKyle Evans 42b5746545SKyle Evans-- Module exports 43fe672a15SKyle Evans-- Commonly appearing constants 44aedd6be5SKyle Evanscore.KEY_BACKSPACE = 8 45aedd6be5SKyle Evanscore.KEY_ENTER = 13 46aedd6be5SKyle Evanscore.KEY_DELETE = 127 47fe672a15SKyle Evans 48aedd6be5SKyle Evanscore.KEYSTR_ESCAPE = "\027" 4939006570SKyle Evans 50aedd6be5SKyle Evanscore.MENU_RETURN = "return" 51aedd6be5SKyle Evanscore.MENU_ENTRY = "entry" 52aedd6be5SKyle Evanscore.MENU_SEPARATOR = "separator" 53aedd6be5SKyle Evanscore.MENU_SUBMENU = "submenu" 54aedd6be5SKyle Evanscore.MENU_CAROUSEL_ENTRY = "carousel_entry" 55a7cf0562SKyle Evans 56088b4f5fSWarner Loshfunction core.setVerbose(b) 579f71d421SKyle Evans if b == nil then 58aedd6be5SKyle Evans b = not core.verbose 59088b4f5fSWarner Losh end 60088b4f5fSWarner Losh 6149550489SKyle Evans if b then 62aedd6be5SKyle Evans loader.setenv("boot_verbose", "YES") 63088b4f5fSWarner Losh else 64aedd6be5SKyle Evans loader.unsetenv("boot_verbose") 65088b4f5fSWarner Losh end 66aedd6be5SKyle Evans core.verbose = b 67088b4f5fSWarner Loshend 68088b4f5fSWarner Losh 69088b4f5fSWarner Loshfunction core.setSingleUser(b) 709f71d421SKyle Evans if b == nil then 71aedd6be5SKyle Evans b = not core.su 72088b4f5fSWarner Losh end 73088b4f5fSWarner Losh 7449550489SKyle Evans if b then 75aedd6be5SKyle Evans loader.setenv("boot_single", "YES") 76088b4f5fSWarner Losh else 77aedd6be5SKyle Evans loader.unsetenv("boot_single") 78088b4f5fSWarner Losh end 79aedd6be5SKyle Evans core.su = b 80088b4f5fSWarner Loshend 81088b4f5fSWarner Losh 826401094fSKyle Evansfunction core.getACPIPresent(checkingSystemDefaults) 83aedd6be5SKyle Evans local c = loader.getenv("hint.acpi.0.rsdp") 846401094fSKyle Evans 859f71d421SKyle Evans if c ~= nil then 8649550489SKyle Evans if checkingSystemDefaults then 87aedd6be5SKyle Evans return true 886401094fSKyle Evans end 896401094fSKyle Evans -- Otherwise, respect disabled if it's set 90aedd6be5SKyle Evans c = loader.getenv("hint.acpi.0.disabled") 919f71d421SKyle Evans return c == nil or tonumber(c) ~= 1 926401094fSKyle Evans end 93aedd6be5SKyle Evans return false 946401094fSKyle Evansend 956401094fSKyle Evans 96088b4f5fSWarner Loshfunction core.setACPI(b) 979f71d421SKyle Evans if b == nil then 98aedd6be5SKyle Evans b = not core.acpi 99088b4f5fSWarner Losh end 100088b4f5fSWarner Losh 10149550489SKyle Evans if b then 102aedd6be5SKyle Evans loader.setenv("acpi_load", "YES") 103aedd6be5SKyle Evans loader.setenv("hint.acpi.0.disabled", "0") 104aedd6be5SKyle Evans loader.unsetenv("loader.acpi_disabled_by_user") 105088b4f5fSWarner Losh else 106aedd6be5SKyle Evans loader.unsetenv("acpi_load") 107aedd6be5SKyle Evans loader.setenv("hint.acpi.0.disabled", "1") 108aedd6be5SKyle Evans loader.setenv("loader.acpi_disabled_by_user", "1") 109088b4f5fSWarner Losh end 110aedd6be5SKyle Evans core.acpi = b 111088b4f5fSWarner Loshend 112088b4f5fSWarner Losh 113088b4f5fSWarner Loshfunction core.setSafeMode(b) 1149f71d421SKyle Evans if b == nil then 115aedd6be5SKyle Evans b = not core.sm 116088b4f5fSWarner Losh end 11749550489SKyle Evans if b then 118aedd6be5SKyle Evans loader.setenv("kern.smp.disabled", "1") 119aedd6be5SKyle Evans loader.setenv("hw.ata.ata_dma", "0") 120aedd6be5SKyle Evans loader.setenv("hw.ata.atapi_dma", "0") 121aedd6be5SKyle Evans loader.setenv("hw.ata.wc", "0") 122aedd6be5SKyle Evans loader.setenv("hw.eisa_slots", "0") 123aedd6be5SKyle Evans loader.setenv("kern.eventtimer.periodic", "1") 124aedd6be5SKyle Evans loader.setenv("kern.geom.part.check_integrity", "0") 125088b4f5fSWarner Losh else 126aedd6be5SKyle Evans loader.unsetenv("kern.smp.disabled") 127aedd6be5SKyle Evans loader.unsetenv("hw.ata.ata_dma") 128aedd6be5SKyle Evans loader.unsetenv("hw.ata.atapi_dma") 129aedd6be5SKyle Evans loader.unsetenv("hw.ata.wc") 130aedd6be5SKyle Evans loader.unsetenv("hw.eisa_slots") 131aedd6be5SKyle Evans loader.unsetenv("kern.eventtimer.periodic") 132aedd6be5SKyle Evans loader.unsetenv("kern.geom.part.check_integrity") 133088b4f5fSWarner Losh end 134aedd6be5SKyle Evans core.sm = b 135088b4f5fSWarner Loshend 136088b4f5fSWarner Losh 137088b4f5fSWarner Loshfunction core.kernelList() 138aedd6be5SKyle Evans local k = loader.getenv("kernel") 1393f4eb56bSKyle Evans local v = loader.getenv("kernels") 1403889e6cdSKyle Evans local autodetect = loader.getenv("kernels_autodetect") or "" 141088b4f5fSWarner Losh 142aedd6be5SKyle Evans local kernels = {} 143aedd6be5SKyle Evans local unique = {} 144aedd6be5SKyle Evans local i = 0 1459f71d421SKyle Evans if k ~= nil then 146aedd6be5SKyle Evans i = i + 1 147aedd6be5SKyle Evans kernels[i] = k 148aedd6be5SKyle Evans unique[k] = true 149088b4f5fSWarner Losh end 150088b4f5fSWarner Losh 1513f4eb56bSKyle Evans if v ~= nil then 152088b4f5fSWarner Losh for n in v:gmatch("([^; ]+)[; ]?") do 1539f71d421SKyle Evans if unique[n] == nil then 154aedd6be5SKyle Evans i = i + 1 155aedd6be5SKyle Evans kernels[i] = n 156aedd6be5SKyle Evans unique[n] = true 157088b4f5fSWarner Losh end 158088b4f5fSWarner Losh end 1593889e6cdSKyle Evans end 160a108046fSConrad Meyer 1613889e6cdSKyle Evans -- Base whether we autodetect kernels or not on a loader.conf(5) 1623889e6cdSKyle Evans -- setting, kernels_autodetect. If it's set to 'yes', we'll add 1633889e6cdSKyle Evans -- any kernels we detect based on the criteria described. 1643889e6cdSKyle Evans if autodetect:lower() ~= "yes" then 1653f4eb56bSKyle Evans return kernels 1663f4eb56bSKyle Evans end 1673f4eb56bSKyle Evans 168a108046fSConrad Meyer -- Automatically detect other bootable kernel directories using a 169a108046fSConrad Meyer -- heuristic. Any directory in /boot that contains an ordinary file 170a108046fSConrad Meyer -- named "kernel" is considered eligible. 171a108046fSConrad Meyer for file in lfs.dir("/boot") do 172aedd6be5SKyle Evans local fname = "/boot/" .. file 173a108046fSConrad Meyer 1749f71d421SKyle Evans if file == "." or file == ".." then 175aedd6be5SKyle Evans goto continue 176a108046fSConrad Meyer end 177a108046fSConrad Meyer 1789f71d421SKyle Evans if lfs.attributes(fname, "mode") ~= "directory" then 179aedd6be5SKyle Evans goto continue 180a108046fSConrad Meyer end 181a108046fSConrad Meyer 1829f71d421SKyle Evans if lfs.attributes(fname .. "/kernel", "mode") ~= "file" then 183aedd6be5SKyle Evans goto continue 184a108046fSConrad Meyer end 185a108046fSConrad Meyer 1869f71d421SKyle Evans if unique[file] == nil then 187aedd6be5SKyle Evans i = i + 1 188aedd6be5SKyle Evans kernels[i] = file 189aedd6be5SKyle Evans unique[file] = true 190a108046fSConrad Meyer end 191a108046fSConrad Meyer 192a108046fSConrad Meyer ::continue:: 193a108046fSConrad Meyer end 194aedd6be5SKyle Evans return kernels 195088b4f5fSWarner Loshend 196088b4f5fSWarner Losh 1977efc058fSKyle Evansfunction core.bootenvDefault() 1987efc058fSKyle Evans return loader.getenv("zfs_be_active") 1997efc058fSKyle Evansend 2007efc058fSKyle Evans 2017efc058fSKyle Evansfunction core.bootenvList() 2027efc058fSKyle Evans local bootenv_count = tonumber(loader.getenv("bootenvs_count")) 2037efc058fSKyle Evans local bootenvs = {} 2047efc058fSKyle Evans local curenv 2057efc058fSKyle Evans local envcount = 0 2067efc058fSKyle Evans local unique = {} 2077efc058fSKyle Evans 2087efc058fSKyle Evans if bootenv_count == nil or bootenv_count <= 0 then 2097efc058fSKyle Evans return bootenvs 2107efc058fSKyle Evans end 2117efc058fSKyle Evans 2127efc058fSKyle Evans -- Currently selected bootenv is always first/default 2137efc058fSKyle Evans curenv = core.bootenvDefault() 2147efc058fSKyle Evans if curenv ~= nil then 2157efc058fSKyle Evans envcount = envcount + 1 2167efc058fSKyle Evans bootenvs[envcount] = curenv 2177efc058fSKyle Evans unique[curenv] = true 2187efc058fSKyle Evans end 2197efc058fSKyle Evans 2207efc058fSKyle Evans for curenv_idx = 0, bootenv_count - 1 do 2217efc058fSKyle Evans curenv = loader.getenv("bootenvs[" .. curenv_idx .. "]") 2227efc058fSKyle Evans if curenv ~= nil and unique[curenv] == nil then 2237efc058fSKyle Evans envcount = envcount + 1 2247efc058fSKyle Evans bootenvs[envcount] = curenv 2257efc058fSKyle Evans unique[curenv] = true 2267efc058fSKyle Evans end 2277efc058fSKyle Evans end 2287efc058fSKyle Evans return bootenvs 2297efc058fSKyle Evansend 2307efc058fSKyle Evans 231088b4f5fSWarner Loshfunction core.setDefaults() 232aedd6be5SKyle Evans core.setACPI(core.getACPIPresent(true)) 233aedd6be5SKyle Evans core.setSafeMode(false) 234aedd6be5SKyle Evans core.setSingleUser(false) 235aedd6be5SKyle Evans core.setVerbose(false) 236088b4f5fSWarner Loshend 237088b4f5fSWarner Losh 2386d4ed94dSKyle Evansfunction core.autoboot(argstr) 239aedd6be5SKyle Evans config.loadelf() 240aedd6be5SKyle Evans loader.perform(compose_loader_cmd("autoboot", argstr)) 241088b4f5fSWarner Loshend 242088b4f5fSWarner Losh 2436d4ed94dSKyle Evansfunction core.boot(argstr) 244aedd6be5SKyle Evans config.loadelf() 245aedd6be5SKyle Evans loader.perform(compose_loader_cmd("boot", argstr)) 246088b4f5fSWarner Loshend 247088b4f5fSWarner Losh 248e07fc39cSKyle Evansfunction core.isSingleUserBoot() 249aedd6be5SKyle Evans local single_user = loader.getenv("boot_single") 250aedd6be5SKyle Evans return single_user ~= nil and single_user:lower() == "yes" 251e07fc39cSKyle Evansend 252e07fc39cSKyle Evans 2537efc058fSKyle Evansfunction core.isZFSBoot() 2547efc058fSKyle Evans local c = loader.getenv("currdev") 2557efc058fSKyle Evans 2567efc058fSKyle Evans if c ~= nil then 2577efc058fSKyle Evans return c:match("^zfs:") ~= nil 2587efc058fSKyle Evans end 2597efc058fSKyle Evans return false 2607efc058fSKyle Evansend 2617efc058fSKyle Evans 262b140d14bSKyle Evansfunction core.isSerialBoot() 263aedd6be5SKyle Evans local c = loader.getenv("console") 264088b4f5fSWarner Losh 2659f71d421SKyle Evans if c ~= nil then 2669f71d421SKyle Evans if c:find("comconsole") ~= nil then 267aedd6be5SKyle Evans return true 268088b4f5fSWarner Losh end 269088b4f5fSWarner Losh end 270088b4f5fSWarner Losh 271aedd6be5SKyle Evans local s = loader.getenv("boot_serial") 2729f71d421SKyle Evans if s ~= nil then 273aedd6be5SKyle Evans return true 274088b4f5fSWarner Losh end 275088b4f5fSWarner Losh 276aedd6be5SKyle Evans local m = loader.getenv("boot_multicons") 2779f71d421SKyle Evans if m ~= nil then 278aedd6be5SKyle Evans return true 279088b4f5fSWarner Losh end 280aedd6be5SKyle Evans return false 281088b4f5fSWarner Loshend 282088b4f5fSWarner Losh 283c1ab36f5SKyle Evansfunction core.isSystem386() 2849f71d421SKyle Evans return loader.machine_arch == "i386" 285c1ab36f5SKyle Evansend 286c1ab36f5SKyle Evans 2875c1b5165SKyle Evans-- This may be a better candidate for a 'utility' module. 2885c1b5165SKyle Evansfunction core.shallowCopyTable(tbl) 289aedd6be5SKyle Evans local new_tbl = {} 2905c1b5165SKyle Evans for k, v in pairs(tbl) do 2919f71d421SKyle Evans if type(v) == "table" then 292aedd6be5SKyle Evans new_tbl[k] = core.shallowCopyTable(v) 2935c1b5165SKyle Evans else 294aedd6be5SKyle Evans new_tbl[k] = v 2955c1b5165SKyle Evans end 2965c1b5165SKyle Evans end 297aedd6be5SKyle Evans return new_tbl 2985c1b5165SKyle Evansend 2995c1b5165SKyle Evans 3006d4ed94dSKyle Evans-- XXX This should go away if we get the table lib into shape for importing. 3016d4ed94dSKyle Evans-- As of now, it requires some 'os' functions, so we'll implement this in lua 3026d4ed94dSKyle Evans-- for our uses 3036d4ed94dSKyle Evansfunction core.popFrontTable(tbl) 3046d4ed94dSKyle Evans -- Shouldn't reasonably happen 3059f71d421SKyle Evans if #tbl == 0 then 306aedd6be5SKyle Evans return nil, nil 3079f71d421SKyle Evans elseif #tbl == 1 then 308aedd6be5SKyle Evans return tbl[1], {} 3096d4ed94dSKyle Evans end 3106d4ed94dSKyle Evans 311aedd6be5SKyle Evans local first_value = tbl[1] 312aedd6be5SKyle Evans local new_tbl = {} 3136d4ed94dSKyle Evans -- This is not a cheap operation 3146d4ed94dSKyle Evans for k, v in ipairs(tbl) do 3159f71d421SKyle Evans if k > 1 then 316aedd6be5SKyle Evans new_tbl[k - 1] = v 3176d4ed94dSKyle Evans end 3186d4ed94dSKyle Evans end 3196d4ed94dSKyle Evans 320aedd6be5SKyle Evans return first_value, new_tbl 3216d4ed94dSKyle Evansend 3226d4ed94dSKyle Evans 3236f412147SKyle Evans-- On i386, hint.acpi.0.rsdp will be set before we're loaded. On !i386, it will 3246f412147SKyle Evans-- generally be set upon execution of the kernel. Because of this, we can't (or 3256f412147SKyle Evans-- don't really want to) detect/disable ACPI on !i386 reliably. Just set it 3266f412147SKyle Evans-- enabled if we detect it and leave well enough alone if we don't. 3279f71d421SKyle Evansif core.isSystem386() and core.getACPIPresent(false) then 328aedd6be5SKyle Evans core.setACPI(true) 3296f412147SKyle Evansend 330aedd6be5SKyle Evansreturn core 331