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