xref: /freebsd/stand/lua/core.lua (revision 72e39d711d5300beb8f7fa07c17c62d88e2a31b6)
1088b4f5fSWarner Losh--
2*72e39d71SKyle Evans-- SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*72e39d71SKyle Evans--
4088b4f5fSWarner Losh-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org>
5088b4f5fSWarner Losh-- All rights reserved.
6088b4f5fSWarner Losh--
7088b4f5fSWarner Losh-- Redistribution and use in source and binary forms, with or without
8088b4f5fSWarner Losh-- modification, are permitted provided that the following conditions
9088b4f5fSWarner Losh-- are met:
10088b4f5fSWarner Losh-- 1. Redistributions of source code must retain the above copyright
11088b4f5fSWarner Losh--    notice, this list of conditions and the following disclaimer.
12088b4f5fSWarner Losh-- 2. Redistributions in binary form must reproduce the above copyright
13088b4f5fSWarner Losh--    notice, this list of conditions and the following disclaimer in the
14088b4f5fSWarner Losh--    documentation and/or other materials provided with the distribution.
15088b4f5fSWarner Losh--
16088b4f5fSWarner Losh-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17088b4f5fSWarner Losh-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18088b4f5fSWarner Losh-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19088b4f5fSWarner Losh-- ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20088b4f5fSWarner Losh-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21088b4f5fSWarner Losh-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22088b4f5fSWarner Losh-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23088b4f5fSWarner Losh-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24088b4f5fSWarner Losh-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25088b4f5fSWarner Losh-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26088b4f5fSWarner Losh-- SUCH DAMAGE.
27088b4f5fSWarner Losh--
28088b4f5fSWarner Losh-- $FreeBSD$
29088b4f5fSWarner Losh--
30088b4f5fSWarner Losh
31011eae6cSKyle Evanslocal config = require("config")
32fa4a2394SKyle Evans
33aedd6be5SKyle Evanslocal core = {}
34088b4f5fSWarner Losh
356d4ed94dSKyle Evanslocal compose_loader_cmd = function(cmd_name, argstr)
369f71d421SKyle Evans	if argstr ~= nil then
37aedd6be5SKyle Evans		cmd_name = cmd_name .. " " .. argstr
386d4ed94dSKyle Evans	end
39aedd6be5SKyle Evans	return cmd_name
406d4ed94dSKyle Evansend
416d4ed94dSKyle Evans
42b5746545SKyle Evans-- Module exports
43fe672a15SKyle Evans-- Commonly appearing constants
44aedd6be5SKyle Evanscore.KEY_BACKSPACE	= 8
45aedd6be5SKyle Evanscore.KEY_ENTER		= 13
46aedd6be5SKyle Evanscore.KEY_DELETE		= 127
47fe672a15SKyle Evans
48aedd6be5SKyle Evanscore.KEYSTR_ESCAPE	= "\027"
4939006570SKyle Evans
50aedd6be5SKyle Evanscore.MENU_RETURN	= "return"
51aedd6be5SKyle Evanscore.MENU_ENTRY		= "entry"
52aedd6be5SKyle Evanscore.MENU_SEPARATOR	= "separator"
53aedd6be5SKyle Evanscore.MENU_SUBMENU	= "submenu"
54aedd6be5SKyle Evanscore.MENU_CAROUSEL_ENTRY	= "carousel_entry"
55a7cf0562SKyle Evans
56088b4f5fSWarner Loshfunction core.setVerbose(b)
579f71d421SKyle Evans	if b == nil then
58aedd6be5SKyle Evans		b = not core.verbose
59088b4f5fSWarner Losh	end
60088b4f5fSWarner Losh
6149550489SKyle Evans	if b then
62aedd6be5SKyle Evans		loader.setenv("boot_verbose", "YES")
63088b4f5fSWarner Losh	else
64aedd6be5SKyle Evans		loader.unsetenv("boot_verbose")
65088b4f5fSWarner Losh	end
66aedd6be5SKyle Evans	core.verbose = b
67088b4f5fSWarner Loshend
68088b4f5fSWarner Losh
69088b4f5fSWarner Loshfunction core.setSingleUser(b)
709f71d421SKyle Evans	if b == nil then
71aedd6be5SKyle Evans		b = not core.su
72088b4f5fSWarner Losh	end
73088b4f5fSWarner Losh
7449550489SKyle Evans	if b then
75aedd6be5SKyle Evans		loader.setenv("boot_single", "YES")
76088b4f5fSWarner Losh	else
77aedd6be5SKyle Evans		loader.unsetenv("boot_single")
78088b4f5fSWarner Losh	end
79aedd6be5SKyle Evans	core.su = b
80088b4f5fSWarner Loshend
81088b4f5fSWarner Losh
826401094fSKyle Evansfunction core.getACPIPresent(checkingSystemDefaults)
83aedd6be5SKyle Evans	local c = loader.getenv("hint.acpi.0.rsdp")
846401094fSKyle Evans
859f71d421SKyle Evans	if c ~= nil then
8649550489SKyle Evans		if checkingSystemDefaults then
87aedd6be5SKyle Evans			return true
886401094fSKyle Evans		end
896401094fSKyle Evans		-- Otherwise, respect disabled if it's set
90aedd6be5SKyle Evans		c = loader.getenv("hint.acpi.0.disabled")
919f71d421SKyle Evans		return c == nil or tonumber(c) ~= 1
926401094fSKyle Evans	end
93aedd6be5SKyle Evans	return false
946401094fSKyle Evansend
956401094fSKyle Evans
96088b4f5fSWarner Loshfunction core.setACPI(b)
979f71d421SKyle Evans	if b == nil then
98aedd6be5SKyle Evans		b = not core.acpi
99088b4f5fSWarner Losh	end
100088b4f5fSWarner Losh
10149550489SKyle Evans	if b then
102aedd6be5SKyle Evans		loader.setenv("acpi_load", "YES")
103aedd6be5SKyle Evans		loader.setenv("hint.acpi.0.disabled", "0")
104aedd6be5SKyle Evans		loader.unsetenv("loader.acpi_disabled_by_user")
105088b4f5fSWarner Losh	else
106aedd6be5SKyle Evans		loader.unsetenv("acpi_load")
107aedd6be5SKyle Evans		loader.setenv("hint.acpi.0.disabled", "1")
108aedd6be5SKyle Evans		loader.setenv("loader.acpi_disabled_by_user", "1")
109088b4f5fSWarner Losh	end
110aedd6be5SKyle Evans	core.acpi = b
111088b4f5fSWarner Loshend
112088b4f5fSWarner Losh
113088b4f5fSWarner Loshfunction core.setSafeMode(b)
1149f71d421SKyle Evans	if b == nil then
115aedd6be5SKyle Evans		b = not core.sm
116088b4f5fSWarner Losh	end
11749550489SKyle Evans	if b then
118aedd6be5SKyle Evans		loader.setenv("kern.smp.disabled", "1")
119aedd6be5SKyle Evans		loader.setenv("hw.ata.ata_dma", "0")
120aedd6be5SKyle Evans		loader.setenv("hw.ata.atapi_dma", "0")
121aedd6be5SKyle Evans		loader.setenv("hw.ata.wc", "0")
122aedd6be5SKyle Evans		loader.setenv("hw.eisa_slots", "0")
123aedd6be5SKyle Evans		loader.setenv("kern.eventtimer.periodic", "1")
124aedd6be5SKyle Evans		loader.setenv("kern.geom.part.check_integrity", "0")
125088b4f5fSWarner Losh	else
126aedd6be5SKyle Evans		loader.unsetenv("kern.smp.disabled")
127aedd6be5SKyle Evans		loader.unsetenv("hw.ata.ata_dma")
128aedd6be5SKyle Evans		loader.unsetenv("hw.ata.atapi_dma")
129aedd6be5SKyle Evans		loader.unsetenv("hw.ata.wc")
130aedd6be5SKyle Evans		loader.unsetenv("hw.eisa_slots")
131aedd6be5SKyle Evans		loader.unsetenv("kern.eventtimer.periodic")
132aedd6be5SKyle Evans		loader.unsetenv("kern.geom.part.check_integrity")
133088b4f5fSWarner Losh	end
134aedd6be5SKyle Evans	core.sm = b
135088b4f5fSWarner Loshend
136088b4f5fSWarner Losh
137088b4f5fSWarner Loshfunction core.kernelList()
138aedd6be5SKyle Evans	local k = loader.getenv("kernel")
1393f4eb56bSKyle Evans	local v = loader.getenv("kernels")
1403889e6cdSKyle Evans	local autodetect = loader.getenv("kernels_autodetect") or ""
141088b4f5fSWarner Losh
142aedd6be5SKyle Evans	local kernels = {}
143aedd6be5SKyle Evans	local unique = {}
144aedd6be5SKyle Evans	local i = 0
1459f71d421SKyle Evans	if k ~= nil then
146aedd6be5SKyle Evans		i = i + 1
147aedd6be5SKyle Evans		kernels[i] = k
148aedd6be5SKyle Evans		unique[k] = true
149088b4f5fSWarner Losh	end
150088b4f5fSWarner Losh
1513f4eb56bSKyle Evans	if v ~= nil then
152088b4f5fSWarner Losh		for n in v:gmatch("([^; ]+)[; ]?") do
1539f71d421SKyle Evans			if unique[n] == nil then
154aedd6be5SKyle Evans				i = i + 1
155aedd6be5SKyle Evans				kernels[i] = n
156aedd6be5SKyle Evans				unique[n] = true
157088b4f5fSWarner Losh			end
158088b4f5fSWarner Losh		end
1593889e6cdSKyle Evans	end
160a108046fSConrad Meyer
1613889e6cdSKyle Evans	-- Base whether we autodetect kernels or not on a loader.conf(5)
1623889e6cdSKyle Evans	-- setting, kernels_autodetect. If it's set to 'yes', we'll add
1633889e6cdSKyle Evans	-- any kernels we detect based on the criteria described.
1643889e6cdSKyle Evans	if autodetect:lower() ~= "yes" then
1653f4eb56bSKyle Evans		return kernels
1663f4eb56bSKyle Evans	end
1673f4eb56bSKyle Evans
168a108046fSConrad Meyer	-- Automatically detect other bootable kernel directories using a
169a108046fSConrad Meyer	-- heuristic.  Any directory in /boot that contains an ordinary file
170a108046fSConrad Meyer	-- named "kernel" is considered eligible.
171a108046fSConrad Meyer	for file in lfs.dir("/boot") do
172aedd6be5SKyle Evans		local fname = "/boot/" .. file
173a108046fSConrad Meyer
1749f71d421SKyle Evans		if file == "." or file == ".." then
175aedd6be5SKyle Evans			goto continue
176a108046fSConrad Meyer		end
177a108046fSConrad Meyer
1789f71d421SKyle Evans		if lfs.attributes(fname, "mode") ~= "directory" then
179aedd6be5SKyle Evans			goto continue
180a108046fSConrad Meyer		end
181a108046fSConrad Meyer
1829f71d421SKyle Evans		if lfs.attributes(fname .. "/kernel", "mode") ~= "file" then
183aedd6be5SKyle Evans			goto continue
184a108046fSConrad Meyer		end
185a108046fSConrad Meyer
1869f71d421SKyle Evans		if unique[file] == nil then
187aedd6be5SKyle Evans			i = i + 1
188aedd6be5SKyle Evans			kernels[i] = file
189aedd6be5SKyle Evans			unique[file] = true
190a108046fSConrad Meyer		end
191a108046fSConrad Meyer
192a108046fSConrad Meyer		::continue::
193a108046fSConrad Meyer	end
194aedd6be5SKyle Evans	return kernels
195088b4f5fSWarner Loshend
196088b4f5fSWarner Losh
1977efc058fSKyle Evansfunction core.bootenvDefault()
1987efc058fSKyle Evans	return loader.getenv("zfs_be_active")
1997efc058fSKyle Evansend
2007efc058fSKyle Evans
2017efc058fSKyle Evansfunction core.bootenvList()
2027efc058fSKyle Evans	local bootenv_count = tonumber(loader.getenv("bootenvs_count"))
2037efc058fSKyle Evans	local bootenvs = {}
2047efc058fSKyle Evans	local curenv
2057efc058fSKyle Evans	local envcount = 0
2067efc058fSKyle Evans	local unique = {}
2077efc058fSKyle Evans
2087efc058fSKyle Evans	if bootenv_count == nil or bootenv_count <= 0 then
2097efc058fSKyle Evans		return bootenvs
2107efc058fSKyle Evans	end
2117efc058fSKyle Evans
2127efc058fSKyle Evans	-- Currently selected bootenv is always first/default
2137efc058fSKyle Evans	curenv = core.bootenvDefault()
2147efc058fSKyle Evans	if curenv ~= nil then
2157efc058fSKyle Evans		envcount = envcount + 1
2167efc058fSKyle Evans		bootenvs[envcount] = curenv
2177efc058fSKyle Evans		unique[curenv] = true
2187efc058fSKyle Evans	end
2197efc058fSKyle Evans
2207efc058fSKyle Evans	for curenv_idx = 0, bootenv_count - 1 do
2217efc058fSKyle Evans		curenv = loader.getenv("bootenvs[" .. curenv_idx .. "]")
2227efc058fSKyle Evans		if curenv ~= nil and unique[curenv] == nil then
2237efc058fSKyle Evans			envcount = envcount + 1
2247efc058fSKyle Evans			bootenvs[envcount] = curenv
2257efc058fSKyle Evans			unique[curenv] = true
2267efc058fSKyle Evans		end
2277efc058fSKyle Evans	end
2287efc058fSKyle Evans	return bootenvs
2297efc058fSKyle Evansend
2307efc058fSKyle Evans
231088b4f5fSWarner Loshfunction core.setDefaults()
232aedd6be5SKyle Evans	core.setACPI(core.getACPIPresent(true))
233aedd6be5SKyle Evans	core.setSafeMode(false)
234aedd6be5SKyle Evans	core.setSingleUser(false)
235aedd6be5SKyle Evans	core.setVerbose(false)
236088b4f5fSWarner Loshend
237088b4f5fSWarner Losh
2386d4ed94dSKyle Evansfunction core.autoboot(argstr)
239aedd6be5SKyle Evans	config.loadelf()
240aedd6be5SKyle Evans	loader.perform(compose_loader_cmd("autoboot", argstr))
241088b4f5fSWarner Loshend
242088b4f5fSWarner Losh
2436d4ed94dSKyle Evansfunction core.boot(argstr)
244aedd6be5SKyle Evans	config.loadelf()
245aedd6be5SKyle Evans	loader.perform(compose_loader_cmd("boot", argstr))
246088b4f5fSWarner Loshend
247088b4f5fSWarner Losh
248e07fc39cSKyle Evansfunction core.isSingleUserBoot()
249aedd6be5SKyle Evans	local single_user = loader.getenv("boot_single")
250aedd6be5SKyle Evans	return single_user ~= nil and single_user:lower() == "yes"
251e07fc39cSKyle Evansend
252e07fc39cSKyle Evans
2537efc058fSKyle Evansfunction core.isZFSBoot()
2547efc058fSKyle Evans	local c = loader.getenv("currdev")
2557efc058fSKyle Evans
2567efc058fSKyle Evans	if c ~= nil then
2577efc058fSKyle Evans		return c:match("^zfs:") ~= nil
2587efc058fSKyle Evans	end
2597efc058fSKyle Evans	return false
2607efc058fSKyle Evansend
2617efc058fSKyle Evans
262b140d14bSKyle Evansfunction core.isSerialBoot()
263aedd6be5SKyle Evans	local c = loader.getenv("console")
264088b4f5fSWarner Losh
2659f71d421SKyle Evans	if c ~= nil then
2669f71d421SKyle Evans		if c:find("comconsole") ~= nil then
267aedd6be5SKyle Evans			return true
268088b4f5fSWarner Losh		end
269088b4f5fSWarner Losh	end
270088b4f5fSWarner Losh
271aedd6be5SKyle Evans	local s = loader.getenv("boot_serial")
2729f71d421SKyle Evans	if s ~= nil then
273aedd6be5SKyle Evans		return true
274088b4f5fSWarner Losh	end
275088b4f5fSWarner Losh
276aedd6be5SKyle Evans	local m = loader.getenv("boot_multicons")
2779f71d421SKyle Evans	if m ~= nil then
278aedd6be5SKyle Evans		return true
279088b4f5fSWarner Losh	end
280aedd6be5SKyle Evans	return false
281088b4f5fSWarner Loshend
282088b4f5fSWarner Losh
283c1ab36f5SKyle Evansfunction core.isSystem386()
2849f71d421SKyle Evans	return loader.machine_arch == "i386"
285c1ab36f5SKyle Evansend
286c1ab36f5SKyle Evans
2875c1b5165SKyle Evans-- This may be a better candidate for a 'utility' module.
2885c1b5165SKyle Evansfunction core.shallowCopyTable(tbl)
289aedd6be5SKyle Evans	local new_tbl = {}
2905c1b5165SKyle Evans	for k, v in pairs(tbl) do
2919f71d421SKyle Evans		if type(v) == "table" then
292aedd6be5SKyle Evans			new_tbl[k] = core.shallowCopyTable(v)
2935c1b5165SKyle Evans		else
294aedd6be5SKyle Evans			new_tbl[k] = v
2955c1b5165SKyle Evans		end
2965c1b5165SKyle Evans	end
297aedd6be5SKyle Evans	return new_tbl
2985c1b5165SKyle Evansend
2995c1b5165SKyle Evans
3006d4ed94dSKyle Evans-- XXX This should go away if we get the table lib into shape for importing.
3016d4ed94dSKyle Evans-- As of now, it requires some 'os' functions, so we'll implement this in lua
3026d4ed94dSKyle Evans-- for our uses
3036d4ed94dSKyle Evansfunction core.popFrontTable(tbl)
3046d4ed94dSKyle Evans	-- Shouldn't reasonably happen
3059f71d421SKyle Evans	if #tbl == 0 then
306aedd6be5SKyle Evans		return nil, nil
3079f71d421SKyle Evans	elseif #tbl == 1 then
308aedd6be5SKyle Evans		return tbl[1], {}
3096d4ed94dSKyle Evans	end
3106d4ed94dSKyle Evans
311aedd6be5SKyle Evans	local first_value = tbl[1]
312aedd6be5SKyle Evans	local new_tbl = {}
3136d4ed94dSKyle Evans	-- This is not a cheap operation
3146d4ed94dSKyle Evans	for k, v in ipairs(tbl) do
3159f71d421SKyle Evans		if k > 1 then
316aedd6be5SKyle Evans			new_tbl[k - 1] = v
3176d4ed94dSKyle Evans		end
3186d4ed94dSKyle Evans	end
3196d4ed94dSKyle Evans
320aedd6be5SKyle Evans	return first_value, new_tbl
3216d4ed94dSKyle Evansend
3226d4ed94dSKyle Evans
3236f412147SKyle Evans-- On i386, hint.acpi.0.rsdp will be set before we're loaded. On !i386, it will
3246f412147SKyle Evans-- generally be set upon execution of the kernel. Because of this, we can't (or
3256f412147SKyle Evans-- don't really want to) detect/disable ACPI on !i386 reliably. Just set it
3266f412147SKyle Evans-- enabled if we detect it and leave well enough alone if we don't.
3279f71d421SKyle Evansif core.isSystem386() and core.getACPIPresent(false) then
328aedd6be5SKyle Evans	core.setACPI(true)
3296f412147SKyle Evansend
330aedd6be5SKyle Evansreturn core
331