1088b4f5fSWarner Losh-- 2088b4f5fSWarner Losh-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org> 3088b4f5fSWarner Losh-- All rights reserved. 4088b4f5fSWarner Losh-- 5088b4f5fSWarner Losh-- Redistribution and use in source and binary forms, with or without 6088b4f5fSWarner Losh-- modification, are permitted provided that the following conditions 7088b4f5fSWarner Losh-- are met: 8088b4f5fSWarner Losh-- 1. Redistributions of source code must retain the above copyright 9088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer. 10088b4f5fSWarner Losh-- 2. Redistributions in binary form must reproduce the above copyright 11088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer in the 12088b4f5fSWarner Losh-- documentation and/or other materials provided with the distribution. 13088b4f5fSWarner Losh-- 14088b4f5fSWarner Losh-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15088b4f5fSWarner Losh-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16088b4f5fSWarner Losh-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17088b4f5fSWarner Losh-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18088b4f5fSWarner Losh-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19088b4f5fSWarner Losh-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20088b4f5fSWarner Losh-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21088b4f5fSWarner Losh-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22088b4f5fSWarner Losh-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23088b4f5fSWarner Losh-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24088b4f5fSWarner Losh-- SUCH DAMAGE. 25088b4f5fSWarner Losh-- 26088b4f5fSWarner Losh-- $FreeBSD$ 27088b4f5fSWarner Losh-- 28088b4f5fSWarner Losh 29*011eae6cSKyle Evanslocal config = require("config") 30fa4a2394SKyle Evans 31aedd6be5SKyle Evanslocal core = {} 32088b4f5fSWarner Losh 336d4ed94dSKyle Evanslocal compose_loader_cmd = function(cmd_name, argstr) 349f71d421SKyle Evans if argstr ~= nil then 35aedd6be5SKyle Evans cmd_name = cmd_name .. " " .. argstr 366d4ed94dSKyle Evans end 37aedd6be5SKyle Evans return cmd_name 386d4ed94dSKyle Evansend 396d4ed94dSKyle Evans 40b5746545SKyle Evans-- Module exports 41fe672a15SKyle Evans-- Commonly appearing constants 42aedd6be5SKyle Evanscore.KEY_BACKSPACE = 8 43aedd6be5SKyle Evanscore.KEY_ENTER = 13 44aedd6be5SKyle Evanscore.KEY_DELETE = 127 45fe672a15SKyle Evans 46aedd6be5SKyle Evanscore.KEYSTR_ESCAPE = "\027" 4739006570SKyle Evans 48aedd6be5SKyle Evanscore.MENU_RETURN = "return" 49aedd6be5SKyle Evanscore.MENU_ENTRY = "entry" 50aedd6be5SKyle Evanscore.MENU_SEPARATOR = "separator" 51aedd6be5SKyle Evanscore.MENU_SUBMENU = "submenu" 52aedd6be5SKyle Evanscore.MENU_CAROUSEL_ENTRY = "carousel_entry" 53a7cf0562SKyle Evans 54088b4f5fSWarner Loshfunction core.setVerbose(b) 559f71d421SKyle Evans if b == nil then 56aedd6be5SKyle Evans b = not core.verbose 57088b4f5fSWarner Losh end 58088b4f5fSWarner Losh 5949550489SKyle Evans if b then 60aedd6be5SKyle Evans loader.setenv("boot_verbose", "YES") 61088b4f5fSWarner Losh else 62aedd6be5SKyle Evans loader.unsetenv("boot_verbose") 63088b4f5fSWarner Losh end 64aedd6be5SKyle Evans core.verbose = b 65088b4f5fSWarner Loshend 66088b4f5fSWarner Losh 67088b4f5fSWarner Loshfunction core.setSingleUser(b) 689f71d421SKyle Evans if b == nil then 69aedd6be5SKyle Evans b = not core.su 70088b4f5fSWarner Losh end 71088b4f5fSWarner Losh 7249550489SKyle Evans if b then 73aedd6be5SKyle Evans loader.setenv("boot_single", "YES") 74088b4f5fSWarner Losh else 75aedd6be5SKyle Evans loader.unsetenv("boot_single") 76088b4f5fSWarner Losh end 77aedd6be5SKyle Evans core.su = b 78088b4f5fSWarner Loshend 79088b4f5fSWarner Losh 806401094fSKyle Evansfunction core.getACPIPresent(checkingSystemDefaults) 81aedd6be5SKyle Evans local c = loader.getenv("hint.acpi.0.rsdp") 826401094fSKyle Evans 839f71d421SKyle Evans if c ~= nil then 8449550489SKyle Evans if checkingSystemDefaults then 85aedd6be5SKyle Evans return true 866401094fSKyle Evans end 876401094fSKyle Evans -- Otherwise, respect disabled if it's set 88aedd6be5SKyle Evans c = loader.getenv("hint.acpi.0.disabled") 899f71d421SKyle Evans return c == nil or tonumber(c) ~= 1 906401094fSKyle Evans end 91aedd6be5SKyle Evans return false 926401094fSKyle Evansend 936401094fSKyle Evans 94088b4f5fSWarner Loshfunction core.setACPI(b) 959f71d421SKyle Evans if b == nil then 96aedd6be5SKyle Evans b = not core.acpi 97088b4f5fSWarner Losh end 98088b4f5fSWarner Losh 9949550489SKyle Evans if b then 100aedd6be5SKyle Evans loader.setenv("acpi_load", "YES") 101aedd6be5SKyle Evans loader.setenv("hint.acpi.0.disabled", "0") 102aedd6be5SKyle Evans loader.unsetenv("loader.acpi_disabled_by_user") 103088b4f5fSWarner Losh else 104aedd6be5SKyle Evans loader.unsetenv("acpi_load") 105aedd6be5SKyle Evans loader.setenv("hint.acpi.0.disabled", "1") 106aedd6be5SKyle Evans loader.setenv("loader.acpi_disabled_by_user", "1") 107088b4f5fSWarner Losh end 108aedd6be5SKyle Evans core.acpi = b 109088b4f5fSWarner Loshend 110088b4f5fSWarner Losh 111088b4f5fSWarner Loshfunction core.setSafeMode(b) 1129f71d421SKyle Evans if b == nil then 113aedd6be5SKyle Evans b = not core.sm 114088b4f5fSWarner Losh end 11549550489SKyle Evans if b then 116aedd6be5SKyle Evans loader.setenv("kern.smp.disabled", "1") 117aedd6be5SKyle Evans loader.setenv("hw.ata.ata_dma", "0") 118aedd6be5SKyle Evans loader.setenv("hw.ata.atapi_dma", "0") 119aedd6be5SKyle Evans loader.setenv("hw.ata.wc", "0") 120aedd6be5SKyle Evans loader.setenv("hw.eisa_slots", "0") 121aedd6be5SKyle Evans loader.setenv("kern.eventtimer.periodic", "1") 122aedd6be5SKyle Evans loader.setenv("kern.geom.part.check_integrity", "0") 123088b4f5fSWarner Losh else 124aedd6be5SKyle Evans loader.unsetenv("kern.smp.disabled") 125aedd6be5SKyle Evans loader.unsetenv("hw.ata.ata_dma") 126aedd6be5SKyle Evans loader.unsetenv("hw.ata.atapi_dma") 127aedd6be5SKyle Evans loader.unsetenv("hw.ata.wc") 128aedd6be5SKyle Evans loader.unsetenv("hw.eisa_slots") 129aedd6be5SKyle Evans loader.unsetenv("kern.eventtimer.periodic") 130aedd6be5SKyle Evans loader.unsetenv("kern.geom.part.check_integrity") 131088b4f5fSWarner Losh end 132aedd6be5SKyle Evans core.sm = b 133088b4f5fSWarner Loshend 134088b4f5fSWarner Losh 135088b4f5fSWarner Loshfunction core.kernelList() 136aedd6be5SKyle Evans local k = loader.getenv("kernel") 1373f4eb56bSKyle Evans local v = loader.getenv("kernels") 1383889e6cdSKyle Evans local autodetect = loader.getenv("kernels_autodetect") or "" 139088b4f5fSWarner Losh 140aedd6be5SKyle Evans local kernels = {} 141aedd6be5SKyle Evans local unique = {} 142aedd6be5SKyle Evans local i = 0 1439f71d421SKyle Evans if k ~= nil then 144aedd6be5SKyle Evans i = i + 1 145aedd6be5SKyle Evans kernels[i] = k 146aedd6be5SKyle Evans unique[k] = true 147088b4f5fSWarner Losh end 148088b4f5fSWarner Losh 1493f4eb56bSKyle Evans if v ~= nil then 150088b4f5fSWarner Losh for n in v:gmatch("([^; ]+)[; ]?") do 1519f71d421SKyle Evans if unique[n] == nil then 152aedd6be5SKyle Evans i = i + 1 153aedd6be5SKyle Evans kernels[i] = n 154aedd6be5SKyle Evans unique[n] = true 155088b4f5fSWarner Losh end 156088b4f5fSWarner Losh end 1573889e6cdSKyle Evans end 158a108046fSConrad Meyer 1593889e6cdSKyle Evans -- Base whether we autodetect kernels or not on a loader.conf(5) 1603889e6cdSKyle Evans -- setting, kernels_autodetect. If it's set to 'yes', we'll add 1613889e6cdSKyle Evans -- any kernels we detect based on the criteria described. 1623889e6cdSKyle Evans if autodetect:lower() ~= "yes" then 1633f4eb56bSKyle Evans return kernels 1643f4eb56bSKyle Evans end 1653f4eb56bSKyle Evans 166a108046fSConrad Meyer -- Automatically detect other bootable kernel directories using a 167a108046fSConrad Meyer -- heuristic. Any directory in /boot that contains an ordinary file 168a108046fSConrad Meyer -- named "kernel" is considered eligible. 169a108046fSConrad Meyer for file in lfs.dir("/boot") do 170aedd6be5SKyle Evans local fname = "/boot/" .. file 171a108046fSConrad Meyer 1729f71d421SKyle Evans if file == "." or file == ".." then 173aedd6be5SKyle Evans goto continue 174a108046fSConrad Meyer end 175a108046fSConrad Meyer 1769f71d421SKyle Evans if lfs.attributes(fname, "mode") ~= "directory" then 177aedd6be5SKyle Evans goto continue 178a108046fSConrad Meyer end 179a108046fSConrad Meyer 1809f71d421SKyle Evans if lfs.attributes(fname .. "/kernel", "mode") ~= "file" then 181aedd6be5SKyle Evans goto continue 182a108046fSConrad Meyer end 183a108046fSConrad Meyer 1849f71d421SKyle Evans if unique[file] == nil then 185aedd6be5SKyle Evans i = i + 1 186aedd6be5SKyle Evans kernels[i] = file 187aedd6be5SKyle Evans unique[file] = true 188a108046fSConrad Meyer end 189a108046fSConrad Meyer 190a108046fSConrad Meyer ::continue:: 191a108046fSConrad Meyer end 192aedd6be5SKyle Evans return kernels 193088b4f5fSWarner Loshend 194088b4f5fSWarner Losh 1957efc058fSKyle Evansfunction core.bootenvDefault() 1967efc058fSKyle Evans return loader.getenv("zfs_be_active") 1977efc058fSKyle Evansend 1987efc058fSKyle Evans 1997efc058fSKyle Evansfunction core.bootenvList() 2007efc058fSKyle Evans local bootenv_count = tonumber(loader.getenv("bootenvs_count")) 2017efc058fSKyle Evans local bootenvs = {} 2027efc058fSKyle Evans local curenv 2037efc058fSKyle Evans local curenv_idx = 0 2047efc058fSKyle Evans local envcount = 0 2057efc058fSKyle Evans local unique = {} 2067efc058fSKyle Evans 2077efc058fSKyle Evans if bootenv_count == nil or bootenv_count <= 0 then 2087efc058fSKyle Evans return bootenvs 2097efc058fSKyle Evans end 2107efc058fSKyle Evans 2117efc058fSKyle Evans -- Currently selected bootenv is always first/default 2127efc058fSKyle Evans curenv = core.bootenvDefault() 2137efc058fSKyle Evans if curenv ~= nil then 2147efc058fSKyle Evans envcount = envcount + 1 2157efc058fSKyle Evans bootenvs[envcount] = curenv 2167efc058fSKyle Evans unique[curenv] = true 2177efc058fSKyle Evans end 2187efc058fSKyle Evans 2197efc058fSKyle Evans for curenv_idx = 0, bootenv_count - 1 do 2207efc058fSKyle Evans curenv = loader.getenv("bootenvs[" .. curenv_idx .. "]") 2217efc058fSKyle Evans if curenv ~= nil and unique[curenv] == nil then 2227efc058fSKyle Evans envcount = envcount + 1 2237efc058fSKyle Evans bootenvs[envcount] = curenv 2247efc058fSKyle Evans unique[curenv] = true 2257efc058fSKyle Evans end 2267efc058fSKyle Evans end 2277efc058fSKyle Evans return bootenvs 2287efc058fSKyle Evansend 2297efc058fSKyle Evans 230088b4f5fSWarner Loshfunction core.setDefaults() 231aedd6be5SKyle Evans core.setACPI(core.getACPIPresent(true)) 232aedd6be5SKyle Evans core.setSafeMode(false) 233aedd6be5SKyle Evans core.setSingleUser(false) 234aedd6be5SKyle Evans core.setVerbose(false) 235088b4f5fSWarner Loshend 236088b4f5fSWarner Losh 2376d4ed94dSKyle Evansfunction core.autoboot(argstr) 238aedd6be5SKyle Evans config.loadelf() 239aedd6be5SKyle Evans loader.perform(compose_loader_cmd("autoboot", argstr)) 240088b4f5fSWarner Loshend 241088b4f5fSWarner Losh 2426d4ed94dSKyle Evansfunction core.boot(argstr) 243aedd6be5SKyle Evans config.loadelf() 244aedd6be5SKyle Evans loader.perform(compose_loader_cmd("boot", argstr)) 245088b4f5fSWarner Loshend 246088b4f5fSWarner Losh 247e07fc39cSKyle Evansfunction core.isSingleUserBoot() 248aedd6be5SKyle Evans local single_user = loader.getenv("boot_single") 249aedd6be5SKyle Evans return single_user ~= nil and single_user:lower() == "yes" 250e07fc39cSKyle Evansend 251e07fc39cSKyle Evans 2527efc058fSKyle Evansfunction core.isZFSBoot() 2537efc058fSKyle Evans local c = loader.getenv("currdev") 2547efc058fSKyle Evans 2557efc058fSKyle Evans if c ~= nil then 2567efc058fSKyle Evans return c:match("^zfs:") ~= nil 2577efc058fSKyle Evans end 2587efc058fSKyle Evans return false 2597efc058fSKyle Evansend 2607efc058fSKyle Evans 261b140d14bSKyle Evansfunction core.isSerialBoot() 262aedd6be5SKyle Evans local c = loader.getenv("console") 263088b4f5fSWarner Losh 2649f71d421SKyle Evans if c ~= nil then 2659f71d421SKyle Evans if c:find("comconsole") ~= nil then 266aedd6be5SKyle Evans return true 267088b4f5fSWarner Losh end 268088b4f5fSWarner Losh end 269088b4f5fSWarner Losh 270aedd6be5SKyle Evans local s = loader.getenv("boot_serial") 2719f71d421SKyle Evans if s ~= nil then 272aedd6be5SKyle Evans return true 273088b4f5fSWarner Losh end 274088b4f5fSWarner Losh 275aedd6be5SKyle Evans local m = loader.getenv("boot_multicons") 2769f71d421SKyle Evans if m ~= nil then 277aedd6be5SKyle Evans return true 278088b4f5fSWarner Losh end 279aedd6be5SKyle Evans return false 280088b4f5fSWarner Loshend 281088b4f5fSWarner Losh 282c1ab36f5SKyle Evansfunction core.isSystem386() 2839f71d421SKyle Evans return loader.machine_arch == "i386" 284c1ab36f5SKyle Evansend 285c1ab36f5SKyle Evans 2865c1b5165SKyle Evans-- This may be a better candidate for a 'utility' module. 2875c1b5165SKyle Evansfunction core.shallowCopyTable(tbl) 288aedd6be5SKyle Evans local new_tbl = {} 2895c1b5165SKyle Evans for k, v in pairs(tbl) do 2909f71d421SKyle Evans if type(v) == "table" then 291aedd6be5SKyle Evans new_tbl[k] = core.shallowCopyTable(v) 2925c1b5165SKyle Evans else 293aedd6be5SKyle Evans new_tbl[k] = v 2945c1b5165SKyle Evans end 2955c1b5165SKyle Evans end 296aedd6be5SKyle Evans return new_tbl 2975c1b5165SKyle Evansend 2985c1b5165SKyle Evans 2996d4ed94dSKyle Evans-- XXX This should go away if we get the table lib into shape for importing. 3006d4ed94dSKyle Evans-- As of now, it requires some 'os' functions, so we'll implement this in lua 3016d4ed94dSKyle Evans-- for our uses 3026d4ed94dSKyle Evansfunction core.popFrontTable(tbl) 3036d4ed94dSKyle Evans -- Shouldn't reasonably happen 3049f71d421SKyle Evans if #tbl == 0 then 305aedd6be5SKyle Evans return nil, nil 3069f71d421SKyle Evans elseif #tbl == 1 then 307aedd6be5SKyle Evans return tbl[1], {} 3086d4ed94dSKyle Evans end 3096d4ed94dSKyle Evans 310aedd6be5SKyle Evans local first_value = tbl[1] 311aedd6be5SKyle Evans local new_tbl = {} 3126d4ed94dSKyle Evans -- This is not a cheap operation 3136d4ed94dSKyle Evans for k, v in ipairs(tbl) do 3149f71d421SKyle Evans if k > 1 then 315aedd6be5SKyle Evans new_tbl[k - 1] = v 3166d4ed94dSKyle Evans end 3176d4ed94dSKyle Evans end 3186d4ed94dSKyle Evans 319aedd6be5SKyle Evans return first_value, new_tbl 3206d4ed94dSKyle Evansend 3216d4ed94dSKyle Evans 3226f412147SKyle Evans-- On i386, hint.acpi.0.rsdp will be set before we're loaded. On !i386, it will 3236f412147SKyle Evans-- generally be set upon execution of the kernel. Because of this, we can't (or 3246f412147SKyle Evans-- don't really want to) detect/disable ACPI on !i386 reliably. Just set it 3256f412147SKyle Evans-- enabled if we detect it and leave well enough alone if we don't. 3269f71d421SKyle Evansif core.isSystem386() and core.getACPIPresent(false) then 327aedd6be5SKyle Evans core.setACPI(true) 3286f412147SKyle Evansend 329aedd6be5SKyle Evansreturn core 330