xref: /freebsd/stand/lua/core.lua (revision 011eae6c576481685784c6e0afec414c5af92e19)
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