xref: /freebsd/stand/lua/core.lua (revision aedd6be5c7c3096828fafa6c1528f3966b9e3aa5)
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*aedd6be5SKyle Evanslocal config = require('config')
30fa4a2394SKyle Evans
31*aedd6be5SKyle Evanslocal core = {}
32088b4f5fSWarner Losh
336d4ed94dSKyle Evanslocal compose_loader_cmd = function(cmd_name, argstr)
346d4ed94dSKyle Evans	if (argstr ~= nil) then
35*aedd6be5SKyle Evans		cmd_name = cmd_name .. " " .. argstr
366d4ed94dSKyle Evans	end
37*aedd6be5SKyle 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)
46f0cb3b6bSKyle Evans	if (#argv == 0) then
47*aedd6be5SKyle Evans		return nil, ""
48f0cb3b6bSKyle Evans	end
496d3bcc06SKyle Evans	if (with_kernel == nil) then
50*aedd6be5SKyle Evans		with_kernel = true
516d3bcc06SKyle Evans	end
52*aedd6be5SKyle Evans	local kernel_name
53*aedd6be5SKyle Evans	local argstr = ""
54f0cb3b6bSKyle Evans
55f0cb3b6bSKyle Evans	for k, v in ipairs(argv) do
566d3bcc06SKyle Evans		if (with_kernel) and (v:sub(1,1) ~= "-") then
57*aedd6be5SKyle Evans			kernel_name = v
58f0cb3b6bSKyle Evans		else
59*aedd6be5SKyle Evans			argstr = argstr .. " " .. v
60f0cb3b6bSKyle Evans		end
61f0cb3b6bSKyle Evans	end
626d3bcc06SKyle Evans	if (with_kernel) then
63*aedd6be5SKyle Evans		return kernel_name, argstr
646d3bcc06SKyle Evans	else
65*aedd6be5SKyle Evans		return argstr
666d3bcc06SKyle Evans	end
67f0cb3b6bSKyle Evansend
68f0cb3b6bSKyle Evans
69f0cb3b6bSKyle Evans-- Globals
70f0cb3b6bSKyle Evansfunction boot(...)
71*aedd6be5SKyle Evans	local argv = {...}
72*aedd6be5SKyle Evans	local cmd_name = ""
73*aedd6be5SKyle Evans	cmd_name, argv = core.popFrontTable(argv)
74*aedd6be5SKyle Evans	local kernel, argstr = parse_boot_args(argv)
75f0cb3b6bSKyle Evans	if (kernel ~= nil) then
76*aedd6be5SKyle Evans		loader.perform("unload")
77*aedd6be5SKyle Evans		config.selectkernel(kernel)
78f0cb3b6bSKyle Evans	end
79*aedd6be5SKyle Evans	core.boot(argstr)
80f0cb3b6bSKyle Evansend
81f0cb3b6bSKyle Evans
826d3bcc06SKyle Evansfunction autoboot(...)
836d3bcc06SKyle Evans	local argv = {...}
84*aedd6be5SKyle Evans	local cmd_name = ""
85*aedd6be5SKyle Evans	cmd_name, argv = core.popFrontTable(argv)
86*aedd6be5SKyle Evans	local argstr = parse_boot_args(argv, false)
87*aedd6be5SKyle Evans	core.autoboot(argstr)
886d3bcc06SKyle Evansend
896d3bcc06SKyle Evans
90b5746545SKyle Evans-- Module exports
91fe672a15SKyle Evans-- Commonly appearing constants
92*aedd6be5SKyle Evanscore.KEY_BACKSPACE	= 8
93*aedd6be5SKyle Evanscore.KEY_ENTER		= 13
94*aedd6be5SKyle Evanscore.KEY_DELETE		= 127
95fe672a15SKyle Evans
96*aedd6be5SKyle Evanscore.KEYSTR_ESCAPE	= "\027"
9739006570SKyle Evans
98*aedd6be5SKyle Evanscore.MENU_RETURN	= "return"
99*aedd6be5SKyle Evanscore.MENU_ENTRY		= "entry"
100*aedd6be5SKyle Evanscore.MENU_SEPARATOR	= "separator"
101*aedd6be5SKyle Evanscore.MENU_SUBMENU	= "submenu"
102*aedd6be5SKyle Evanscore.MENU_CAROUSEL_ENTRY	= "carousel_entry"
103a7cf0562SKyle Evans
104088b4f5fSWarner Loshfunction core.setVerbose(b)
105088b4f5fSWarner Losh	if (b == nil) then
106*aedd6be5SKyle Evans		b = not core.verbose
107088b4f5fSWarner Losh	end
108088b4f5fSWarner Losh
109088b4f5fSWarner Losh	if (b == true) then
110*aedd6be5SKyle Evans		loader.setenv("boot_verbose", "YES")
111088b4f5fSWarner Losh	else
112*aedd6be5SKyle Evans		loader.unsetenv("boot_verbose")
113088b4f5fSWarner Losh	end
114*aedd6be5SKyle Evans	core.verbose = b
115088b4f5fSWarner Loshend
116088b4f5fSWarner Losh
117088b4f5fSWarner Loshfunction core.setSingleUser(b)
118088b4f5fSWarner Losh	if (b == nil) then
119*aedd6be5SKyle Evans		b = not core.su
120088b4f5fSWarner Losh	end
121088b4f5fSWarner Losh
122088b4f5fSWarner Losh	if (b == true) then
123*aedd6be5SKyle Evans		loader.setenv("boot_single", "YES")
124088b4f5fSWarner Losh	else
125*aedd6be5SKyle Evans		loader.unsetenv("boot_single")
126088b4f5fSWarner Losh	end
127*aedd6be5SKyle Evans	core.su = b
128088b4f5fSWarner Loshend
129088b4f5fSWarner Losh
1306401094fSKyle Evansfunction core.getACPIPresent(checkingSystemDefaults)
131*aedd6be5SKyle Evans	local c = loader.getenv("hint.acpi.0.rsdp")
1326401094fSKyle Evans
1336401094fSKyle Evans	if (c ~= nil) then
1346401094fSKyle Evans		if (checkingSystemDefaults == true) then
135*aedd6be5SKyle Evans			return true
1366401094fSKyle Evans		end
1376401094fSKyle Evans		-- Otherwise, respect disabled if it's set
138*aedd6be5SKyle Evans		c = loader.getenv("hint.acpi.0.disabled")
139*aedd6be5SKyle Evans		return (c == nil) or (tonumber(c) ~= 1)
1406401094fSKyle Evans	end
141*aedd6be5SKyle Evans	return false
1426401094fSKyle Evansend
1436401094fSKyle Evans
144088b4f5fSWarner Loshfunction core.setACPI(b)
145088b4f5fSWarner Losh	if (b == nil) then
146*aedd6be5SKyle Evans		b = not core.acpi
147088b4f5fSWarner Losh	end
148088b4f5fSWarner Losh
149088b4f5fSWarner Losh	if (b == true) then
150*aedd6be5SKyle Evans		loader.setenv("acpi_load", "YES")
151*aedd6be5SKyle Evans		loader.setenv("hint.acpi.0.disabled", "0")
152*aedd6be5SKyle Evans		loader.unsetenv("loader.acpi_disabled_by_user")
153088b4f5fSWarner Losh	else
154*aedd6be5SKyle Evans		loader.unsetenv("acpi_load")
155*aedd6be5SKyle Evans		loader.setenv("hint.acpi.0.disabled", "1")
156*aedd6be5SKyle Evans		loader.setenv("loader.acpi_disabled_by_user", "1")
157088b4f5fSWarner Losh	end
158*aedd6be5SKyle Evans	core.acpi = b
159088b4f5fSWarner Loshend
160088b4f5fSWarner Losh
161088b4f5fSWarner Loshfunction core.setSafeMode(b)
162088b4f5fSWarner Losh	if (b == nil) then
163*aedd6be5SKyle Evans		b = not core.sm
164088b4f5fSWarner Losh	end
165088b4f5fSWarner Losh	if (b == true) then
166*aedd6be5SKyle Evans		loader.setenv("kern.smp.disabled", "1")
167*aedd6be5SKyle Evans		loader.setenv("hw.ata.ata_dma", "0")
168*aedd6be5SKyle Evans		loader.setenv("hw.ata.atapi_dma", "0")
169*aedd6be5SKyle Evans		loader.setenv("hw.ata.wc", "0")
170*aedd6be5SKyle Evans		loader.setenv("hw.eisa_slots", "0")
171*aedd6be5SKyle Evans		loader.setenv("kern.eventtimer.periodic", "1")
172*aedd6be5SKyle Evans		loader.setenv("kern.geom.part.check_integrity", "0")
173088b4f5fSWarner Losh	else
174*aedd6be5SKyle Evans		loader.unsetenv("kern.smp.disabled")
175*aedd6be5SKyle Evans		loader.unsetenv("hw.ata.ata_dma")
176*aedd6be5SKyle Evans		loader.unsetenv("hw.ata.atapi_dma")
177*aedd6be5SKyle Evans		loader.unsetenv("hw.ata.wc")
178*aedd6be5SKyle Evans		loader.unsetenv("hw.eisa_slots")
179*aedd6be5SKyle Evans		loader.unsetenv("kern.eventtimer.periodic")
180*aedd6be5SKyle Evans		loader.unsetenv("kern.geom.part.check_integrity")
181088b4f5fSWarner Losh	end
182*aedd6be5SKyle Evans	core.sm = b
183088b4f5fSWarner Loshend
184088b4f5fSWarner Losh
185088b4f5fSWarner Loshfunction core.kernelList()
186*aedd6be5SKyle Evans	local k = loader.getenv("kernel")
187*aedd6be5SKyle Evans	local v = loader.getenv("kernels") or ""
188088b4f5fSWarner Losh
189*aedd6be5SKyle Evans	local kernels = {}
190*aedd6be5SKyle Evans	local unique = {}
191*aedd6be5SKyle Evans	local i = 0
19224a1bd54SKyle Evans	if (k ~= nil) then
193*aedd6be5SKyle Evans		i = i + 1
194*aedd6be5SKyle Evans		kernels[i] = k
195*aedd6be5SKyle Evans		unique[k] = true
196088b4f5fSWarner Losh	end
197088b4f5fSWarner Losh
198088b4f5fSWarner Losh	for n in v:gmatch("([^; ]+)[; ]?") do
199a108046fSConrad Meyer		if (unique[n] == nil) then
200*aedd6be5SKyle Evans			i = i + 1
201*aedd6be5SKyle Evans			kernels[i] = n
202*aedd6be5SKyle 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
210*aedd6be5SKyle Evans		local fname = "/boot/" .. file
211a108046fSConrad Meyer
212a108046fSConrad Meyer		if (file == "." or file == "..") then
213*aedd6be5SKyle Evans			goto continue
214a108046fSConrad Meyer		end
215a108046fSConrad Meyer
216a108046fSConrad Meyer		if (lfs.attributes(fname, "mode") ~= "directory") then
217*aedd6be5SKyle Evans			goto continue
218a108046fSConrad Meyer		end
219a108046fSConrad Meyer
220a108046fSConrad Meyer		if (lfs.attributes(fname .. "/kernel", "mode") ~= "file") then
221*aedd6be5SKyle Evans			goto continue
222a108046fSConrad Meyer		end
223a108046fSConrad Meyer
224a108046fSConrad Meyer		if (unique[file] == nil) then
225*aedd6be5SKyle Evans			i = i + 1
226*aedd6be5SKyle Evans			kernels[i] = file
227*aedd6be5SKyle Evans			unique[file] = true
228a108046fSConrad Meyer		end
229a108046fSConrad Meyer
230a108046fSConrad Meyer		::continue::
231a108046fSConrad Meyer	end
232*aedd6be5SKyle Evans	return kernels
233088b4f5fSWarner Loshend
234088b4f5fSWarner Losh
235088b4f5fSWarner Loshfunction core.setDefaults()
236*aedd6be5SKyle Evans	core.setACPI(core.getACPIPresent(true))
237*aedd6be5SKyle Evans	core.setSafeMode(false)
238*aedd6be5SKyle Evans	core.setSingleUser(false)
239*aedd6be5SKyle Evans	core.setVerbose(false)
240088b4f5fSWarner Loshend
241088b4f5fSWarner Losh
2426d4ed94dSKyle Evansfunction core.autoboot(argstr)
243*aedd6be5SKyle Evans	config.loadelf()
244*aedd6be5SKyle Evans	loader.perform(compose_loader_cmd("autoboot", argstr))
245088b4f5fSWarner Loshend
246088b4f5fSWarner Losh
2476d4ed94dSKyle Evansfunction core.boot(argstr)
248*aedd6be5SKyle Evans	config.loadelf()
249*aedd6be5SKyle Evans	loader.perform(compose_loader_cmd("boot", argstr))
250088b4f5fSWarner Loshend
251088b4f5fSWarner Losh
252e07fc39cSKyle Evansfunction core.isSingleUserBoot()
253*aedd6be5SKyle Evans	local single_user = loader.getenv("boot_single")
254*aedd6be5SKyle Evans	return single_user ~= nil and single_user:lower() == "yes"
255e07fc39cSKyle Evansend
256e07fc39cSKyle Evans
257b140d14bSKyle Evansfunction core.isSerialBoot()
258*aedd6be5SKyle Evans	local c = loader.getenv("console")
259088b4f5fSWarner Losh
26024a1bd54SKyle Evans	if (c ~= nil) then
26124a1bd54SKyle Evans		if (c:find("comconsole") ~= nil) then
262*aedd6be5SKyle Evans			return true
263088b4f5fSWarner Losh		end
264088b4f5fSWarner Losh	end
265088b4f5fSWarner Losh
266*aedd6be5SKyle Evans	local s = loader.getenv("boot_serial")
26724a1bd54SKyle Evans	if (s ~= nil) then
268*aedd6be5SKyle Evans		return true
269088b4f5fSWarner Losh	end
270088b4f5fSWarner Losh
271*aedd6be5SKyle Evans	local m = loader.getenv("boot_multicons")
27224a1bd54SKyle Evans	if (m ~= nil) then
273*aedd6be5SKyle Evans		return true
274088b4f5fSWarner Losh	end
275*aedd6be5SKyle Evans	return false
276088b4f5fSWarner Loshend
277088b4f5fSWarner Losh
278c1ab36f5SKyle Evansfunction core.isSystem386()
279*aedd6be5SKyle 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)
284*aedd6be5SKyle Evans	local new_tbl = {}
2855c1b5165SKyle Evans	for k, v in pairs(tbl) do
2865c1b5165SKyle Evans		if (type(v) == "table") then
287*aedd6be5SKyle Evans			new_tbl[k] = core.shallowCopyTable(v)
2885c1b5165SKyle Evans		else
289*aedd6be5SKyle Evans			new_tbl[k] = v
2905c1b5165SKyle Evans		end
2915c1b5165SKyle Evans	end
292*aedd6be5SKyle 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
3006d4ed94dSKyle Evans	if (#tbl == 0) then
301*aedd6be5SKyle Evans		return nil, nil
3026d4ed94dSKyle Evans	elseif (#tbl == 1) then
303*aedd6be5SKyle Evans		return tbl[1], {}
3046d4ed94dSKyle Evans	end
3056d4ed94dSKyle Evans
306*aedd6be5SKyle Evans	local first_value = tbl[1]
307*aedd6be5SKyle Evans	local new_tbl = {}
3086d4ed94dSKyle Evans	-- This is not a cheap operation
3096d4ed94dSKyle Evans	for k, v in ipairs(tbl) do
3106d4ed94dSKyle Evans		if (k > 1) then
311*aedd6be5SKyle Evans			new_tbl[k - 1] = v
3126d4ed94dSKyle Evans		end
3136d4ed94dSKyle Evans	end
3146d4ed94dSKyle Evans
315*aedd6be5SKyle 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.
322c1ab36f5SKyle Evansif (core.isSystem386()) and (core.getACPIPresent(false)) then
323*aedd6be5SKyle Evans	core.setACPI(true)
3246f412147SKyle Evansend
325*aedd6be5SKyle Evansreturn core
326