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 3725c73b3e0SColin Percival loader.perform("efi-seed-entropy") 3735c73b3e0SColin Percival end 3745c73b3e0SColin Percival end 3755c73b3e0SColin Percivalend 3765c73b3e0SColin Percival 377088b4f5fSWarner Loshfunction core.setDefaults() 378e0f3dc82SR. Christian McDonald core.setACPI(default_acpi) 3791613f091SKyle Evans core.setSafeMode(default_safe_mode) 3801613f091SKyle Evans core.setSingleUser(default_single_user) 3811613f091SKyle Evans core.setVerbose(default_verbose) 382088b4f5fSWarner Loshend 383088b4f5fSWarner Losh 3846d4ed94dSKyle Evansfunction core.autoboot(argstr) 385a2a7830eSKyle Evans -- loadelf() only if we've not already loaded a kernel 386a2a7830eSKyle Evans if loader.getenv("kernelname") == nil then 387aedd6be5SKyle Evans config.loadelf() 388a2a7830eSKyle Evans end 3895c73b3e0SColin Percival core.loadEntropy() 390322a2dddSKyle Evans loader.perform(composeLoaderCmd("autoboot", argstr)) 391088b4f5fSWarner Loshend 392088b4f5fSWarner Losh 3936d4ed94dSKyle Evansfunction core.boot(argstr) 394a2a7830eSKyle Evans -- loadelf() only if we've not already loaded a kernel 395a2a7830eSKyle Evans if loader.getenv("kernelname") == nil then 396aedd6be5SKyle Evans config.loadelf() 397a2a7830eSKyle Evans end 3985c73b3e0SColin Percival core.loadEntropy() 399322a2dddSKyle Evans loader.perform(composeLoaderCmd("boot", argstr)) 400088b4f5fSWarner Loshend 401088b4f5fSWarner Losh 4021631382cSKyle Evansfunction core.hasFeature(name) 4031631382cSKyle Evans if not loader.has_feature then 4041631382cSKyle Evans -- Loader too old, no feature support 4051631382cSKyle Evans return nil, "No feature support in loaded loader" 4061631382cSKyle Evans end 4071631382cSKyle Evans 4081631382cSKyle Evans return loader.has_feature(name) 4091631382cSKyle Evansend 4101631382cSKyle Evans 411e07fc39cSKyle Evansfunction core.isSingleUserBoot() 412aedd6be5SKyle Evans local single_user = loader.getenv("boot_single") 413aedd6be5SKyle Evans return single_user ~= nil and single_user:lower() == "yes" 414e07fc39cSKyle Evansend 415e07fc39cSKyle Evans 4165f8cfbe1SKyle Evansfunction core.isUEFIBoot() 4175f8cfbe1SKyle Evans local efiver = loader.getenv("efi-version") 4185f8cfbe1SKyle Evans 4195f8cfbe1SKyle Evans return efiver ~= nil 4205f8cfbe1SKyle Evansend 4215f8cfbe1SKyle Evans 4227efc058fSKyle Evansfunction core.isZFSBoot() 4237efc058fSKyle Evans local c = loader.getenv("currdev") 4247efc058fSKyle Evans 4257efc058fSKyle Evans if c ~= nil then 4267efc058fSKyle Evans return c:match("^zfs:") ~= nil 4277efc058fSKyle Evans end 4287efc058fSKyle Evans return false 4297efc058fSKyle Evansend 4307efc058fSKyle Evans 4313630506bSToomas Soomefunction core.isFramebufferConsole() 4323630506bSToomas Soome local c = loader.getenv("console") 4333630506bSToomas Soome if c ~= nil then 4343630506bSToomas Soome if c:find("efi") == nil and c:find("vidconsole") == nil then 4353630506bSToomas Soome return false 4363630506bSToomas Soome end 4373630506bSToomas Soome if loader.getenv("screen.depth") ~= nil then 4383630506bSToomas Soome return true 4393630506bSToomas Soome end 4403630506bSToomas Soome end 4413630506bSToomas Soome return false 4423630506bSToomas Soomeend 4433630506bSToomas Soome 44490a25417SKyle Evansfunction core.isSerialConsole() 44590a25417SKyle Evans local c = loader.getenv("console") 44690a25417SKyle Evans if c ~= nil then 4475d8c062fSToomas Soome -- serial console is comconsole, but also userboot. 4485d8c062fSToomas Soome -- userboot is there, because we have no way to know 4495d8c062fSToomas Soome -- if the user terminal can draw unicode box chars or not. 4505d8c062fSToomas Soome if c:find("comconsole") ~= nil or c:find("userboot") ~= nil then 45190a25417SKyle Evans return true 45290a25417SKyle Evans end 45390a25417SKyle Evans end 45490a25417SKyle Evans return false 45590a25417SKyle Evansend 45690a25417SKyle Evans 457b140d14bSKyle Evansfunction core.isSerialBoot() 458aedd6be5SKyle Evans local s = loader.getenv("boot_serial") 4599f71d421SKyle Evans if s ~= nil then 460aedd6be5SKyle Evans return true 461088b4f5fSWarner Losh end 462088b4f5fSWarner Losh 463aedd6be5SKyle Evans local m = loader.getenv("boot_multicons") 4649f71d421SKyle Evans if m ~= nil then 465aedd6be5SKyle Evans return true 466088b4f5fSWarner Losh end 467aedd6be5SKyle Evans return false 468088b4f5fSWarner Loshend 469088b4f5fSWarner Losh 4709937e979SKyle Evans-- Is the menu skipped in the environment in which we've booted? 4719937e979SKyle Evansfunction core.isMenuSkipped() 472b83a355dSKyle Evans return string.lower(loader.getenv("beastie_disable") or "") == "yes" 4739937e979SKyle Evansend 4749937e979SKyle Evans 4755c1b5165SKyle Evans-- This may be a better candidate for a 'utility' module. 476ee4e69f1SKyle Evansfunction core.deepCopyTable(tbl) 477aedd6be5SKyle Evans local new_tbl = {} 4785c1b5165SKyle Evans for k, v in pairs(tbl) do 4799f71d421SKyle Evans if type(v) == "table" then 480ee4e69f1SKyle Evans new_tbl[k] = core.deepCopyTable(v) 4815c1b5165SKyle Evans else 482aedd6be5SKyle Evans new_tbl[k] = v 4835c1b5165SKyle Evans end 4845c1b5165SKyle Evans end 485aedd6be5SKyle Evans return new_tbl 4865c1b5165SKyle Evansend 4875c1b5165SKyle Evans 4886d4ed94dSKyle Evans-- XXX This should go away if we get the table lib into shape for importing. 4896d4ed94dSKyle Evans-- As of now, it requires some 'os' functions, so we'll implement this in lua 4906d4ed94dSKyle Evans-- for our uses 4916d4ed94dSKyle Evansfunction core.popFrontTable(tbl) 4926d4ed94dSKyle Evans -- Shouldn't reasonably happen 4939f71d421SKyle Evans if #tbl == 0 then 494aedd6be5SKyle Evans return nil, nil 4959f71d421SKyle Evans elseif #tbl == 1 then 496aedd6be5SKyle Evans return tbl[1], {} 4976d4ed94dSKyle Evans end 4986d4ed94dSKyle Evans 499aedd6be5SKyle Evans local first_value = tbl[1] 500aedd6be5SKyle Evans local new_tbl = {} 5016d4ed94dSKyle Evans -- This is not a cheap operation 5026d4ed94dSKyle Evans for k, v in ipairs(tbl) do 5039f71d421SKyle Evans if k > 1 then 504aedd6be5SKyle Evans new_tbl[k - 1] = v 5056d4ed94dSKyle Evans end 5066d4ed94dSKyle Evans end 5076d4ed94dSKyle Evans 508aedd6be5SKyle Evans return first_value, new_tbl 5096d4ed94dSKyle Evansend 5106d4ed94dSKyle Evans 5118f3b3610SWarner Loshfunction core.getConsoleName() 5128f3b3610SWarner Losh if loader.getenv("boot_multicons") ~= nil then 5138f3b3610SWarner Losh if loader.getenv("boot_serial") ~= nil then 5148f3b3610SWarner Losh return "Dual (Serial primary)" 5158f3b3610SWarner Losh else 5168f3b3610SWarner Losh return "Dual (Video primary)" 5178f3b3610SWarner Losh end 5188f3b3610SWarner Losh else 5198f3b3610SWarner Losh if loader.getenv("boot_serial") ~= nil then 5208f3b3610SWarner Losh return "Serial" 5218f3b3610SWarner Losh else 5228f3b3610SWarner Losh return "Video" 5238f3b3610SWarner Losh end 5248f3b3610SWarner Losh end 5258f3b3610SWarner Loshend 5268f3b3610SWarner Losh 5278f3b3610SWarner Loshfunction core.nextConsoleChoice() 5288f3b3610SWarner Losh if loader.getenv("boot_multicons") ~= nil then 5298f3b3610SWarner Losh if loader.getenv("boot_serial") ~= nil then 5308f3b3610SWarner Losh loader.unsetenv("boot_serial") 5318f3b3610SWarner Losh else 5328f3b3610SWarner Losh loader.unsetenv("boot_multicons") 5338f3b3610SWarner Losh loader.setenv("boot_serial", "YES") 5348f3b3610SWarner Losh end 5358f3b3610SWarner Losh else 5368f3b3610SWarner Losh if loader.getenv("boot_serial") ~= nil then 5378f3b3610SWarner Losh loader.unsetenv("boot_serial") 5388f3b3610SWarner Losh else 5398f3b3610SWarner Losh loader.setenv("boot_multicons", "YES") 5408f3b3610SWarner Losh loader.setenv("boot_serial", "YES") 5418f3b3610SWarner Losh end 5428f3b3610SWarner Losh end 5438f3b3610SWarner Loshend 5448f3b3610SWarner Losh 545*a2fd7ae8SWarner Losh-- Sanity check the boot loader revision 546*a2fd7ae8SWarner Losh-- Loaders with version 3.0 have everything that we need without backwards 547*a2fd7ae8SWarner Losh-- compatible hacks. Warn users that still have old versions to upgrade so 548*a2fd7ae8SWarner Losh-- that we can remove the backwards compatible hacks in the future since 549*a2fd7ae8SWarner Losh-- they have been there a long time. 550*a2fd7ae8SWarner Loshlocal loader_major = 3 551*a2fd7ae8SWarner Losh 552*a2fd7ae8SWarner Loshfunction core.loaderTooOld() 553*a2fd7ae8SWarner Losh return loader.version == nil or loader.version < loader_major * 1000 554*a2fd7ae8SWarner Loshend 555*a2fd7ae8SWarner Losh 556*a2fd7ae8SWarner Loshif core.loaderTooOld() then 557*a2fd7ae8SWarner Losh print("**********************************************************************") 558*a2fd7ae8SWarner Losh print("**********************************************************************") 559*a2fd7ae8SWarner Losh print("***** *****") 560*a2fd7ae8SWarner Losh print("***** BOOT LOADER IS TOO OLD. PLEASE UPGRADE. *****") 561*a2fd7ae8SWarner Losh print("***** *****") 562*a2fd7ae8SWarner Losh print("**********************************************************************") 563*a2fd7ae8SWarner Losh print("**********************************************************************") 564*a2fd7ae8SWarner Loshend 565*a2fd7ae8SWarner Losh 5661613f091SKyle EvansrecordDefaults() 567aea262bfSKyle Evanshook.register("config.reloaded", core.clearCachedKernels) 568aedd6be5SKyle Evansreturn core 569