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