core.lua (6d3bcc06e27a9f0c860770442b50dd9650dc8e24) core.lua (aedd6be5c7c3096828fafa6c1528f3966b9e3aa5)
1--
2-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org>
3-- All rights reserved.
4--
5-- Redistribution and use in source and binary forms, with or without
6-- modification, are permitted provided that the following conditions
7-- are met:
8-- 1. Redistributions of source code must retain the above copyright

--- 12 unchanged lines hidden (view full) ---

21-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24-- SUCH DAMAGE.
25--
26-- $FreeBSD$
27--
28
1--
2-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org>
3-- All rights reserved.
4--
5-- Redistribution and use in source and binary forms, with or without
6-- modification, are permitted provided that the following conditions
7-- are met:
8-- 1. Redistributions of source code must retain the above copyright

--- 12 unchanged lines hidden (view full) ---

21-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24-- SUCH DAMAGE.
25--
26-- $FreeBSD$
27--
28
29local config = require('config');
29local config = require('config')
30
30
31local core = {};
31local core = {}
32
33local compose_loader_cmd = function(cmd_name, argstr)
34 if (argstr ~= nil) then
32
33local compose_loader_cmd = function(cmd_name, argstr)
34 if (argstr ~= nil) then
35 cmd_name = cmd_name .. " " .. argstr;
35 cmd_name = cmd_name .. " " .. argstr
36 end
36 end
37 return cmd_name;
37 return cmd_name
38end
39
40-- Internal function
41-- Parses arguments to boot and returns two values: kernel_name, argstr
42-- Defaults to nil and "" respectively.
43-- This will also parse arguments to autoboot, but the with_kernel argument
44-- will need to be explicitly overwritten to false
45local parse_boot_args = function(argv, with_kernel)
46 if (#argv == 0) then
38end
39
40-- Internal function
41-- Parses arguments to boot and returns two values: kernel_name, argstr
42-- Defaults to nil and "" respectively.
43-- This will also parse arguments to autoboot, but the with_kernel argument
44-- will need to be explicitly overwritten to false
45local parse_boot_args = function(argv, with_kernel)
46 if (#argv == 0) then
47 return nil, "";
47 return nil, ""
48 end
49 if (with_kernel == nil) then
48 end
49 if (with_kernel == nil) then
50 with_kernel = true;
50 with_kernel = true
51 end
51 end
52 local kernel_name;
53 local argstr = "";
52 local kernel_name
53 local argstr = ""
54
55 for k, v in ipairs(argv) do
56 if (with_kernel) and (v:sub(1,1) ~= "-") then
54
55 for k, v in ipairs(argv) do
56 if (with_kernel) and (v:sub(1,1) ~= "-") then
57 kernel_name = v;
57 kernel_name = v
58 else
58 else
59 argstr = argstr .. " " .. v;
59 argstr = argstr .. " " .. v
60 end
61 end
62 if (with_kernel) then
60 end
61 end
62 if (with_kernel) then
63 return kernel_name, argstr;
63 return kernel_name, argstr
64 else
64 else
65 return argstr;
65 return argstr
66 end
67end
68
69-- Globals
70function boot(...)
66 end
67end
68
69-- Globals
70function boot(...)
71 local argv = {...};
72 local cmd_name = "";
73 cmd_name, argv = core.popFrontTable(argv);
74 local kernel, argstr = parse_boot_args(argv);
71 local argv = {...}
72 local cmd_name = ""
73 cmd_name, argv = core.popFrontTable(argv)
74 local kernel, argstr = parse_boot_args(argv)
75 if (kernel ~= nil) then
75 if (kernel ~= nil) then
76 loader.perform("unload");
77 config.selectkernel(kernel);
76 loader.perform("unload")
77 config.selectkernel(kernel)
78 end
78 end
79 core.boot(argstr);
79 core.boot(argstr)
80end
81
82function autoboot(...)
83 local argv = {...}
80end
81
82function autoboot(...)
83 local argv = {...}
84 local cmd_name = "";
85 cmd_name, argv = core.popFrontTable(argv);
86 local argstr = parse_boot_args(argv, false);
87 core.autoboot(argstr);
84 local cmd_name = ""
85 cmd_name, argv = core.popFrontTable(argv)
86 local argstr = parse_boot_args(argv, false)
87 core.autoboot(argstr)
88end
89
90-- Module exports
91-- Commonly appearing constants
88end
89
90-- Module exports
91-- Commonly appearing constants
92core.KEY_BACKSPACE = 8;
93core.KEY_ENTER = 13;
94core.KEY_DELETE = 127;
92core.KEY_BACKSPACE = 8
93core.KEY_ENTER = 13
94core.KEY_DELETE = 127
95
95
96core.KEYSTR_ESCAPE = "\027";
96core.KEYSTR_ESCAPE = "\027"
97
97
98core.MENU_RETURN = "return";
99core.MENU_ENTRY = "entry";
100core.MENU_SEPARATOR = "separator";
101core.MENU_SUBMENU = "submenu";
102core.MENU_CAROUSEL_ENTRY = "carousel_entry";
98core.MENU_RETURN = "return"
99core.MENU_ENTRY = "entry"
100core.MENU_SEPARATOR = "separator"
101core.MENU_SUBMENU = "submenu"
102core.MENU_CAROUSEL_ENTRY = "carousel_entry"
103
104function core.setVerbose(b)
105 if (b == nil) then
103
104function core.setVerbose(b)
105 if (b == nil) then
106 b = not core.verbose;
106 b = not core.verbose
107 end
108
109 if (b == true) then
107 end
108
109 if (b == true) then
110 loader.setenv("boot_verbose", "YES");
110 loader.setenv("boot_verbose", "YES")
111 else
111 else
112 loader.unsetenv("boot_verbose");
112 loader.unsetenv("boot_verbose")
113 end
113 end
114 core.verbose = b;
114 core.verbose = b
115end
116
117function core.setSingleUser(b)
118 if (b == nil) then
115end
116
117function core.setSingleUser(b)
118 if (b == nil) then
119 b = not core.su;
119 b = not core.su
120 end
121
122 if (b == true) then
120 end
121
122 if (b == true) then
123 loader.setenv("boot_single", "YES");
123 loader.setenv("boot_single", "YES")
124 else
124 else
125 loader.unsetenv("boot_single");
125 loader.unsetenv("boot_single")
126 end
126 end
127 core.su = b;
127 core.su = b
128end
129
130function core.getACPIPresent(checkingSystemDefaults)
128end
129
130function core.getACPIPresent(checkingSystemDefaults)
131 local c = loader.getenv("hint.acpi.0.rsdp");
131 local c = loader.getenv("hint.acpi.0.rsdp")
132
133 if (c ~= nil) then
134 if (checkingSystemDefaults == true) then
132
133 if (c ~= nil) then
134 if (checkingSystemDefaults == true) then
135 return true;
135 return true
136 end
137 -- Otherwise, respect disabled if it's set
136 end
137 -- Otherwise, respect disabled if it's set
138 c = loader.getenv("hint.acpi.0.disabled");
139 return (c == nil) or (tonumber(c) ~= 1);
138 c = loader.getenv("hint.acpi.0.disabled")
139 return (c == nil) or (tonumber(c) ~= 1)
140 end
140 end
141 return false;
141 return false
142end
143
144function core.setACPI(b)
145 if (b == nil) then
142end
143
144function core.setACPI(b)
145 if (b == nil) then
146 b = not core.acpi;
146 b = not core.acpi
147 end
148
149 if (b == true) then
147 end
148
149 if (b == true) then
150 loader.setenv("acpi_load", "YES");
151 loader.setenv("hint.acpi.0.disabled", "0");
152 loader.unsetenv("loader.acpi_disabled_by_user");
150 loader.setenv("acpi_load", "YES")
151 loader.setenv("hint.acpi.0.disabled", "0")
152 loader.unsetenv("loader.acpi_disabled_by_user")
153 else
153 else
154 loader.unsetenv("acpi_load");
155 loader.setenv("hint.acpi.0.disabled", "1");
156 loader.setenv("loader.acpi_disabled_by_user", "1");
154 loader.unsetenv("acpi_load")
155 loader.setenv("hint.acpi.0.disabled", "1")
156 loader.setenv("loader.acpi_disabled_by_user", "1")
157 end
157 end
158 core.acpi = b;
158 core.acpi = b
159end
160
161function core.setSafeMode(b)
162 if (b == nil) then
159end
160
161function core.setSafeMode(b)
162 if (b == nil) then
163 b = not core.sm;
163 b = not core.sm
164 end
165 if (b == true) then
164 end
165 if (b == true) then
166 loader.setenv("kern.smp.disabled", "1");
167 loader.setenv("hw.ata.ata_dma", "0");
168 loader.setenv("hw.ata.atapi_dma", "0");
169 loader.setenv("hw.ata.wc", "0");
170 loader.setenv("hw.eisa_slots", "0");
171 loader.setenv("kern.eventtimer.periodic", "1");
172 loader.setenv("kern.geom.part.check_integrity", "0");
166 loader.setenv("kern.smp.disabled", "1")
167 loader.setenv("hw.ata.ata_dma", "0")
168 loader.setenv("hw.ata.atapi_dma", "0")
169 loader.setenv("hw.ata.wc", "0")
170 loader.setenv("hw.eisa_slots", "0")
171 loader.setenv("kern.eventtimer.periodic", "1")
172 loader.setenv("kern.geom.part.check_integrity", "0")
173 else
173 else
174 loader.unsetenv("kern.smp.disabled");
175 loader.unsetenv("hw.ata.ata_dma");
176 loader.unsetenv("hw.ata.atapi_dma");
177 loader.unsetenv("hw.ata.wc");
178 loader.unsetenv("hw.eisa_slots");
179 loader.unsetenv("kern.eventtimer.periodic");
180 loader.unsetenv("kern.geom.part.check_integrity");
174 loader.unsetenv("kern.smp.disabled")
175 loader.unsetenv("hw.ata.ata_dma")
176 loader.unsetenv("hw.ata.atapi_dma")
177 loader.unsetenv("hw.ata.wc")
178 loader.unsetenv("hw.eisa_slots")
179 loader.unsetenv("kern.eventtimer.periodic")
180 loader.unsetenv("kern.geom.part.check_integrity")
181 end
181 end
182 core.sm = b;
182 core.sm = b
183end
184
185function core.kernelList()
183end
184
185function core.kernelList()
186 local k = loader.getenv("kernel");
187 local v = loader.getenv("kernels") or "";
186 local k = loader.getenv("kernel")
187 local v = loader.getenv("kernels") or ""
188
188
189 local kernels = {};
190 local unique = {};
191 local i = 0;
189 local kernels = {}
190 local unique = {}
191 local i = 0
192 if (k ~= nil) then
192 if (k ~= nil) then
193 i = i + 1;
194 kernels[i] = k;
195 unique[k] = true;
193 i = i + 1
194 kernels[i] = k
195 unique[k] = true
196 end
197
198 for n in v:gmatch("([^; ]+)[; ]?") do
199 if (unique[n] == nil) then
196 end
197
198 for n in v:gmatch("([^; ]+)[; ]?") do
199 if (unique[n] == nil) then
200 i = i + 1;
201 kernels[i] = n;
202 unique[n] = true;
200 i = i + 1
201 kernels[i] = n
202 unique[n] = true
203 end
204 end
205
206 -- Automatically detect other bootable kernel directories using a
207 -- heuristic. Any directory in /boot that contains an ordinary file
208 -- named "kernel" is considered eligible.
209 for file in lfs.dir("/boot") do
203 end
204 end
205
206 -- Automatically detect other bootable kernel directories using a
207 -- heuristic. Any directory in /boot that contains an ordinary file
208 -- named "kernel" is considered eligible.
209 for file in lfs.dir("/boot") do
210 local fname = "/boot/" .. file;
210 local fname = "/boot/" .. file
211
212 if (file == "." or file == "..") then
211
212 if (file == "." or file == "..") then
213 goto continue;
213 goto continue
214 end
215
216 if (lfs.attributes(fname, "mode") ~= "directory") then
214 end
215
216 if (lfs.attributes(fname, "mode") ~= "directory") then
217 goto continue;
217 goto continue
218 end
219
220 if (lfs.attributes(fname .. "/kernel", "mode") ~= "file") then
218 end
219
220 if (lfs.attributes(fname .. "/kernel", "mode") ~= "file") then
221 goto continue;
221 goto continue
222 end
223
224 if (unique[file] == nil) then
222 end
223
224 if (unique[file] == nil) then
225 i = i + 1;
226 kernels[i] = file;
227 unique[file] = true;
225 i = i + 1
226 kernels[i] = file
227 unique[file] = true
228 end
229
230 ::continue::
231 end
228 end
229
230 ::continue::
231 end
232 return kernels;
232 return kernels
233end
234
235function core.setDefaults()
233end
234
235function core.setDefaults()
236 core.setACPI(core.getACPIPresent(true));
237 core.setSafeMode(false);
238 core.setSingleUser(false);
239 core.setVerbose(false);
236 core.setACPI(core.getACPIPresent(true))
237 core.setSafeMode(false)
238 core.setSingleUser(false)
239 core.setVerbose(false)
240end
241
242function core.autoboot(argstr)
240end
241
242function core.autoboot(argstr)
243 config.loadelf();
244 loader.perform(compose_loader_cmd("autoboot", argstr));
243 config.loadelf()
244 loader.perform(compose_loader_cmd("autoboot", argstr))
245end
246
247function core.boot(argstr)
245end
246
247function core.boot(argstr)
248 config.loadelf();
249 loader.perform(compose_loader_cmd("boot", argstr));
248 config.loadelf()
249 loader.perform(compose_loader_cmd("boot", argstr))
250end
251
252function core.isSingleUserBoot()
250end
251
252function core.isSingleUserBoot()
253 local single_user = loader.getenv("boot_single");
254 return single_user ~= nil and single_user:lower() == "yes";
253 local single_user = loader.getenv("boot_single")
254 return single_user ~= nil and single_user:lower() == "yes"
255end
256
257function core.isSerialBoot()
255end
256
257function core.isSerialBoot()
258 local c = loader.getenv("console");
258 local c = loader.getenv("console")
259
260 if (c ~= nil) then
261 if (c:find("comconsole") ~= nil) then
259
260 if (c ~= nil) then
261 if (c:find("comconsole") ~= nil) then
262 return true;
262 return true
263 end
264 end
265
263 end
264 end
265
266 local s = loader.getenv("boot_serial");
266 local s = loader.getenv("boot_serial")
267 if (s ~= nil) then
267 if (s ~= nil) then
268 return true;
268 return true
269 end
270
269 end
270
271 local m = loader.getenv("boot_multicons");
271 local m = loader.getenv("boot_multicons")
272 if (m ~= nil) then
272 if (m ~= nil) then
273 return true;
273 return true
274 end
274 end
275 return false;
275 return false
276end
277
278function core.isSystem386()
276end
277
278function core.isSystem386()
279 return (loader.machine_arch == "i386");
279 return (loader.machine_arch == "i386")
280end
281
282-- This may be a better candidate for a 'utility' module.
283function core.shallowCopyTable(tbl)
280end
281
282-- This may be a better candidate for a 'utility' module.
283function core.shallowCopyTable(tbl)
284 local new_tbl = {};
284 local new_tbl = {}
285 for k, v in pairs(tbl) do
286 if (type(v) == "table") then
285 for k, v in pairs(tbl) do
286 if (type(v) == "table") then
287 new_tbl[k] = core.shallowCopyTable(v);
287 new_tbl[k] = core.shallowCopyTable(v)
288 else
288 else
289 new_tbl[k] = v;
289 new_tbl[k] = v
290 end
291 end
290 end
291 end
292 return new_tbl;
292 return new_tbl
293end
294
295-- XXX This should go away if we get the table lib into shape for importing.
296-- As of now, it requires some 'os' functions, so we'll implement this in lua
297-- for our uses
298function core.popFrontTable(tbl)
299 -- Shouldn't reasonably happen
300 if (#tbl == 0) then
293end
294
295-- XXX This should go away if we get the table lib into shape for importing.
296-- As of now, it requires some 'os' functions, so we'll implement this in lua
297-- for our uses
298function core.popFrontTable(tbl)
299 -- Shouldn't reasonably happen
300 if (#tbl == 0) then
301 return nil, nil;
301 return nil, nil
302 elseif (#tbl == 1) then
302 elseif (#tbl == 1) then
303 return tbl[1], {};
303 return tbl[1], {}
304 end
305
304 end
305
306 local first_value = tbl[1];
307 local new_tbl = {};
306 local first_value = tbl[1]
307 local new_tbl = {}
308 -- This is not a cheap operation
309 for k, v in ipairs(tbl) do
310 if (k > 1) then
308 -- This is not a cheap operation
309 for k, v in ipairs(tbl) do
310 if (k > 1) then
311 new_tbl[k - 1] = v;
311 new_tbl[k - 1] = v
312 end
313 end
314
312 end
313 end
314
315 return first_value, new_tbl;
315 return first_value, new_tbl
316end
317
318-- On i386, hint.acpi.0.rsdp will be set before we're loaded. On !i386, it will
319-- generally be set upon execution of the kernel. Because of this, we can't (or
320-- don't really want to) detect/disable ACPI on !i386 reliably. Just set it
321-- enabled if we detect it and leave well enough alone if we don't.
322if (core.isSystem386()) and (core.getACPIPresent(false)) then
316end
317
318-- On i386, hint.acpi.0.rsdp will be set before we're loaded. On !i386, it will
319-- generally be set upon execution of the kernel. Because of this, we can't (or
320-- don't really want to) detect/disable ACPI on !i386 reliably. Just set it
321-- enabled if we detect it and leave well enough alone if we don't.
322if (core.isSystem386()) and (core.getACPIPresent(false)) then
323 core.setACPI(true);
323 core.setACPI(true)
324end
324end
325return core;
325return core