xref: /freebsd/stand/lua/core.lua (revision 1d38e553eb7c787f2a8a93ff8f3dd711df3a7d94)
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
49*1d38e553SKyle Evans	if #argv == 0 then
50*1d38e553SKyle Evans		if with_kernel then
51*1d38e553SKyle Evans			return nil, ""
52*1d38e553SKyle Evans		else
53*1d38e553SKyle Evans			return ""
54*1d38e553SKyle Evans		end
55*1d38e553SKyle 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")
191aedd6be5SKyle Evans	local v = loader.getenv("kernels") or ""
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
202088b4f5fSWarner Losh	for n in v:gmatch("([^; ]+)[; ]?") do
2039f71d421SKyle Evans		if unique[n] == nil then
204aedd6be5SKyle Evans			i = i + 1
205aedd6be5SKyle Evans			kernels[i] = n
206aedd6be5SKyle Evans			unique[n] = true
207088b4f5fSWarner Losh		end
208088b4f5fSWarner Losh	end
209a108046fSConrad Meyer
210a108046fSConrad Meyer	-- Automatically detect other bootable kernel directories using a
211a108046fSConrad Meyer	-- heuristic.  Any directory in /boot that contains an ordinary file
212a108046fSConrad Meyer	-- named "kernel" is considered eligible.
213a108046fSConrad Meyer	for file in lfs.dir("/boot") do
214aedd6be5SKyle Evans		local fname = "/boot/" .. file
215a108046fSConrad Meyer
2169f71d421SKyle Evans		if file == "." or file == ".." then
217aedd6be5SKyle Evans			goto continue
218a108046fSConrad Meyer		end
219a108046fSConrad Meyer
2209f71d421SKyle Evans		if lfs.attributes(fname, "mode") ~= "directory" then
221aedd6be5SKyle Evans			goto continue
222a108046fSConrad Meyer		end
223a108046fSConrad Meyer
2249f71d421SKyle Evans		if lfs.attributes(fname .. "/kernel", "mode") ~= "file" then
225aedd6be5SKyle Evans			goto continue
226a108046fSConrad Meyer		end
227a108046fSConrad Meyer
2289f71d421SKyle Evans		if unique[file] == nil then
229aedd6be5SKyle Evans			i = i + 1
230aedd6be5SKyle Evans			kernels[i] = file
231aedd6be5SKyle Evans			unique[file] = true
232a108046fSConrad Meyer		end
233a108046fSConrad Meyer
234a108046fSConrad Meyer		::continue::
235a108046fSConrad Meyer	end
236aedd6be5SKyle Evans	return kernels
237088b4f5fSWarner Loshend
238088b4f5fSWarner Losh
239088b4f5fSWarner Loshfunction core.setDefaults()
240aedd6be5SKyle Evans	core.setACPI(core.getACPIPresent(true))
241aedd6be5SKyle Evans	core.setSafeMode(false)
242aedd6be5SKyle Evans	core.setSingleUser(false)
243aedd6be5SKyle Evans	core.setVerbose(false)
244088b4f5fSWarner Loshend
245088b4f5fSWarner Losh
2466d4ed94dSKyle Evansfunction core.autoboot(argstr)
247aedd6be5SKyle Evans	config.loadelf()
248aedd6be5SKyle Evans	loader.perform(compose_loader_cmd("autoboot", argstr))
249088b4f5fSWarner Loshend
250088b4f5fSWarner Losh
2516d4ed94dSKyle Evansfunction core.boot(argstr)
252aedd6be5SKyle Evans	config.loadelf()
253aedd6be5SKyle Evans	loader.perform(compose_loader_cmd("boot", argstr))
254088b4f5fSWarner Loshend
255088b4f5fSWarner Losh
256e07fc39cSKyle Evansfunction core.isSingleUserBoot()
257aedd6be5SKyle Evans	local single_user = loader.getenv("boot_single")
258aedd6be5SKyle Evans	return single_user ~= nil and single_user:lower() == "yes"
259e07fc39cSKyle Evansend
260e07fc39cSKyle 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