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 29aedd6be5SKyle 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 406d3bcc06SKyle Evans-- Internal function 41f0cb3b6bSKyle Evans-- Parses arguments to boot and returns two values: kernel_name, argstr 42f0cb3b6bSKyle Evans-- Defaults to nil and "" respectively. 436d3bcc06SKyle Evans-- This will also parse arguments to autoboot, but the with_kernel argument 446d3bcc06SKyle Evans-- will need to be explicitly overwritten to false 456d3bcc06SKyle Evanslocal parse_boot_args = function(argv, with_kernel) 469f71d421SKyle Evans if with_kernel == nil then 47aedd6be5SKyle Evans with_kernel = true 486d3bcc06SKyle Evans end 491d38e553SKyle Evans if #argv == 0 then 501d38e553SKyle Evans if with_kernel then 511d38e553SKyle Evans return nil, "" 521d38e553SKyle Evans else 531d38e553SKyle Evans return "" 541d38e553SKyle Evans end 551d38e553SKyle Evans end 56aedd6be5SKyle Evans local kernel_name 57aedd6be5SKyle Evans local argstr = "" 58f0cb3b6bSKyle Evans 59f0cb3b6bSKyle Evans for k, v in ipairs(argv) do 609f71d421SKyle Evans if with_kernel and v:sub(1,1) ~= "-" then 61aedd6be5SKyle Evans kernel_name = v 62f0cb3b6bSKyle Evans else 63aedd6be5SKyle Evans argstr = argstr .. " " .. v 64f0cb3b6bSKyle Evans end 65f0cb3b6bSKyle Evans end 669f71d421SKyle Evans if with_kernel then 67aedd6be5SKyle Evans return kernel_name, argstr 686d3bcc06SKyle Evans else 69aedd6be5SKyle Evans return argstr 706d3bcc06SKyle Evans end 71f0cb3b6bSKyle Evansend 72f0cb3b6bSKyle Evans 73f0cb3b6bSKyle Evans-- Globals 74f0cb3b6bSKyle Evansfunction boot(...) 75aedd6be5SKyle Evans local argv = {...} 76aedd6be5SKyle Evans local cmd_name = "" 77aedd6be5SKyle Evans cmd_name, argv = core.popFrontTable(argv) 78aedd6be5SKyle Evans local kernel, argstr = parse_boot_args(argv) 799f71d421SKyle Evans if kernel ~= nil then 80aedd6be5SKyle Evans loader.perform("unload") 81aedd6be5SKyle Evans config.selectkernel(kernel) 82f0cb3b6bSKyle Evans end 83aedd6be5SKyle Evans core.boot(argstr) 84f0cb3b6bSKyle Evansend 85f0cb3b6bSKyle Evans 866d3bcc06SKyle Evansfunction autoboot(...) 876d3bcc06SKyle Evans local argv = {...} 88aedd6be5SKyle Evans local cmd_name = "" 89aedd6be5SKyle Evans cmd_name, argv = core.popFrontTable(argv) 90aedd6be5SKyle Evans local argstr = parse_boot_args(argv, false) 91aedd6be5SKyle Evans core.autoboot(argstr) 926d3bcc06SKyle Evansend 936d3bcc06SKyle Evans 94b5746545SKyle Evans-- Module exports 95fe672a15SKyle Evans-- Commonly appearing constants 96aedd6be5SKyle Evanscore.KEY_BACKSPACE = 8 97aedd6be5SKyle Evanscore.KEY_ENTER = 13 98aedd6be5SKyle Evanscore.KEY_DELETE = 127 99fe672a15SKyle Evans 100aedd6be5SKyle Evanscore.KEYSTR_ESCAPE = "\027" 10139006570SKyle Evans 102aedd6be5SKyle Evanscore.MENU_RETURN = "return" 103aedd6be5SKyle Evanscore.MENU_ENTRY = "entry" 104aedd6be5SKyle Evanscore.MENU_SEPARATOR = "separator" 105aedd6be5SKyle Evanscore.MENU_SUBMENU = "submenu" 106aedd6be5SKyle Evanscore.MENU_CAROUSEL_ENTRY = "carousel_entry" 107a7cf0562SKyle Evans 108088b4f5fSWarner Loshfunction core.setVerbose(b) 1099f71d421SKyle Evans if b == nil then 110aedd6be5SKyle Evans b = not core.verbose 111088b4f5fSWarner Losh end 112088b4f5fSWarner Losh 11349550489SKyle Evans if b then 114aedd6be5SKyle Evans loader.setenv("boot_verbose", "YES") 115088b4f5fSWarner Losh else 116aedd6be5SKyle Evans loader.unsetenv("boot_verbose") 117088b4f5fSWarner Losh end 118aedd6be5SKyle Evans core.verbose = b 119088b4f5fSWarner Loshend 120088b4f5fSWarner Losh 121088b4f5fSWarner Loshfunction core.setSingleUser(b) 1229f71d421SKyle Evans if b == nil then 123aedd6be5SKyle Evans b = not core.su 124088b4f5fSWarner Losh end 125088b4f5fSWarner Losh 12649550489SKyle Evans if b then 127aedd6be5SKyle Evans loader.setenv("boot_single", "YES") 128088b4f5fSWarner Losh else 129aedd6be5SKyle Evans loader.unsetenv("boot_single") 130088b4f5fSWarner Losh end 131aedd6be5SKyle Evans core.su = b 132088b4f5fSWarner Loshend 133088b4f5fSWarner Losh 1346401094fSKyle Evansfunction core.getACPIPresent(checkingSystemDefaults) 135aedd6be5SKyle Evans local c = loader.getenv("hint.acpi.0.rsdp") 1366401094fSKyle Evans 1379f71d421SKyle Evans if c ~= nil then 13849550489SKyle Evans if checkingSystemDefaults then 139aedd6be5SKyle Evans return true 1406401094fSKyle Evans end 1416401094fSKyle Evans -- Otherwise, respect disabled if it's set 142aedd6be5SKyle Evans c = loader.getenv("hint.acpi.0.disabled") 1439f71d421SKyle Evans return c == nil or tonumber(c) ~= 1 1446401094fSKyle Evans end 145aedd6be5SKyle Evans return false 1466401094fSKyle Evansend 1476401094fSKyle Evans 148088b4f5fSWarner Loshfunction core.setACPI(b) 1499f71d421SKyle Evans if b == nil then 150aedd6be5SKyle Evans b = not core.acpi 151088b4f5fSWarner Losh end 152088b4f5fSWarner Losh 15349550489SKyle Evans if b then 154aedd6be5SKyle Evans loader.setenv("acpi_load", "YES") 155aedd6be5SKyle Evans loader.setenv("hint.acpi.0.disabled", "0") 156aedd6be5SKyle Evans loader.unsetenv("loader.acpi_disabled_by_user") 157088b4f5fSWarner Losh else 158aedd6be5SKyle Evans loader.unsetenv("acpi_load") 159aedd6be5SKyle Evans loader.setenv("hint.acpi.0.disabled", "1") 160aedd6be5SKyle Evans loader.setenv("loader.acpi_disabled_by_user", "1") 161088b4f5fSWarner Losh end 162aedd6be5SKyle Evans core.acpi = b 163088b4f5fSWarner Loshend 164088b4f5fSWarner Losh 165088b4f5fSWarner Loshfunction core.setSafeMode(b) 1669f71d421SKyle Evans if b == nil then 167aedd6be5SKyle Evans b = not core.sm 168088b4f5fSWarner Losh end 16949550489SKyle Evans if b then 170aedd6be5SKyle Evans loader.setenv("kern.smp.disabled", "1") 171aedd6be5SKyle Evans loader.setenv("hw.ata.ata_dma", "0") 172aedd6be5SKyle Evans loader.setenv("hw.ata.atapi_dma", "0") 173aedd6be5SKyle Evans loader.setenv("hw.ata.wc", "0") 174aedd6be5SKyle Evans loader.setenv("hw.eisa_slots", "0") 175aedd6be5SKyle Evans loader.setenv("kern.eventtimer.periodic", "1") 176aedd6be5SKyle Evans loader.setenv("kern.geom.part.check_integrity", "0") 177088b4f5fSWarner Losh else 178aedd6be5SKyle Evans loader.unsetenv("kern.smp.disabled") 179aedd6be5SKyle Evans loader.unsetenv("hw.ata.ata_dma") 180aedd6be5SKyle Evans loader.unsetenv("hw.ata.atapi_dma") 181aedd6be5SKyle Evans loader.unsetenv("hw.ata.wc") 182aedd6be5SKyle Evans loader.unsetenv("hw.eisa_slots") 183aedd6be5SKyle Evans loader.unsetenv("kern.eventtimer.periodic") 184aedd6be5SKyle Evans loader.unsetenv("kern.geom.part.check_integrity") 185088b4f5fSWarner Losh end 186aedd6be5SKyle Evans core.sm = b 187088b4f5fSWarner Loshend 188088b4f5fSWarner Losh 189088b4f5fSWarner Loshfunction core.kernelList() 190aedd6be5SKyle Evans local k = loader.getenv("kernel") 1913f4eb56bSKyle Evans local v = loader.getenv("kernels") 192088b4f5fSWarner Losh 193aedd6be5SKyle Evans local kernels = {} 194aedd6be5SKyle Evans local unique = {} 195aedd6be5SKyle Evans local i = 0 1969f71d421SKyle Evans if k ~= nil then 197aedd6be5SKyle Evans i = i + 1 198aedd6be5SKyle Evans kernels[i] = k 199aedd6be5SKyle Evans unique[k] = true 200088b4f5fSWarner Losh end 201088b4f5fSWarner Losh 2023f4eb56bSKyle Evans if v ~= nil then 203088b4f5fSWarner Losh for n in v:gmatch("([^; ]+)[; ]?") do 2049f71d421SKyle Evans if unique[n] == nil then 205aedd6be5SKyle Evans i = i + 1 206aedd6be5SKyle Evans kernels[i] = n 207aedd6be5SKyle Evans unique[n] = true 208088b4f5fSWarner Losh end 209088b4f5fSWarner Losh end 210a108046fSConrad Meyer 2113f4eb56bSKyle Evans -- We will not automatically detect kernels to be displayed if 2123f4eb56bSKyle Evans -- loader.conf(5) explicitly set 'kernels'. 2133f4eb56bSKyle Evans return kernels 2143f4eb56bSKyle Evans end 2153f4eb56bSKyle Evans 216a108046fSConrad Meyer -- Automatically detect other bootable kernel directories using a 217a108046fSConrad Meyer -- heuristic. Any directory in /boot that contains an ordinary file 218a108046fSConrad Meyer -- named "kernel" is considered eligible. 219a108046fSConrad Meyer for file in lfs.dir("/boot") do 220aedd6be5SKyle Evans local fname = "/boot/" .. file 221a108046fSConrad Meyer 2229f71d421SKyle Evans if file == "." or file == ".." then 223aedd6be5SKyle Evans goto continue 224a108046fSConrad Meyer end 225a108046fSConrad Meyer 2269f71d421SKyle Evans if lfs.attributes(fname, "mode") ~= "directory" then 227aedd6be5SKyle Evans goto continue 228a108046fSConrad Meyer end 229a108046fSConrad Meyer 2309f71d421SKyle Evans if lfs.attributes(fname .. "/kernel", "mode") ~= "file" then 231aedd6be5SKyle Evans goto continue 232a108046fSConrad Meyer end 233a108046fSConrad Meyer 2349f71d421SKyle Evans if unique[file] == nil then 235aedd6be5SKyle Evans i = i + 1 236aedd6be5SKyle Evans kernels[i] = file 237aedd6be5SKyle Evans unique[file] = true 238a108046fSConrad Meyer end 239a108046fSConrad Meyer 240a108046fSConrad Meyer ::continue:: 241a108046fSConrad Meyer end 242aedd6be5SKyle Evans return kernels 243088b4f5fSWarner Loshend 244088b4f5fSWarner Losh 245*7efc058fSKyle Evansfunction core.bootenvDefault() 246*7efc058fSKyle Evans return loader.getenv("zfs_be_active") 247*7efc058fSKyle Evansend 248*7efc058fSKyle Evans 249*7efc058fSKyle Evansfunction core.bootenvList() 250*7efc058fSKyle Evans local bootenv_count = tonumber(loader.getenv("bootenvs_count")) 251*7efc058fSKyle Evans local bootenvs = {} 252*7efc058fSKyle Evans local curenv 253*7efc058fSKyle Evans local curenv_idx = 0 254*7efc058fSKyle Evans local envcount = 0 255*7efc058fSKyle Evans local unique = {} 256*7efc058fSKyle Evans 257*7efc058fSKyle Evans if bootenv_count == nil or bootenv_count <= 0 then 258*7efc058fSKyle Evans return bootenvs 259*7efc058fSKyle Evans end 260*7efc058fSKyle Evans 261*7efc058fSKyle Evans -- Currently selected bootenv is always first/default 262*7efc058fSKyle Evans curenv = core.bootenvDefault() 263*7efc058fSKyle Evans if curenv ~= nil then 264*7efc058fSKyle Evans envcount = envcount + 1 265*7efc058fSKyle Evans bootenvs[envcount] = curenv 266*7efc058fSKyle Evans unique[curenv] = true 267*7efc058fSKyle Evans end 268*7efc058fSKyle Evans 269*7efc058fSKyle Evans for curenv_idx = 0, bootenv_count - 1 do 270*7efc058fSKyle Evans curenv = loader.getenv("bootenvs[" .. curenv_idx .. "]") 271*7efc058fSKyle Evans if curenv ~= nil and unique[curenv] == nil then 272*7efc058fSKyle Evans envcount = envcount + 1 273*7efc058fSKyle Evans bootenvs[envcount] = curenv 274*7efc058fSKyle Evans unique[curenv] = true 275*7efc058fSKyle Evans end 276*7efc058fSKyle Evans end 277*7efc058fSKyle Evans return bootenvs 278*7efc058fSKyle Evansend 279*7efc058fSKyle Evans 280088b4f5fSWarner Loshfunction core.setDefaults() 281aedd6be5SKyle Evans core.setACPI(core.getACPIPresent(true)) 282aedd6be5SKyle Evans core.setSafeMode(false) 283aedd6be5SKyle Evans core.setSingleUser(false) 284aedd6be5SKyle Evans core.setVerbose(false) 285088b4f5fSWarner Loshend 286088b4f5fSWarner Losh 2876d4ed94dSKyle Evansfunction core.autoboot(argstr) 288aedd6be5SKyle Evans config.loadelf() 289aedd6be5SKyle Evans loader.perform(compose_loader_cmd("autoboot", argstr)) 290088b4f5fSWarner Loshend 291088b4f5fSWarner Losh 2926d4ed94dSKyle Evansfunction core.boot(argstr) 293aedd6be5SKyle Evans config.loadelf() 294aedd6be5SKyle Evans loader.perform(compose_loader_cmd("boot", argstr)) 295088b4f5fSWarner Loshend 296088b4f5fSWarner Losh 297e07fc39cSKyle Evansfunction core.isSingleUserBoot() 298aedd6be5SKyle Evans local single_user = loader.getenv("boot_single") 299aedd6be5SKyle Evans return single_user ~= nil and single_user:lower() == "yes" 300e07fc39cSKyle Evansend 301e07fc39cSKyle Evans 302*7efc058fSKyle Evansfunction core.isZFSBoot() 303*7efc058fSKyle Evans local c = loader.getenv("currdev") 304*7efc058fSKyle Evans 305*7efc058fSKyle Evans if c ~= nil then 306*7efc058fSKyle Evans return c:match("^zfs:") ~= nil 307*7efc058fSKyle Evans end 308*7efc058fSKyle Evans return false 309*7efc058fSKyle Evansend 310*7efc058fSKyle Evans 311b140d14bSKyle Evansfunction core.isSerialBoot() 312aedd6be5SKyle Evans local c = loader.getenv("console") 313088b4f5fSWarner Losh 3149f71d421SKyle Evans if c ~= nil then 3159f71d421SKyle Evans if c:find("comconsole") ~= nil then 316aedd6be5SKyle Evans return true 317088b4f5fSWarner Losh end 318088b4f5fSWarner Losh end 319088b4f5fSWarner Losh 320aedd6be5SKyle Evans local s = loader.getenv("boot_serial") 3219f71d421SKyle Evans if s ~= nil then 322aedd6be5SKyle Evans return true 323088b4f5fSWarner Losh end 324088b4f5fSWarner Losh 325aedd6be5SKyle Evans local m = loader.getenv("boot_multicons") 3269f71d421SKyle Evans if m ~= nil then 327aedd6be5SKyle Evans return true 328088b4f5fSWarner Losh end 329aedd6be5SKyle Evans return false 330088b4f5fSWarner Loshend 331088b4f5fSWarner Losh 332c1ab36f5SKyle Evansfunction core.isSystem386() 3339f71d421SKyle Evans return loader.machine_arch == "i386" 334c1ab36f5SKyle Evansend 335c1ab36f5SKyle Evans 3365c1b5165SKyle Evans-- This may be a better candidate for a 'utility' module. 3375c1b5165SKyle Evansfunction core.shallowCopyTable(tbl) 338aedd6be5SKyle Evans local new_tbl = {} 3395c1b5165SKyle Evans for k, v in pairs(tbl) do 3409f71d421SKyle Evans if type(v) == "table" then 341aedd6be5SKyle Evans new_tbl[k] = core.shallowCopyTable(v) 3425c1b5165SKyle Evans else 343aedd6be5SKyle Evans new_tbl[k] = v 3445c1b5165SKyle Evans end 3455c1b5165SKyle Evans end 346aedd6be5SKyle Evans return new_tbl 3475c1b5165SKyle Evansend 3485c1b5165SKyle Evans 3496d4ed94dSKyle Evans-- XXX This should go away if we get the table lib into shape for importing. 3506d4ed94dSKyle Evans-- As of now, it requires some 'os' functions, so we'll implement this in lua 3516d4ed94dSKyle Evans-- for our uses 3526d4ed94dSKyle Evansfunction core.popFrontTable(tbl) 3536d4ed94dSKyle Evans -- Shouldn't reasonably happen 3549f71d421SKyle Evans if #tbl == 0 then 355aedd6be5SKyle Evans return nil, nil 3569f71d421SKyle Evans elseif #tbl == 1 then 357aedd6be5SKyle Evans return tbl[1], {} 3586d4ed94dSKyle Evans end 3596d4ed94dSKyle Evans 360aedd6be5SKyle Evans local first_value = tbl[1] 361aedd6be5SKyle Evans local new_tbl = {} 3626d4ed94dSKyle Evans -- This is not a cheap operation 3636d4ed94dSKyle Evans for k, v in ipairs(tbl) do 3649f71d421SKyle Evans if k > 1 then 365aedd6be5SKyle Evans new_tbl[k - 1] = v 3666d4ed94dSKyle Evans end 3676d4ed94dSKyle Evans end 3686d4ed94dSKyle Evans 369aedd6be5SKyle Evans return first_value, new_tbl 3706d4ed94dSKyle Evansend 3716d4ed94dSKyle Evans 3726f412147SKyle Evans-- On i386, hint.acpi.0.rsdp will be set before we're loaded. On !i386, it will 3736f412147SKyle Evans-- generally be set upon execution of the kernel. Because of this, we can't (or 3746f412147SKyle Evans-- don't really want to) detect/disable ACPI on !i386 reliably. Just set it 3756f412147SKyle Evans-- enabled if we detect it and leave well enough alone if we don't. 3769f71d421SKyle Evansif core.isSystem386() and core.getACPIPresent(false) then 377aedd6be5SKyle Evans core.setACPI(true) 3786f412147SKyle Evansend 379aedd6be5SKyle Evansreturn core 380