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") 191*3f4eb56bSKyle 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 202*3f4eb56bSKyle 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 211*3f4eb56bSKyle Evans -- We will not automatically detect kernels to be displayed if 212*3f4eb56bSKyle Evans -- loader.conf(5) explicitly set 'kernels'. 213*3f4eb56bSKyle Evans return kernels 214*3f4eb56bSKyle Evans end 215*3f4eb56bSKyle 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 245088b4f5fSWarner Loshfunction core.setDefaults() 246aedd6be5SKyle Evans core.setACPI(core.getACPIPresent(true)) 247aedd6be5SKyle Evans core.setSafeMode(false) 248aedd6be5SKyle Evans core.setSingleUser(false) 249aedd6be5SKyle Evans core.setVerbose(false) 250088b4f5fSWarner Loshend 251088b4f5fSWarner Losh 2526d4ed94dSKyle Evansfunction core.autoboot(argstr) 253aedd6be5SKyle Evans config.loadelf() 254aedd6be5SKyle Evans loader.perform(compose_loader_cmd("autoboot", argstr)) 255088b4f5fSWarner Loshend 256088b4f5fSWarner Losh 2576d4ed94dSKyle Evansfunction core.boot(argstr) 258aedd6be5SKyle Evans config.loadelf() 259aedd6be5SKyle Evans loader.perform(compose_loader_cmd("boot", argstr)) 260088b4f5fSWarner Loshend 261088b4f5fSWarner Losh 262e07fc39cSKyle Evansfunction core.isSingleUserBoot() 263aedd6be5SKyle Evans local single_user = loader.getenv("boot_single") 264aedd6be5SKyle Evans return single_user ~= nil and single_user:lower() == "yes" 265e07fc39cSKyle Evansend 266e07fc39cSKyle Evans 267b140d14bSKyle Evansfunction core.isSerialBoot() 268aedd6be5SKyle Evans local c = loader.getenv("console") 269088b4f5fSWarner Losh 2709f71d421SKyle Evans if c ~= nil then 2719f71d421SKyle Evans if c:find("comconsole") ~= nil then 272aedd6be5SKyle Evans return true 273088b4f5fSWarner Losh end 274088b4f5fSWarner Losh end 275088b4f5fSWarner Losh 276aedd6be5SKyle Evans local s = loader.getenv("boot_serial") 2779f71d421SKyle Evans if s ~= nil then 278aedd6be5SKyle Evans return true 279088b4f5fSWarner Losh end 280088b4f5fSWarner Losh 281aedd6be5SKyle Evans local m = loader.getenv("boot_multicons") 2829f71d421SKyle Evans if m ~= nil then 283aedd6be5SKyle Evans return true 284088b4f5fSWarner Losh end 285aedd6be5SKyle Evans return false 286088b4f5fSWarner Loshend 287088b4f5fSWarner Losh 288c1ab36f5SKyle Evansfunction core.isSystem386() 2899f71d421SKyle Evans return loader.machine_arch == "i386" 290c1ab36f5SKyle Evansend 291c1ab36f5SKyle Evans 2925c1b5165SKyle Evans-- This may be a better candidate for a 'utility' module. 2935c1b5165SKyle Evansfunction core.shallowCopyTable(tbl) 294aedd6be5SKyle Evans local new_tbl = {} 2955c1b5165SKyle Evans for k, v in pairs(tbl) do 2969f71d421SKyle Evans if type(v) == "table" then 297aedd6be5SKyle Evans new_tbl[k] = core.shallowCopyTable(v) 2985c1b5165SKyle Evans else 299aedd6be5SKyle Evans new_tbl[k] = v 3005c1b5165SKyle Evans end 3015c1b5165SKyle Evans end 302aedd6be5SKyle Evans return new_tbl 3035c1b5165SKyle Evansend 3045c1b5165SKyle Evans 3056d4ed94dSKyle Evans-- XXX This should go away if we get the table lib into shape for importing. 3066d4ed94dSKyle Evans-- As of now, it requires some 'os' functions, so we'll implement this in lua 3076d4ed94dSKyle Evans-- for our uses 3086d4ed94dSKyle Evansfunction core.popFrontTable(tbl) 3096d4ed94dSKyle Evans -- Shouldn't reasonably happen 3109f71d421SKyle Evans if #tbl == 0 then 311aedd6be5SKyle Evans return nil, nil 3129f71d421SKyle Evans elseif #tbl == 1 then 313aedd6be5SKyle Evans return tbl[1], {} 3146d4ed94dSKyle Evans end 3156d4ed94dSKyle Evans 316aedd6be5SKyle Evans local first_value = tbl[1] 317aedd6be5SKyle Evans local new_tbl = {} 3186d4ed94dSKyle Evans -- This is not a cheap operation 3196d4ed94dSKyle Evans for k, v in ipairs(tbl) do 3209f71d421SKyle Evans if k > 1 then 321aedd6be5SKyle Evans new_tbl[k - 1] = v 3226d4ed94dSKyle Evans end 3236d4ed94dSKyle Evans end 3246d4ed94dSKyle Evans 325aedd6be5SKyle Evans return first_value, new_tbl 3266d4ed94dSKyle Evansend 3276d4ed94dSKyle Evans 3286f412147SKyle Evans-- On i386, hint.acpi.0.rsdp will be set before we're loaded. On !i386, it will 3296f412147SKyle Evans-- generally be set upon execution of the kernel. Because of this, we can't (or 3306f412147SKyle Evans-- don't really want to) detect/disable ACPI on !i386 reliably. Just set it 3316f412147SKyle Evans-- enabled if we detect it and leave well enough alone if we don't. 3329f71d421SKyle Evansif core.isSystem386() and core.getACPIPresent(false) then 333aedd6be5SKyle Evans core.setACPI(true) 3346f412147SKyle Evansend 335aedd6be5SKyle Evansreturn core 336