]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/lua/core.lua
lualoader: Track the menu currently drawn, instead of validity
[FreeBSD/FreeBSD.git] / stand / lua / core.lua
1 --
2 -- SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 --
4 -- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org>
5 -- Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org>
6 -- All rights reserved.
7 --
8 -- Redistribution and use in source and binary forms, with or without
9 -- modification, are permitted provided that the following conditions
10 -- are met:
11 -- 1. Redistributions of source code must retain the above copyright
12 --    notice, this list of conditions and the following disclaimer.
13 -- 2. Redistributions in binary form must reproduce the above copyright
14 --    notice, this list of conditions and the following disclaimer in the
15 --    documentation and/or other materials provided with the distribution.
16 --
17 -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 -- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 -- ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 -- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 -- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 -- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 -- SUCH DAMAGE.
28 --
29 -- $FreeBSD$
30 --
31
32 local config = require("config")
33
34 local core = {}
35
36 local function composeLoaderCmd(cmd_name, argstr)
37         if argstr ~= nil then
38                 cmd_name = cmd_name .. " " .. argstr
39         end
40         return cmd_name
41 end
42
43 -- Module exports
44 -- Commonly appearing constants
45 core.KEY_BACKSPACE      = 8
46 core.KEY_ENTER          = 13
47 core.KEY_DELETE         = 127
48
49 core.KEYSTR_ESCAPE      = "\027"
50
51 core.MENU_RETURN        = "return"
52 core.MENU_ENTRY         = "entry"
53 core.MENU_SEPARATOR     = "separator"
54 core.MENU_SUBMENU       = "submenu"
55 core.MENU_CAROUSEL_ENTRY        = "carousel_entry"
56
57 function core.setVerbose(b)
58         if b == nil then
59                 b = not core.verbose
60         end
61
62         if b then
63                 loader.setenv("boot_verbose", "YES")
64         else
65                 loader.unsetenv("boot_verbose")
66         end
67         core.verbose = b
68 end
69
70 function core.setSingleUser(b)
71         if b == nil then
72                 b = not core.su
73         end
74
75         if b then
76                 loader.setenv("boot_single", "YES")
77         else
78                 loader.unsetenv("boot_single")
79         end
80         core.su = b
81 end
82
83 function core.getACPIPresent(checkingSystemDefaults)
84         local c = loader.getenv("hint.acpi.0.rsdp")
85
86         if c ~= nil then
87                 if checkingSystemDefaults then
88                         return true
89                 end
90                 -- Otherwise, respect disabled if it's set
91                 c = loader.getenv("hint.acpi.0.disabled")
92                 return c == nil or tonumber(c) ~= 1
93         end
94         return false
95 end
96
97 function core.setACPI(b)
98         if b == nil then
99                 b = not core.acpi
100         end
101
102         if b then
103                 loader.setenv("acpi_load", "YES")
104                 loader.setenv("hint.acpi.0.disabled", "0")
105                 loader.unsetenv("loader.acpi_disabled_by_user")
106         else
107                 loader.unsetenv("acpi_load")
108                 loader.setenv("hint.acpi.0.disabled", "1")
109                 loader.setenv("loader.acpi_disabled_by_user", "1")
110         end
111         core.acpi = b
112 end
113
114 function core.setSafeMode(b)
115         if b == nil then
116                 b = not core.sm
117         end
118         if b then
119                 loader.setenv("kern.smp.disabled", "1")
120                 loader.setenv("hw.ata.ata_dma", "0")
121                 loader.setenv("hw.ata.atapi_dma", "0")
122                 loader.setenv("hw.ata.wc", "0")
123                 loader.setenv("hw.eisa_slots", "0")
124                 loader.setenv("kern.eventtimer.periodic", "1")
125                 loader.setenv("kern.geom.part.check_integrity", "0")
126         else
127                 loader.unsetenv("kern.smp.disabled")
128                 loader.unsetenv("hw.ata.ata_dma")
129                 loader.unsetenv("hw.ata.atapi_dma")
130                 loader.unsetenv("hw.ata.wc")
131                 loader.unsetenv("hw.eisa_slots")
132                 loader.unsetenv("kern.eventtimer.periodic")
133                 loader.unsetenv("kern.geom.part.check_integrity")
134         end
135         core.sm = b
136 end
137
138 function core.kernelList()
139         local k = loader.getenv("kernel")
140         local v = loader.getenv("kernels")
141         local autodetect = loader.getenv("kernels_autodetect") or ""
142
143         local kernels = {}
144         local unique = {}
145         local i = 0
146         if k ~= nil then
147                 i = i + 1
148                 kernels[i] = k
149                 unique[k] = true
150         end
151
152         if v ~= nil then
153                 for n in v:gmatch("([^; ]+)[; ]?") do
154                         if unique[n] == nil then
155                                 i = i + 1
156                                 kernels[i] = n
157                                 unique[n] = true
158                         end
159                 end
160         end
161
162         -- Base whether we autodetect kernels or not on a loader.conf(5)
163         -- setting, kernels_autodetect. If it's set to 'yes', we'll add
164         -- any kernels we detect based on the criteria described.
165         if autodetect:lower() ~= "yes" then
166                 return kernels
167         end
168
169         -- Automatically detect other bootable kernel directories using a
170         -- heuristic.  Any directory in /boot that contains an ordinary file
171         -- named "kernel" is considered eligible.
172         for file in lfs.dir("/boot") do
173                 local fname = "/boot/" .. file
174
175                 if file == "." or file == ".." then
176                         goto continue
177                 end
178
179                 if lfs.attributes(fname, "mode") ~= "directory" then
180                         goto continue
181                 end
182
183                 if lfs.attributes(fname .. "/kernel", "mode") ~= "file" then
184                         goto continue
185                 end
186
187                 if unique[file] == nil then
188                         i = i + 1
189                         kernels[i] = file
190                         unique[file] = true
191                 end
192
193                 ::continue::
194         end
195         return kernels
196 end
197
198 function core.bootenvDefault()
199         return loader.getenv("zfs_be_active")
200 end
201
202 function core.bootenvList()
203         local bootenv_count = tonumber(loader.getenv("bootenvs_count"))
204         local bootenvs = {}
205         local curenv
206         local envcount = 0
207         local unique = {}
208
209         if bootenv_count == nil or bootenv_count <= 0 then
210                 return bootenvs
211         end
212
213         -- Currently selected bootenv is always first/default
214         curenv = core.bootenvDefault()
215         if curenv ~= nil then
216                 envcount = envcount + 1
217                 bootenvs[envcount] = curenv
218                 unique[curenv] = true
219         end
220
221         for curenv_idx = 0, bootenv_count - 1 do
222                 curenv = loader.getenv("bootenvs[" .. curenv_idx .. "]")
223                 if curenv ~= nil and unique[curenv] == nil then
224                         envcount = envcount + 1
225                         bootenvs[envcount] = curenv
226                         unique[curenv] = true
227                 end
228         end
229         return bootenvs
230 end
231
232 function core.setDefaults()
233         core.setACPI(core.getACPIPresent(true))
234         core.setSafeMode(false)
235         core.setSingleUser(false)
236         core.setVerbose(false)
237 end
238
239 function core.autoboot(argstr)
240         config.loadelf()
241         loader.perform(composeLoaderCmd("autoboot", argstr))
242 end
243
244 function core.boot(argstr)
245         config.loadelf()
246         loader.perform(composeLoaderCmd("boot", argstr))
247 end
248
249 function core.isSingleUserBoot()
250         local single_user = loader.getenv("boot_single")
251         return single_user ~= nil and single_user:lower() == "yes"
252 end
253
254 function core.isZFSBoot()
255         local c = loader.getenv("currdev")
256
257         if c ~= nil then
258                 return c:match("^zfs:") ~= nil
259         end
260         return false
261 end
262
263 function core.isSerialBoot()
264         local c = loader.getenv("console")
265
266         if c ~= nil then
267                 if c:find("comconsole") ~= nil then
268                         return true
269                 end
270         end
271
272         local s = loader.getenv("boot_serial")
273         if s ~= nil then
274                 return true
275         end
276
277         local m = loader.getenv("boot_multicons")
278         if m ~= nil then
279                 return true
280         end
281         return false
282 end
283
284 function core.isSystem386()
285         return loader.machine_arch == "i386"
286 end
287
288 -- This may be a better candidate for a 'utility' module.
289 function core.deepCopyTable(tbl)
290         local new_tbl = {}
291         for k, v in pairs(tbl) do
292                 if type(v) == "table" then
293                         new_tbl[k] = core.deepCopyTable(v)
294                 else
295                         new_tbl[k] = v
296                 end
297         end
298         return new_tbl
299 end
300
301 -- XXX This should go away if we get the table lib into shape for importing.
302 -- As of now, it requires some 'os' functions, so we'll implement this in lua
303 -- for our uses
304 function core.popFrontTable(tbl)
305         -- Shouldn't reasonably happen
306         if #tbl == 0 then
307                 return nil, nil
308         elseif #tbl == 1 then
309                 return tbl[1], {}
310         end
311
312         local first_value = tbl[1]
313         local new_tbl = {}
314         -- This is not a cheap operation
315         for k, v in ipairs(tbl) do
316                 if k > 1 then
317                         new_tbl[k - 1] = v
318                 end
319         end
320
321         return first_value, new_tbl
322 end
323
324 -- On i386, hint.acpi.0.rsdp will be set before we're loaded. On !i386, it will
325 -- generally be set upon execution of the kernel. Because of this, we can't (or
326 -- don't really want to) detect/disable ACPI on !i386 reliably. Just set it
327 -- enabled if we detect it and leave well enough alone if we don't.
328 if core.isSystem386() and core.getACPIPresent(false) then
329         core.setACPI(true)
330 end
331 return core