1088b4f5fSWarner Losh-- 24d846d26SWarner Losh-- SPDX-License-Identifier: BSD-2-Clause 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 30011eae6cSKyle Evanslocal config = require("config") 31aea262bfSKyle Evanslocal hook = require("hook") 32fa4a2394SKyle Evans 33aedd6be5SKyle Evanslocal core = {} 34088b4f5fSWarner Losh 35e0f3dc82SR. Christian McDonaldlocal default_acpi = false 361613f091SKyle Evanslocal default_safe_mode = false 371613f091SKyle Evanslocal default_single_user = false 381613f091SKyle Evanslocal default_verbose = false 391613f091SKyle Evans 40277f38abSMariusz Zaborskilocal bootenv_list = "bootenvs" 41277f38abSMariusz Zaborski 42322a2dddSKyle Evanslocal function composeLoaderCmd(cmd_name, argstr) 439f71d421SKyle Evans if argstr ~= nil then 44aedd6be5SKyle Evans cmd_name = cmd_name .. " " .. argstr 456d4ed94dSKyle Evans end 46aedd6be5SKyle Evans return cmd_name 476d4ed94dSKyle Evansend 486d4ed94dSKyle Evans 491613f091SKyle Evanslocal function recordDefaults() 501613f091SKyle Evans local boot_single = loader.getenv("boot_single") or "no" 511613f091SKyle Evans local boot_verbose = loader.getenv("boot_verbose") or "no" 52e0f3dc82SR. Christian McDonald 53e0f3dc82SR. Christian McDonald default_acpi = core.getACPI() 541613f091SKyle Evans default_single_user = boot_single:lower() ~= "no" 551613f091SKyle Evans default_verbose = boot_verbose:lower() ~= "no" 561613f091SKyle Evans 57e0f3dc82SR. Christian McDonald core.setACPI(default_acpi) 581613f091SKyle Evans core.setSingleUser(default_single_user) 591613f091SKyle Evans core.setVerbose(default_verbose) 601613f091SKyle Evansend 611613f091SKyle Evans 621613f091SKyle Evans 6307faaf78SKyle Evans-- Globals 645beb5507SKyle Evans-- try_include will return the loaded module on success, or false and the error 655beb5507SKyle Evans-- message on failure. 6607faaf78SKyle Evansfunction try_include(module) 67bac5966eSKyle Evans if module:sub(1, 1) ~= "/" then 68522a65a8SWarner Losh local lua_path = loader.lua_path 69522a65a8SWarner Losh -- XXX Temporary compat shim; this should be removed once the 70522a65a8SWarner Losh -- loader.lua_path export has sufficiently spread. 71522a65a8SWarner Losh if lua_path == nil then 72522a65a8SWarner Losh lua_path = "/boot/lua" 73522a65a8SWarner Losh end 74522a65a8SWarner Losh module = lua_path .. "/" .. module 75bac5966eSKyle Evans -- We only attempt to append an extension if an absolute path 76bac5966eSKyle Evans -- wasn't specified. This assumes that the caller either wants 77bac5966eSKyle Evans -- to treat this like it would require() and specify just the 78bac5966eSKyle Evans -- base filename, or they know what they're doing as they've 79bac5966eSKyle Evans -- specified an absolute path and we shouldn't impede. 80bac5966eSKyle Evans if module:match(".lua$") == nil then 81bac5966eSKyle Evans module = module .. ".lua" 82bac5966eSKyle Evans end 83bac5966eSKyle Evans end 84bac5966eSKyle Evans if lfs.attributes(module, "mode") ~= "file" then 85bac5966eSKyle Evans return 86bac5966eSKyle Evans end 87bac5966eSKyle Evans 88bac5966eSKyle Evans return dofile(module) 8907faaf78SKyle Evansend 9007faaf78SKyle Evans 91b5746545SKyle Evans-- Module exports 92fe672a15SKyle Evans-- Commonly appearing constants 93aedd6be5SKyle Evanscore.KEY_BACKSPACE = 8 94aedd6be5SKyle Evanscore.KEY_ENTER = 13 95aedd6be5SKyle Evanscore.KEY_DELETE = 127 96fe672a15SKyle Evans 97230061c5SKyle Evans-- Note that this is a decimal representation, despite the leading 0 that in 98230061c5SKyle Evans-- other contexts (outside of Lua) may mean 'octal' 99aedd6be5SKyle Evanscore.KEYSTR_ESCAPE = "\027" 1002bb86aefSKyle Evanscore.KEYSTR_CSI = core.KEYSTR_ESCAPE .. "[" 10173531a2aSRyan Moellercore.KEYSTR_RESET = core.KEYSTR_ESCAPE .. "c" 10239006570SKyle Evans 103aedd6be5SKyle Evanscore.MENU_RETURN = "return" 104aedd6be5SKyle Evanscore.MENU_ENTRY = "entry" 105aedd6be5SKyle Evanscore.MENU_SEPARATOR = "separator" 106aedd6be5SKyle Evanscore.MENU_SUBMENU = "submenu" 107aedd6be5SKyle Evanscore.MENU_CAROUSEL_ENTRY = "carousel_entry" 108a7cf0562SKyle Evans 10904af4229SKyle Evansfunction core.setVerbose(verbose) 11004af4229SKyle Evans if verbose == nil then 11104af4229SKyle Evans verbose = not core.verbose 112088b4f5fSWarner Losh end 113088b4f5fSWarner Losh 11404af4229SKyle Evans if verbose then 115aedd6be5SKyle Evans loader.setenv("boot_verbose", "YES") 116088b4f5fSWarner Losh else 117aedd6be5SKyle Evans loader.unsetenv("boot_verbose") 118088b4f5fSWarner Losh end 11904af4229SKyle Evans core.verbose = verbose 120088b4f5fSWarner Loshend 121088b4f5fSWarner Losh 12204af4229SKyle Evansfunction core.setSingleUser(single_user) 12304af4229SKyle Evans if single_user == nil then 12404af4229SKyle Evans single_user = not core.su 125088b4f5fSWarner Losh end 126088b4f5fSWarner Losh 12704af4229SKyle Evans if single_user then 128aedd6be5SKyle Evans loader.setenv("boot_single", "YES") 129088b4f5fSWarner Losh else 130aedd6be5SKyle Evans loader.unsetenv("boot_single") 131088b4f5fSWarner Losh end 13204af4229SKyle Evans core.su = single_user 133088b4f5fSWarner Loshend 134088b4f5fSWarner Losh 135e0f3dc82SR. Christian McDonaldfunction core.hasACPI() 136e183039fSKyle Evans -- We can't trust acpi.rsdp to be set if the loader binary doesn't do 137e183039fSKyle Evans -- ACPI detection early enough. UEFI loader historically didn't, so 138e183039fSKyle Evans -- we'll fallback to assuming ACPI is enabled if this binary does not 139e183039fSKyle Evans -- declare that it probes for ACPI early enough 140e183039fSKyle Evans if loader.getenv("acpi.rsdp") ~= nil then 141e183039fSKyle Evans return true 142e0f3dc82SR. Christian McDonald end 1436401094fSKyle Evans 144e183039fSKyle Evans return not core.hasFeature("EARLY_ACPI") 1450abe05aeSWarner Loshend 1460abe05aeSWarner Losh 147e0f3dc82SR. Christian McDonaldfunction core.getACPI() 148e0f3dc82SR. Christian McDonald if not core.hasACPI() then 149e183039fSKyle Evans return false 1506401094fSKyle Evans end 1516401094fSKyle Evans 152e0f3dc82SR. Christian McDonald -- Otherwise, respect disabled if it's set 153e0f3dc82SR. Christian McDonald local c = loader.getenv("hint.acpi.0.disabled") 154e0f3dc82SR. Christian McDonald return c == nil or tonumber(c) ~= 1 155e0f3dc82SR. Christian McDonaldend 156e0f3dc82SR. Christian McDonald 15704af4229SKyle Evansfunction core.setACPI(acpi) 15804af4229SKyle Evans if acpi == nil then 15904af4229SKyle Evans acpi = not core.acpi 160088b4f5fSWarner Losh end 161088b4f5fSWarner Losh 16204af4229SKyle Evans if acpi then 163e183039fSKyle Evans config.enableModule("acpi") 164aedd6be5SKyle Evans loader.setenv("hint.acpi.0.disabled", "0") 165088b4f5fSWarner Losh else 166e183039fSKyle Evans config.disableModule("acpi") 167aedd6be5SKyle Evans loader.setenv("hint.acpi.0.disabled", "1") 168088b4f5fSWarner Losh end 16904af4229SKyle Evans core.acpi = acpi 170088b4f5fSWarner Loshend 171088b4f5fSWarner Losh 17204af4229SKyle Evansfunction core.setSafeMode(safe_mode) 17304af4229SKyle Evans if safe_mode == nil then 17404af4229SKyle Evans safe_mode = not core.sm 175088b4f5fSWarner Losh end 17604af4229SKyle Evans if safe_mode then 177aedd6be5SKyle Evans loader.setenv("kern.smp.disabled", "1") 178aedd6be5SKyle Evans loader.setenv("hw.ata.ata_dma", "0") 179aedd6be5SKyle Evans loader.setenv("hw.ata.atapi_dma", "0") 180aedd6be5SKyle Evans loader.setenv("kern.eventtimer.periodic", "1") 181aedd6be5SKyle Evans loader.setenv("kern.geom.part.check_integrity", "0") 182088b4f5fSWarner Losh else 183aedd6be5SKyle Evans loader.unsetenv("kern.smp.disabled") 184aedd6be5SKyle Evans loader.unsetenv("hw.ata.ata_dma") 185aedd6be5SKyle Evans loader.unsetenv("hw.ata.atapi_dma") 186aedd6be5SKyle Evans loader.unsetenv("kern.eventtimer.periodic") 187aedd6be5SKyle Evans loader.unsetenv("kern.geom.part.check_integrity") 188088b4f5fSWarner Losh end 18904af4229SKyle Evans core.sm = safe_mode 190088b4f5fSWarner Loshend 191088b4f5fSWarner Losh 192aea262bfSKyle Evansfunction core.clearCachedKernels() 19335b0c718SKyle Evans -- Clear the kernel cache on config changes, autodetect might have 19435b0c718SKyle Evans -- changed or if we've switched boot environments then we could have 19535b0c718SKyle Evans -- a new kernel set. 19635b0c718SKyle Evans core.cached_kernels = nil 19735b0c718SKyle Evansend 19835b0c718SKyle Evans 199088b4f5fSWarner Loshfunction core.kernelList() 20035b0c718SKyle Evans if core.cached_kernels ~= nil then 20135b0c718SKyle Evans return core.cached_kernels 20235b0c718SKyle Evans end 20335b0c718SKyle Evans 204d04415c5SKyle Evans local default_kernel = loader.getenv("kernel") 2053f4eb56bSKyle Evans local v = loader.getenv("kernels") 2063889e6cdSKyle Evans local autodetect = loader.getenv("kernels_autodetect") or "" 207088b4f5fSWarner Losh 208aedd6be5SKyle Evans local kernels = {} 209aedd6be5SKyle Evans local unique = {} 210aedd6be5SKyle Evans local i = 0 211d04415c5SKyle Evans 212d04415c5SKyle Evans if default_kernel then 213aedd6be5SKyle Evans i = i + 1 214d04415c5SKyle Evans kernels[i] = default_kernel 215d04415c5SKyle Evans unique[default_kernel] = true 216088b4f5fSWarner Losh end 217088b4f5fSWarner Losh 2183f4eb56bSKyle Evans if v ~= nil then 219a5003419SKyle Evans for n in v:gmatch("([^;, ]+)[;, ]?") do 2209f71d421SKyle Evans if unique[n] == nil then 221aedd6be5SKyle Evans i = i + 1 222aedd6be5SKyle Evans kernels[i] = n 223aedd6be5SKyle Evans unique[n] = true 224088b4f5fSWarner Losh end 225088b4f5fSWarner Losh end 2263889e6cdSKyle Evans end 227a108046fSConrad Meyer 228c4dc9072SEmmanuel Vadot -- Do not attempt to autodetect if underlying filesystem 229c4dc9072SEmmanuel Vadot -- do not support directory listing (e.g. tftp, http) 230c4dc9072SEmmanuel Vadot if not lfs.attributes("/boot", "mode") then 231c4dc9072SEmmanuel Vadot autodetect = "no" 232c4dc9072SEmmanuel Vadot loader.setenv("kernels_autodetect", "NO") 233c4dc9072SEmmanuel Vadot end 234c4dc9072SEmmanuel Vadot 2353889e6cdSKyle Evans -- Base whether we autodetect kernels or not on a loader.conf(5) 2363889e6cdSKyle Evans -- setting, kernels_autodetect. If it's set to 'yes', we'll add 2373889e6cdSKyle Evans -- any kernels we detect based on the criteria described. 2383889e6cdSKyle Evans if autodetect:lower() ~= "yes" then 23935b0c718SKyle Evans core.cached_kernels = kernels 24035b0c718SKyle Evans return core.cached_kernels 2413f4eb56bSKyle Evans end 2423f4eb56bSKyle Evans 243d04415c5SKyle Evans local present = {} 244d04415c5SKyle Evans 245a108046fSConrad Meyer -- Automatically detect other bootable kernel directories using a 246a108046fSConrad Meyer -- heuristic. Any directory in /boot that contains an ordinary file 247a108046fSConrad Meyer -- named "kernel" is considered eligible. 248e25ee296SKyle Evans for file, ftype in lfs.dir("/boot") do 249aedd6be5SKyle Evans local fname = "/boot/" .. file 250a108046fSConrad Meyer 2519f71d421SKyle Evans if file == "." or file == ".." then 252aedd6be5SKyle Evans goto continue 253a108046fSConrad Meyer end 254a108046fSConrad Meyer 255e25ee296SKyle Evans if ftype then 256e25ee296SKyle Evans if ftype ~= lfs.DT_DIR then 257e25ee296SKyle Evans goto continue 258e25ee296SKyle Evans end 259e25ee296SKyle Evans elseif lfs.attributes(fname, "mode") ~= "directory" then 260aedd6be5SKyle Evans goto continue 261a108046fSConrad Meyer end 262a108046fSConrad Meyer 2639f71d421SKyle Evans if lfs.attributes(fname .. "/kernel", "mode") ~= "file" then 264aedd6be5SKyle Evans goto continue 265a108046fSConrad Meyer end 266a108046fSConrad Meyer 2679f71d421SKyle Evans if unique[file] == nil then 268aedd6be5SKyle Evans i = i + 1 269aedd6be5SKyle Evans kernels[i] = file 270aedd6be5SKyle Evans unique[file] = true 271a108046fSConrad Meyer end 272a108046fSConrad Meyer 273d04415c5SKyle Evans present[file] = true 274d04415c5SKyle Evans 275a108046fSConrad Meyer ::continue:: 276a108046fSConrad Meyer end 277d04415c5SKyle Evans 278d04415c5SKyle Evans -- If we found more than one kernel, prune the "kernel" specified kernel 279d04415c5SKyle Evans -- off of the list if it wasn't found during traversal. If we didn't 280d04415c5SKyle Evans -- actually find any kernels, we just assume that they know what they're 281d04415c5SKyle Evans -- doing and leave it alone. 282d04415c5SKyle Evans if default_kernel and not present[default_kernel] and #kernels > 1 then 283d04415c5SKyle Evans for i = 1, #kernels do 284d04415c5SKyle Evans if i == #kernels then 285d04415c5SKyle Evans kernels[i] = nil 286d04415c5SKyle Evans else 287d04415c5SKyle Evans kernels[i] = kernels[i + 1] 288d04415c5SKyle Evans end 289d04415c5SKyle Evans end 290d04415c5SKyle Evans end 291d04415c5SKyle Evans 29235b0c718SKyle Evans core.cached_kernels = kernels 29335b0c718SKyle Evans return core.cached_kernels 294088b4f5fSWarner Loshend 295088b4f5fSWarner Losh 2967efc058fSKyle Evansfunction core.bootenvDefault() 2977efc058fSKyle Evans return loader.getenv("zfs_be_active") 2987efc058fSKyle Evansend 2997efc058fSKyle Evans 3007efc058fSKyle Evansfunction core.bootenvList() 301277f38abSMariusz Zaborski local bootenv_count = tonumber(loader.getenv(bootenv_list .. "_count")) 3027efc058fSKyle Evans local bootenvs = {} 3037efc058fSKyle Evans local curenv 3047efc058fSKyle Evans local envcount = 0 3057efc058fSKyle Evans local unique = {} 3067efc058fSKyle Evans 3077efc058fSKyle Evans if bootenv_count == nil or bootenv_count <= 0 then 3087efc058fSKyle Evans return bootenvs 3097efc058fSKyle Evans end 3107efc058fSKyle Evans 3117efc058fSKyle Evans -- Currently selected bootenv is always first/default 312277f38abSMariusz Zaborski -- On the rewinded list the bootenv may not exists 313277f38abSMariusz Zaborski if core.isRewinded() then 314277f38abSMariusz Zaborski curenv = core.bootenvDefaultRewinded() 315277f38abSMariusz Zaborski else 3167efc058fSKyle Evans curenv = core.bootenvDefault() 317277f38abSMariusz Zaborski end 3187efc058fSKyle Evans if curenv ~= nil then 3197efc058fSKyle Evans envcount = envcount + 1 3207efc058fSKyle Evans bootenvs[envcount] = curenv 3217efc058fSKyle Evans unique[curenv] = true 3227efc058fSKyle Evans end 3237efc058fSKyle Evans 3247efc058fSKyle Evans for curenv_idx = 0, bootenv_count - 1 do 325277f38abSMariusz Zaborski curenv = loader.getenv(bootenv_list .. "[" .. curenv_idx .. "]") 3267efc058fSKyle Evans if curenv ~= nil and unique[curenv] == nil then 3277efc058fSKyle Evans envcount = envcount + 1 3287efc058fSKyle Evans bootenvs[envcount] = curenv 3297efc058fSKyle Evans unique[curenv] = true 3307efc058fSKyle Evans end 3317efc058fSKyle Evans end 3327efc058fSKyle Evans return bootenvs 3337efc058fSKyle Evansend 3347efc058fSKyle Evans 335277f38abSMariusz Zaborskifunction core.isCheckpointed() 336277f38abSMariusz Zaborski return loader.getenv("zpool_checkpoint") ~= nil 337277f38abSMariusz Zaborskiend 338277f38abSMariusz Zaborski 339277f38abSMariusz Zaborskifunction core.bootenvDefaultRewinded() 340277f38abSMariusz Zaborski local defname = "zfs:!" .. string.sub(core.bootenvDefault(), 5) 341277f38abSMariusz Zaborski local bootenv_count = tonumber("bootenvs_check_count") 342277f38abSMariusz Zaborski 343277f38abSMariusz Zaborski if bootenv_count == nil or bootenv_count <= 0 then 344277f38abSMariusz Zaborski return defname 345277f38abSMariusz Zaborski end 346277f38abSMariusz Zaborski 347277f38abSMariusz Zaborski for curenv_idx = 0, bootenv_count - 1 do 34894510c29SKyle Evans local curenv = loader.getenv("bootenvs_check[" .. curenv_idx .. "]") 349277f38abSMariusz Zaborski if curenv == defname then 350277f38abSMariusz Zaborski return defname 351277f38abSMariusz Zaborski end 352277f38abSMariusz Zaborski end 353277f38abSMariusz Zaborski 354277f38abSMariusz Zaborski return loader.getenv("bootenvs_check[0]") 355277f38abSMariusz Zaborskiend 356277f38abSMariusz Zaborski 357277f38abSMariusz Zaborskifunction core.isRewinded() 358277f38abSMariusz Zaborski return bootenv_list == "bootenvs_check" 359277f38abSMariusz Zaborskiend 360277f38abSMariusz Zaborski 361277f38abSMariusz Zaborskifunction core.changeRewindCheckpoint() 362277f38abSMariusz Zaborski if core.isRewinded() then 363277f38abSMariusz Zaborski bootenv_list = "bootenvs" 364277f38abSMariusz Zaborski else 365277f38abSMariusz Zaborski bootenv_list = "bootenvs_check" 366277f38abSMariusz Zaborski end 367277f38abSMariusz Zaborskiend 368277f38abSMariusz Zaborski 3695c73b3e0SColin Percivalfunction core.loadEntropy() 3705c73b3e0SColin Percival if core.isUEFIBoot() then 3715c73b3e0SColin Percival if (loader.getenv("entropy_efi_seed") or "no"):lower() == "yes" then 372f4a69a93SColin Percival local seedsize = loader.getenv("entropy_efi_seed_size") or "2048" 373f4a69a93SColin Percival loader.perform("efi-seed-entropy " .. seedsize) 3745c73b3e0SColin Percival end 3755c73b3e0SColin Percival end 3765c73b3e0SColin Percivalend 3775c73b3e0SColin Percival 378088b4f5fSWarner Loshfunction core.setDefaults() 379e0f3dc82SR. Christian McDonald core.setACPI(default_acpi) 3801613f091SKyle Evans core.setSafeMode(default_safe_mode) 3811613f091SKyle Evans core.setSingleUser(default_single_user) 3821613f091SKyle Evans core.setVerbose(default_verbose) 383088b4f5fSWarner Loshend 384088b4f5fSWarner Losh 3856d4ed94dSKyle Evansfunction core.autoboot(argstr) 386a2a7830eSKyle Evans -- loadelf() only if we've not already loaded a kernel 387a2a7830eSKyle Evans if loader.getenv("kernelname") == nil then 388aedd6be5SKyle Evans config.loadelf() 389a2a7830eSKyle Evans end 3905c73b3e0SColin Percival core.loadEntropy() 391322a2dddSKyle Evans loader.perform(composeLoaderCmd("autoboot", argstr)) 392088b4f5fSWarner Loshend 393088b4f5fSWarner Losh 3946d4ed94dSKyle Evansfunction core.boot(argstr) 395a2a7830eSKyle Evans -- loadelf() only if we've not already loaded a kernel 396a2a7830eSKyle Evans if loader.getenv("kernelname") == nil then 397aedd6be5SKyle Evans config.loadelf() 398a2a7830eSKyle Evans end 3995c73b3e0SColin Percival core.loadEntropy() 400322a2dddSKyle Evans loader.perform(composeLoaderCmd("boot", argstr)) 401088b4f5fSWarner Loshend 402088b4f5fSWarner Losh 4031631382cSKyle Evansfunction core.hasFeature(name) 4041631382cSKyle Evans if not loader.has_feature then 4051631382cSKyle Evans -- Loader too old, no feature support 4061631382cSKyle Evans return nil, "No feature support in loaded loader" 4071631382cSKyle Evans end 4081631382cSKyle Evans 4091631382cSKyle Evans return loader.has_feature(name) 4101631382cSKyle Evansend 4111631382cSKyle Evans 412e07fc39cSKyle Evansfunction core.isSingleUserBoot() 413aedd6be5SKyle Evans local single_user = loader.getenv("boot_single") 414aedd6be5SKyle Evans return single_user ~= nil and single_user:lower() == "yes" 415e07fc39cSKyle Evansend 416e07fc39cSKyle Evans 4175f8cfbe1SKyle Evansfunction core.isUEFIBoot() 4185f8cfbe1SKyle Evans local efiver = loader.getenv("efi-version") 4195f8cfbe1SKyle Evans 4205f8cfbe1SKyle Evans return efiver ~= nil 4215f8cfbe1SKyle Evansend 4225f8cfbe1SKyle Evans 4237efc058fSKyle Evansfunction core.isZFSBoot() 4247efc058fSKyle Evans local c = loader.getenv("currdev") 4257efc058fSKyle Evans 4267efc058fSKyle Evans if c ~= nil then 4277efc058fSKyle Evans return c:match("^zfs:") ~= nil 4287efc058fSKyle Evans end 4297efc058fSKyle Evans return false 4307efc058fSKyle Evansend 4317efc058fSKyle Evans 4323630506bSToomas Soomefunction core.isFramebufferConsole() 4333630506bSToomas Soome local c = loader.getenv("console") 4343630506bSToomas Soome if c ~= nil then 4353630506bSToomas Soome if c:find("efi") == nil and c:find("vidconsole") == nil then 4363630506bSToomas Soome return false 4373630506bSToomas Soome end 4383630506bSToomas Soome if loader.getenv("screen.depth") ~= nil then 4393630506bSToomas Soome return true 4403630506bSToomas Soome end 4413630506bSToomas Soome end 4423630506bSToomas Soome return false 4433630506bSToomas Soomeend 4443630506bSToomas Soome 44590a25417SKyle Evansfunction core.isSerialConsole() 44690a25417SKyle Evans local c = loader.getenv("console") 44790a25417SKyle Evans if c ~= nil then 4485d8c062fSToomas Soome -- serial console is comconsole, but also userboot. 4495d8c062fSToomas Soome -- userboot is there, because we have no way to know 4505d8c062fSToomas Soome -- if the user terminal can draw unicode box chars or not. 4515d8c062fSToomas Soome if c:find("comconsole") ~= nil or c:find("userboot") ~= nil then 45290a25417SKyle Evans return true 45390a25417SKyle Evans end 45490a25417SKyle Evans end 45590a25417SKyle Evans return false 45690a25417SKyle Evansend 45790a25417SKyle Evans 458b140d14bSKyle Evansfunction core.isSerialBoot() 459aedd6be5SKyle Evans local s = loader.getenv("boot_serial") 4609f71d421SKyle Evans if s ~= nil then 461aedd6be5SKyle Evans return true 462088b4f5fSWarner Losh end 463088b4f5fSWarner Losh 464aedd6be5SKyle Evans local m = loader.getenv("boot_multicons") 4659f71d421SKyle Evans if m ~= nil then 466aedd6be5SKyle Evans return true 467088b4f5fSWarner Losh end 468aedd6be5SKyle Evans return false 469088b4f5fSWarner Loshend 470088b4f5fSWarner Losh 4719937e979SKyle Evans-- Is the menu skipped in the environment in which we've booted? 4729937e979SKyle Evansfunction core.isMenuSkipped() 473b83a355dSKyle Evans return string.lower(loader.getenv("beastie_disable") or "") == "yes" 4749937e979SKyle Evansend 4759937e979SKyle Evans 4765c1b5165SKyle Evans-- This may be a better candidate for a 'utility' module. 477ee4e69f1SKyle Evansfunction core.deepCopyTable(tbl) 478aedd6be5SKyle Evans local new_tbl = {} 4795c1b5165SKyle Evans for k, v in pairs(tbl) do 4809f71d421SKyle Evans if type(v) == "table" then 481ee4e69f1SKyle Evans new_tbl[k] = core.deepCopyTable(v) 4825c1b5165SKyle Evans else 483aedd6be5SKyle Evans new_tbl[k] = v 4845c1b5165SKyle Evans end 4855c1b5165SKyle Evans end 486aedd6be5SKyle Evans return new_tbl 4875c1b5165SKyle Evansend 4885c1b5165SKyle Evans 4896d4ed94dSKyle Evans-- XXX This should go away if we get the table lib into shape for importing. 4906d4ed94dSKyle Evans-- As of now, it requires some 'os' functions, so we'll implement this in lua 4916d4ed94dSKyle Evans-- for our uses 4926d4ed94dSKyle Evansfunction core.popFrontTable(tbl) 4936d4ed94dSKyle Evans -- Shouldn't reasonably happen 4949f71d421SKyle Evans if #tbl == 0 then 495aedd6be5SKyle Evans return nil, nil 4969f71d421SKyle Evans elseif #tbl == 1 then 497aedd6be5SKyle Evans return tbl[1], {} 4986d4ed94dSKyle Evans end 4996d4ed94dSKyle Evans 500aedd6be5SKyle Evans local first_value = tbl[1] 501aedd6be5SKyle Evans local new_tbl = {} 5026d4ed94dSKyle Evans -- This is not a cheap operation 5036d4ed94dSKyle Evans for k, v in ipairs(tbl) do 5049f71d421SKyle Evans if k > 1 then 505aedd6be5SKyle Evans new_tbl[k - 1] = v 5066d4ed94dSKyle Evans end 5076d4ed94dSKyle Evans end 5086d4ed94dSKyle Evans 509aedd6be5SKyle Evans return first_value, new_tbl 5106d4ed94dSKyle Evansend 5116d4ed94dSKyle Evans 5128f3b3610SWarner Loshfunction core.getConsoleName() 5138f3b3610SWarner Losh if loader.getenv("boot_multicons") ~= nil then 5148f3b3610SWarner Losh if loader.getenv("boot_serial") ~= nil then 5158f3b3610SWarner Losh return "Dual (Serial primary)" 5168f3b3610SWarner Losh else 5178f3b3610SWarner Losh return "Dual (Video primary)" 5188f3b3610SWarner Losh end 5198f3b3610SWarner Losh else 5208f3b3610SWarner Losh if loader.getenv("boot_serial") ~= nil then 5218f3b3610SWarner Losh return "Serial" 5228f3b3610SWarner Losh else 5238f3b3610SWarner Losh return "Video" 5248f3b3610SWarner Losh end 5258f3b3610SWarner Losh end 5268f3b3610SWarner Loshend 5278f3b3610SWarner Losh 5288f3b3610SWarner Loshfunction core.nextConsoleChoice() 5298f3b3610SWarner Losh if loader.getenv("boot_multicons") ~= nil then 5308f3b3610SWarner Losh if loader.getenv("boot_serial") ~= nil then 5318f3b3610SWarner Losh loader.unsetenv("boot_serial") 5328f3b3610SWarner Losh else 5338f3b3610SWarner Losh loader.unsetenv("boot_multicons") 5348f3b3610SWarner Losh loader.setenv("boot_serial", "YES") 5358f3b3610SWarner Losh end 5368f3b3610SWarner Losh else 5378f3b3610SWarner Losh if loader.getenv("boot_serial") ~= nil then 5388f3b3610SWarner Losh loader.unsetenv("boot_serial") 5398f3b3610SWarner Losh else 5408f3b3610SWarner Losh loader.setenv("boot_multicons", "YES") 5418f3b3610SWarner Losh loader.setenv("boot_serial", "YES") 5428f3b3610SWarner Losh end 5438f3b3610SWarner Losh end 5448f3b3610SWarner Loshend 5458f3b3610SWarner Losh 546*c2ba66d4SWarner Losh-- The graphical-enabled loaders have unicode drawing character support. The 547*c2ba66d4SWarner Losh-- text-only ones do not. We check the old and new bindings for term_drawrect as 548*c2ba66d4SWarner Losh-- a proxy for unicode support, which will work on older boot loaders as well 549*c2ba66d4SWarner Losh-- as be future proof for when we remove the old binding. This also abstracts 550*c2ba66d4SWarner Losh-- out the test to one spot in case we start to export this notion more directly. 551*c2ba66d4SWarner Loshfunction core.hasUnicode() 552*c2ba66d4SWarner Losh return gfx.term_drawrect ~= nil or loader.term_drawrect ~= nil 553*c2ba66d4SWarner Loshend 554*c2ba66d4SWarner Losh 555a2fd7ae8SWarner Losh-- Sanity check the boot loader revision 556a2fd7ae8SWarner Losh-- Loaders with version 3.0 have everything that we need without backwards 557a2fd7ae8SWarner Losh-- compatible hacks. Warn users that still have old versions to upgrade so 558a2fd7ae8SWarner Losh-- that we can remove the backwards compatible hacks in the future since 559a2fd7ae8SWarner Losh-- they have been there a long time. 560a2fd7ae8SWarner Loshlocal loader_major = 3 561a2fd7ae8SWarner Losh 562a2fd7ae8SWarner Loshfunction core.loaderTooOld() 563a2fd7ae8SWarner Losh return loader.version == nil or loader.version < loader_major * 1000 564a2fd7ae8SWarner Loshend 565a2fd7ae8SWarner Losh 566a2fd7ae8SWarner Loshif core.loaderTooOld() then 567a2fd7ae8SWarner Losh print("**********************************************************************") 568a2fd7ae8SWarner Losh print("**********************************************************************") 569a2fd7ae8SWarner Losh print("***** *****") 570a2fd7ae8SWarner Losh print("***** BOOT LOADER IS TOO OLD. PLEASE UPGRADE. *****") 571a2fd7ae8SWarner Losh print("***** *****") 572a2fd7ae8SWarner Losh print("**********************************************************************") 573a2fd7ae8SWarner Losh print("**********************************************************************") 574a2fd7ae8SWarner Loshend 575a2fd7ae8SWarner Losh 5761613f091SKyle EvansrecordDefaults() 577aea262bfSKyle Evanshook.register("config.reloaded", core.clearCachedKernels) 578aedd6be5SKyle Evansreturn core 579