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 #argv == 0 then 47aedd6be5SKyle Evans return nil, "" 48f0cb3b6bSKyle Evans end 499f71d421SKyle Evans if with_kernel == nil then 50aedd6be5SKyle Evans with_kernel = true 516d3bcc06SKyle Evans end 52aedd6be5SKyle Evans local kernel_name 53aedd6be5SKyle Evans local argstr = "" 54f0cb3b6bSKyle Evans 55f0cb3b6bSKyle Evans for k, v in ipairs(argv) do 569f71d421SKyle Evans if with_kernel and v:sub(1,1) ~= "-" then 57aedd6be5SKyle Evans kernel_name = v 58f0cb3b6bSKyle Evans else 59aedd6be5SKyle Evans argstr = argstr .. " " .. v 60f0cb3b6bSKyle Evans end 61f0cb3b6bSKyle Evans end 629f71d421SKyle Evans if with_kernel then 63aedd6be5SKyle Evans return kernel_name, argstr 646d3bcc06SKyle Evans else 65aedd6be5SKyle Evans return argstr 666d3bcc06SKyle Evans end 67f0cb3b6bSKyle Evansend 68f0cb3b6bSKyle Evans 69f0cb3b6bSKyle Evans-- Globals 70f0cb3b6bSKyle Evansfunction boot(...) 71aedd6be5SKyle Evans local argv = {...} 72aedd6be5SKyle Evans local cmd_name = "" 73aedd6be5SKyle Evans cmd_name, argv = core.popFrontTable(argv) 74aedd6be5SKyle Evans local kernel, argstr = parse_boot_args(argv) 759f71d421SKyle Evans if kernel ~= nil then 76aedd6be5SKyle Evans loader.perform("unload") 77aedd6be5SKyle Evans config.selectkernel(kernel) 78f0cb3b6bSKyle Evans end 79aedd6be5SKyle Evans core.boot(argstr) 80f0cb3b6bSKyle Evansend 81f0cb3b6bSKyle Evans 826d3bcc06SKyle Evansfunction autoboot(...) 836d3bcc06SKyle Evans local argv = {...} 84aedd6be5SKyle Evans local cmd_name = "" 85aedd6be5SKyle Evans cmd_name, argv = core.popFrontTable(argv) 86aedd6be5SKyle Evans local argstr = parse_boot_args(argv, false) 87aedd6be5SKyle Evans core.autoboot(argstr) 886d3bcc06SKyle Evansend 896d3bcc06SKyle Evans 90b5746545SKyle Evans-- Module exports 91fe672a15SKyle Evans-- Commonly appearing constants 92aedd6be5SKyle Evanscore.KEY_BACKSPACE = 8 93aedd6be5SKyle Evanscore.KEY_ENTER = 13 94aedd6be5SKyle Evanscore.KEY_DELETE = 127 95fe672a15SKyle Evans 96aedd6be5SKyle Evanscore.KEYSTR_ESCAPE = "\027" 9739006570SKyle Evans 98aedd6be5SKyle Evanscore.MENU_RETURN = "return" 99aedd6be5SKyle Evanscore.MENU_ENTRY = "entry" 100aedd6be5SKyle Evanscore.MENU_SEPARATOR = "separator" 101aedd6be5SKyle Evanscore.MENU_SUBMENU = "submenu" 102aedd6be5SKyle Evanscore.MENU_CAROUSEL_ENTRY = "carousel_entry" 103a7cf0562SKyle Evans 104088b4f5fSWarner Loshfunction core.setVerbose(b) 1059f71d421SKyle Evans if b == nil then 106aedd6be5SKyle Evans b = not core.verbose 107088b4f5fSWarner Losh end 108088b4f5fSWarner Losh 109*49550489SKyle Evans if b then 110aedd6be5SKyle Evans loader.setenv("boot_verbose", "YES") 111088b4f5fSWarner Losh else 112aedd6be5SKyle Evans loader.unsetenv("boot_verbose") 113088b4f5fSWarner Losh end 114aedd6be5SKyle Evans core.verbose = b 115088b4f5fSWarner Loshend 116088b4f5fSWarner Losh 117088b4f5fSWarner Loshfunction core.setSingleUser(b) 1189f71d421SKyle Evans if b == nil then 119aedd6be5SKyle Evans b = not core.su 120088b4f5fSWarner Losh end 121088b4f5fSWarner Losh 122*49550489SKyle Evans if b then 123aedd6be5SKyle Evans loader.setenv("boot_single", "YES") 124088b4f5fSWarner Losh else 125aedd6be5SKyle Evans loader.unsetenv("boot_single") 126088b4f5fSWarner Losh end 127aedd6be5SKyle Evans core.su = b 128088b4f5fSWarner Loshend 129088b4f5fSWarner Losh 1306401094fSKyle Evansfunction core.getACPIPresent(checkingSystemDefaults) 131aedd6be5SKyle Evans local c = loader.getenv("hint.acpi.0.rsdp") 1326401094fSKyle Evans 1339f71d421SKyle Evans if c ~= nil then 134*49550489SKyle Evans if checkingSystemDefaults then 135aedd6be5SKyle Evans return true 1366401094fSKyle Evans end 1376401094fSKyle Evans -- Otherwise, respect disabled if it's set 138aedd6be5SKyle Evans c = loader.getenv("hint.acpi.0.disabled") 1399f71d421SKyle Evans return c == nil or tonumber(c) ~= 1 1406401094fSKyle Evans end 141aedd6be5SKyle Evans return false 1426401094fSKyle Evansend 1436401094fSKyle Evans 144088b4f5fSWarner Loshfunction core.setACPI(b) 1459f71d421SKyle Evans if b == nil then 146aedd6be5SKyle Evans b = not core.acpi 147088b4f5fSWarner Losh end 148088b4f5fSWarner Losh 149*49550489SKyle Evans if b then 150aedd6be5SKyle Evans loader.setenv("acpi_load", "YES") 151aedd6be5SKyle Evans loader.setenv("hint.acpi.0.disabled", "0") 152aedd6be5SKyle Evans loader.unsetenv("loader.acpi_disabled_by_user") 153088b4f5fSWarner Losh else 154aedd6be5SKyle Evans loader.unsetenv("acpi_load") 155aedd6be5SKyle Evans loader.setenv("hint.acpi.0.disabled", "1") 156aedd6be5SKyle Evans loader.setenv("loader.acpi_disabled_by_user", "1") 157088b4f5fSWarner Losh end 158aedd6be5SKyle Evans core.acpi = b 159088b4f5fSWarner Loshend 160088b4f5fSWarner Losh 161088b4f5fSWarner Loshfunction core.setSafeMode(b) 1629f71d421SKyle Evans if b == nil then 163aedd6be5SKyle Evans b = not core.sm 164088b4f5fSWarner Losh end 165*49550489SKyle Evans if b then 166aedd6be5SKyle Evans loader.setenv("kern.smp.disabled", "1") 167aedd6be5SKyle Evans loader.setenv("hw.ata.ata_dma", "0") 168aedd6be5SKyle Evans loader.setenv("hw.ata.atapi_dma", "0") 169aedd6be5SKyle Evans loader.setenv("hw.ata.wc", "0") 170aedd6be5SKyle Evans loader.setenv("hw.eisa_slots", "0") 171aedd6be5SKyle Evans loader.setenv("kern.eventtimer.periodic", "1") 172aedd6be5SKyle Evans loader.setenv("kern.geom.part.check_integrity", "0") 173088b4f5fSWarner Losh else 174aedd6be5SKyle Evans loader.unsetenv("kern.smp.disabled") 175aedd6be5SKyle Evans loader.unsetenv("hw.ata.ata_dma") 176aedd6be5SKyle Evans loader.unsetenv("hw.ata.atapi_dma") 177aedd6be5SKyle Evans loader.unsetenv("hw.ata.wc") 178aedd6be5SKyle Evans loader.unsetenv("hw.eisa_slots") 179aedd6be5SKyle Evans loader.unsetenv("kern.eventtimer.periodic") 180aedd6be5SKyle Evans loader.unsetenv("kern.geom.part.check_integrity") 181088b4f5fSWarner Losh end 182aedd6be5SKyle Evans core.sm = b 183088b4f5fSWarner Loshend 184088b4f5fSWarner Losh 185088b4f5fSWarner Loshfunction core.kernelList() 186aedd6be5SKyle Evans local k = loader.getenv("kernel") 187aedd6be5SKyle Evans local v = loader.getenv("kernels") or "" 188088b4f5fSWarner Losh 189aedd6be5SKyle Evans local kernels = {} 190aedd6be5SKyle Evans local unique = {} 191aedd6be5SKyle Evans local i = 0 1929f71d421SKyle Evans if k ~= nil then 193aedd6be5SKyle Evans i = i + 1 194aedd6be5SKyle Evans kernels[i] = k 195aedd6be5SKyle Evans unique[k] = true 196088b4f5fSWarner Losh end 197088b4f5fSWarner Losh 198088b4f5fSWarner Losh for n in v:gmatch("([^; ]+)[; ]?") do 1999f71d421SKyle Evans if unique[n] == nil then 200aedd6be5SKyle Evans i = i + 1 201aedd6be5SKyle Evans kernels[i] = n 202aedd6be5SKyle Evans unique[n] = true 203088b4f5fSWarner Losh end 204088b4f5fSWarner Losh end 205a108046fSConrad Meyer 206a108046fSConrad Meyer -- Automatically detect other bootable kernel directories using a 207a108046fSConrad Meyer -- heuristic. Any directory in /boot that contains an ordinary file 208a108046fSConrad Meyer -- named "kernel" is considered eligible. 209a108046fSConrad Meyer for file in lfs.dir("/boot") do 210aedd6be5SKyle Evans local fname = "/boot/" .. file 211a108046fSConrad Meyer 2129f71d421SKyle Evans if file == "." or file == ".." then 213aedd6be5SKyle Evans goto continue 214a108046fSConrad Meyer end 215a108046fSConrad Meyer 2169f71d421SKyle Evans if lfs.attributes(fname, "mode") ~= "directory" then 217aedd6be5SKyle Evans goto continue 218a108046fSConrad Meyer end 219a108046fSConrad Meyer 2209f71d421SKyle Evans if lfs.attributes(fname .. "/kernel", "mode") ~= "file" then 221aedd6be5SKyle Evans goto continue 222a108046fSConrad Meyer end 223a108046fSConrad Meyer 2249f71d421SKyle Evans if unique[file] == nil then 225aedd6be5SKyle Evans i = i + 1 226aedd6be5SKyle Evans kernels[i] = file 227aedd6be5SKyle Evans unique[file] = true 228a108046fSConrad Meyer end 229a108046fSConrad Meyer 230a108046fSConrad Meyer ::continue:: 231a108046fSConrad Meyer end 232aedd6be5SKyle Evans return kernels 233088b4f5fSWarner Loshend 234088b4f5fSWarner Losh 235088b4f5fSWarner Loshfunction core.setDefaults() 236aedd6be5SKyle Evans core.setACPI(core.getACPIPresent(true)) 237aedd6be5SKyle Evans core.setSafeMode(false) 238aedd6be5SKyle Evans core.setSingleUser(false) 239aedd6be5SKyle Evans core.setVerbose(false) 240088b4f5fSWarner Loshend 241088b4f5fSWarner Losh 2426d4ed94dSKyle Evansfunction core.autoboot(argstr) 243aedd6be5SKyle Evans config.loadelf() 244aedd6be5SKyle Evans loader.perform(compose_loader_cmd("autoboot", argstr)) 245088b4f5fSWarner Loshend 246088b4f5fSWarner Losh 2476d4ed94dSKyle Evansfunction core.boot(argstr) 248aedd6be5SKyle Evans config.loadelf() 249aedd6be5SKyle Evans loader.perform(compose_loader_cmd("boot", argstr)) 250088b4f5fSWarner Loshend 251088b4f5fSWarner Losh 252e07fc39cSKyle Evansfunction core.isSingleUserBoot() 253aedd6be5SKyle Evans local single_user = loader.getenv("boot_single") 254aedd6be5SKyle Evans return single_user ~= nil and single_user:lower() == "yes" 255e07fc39cSKyle Evansend 256e07fc39cSKyle Evans 257b140d14bSKyle Evansfunction core.isSerialBoot() 258aedd6be5SKyle Evans local c = loader.getenv("console") 259088b4f5fSWarner Losh 2609f71d421SKyle Evans if c ~= nil then 2619f71d421SKyle Evans if c:find("comconsole") ~= nil then 262aedd6be5SKyle Evans return true 263088b4f5fSWarner Losh end 264088b4f5fSWarner Losh end 265088b4f5fSWarner Losh 266aedd6be5SKyle Evans local s = loader.getenv("boot_serial") 2679f71d421SKyle Evans if s ~= nil then 268aedd6be5SKyle Evans return true 269088b4f5fSWarner Losh end 270088b4f5fSWarner Losh 271aedd6be5SKyle Evans local m = loader.getenv("boot_multicons") 2729f71d421SKyle Evans if m ~= nil then 273aedd6be5SKyle Evans return true 274088b4f5fSWarner Losh end 275aedd6be5SKyle Evans return false 276088b4f5fSWarner Loshend 277088b4f5fSWarner Losh 278c1ab36f5SKyle Evansfunction core.isSystem386() 2799f71d421SKyle Evans return loader.machine_arch == "i386" 280c1ab36f5SKyle Evansend 281c1ab36f5SKyle Evans 2825c1b5165SKyle Evans-- This may be a better candidate for a 'utility' module. 2835c1b5165SKyle Evansfunction core.shallowCopyTable(tbl) 284aedd6be5SKyle Evans local new_tbl = {} 2855c1b5165SKyle Evans for k, v in pairs(tbl) do 2869f71d421SKyle Evans if type(v) == "table" then 287aedd6be5SKyle Evans new_tbl[k] = core.shallowCopyTable(v) 2885c1b5165SKyle Evans else 289aedd6be5SKyle Evans new_tbl[k] = v 2905c1b5165SKyle Evans end 2915c1b5165SKyle Evans end 292aedd6be5SKyle Evans return new_tbl 2935c1b5165SKyle Evansend 2945c1b5165SKyle Evans 2956d4ed94dSKyle Evans-- XXX This should go away if we get the table lib into shape for importing. 2966d4ed94dSKyle Evans-- As of now, it requires some 'os' functions, so we'll implement this in lua 2976d4ed94dSKyle Evans-- for our uses 2986d4ed94dSKyle Evansfunction core.popFrontTable(tbl) 2996d4ed94dSKyle Evans -- Shouldn't reasonably happen 3009f71d421SKyle Evans if #tbl == 0 then 301aedd6be5SKyle Evans return nil, nil 3029f71d421SKyle Evans elseif #tbl == 1 then 303aedd6be5SKyle Evans return tbl[1], {} 3046d4ed94dSKyle Evans end 3056d4ed94dSKyle Evans 306aedd6be5SKyle Evans local first_value = tbl[1] 307aedd6be5SKyle Evans local new_tbl = {} 3086d4ed94dSKyle Evans -- This is not a cheap operation 3096d4ed94dSKyle Evans for k, v in ipairs(tbl) do 3109f71d421SKyle Evans if k > 1 then 311aedd6be5SKyle Evans new_tbl[k - 1] = v 3126d4ed94dSKyle Evans end 3136d4ed94dSKyle Evans end 3146d4ed94dSKyle Evans 315aedd6be5SKyle Evans return first_value, new_tbl 3166d4ed94dSKyle Evansend 3176d4ed94dSKyle Evans 3186f412147SKyle Evans-- On i386, hint.acpi.0.rsdp will be set before we're loaded. On !i386, it will 3196f412147SKyle Evans-- generally be set upon execution of the kernel. Because of this, we can't (or 3206f412147SKyle Evans-- don't really want to) detect/disable ACPI on !i386 reliably. Just set it 3216f412147SKyle Evans-- enabled if we detect it and leave well enough alone if we don't. 3229f71d421SKyle Evansif core.isSystem386() and core.getACPIPresent(false) then 323aedd6be5SKyle Evans core.setACPI(true) 3246f412147SKyle Evansend 325aedd6be5SKyle Evansreturn core 326