Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F151070567
D55936.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D55936.diff
View Options
diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk
--- a/share/mk/src.opts.mk
+++ b/share/mk/src.opts.mk
@@ -128,13 +128,14 @@
LLVM_COV \
LLVM_CXXFILT \
LOADER_BIOS_TEXTONLY \
+ LOADER_EFIBOOTMGRMENU \
LOADER_GELI \
+ LOADER_IA32 \
LOADER_KBOOT \
LOADER_LUA \
LOADER_OFW \
LOADER_PXEBOOT \
LOADER_UBOOT \
- LOADER_IA32 \
LOCALES \
LOCATE \
LPR \
diff --git a/stand/common/interp_lua.c b/stand/common/interp_lua.c
--- a/stand/common/interp_lua.c
+++ b/stand/common/interp_lua.c
@@ -40,6 +40,7 @@
#include <lerrno.h>
#include <lfs.h>
#include <lutils.h>
+#include <lefibootmgr.h>
struct interp_lua_softc {
lua_State *luap;
@@ -92,6 +93,9 @@
{"io", luaopen_io},
{"lfs", luaopen_lfs},
{"loader", luaopen_loader},
+#ifdef __amd64__
+ {"efibootmgr", luaopen_efibootmgr},
+#endif
{"pager", luaopen_pager},
{NULL, NULL}
};
diff --git a/stand/defs.mk b/stand/defs.mk
--- a/stand/defs.mk
+++ b/stand/defs.mk
@@ -69,7 +69,7 @@
BINDIR?= /boot
# LUAPATH is where we search for and install lua scripts.
-LUAPATH?= /boot/lua
+LUAPATH?= /EFI/FreeBSD/lua
FLUASRC?= ${SRCTOP}/libexec/flua
FLUALIB?= ${SRCTOP}/libexec/flua
diff --git a/stand/efi/loader/Makefile b/stand/efi/loader/Makefile
--- a/stand/efi/loader/Makefile
+++ b/stand/efi/loader/Makefile
@@ -99,6 +99,14 @@
# Always add MI sources
.include "${BOOTSRC}/loader.mk"
+MK_LOADER_EFIBOOTMGRMENU?= no
+.if ${MK_LOADER_LUA} != "no" && ${MK_LOADER_EFIBOOTMGRMENU} != "no"
+SRCS+= efibootmgrmenu.c
+CFLAGS+= -DEFI_LOADER_EFIBOOTMGRMENU -DEFI_LOADER_EFIBOOTMGRMENU_DEBUG
+CFLAGS+= -I${LUASRC} -I${LIBLUASRC}
+LDADD+= lua
+.endif
+
CLEANFILES+= 8x16.c
8x16.c: ${SRCTOP}/contrib/terminus/ter-u16b.bdf
diff --git a/stand/efi/loader/efibootmgrmenu.h b/stand/efi/loader/efibootmgrmenu.h
new file mode 100644
--- /dev/null
+++ b/stand/efi/loader/efibootmgrmenu.h
@@ -0,0 +1,6 @@
+#ifndef EFI_LOADER_EFIBOOTMGRMENU_H
+#define EFI_LOADER_EFIBOOTMGRMENU_H
+
+void efibootmgrmenu(void);
+
+#endif
diff --git a/stand/efi/loader/efibootmgrmenu.c b/stand/efi/loader/efibootmgrmenu.c
new file mode 100644
--- /dev/null
+++ b/stand/efi/loader/efibootmgrmenu.c
@@ -0,0 +1,15 @@
+#include <bootstrap.h>
+
+/*
+ * Build a menu to pick the partition to boot from using the UEFI Boot Manager
+ * policy [1].
+ *
+ * [1] https://uefi.org/specs/UEFI/2.10/03_Boot_Manager.html
+ */
+void
+efibootmgrmenu(void)
+{
+ setenv("loader_lua", "EFI/FreeBSD/lua/efibootmgrmenu.lua", 1);
+ interact();
+ /* NOTREACHED */
+}
diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c
--- a/stand/efi/loader/main.c
+++ b/stand/efi/loader/main.c
@@ -79,6 +79,9 @@
#include <acpi_detect.h>
#include "loader_efi.h"
+#ifdef EFI_LOADER_EFIBOOTMGRMENU
+#include "efibootmgrmenu.h"
+#endif
struct arch_switch archsw = { /* MI/MD interface boundary */
.arch_autoload = efi_autoload,
@@ -1474,6 +1477,10 @@
ve_efi_init();
#endif
+#ifdef EFI_LOADER_EFIBOOTMGRMENU
+ efibootmgrmenu();
+#endif
+
/*
* Try and find a good currdev based on the image that was booted.
* It might be desirable here to have a short pause to allow falling
diff --git a/stand/liblua/Makefile b/stand/liblua/Makefile
--- a/stand/liblua/Makefile
+++ b/stand/liblua/Makefile
@@ -24,6 +24,12 @@
SRCS+= lerrno.c lpager.c lstd.c lutils.c
SRCS+= gfx_utils.c
+# EFI Boot Manager Support
+.if ${MACHINE_ARCH} == "amd64" && ${MK_EFI} != "no"
+SRCS+= lefibootmgr.c
+CFLAGS.lefibootmgr.c+= -I${EDK2INC} -I${EFIINC}
+.endif
+
.PATH: ${FLUASRC}/lfs
SRCS+= lfs.c
.PATH: ${FLUALIB}/libhash
diff --git a/stand/liblua/lefibootmgr.h b/stand/liblua/lefibootmgr.h
new file mode 100644
--- /dev/null
+++ b/stand/liblua/lefibootmgr.h
@@ -0,0 +1,3 @@
+#include <lua.h>
+
+int luaopen_efibootmgr(lua_State *);
diff --git a/stand/liblua/lefibootmgr.c b/stand/liblua/lefibootmgr.c
new file mode 100644
--- /dev/null
+++ b/stand/liblua/lefibootmgr.c
@@ -0,0 +1,131 @@
+#include <efi.h>
+#include <efilib.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+
+static const struct luaL_Reg efibootmgrlib[] = {
+ { NULL, NULL },
+};
+
+int
+luaopen_efibootmgr(lua_State *L)
+{
+ EFI_STATUS rv;
+ size_t boot_order_sz, sz;
+ UINT16 boot_current, boot_order[100];
+ char boot_info[4096], buf[80];
+ int timeout;
+
+ luaL_newlib(L, efibootmgrlib);
+
+ /*
+ * Expose Timeout as an integer.
+ */
+ sz = sizeof(timeout);
+ rv = efi_global_getenv("Timeout", &timeout, &sz);
+ if (rv == EFI_SUCCESS)
+ lua_pushinteger(L, timeout);
+ else
+ lua_pushinteger(L, 10);
+ lua_setfield(L, -2, "timeout");
+
+ /*
+ * Expose BootCurrent as an integer, e.g., 6 for Boot0006.
+ */
+ boot_current = 0;
+ sz = sizeof(boot_current);
+ rv = efi_global_getenv("BootCurrent", &boot_current, &sz);
+ if (rv == EFI_SUCCESS) {
+ char buf[80];
+
+ snprintf(buf, sizeof(buf), "Boot%04X", boot_current);
+ sz = sizeof(boot_info);
+ rv = efi_global_getenv(buf, &boot_info, &sz);
+ if (rv == EFI_SUCCESS)
+ ;
+ lua_pushinteger(L, boot_current);
+ lua_setfield(L, -2, "boot_current");
+ }
+
+ /*
+ * Expose BootOrder as follow:
+ * efibootmgr.boot_order[1..n]
+ * .bootnum The boot number as an integer, e.g., 6 for Boot0006.
+ */
+ sz = sizeof(boot_order);
+ rv = efi_global_getenv("BootOrder", &boot_order, &boot_order_sz);
+ if (rv == EFI_SUCCESS) {
+ size_t boot_order_nitems = boot_order_sz / sizeof(boot_order[0]);
+
+ lua_createtable(L, boot_order_nitems, 0);
+ for (size_t o = 0; o < boot_order_nitems; o++) {
+ char buf[256], boot_info[4096];
+ EFI_LOAD_OPTION *load_option;
+ CHAR16 *description;
+ size_t description_sz;
+ EFI_DEVICE_PATH_PROTOCOL *file_path_list;
+ CHAR16 *devpath;
+#if 0
+ UINT8 *optional_data;
+ size_t optional_data_sz;
+#endif
+
+ snprintf(buf, sizeof(buf), "Boot%04X", boot_order[o]);
+ sz = sizeof(boot_info);
+ rv = efi_global_getenv(buf, &boot_info, &sz);
+ if (rv != EFI_SUCCESS) {
+ printf("WARNING: unable to read load option %s\n", buf);
+ continue;
+ }
+ load_option = (EFI_LOAD_OPTION *)boot_info;
+
+ lua_createtable(L, 1, 0);
+
+ /* bootnum */
+ lua_pushinteger(L, boot_order[o]);
+ lua_setfield(L, -2, "bootnum");
+
+ /* attributes, is_active, is_hidden */
+ lua_pushinteger(L, load_option->Attributes);
+ lua_setfield(L, -2, "attributes");
+ lua_pushboolean(L, load_option->Attributes & LOAD_OPTION_ACTIVE);
+ lua_setfield(L, -2, "is_active");
+ lua_pushboolean(L, load_option->Attributes & LOAD_OPTION_HIDDEN);
+ lua_setfield(L, -2, "is_hidden");
+
+ /* description */
+ description = (CHAR16 *)(boot_info +
+ sizeof(load_option->Attributes) +
+ sizeof(load_option->FilePathListLength));
+ cpy16to8(description, buf, sizeof(buf));
+ lua_pushstring(L, buf);
+ lua_setfield(L, -2, "description");
+
+ /* devpath from file_path_list[0] */
+
+ /* FIXME Find a better approach to get StrSize(CHAR16 *) */
+ cpy16to8(description, buf, sizeof(buf));
+ description_sz = (strlen(buf) + 1) * sizeof(CHAR16);
+
+ file_path_list = (EFI_DEVICE_PATH *)((UINT8 *)description +
+ description_sz);
+ devpath = efi_devpath_name(&file_path_list[0]);
+ cpy16to8(devpath, buf, sizeof(buf));
+ lua_pushstring(L, buf);
+ lua_setfield(L, -2, "devpath");
+
+#if 0
+ /* optional_data */
+ optional_data = (UINT8 *)((UINT8 *)file_path_list +
+ load_option->FilePathListLength);
+ optional_data_sz = sz - (optional_data - (UINT8 *)load_option);
+ /* TODO Find a way to expose the optional data. */
+#endif
+
+ lua_rawseti(L, -2, o + 1);
+ }
+ lua_setfield(L, -2, "boot_order");
+ }
+ return (1);
+}
diff --git a/stand/lua/color.lua b/stand/lua/color.lua
--- a/stand/lua/color.lua
+++ b/stand/lua/color.lua
@@ -105,13 +105,21 @@
return color.escape(color.DEFAULT, color.DEFAULT)
end
-function color.highlight(str)
+function color.mstr(mode, str)
if color.disabled then
return str
end
-- We need to reset attributes as well as color scheme here, just in
-- case the terminal defaults don't match what we're expecting.
- return core.KEYSTR_CSI .. "1m" .. str .. core.KEYSTR_CSI .. "22m"
+ return core.KEYSTR_CSI .. mode .. "m" .. str .. core.KEYSTR_CSI .. "22m"
+end
+
+function color.highlight(str)
+ return color.mstr(color.BRIGHT, str)
+end
+
+function color.dim(str)
+ return color.mstr(color.DIM, str)
end
recalcDisabled()
diff --git a/stand/lua/efibootmgrmenu.lua b/stand/lua/efibootmgrmenu.lua
new file mode 100644
--- /dev/null
+++ b/stand/lua/efibootmgrmenu.lua
@@ -0,0 +1,138 @@
+-- XXX
+printc("package.path: " .. package.path .. "\n")
+printc("loader.lua_path: " .. loader.lua_path .. "\n")
+
+local core = require("core")
+local color = require("color")
+
+DEBUG = true
+DELAY = 5 -- seconds
+SHOW_ACTIVE = true
+SHOW_HIDDEN = true
+
+-- Load option attributes bits:
+LOAD_OPTION_ACTIVE = 0x00000001
+LOAD_OPTION_FORCE_RECONNECT = 0x00000002
+LOAD_OPTION_HIDDEN = 0x00000008
+LOAD_OPTION_CATEGORY = 0x00001f00
+LOAD_OPTION_CATEGORY_BOOT = 0x00000000
+LOAD_OPTION_CATEGORY_APP = 0x00000100
+
+function print_menu()
+ for o = 1,#efibootmgr.boot_order,1 do
+ local load_option = efibootmgr.boot_order[o]
+ local bootnum = load_option.bootnum
+ local is_current = bootnum == efibootmgr.boot_current
+ local is_active = load_option.is_active
+ local is_hidden = load_option.is_hidden
+ local description = load_option.description
+
+ local show = false
+ if SHOW_ACTIVE and is_active then
+ show = true
+ end
+ if SHOW_HIDDEN then
+ if is_hidden then
+ show = true
+ end
+ elseif is_hidden then
+ show = false
+ end
+ if not show then
+ goto continue
+ end
+
+ line = ""
+
+ if o <= 9 then
+ line = line .. "[" .. o .. "] "
+ else
+ line = line .. " "
+ end
+
+ label = ""
+
+ if is_current then
+ line = line .. "+"
+ else
+ line = line .. " "
+ end
+
+ line = line .. string.format("Boot%04x ", bootnum)
+ if is_hidden then
+ line = line .. description
+ else
+ line = line .. color.highlight(description)
+ end
+
+ if is_active then
+ line = line .. "*"
+ end
+
+ if is_hidden then
+ printc(color.dim(line))
+ else
+ printc(line)
+ end
+ printc("\n")
+
+ if DEBUG then
+ printc(" attributes: 0x" .. string.format("%x", load_option.attributes) .. "<")
+ if load_option.attributes & LOAD_OPTION_ACTIVE == LOAD_OPTION_ACTIVE then
+ printc("ACTIVE,")
+ end
+ if load_option.attributes & LOAD_OPTION_HIDDEN == LOAD_OPTION_HIDDEN then
+ printc("HIDDEN,")
+ end
+ if load_option.attributes & LOAD_OPTION_FORCE_RECONNECT == LOAD_OPTION_FORCE_RECONNECT then
+ printc("FORCE_RECONNECT,")
+ end
+ if load_option.attributes & LOAD_OPTION_CATEGORY == LOAD_OPTION_CATEGORY_BOOT then
+ printc("CATEGORY_BOOT,")
+ end
+ if load_option.attributes & LOAD_OPTION_CATEGORY == LOAD_OPTION_CATEGORY_APP then
+ printc("CATEGORY_APP,")
+ end
+ printc(">\n")
+ printc(" devpath: " .. load_option.devpath .. "\n")
+ end
+ ::continue::
+ end
+end
+
+function boot_load_option(load_option)
+ printc(string.format("Booting Boot%04x %s...\n",
+ load_option.bootnum, load_option.description))
+ -- TODO Setup bootenv from load_option
+ core.boot()
+end
+
+printc(">>> EFI Boot Manager Menu\n")
+print_menu()
+
+local load_option = efibootmgr.boot_order[1]
+
+printc(string.format("Default: Boot%04x %s\n",
+ load_option.bootnum, load_option.description))
+
+printc("Choose: ")
+local endtime = loader.time() + efibootmgr.timeout
+repeat
+ time = endtime - loader.time()
+ if io.ischar() then
+ o = io.getchar() - 48
+ if 1 <= o and o <= #efibootmgr.boot_order then
+ load_option = efibootmgr.boot_order[o]
+ else
+ printc(" ")
+ printc(color.highlight("invalid key"))
+ end
+ break
+ end
+ loader.delay(50000)
+until time <= 0
+printc("\n")
+
+boot_load_option(load_option)
+
+printc("<<< EFI Boot Manager Menu\n")
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Apr 6, 7:04 PM (9 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30993879
Default Alt Text
D55936.diff (11 KB)
Attached To
Mode
D55936: loader.efi: Build a boot menu based on UEFI boot manager
Attached
Detach File
Event Timeline
Log In to Comment