lib/bli: implement timeout control
diff --git a/common/lib/bli.c b/common/lib/bli.c
index 4aee0f26..80676fb0 100644
--- a/common/lib/bli.c
+++ b/common/lib/bli.c
@@ -41,6 +41,28 @@ void uint64_to_decwstr(uint64_t value, wchar_t *buf) {
buf[i] = '\0';
}
+bool decwstr_to_size(const wchar_t *buf, size_t buf_size, size_t *value) {
+ size_t i = 0;
+ size_t tmp = 0;
+
+ if (buf == NULL) {
+ return false;
+ }
+
+ while (i * 2 < buf_size && buf[i]) {
+ wchar_t c = buf[i];
+ if (!(c >= L'0' && c <= L'9')) {
+ return false;
+ }
+ tmp = tmp * 10 + (c - L'0');
+ i++;
+ }
+
+ *value = tmp;
+
+ return true;
+}
+
void bli_set_loader_time(wchar_t *variable, uint64_t time) {
if (time == 0)
return;
@@ -67,6 +89,15 @@ void init_bli(void) {
sizeof(LIMINE_BRAND),
LIMINE_BRAND);
+ uint64_t features = (1 << 0) | // Timeout control
+ (1 << 1) | // Oneshot timeout control
+ (1 << 13); // menu-disabled support
+ gRT->SetVariable(L"LoaderFeatures",
+ &bli_vendor_guid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(features),
+ &features);
+
char part_uuid_str[37];
guid_to_string(&boot_volume->part_guid, part_uuid_str);
@@ -87,4 +118,46 @@ void bli_on_boot(void) {
bli_set_loader_time(L"LoaderTimeExecUSec", rdtsc_usec());
}
+static bool handle_timeout(wchar_t *variable, bool erase, size_t *timeout, bool *skip_timeout) {
+ wchar_t timeout_buf[256];
+ UINTN getvar_size = sizeof(timeout_buf) - 2;
+ uint32_t attrs;
+ if (gRT->GetVariable(variable,
+ &bli_vendor_guid,
+ &attrs,
+ &getvar_size,
+ timeout_buf) == 0 && getvar_size > 0) {
+ if (erase) {
+ gRT->SetVariable(variable, &bli_vendor_guid,
+ attrs,
+ 0, NULL);
+ }
+ if (getvar_size == 24 && memcmp(timeout_buf, L"menu-force",24) == 0) {
+ *skip_timeout = true;
+ return true;
+ }
+ if ((getvar_size == 24 && memcmp(timeout_buf, L"menu-hidden",24) == 0) || (getvar_size == 28 && memcmp(timeout_buf, L"menu-disabled",28) == 0)) {
+ // TODO: menu-hidden should enable quiet & set timeout >= 1
+ *timeout = 0;
+ return true;
+ }
+ size_t t;
+ if (!decwstr_to_size(timeout_buf, getvar_size, &t)) {
+ return false;
+ }
+ *timeout = t;
+ return true;
+ }
+ return false;
+
+}
+
+bool bli_update_oneshot_timeout(size_t *timeout, bool *skip_timeout) {
+ return handle_timeout(L"LoaderConfigTimeoutOneShot", true, timeout, skip_timeout);
+}
+
+bool bli_update_timeout(size_t *timeout, bool *skip_timeout) {
+ return handle_timeout(L"LoaderConfigTimeout", false, timeout, skip_timeout);
+}
+
#endif
diff --git a/common/lib/bli.h b/common/lib/bli.h
index 2e48041d..d970d836 100644
--- a/common/lib/bli.h
+++ b/common/lib/bli.h
@@ -5,6 +5,8 @@
void init_bli(void);
void bli_on_boot(void);
+bool bli_update_oneshot_timeout(size_t *timeout, bool *skip_timeout);
+bool bli_update_timeout(size_t *timeout, bool *skip_timeout);
#endif
diff --git a/common/menu.c b/common/menu.c
index 4f2e73a9..955785d8 100644
--- a/common/menu.c
+++ b/common/menu.c
@@ -4,6 +4,7 @@
#include <stdnoreturn.h>
#include <config.h>
#include <menu.h>
+#include <lib/bli.h>
#include <lib/print.h>
#include <lib/misc.h>
#include <lib/libc.h>
@@ -1187,13 +1188,29 @@ noreturn void _menu(bool first_run) {
}
size_t timeout = 5;
- char *timeout_config = config_get_value(NULL, 0, "TIMEOUT");
- if (timeout_config != NULL) {
- if (!strcmp(timeout_config, "no"))
- skip_timeout = true;
- else
- timeout = strtoui(timeout_config, NULL, 10);
+
+ bool has_timeout = false;
+
+#if defined (UEFI)
+ has_timeout = bli_update_oneshot_timeout(&timeout, &skip_timeout);
+#endif
+
+ if (!has_timeout) {
+ char *timeout_config = config_get_value(NULL, 0, "TIMEOUT");
+ if (timeout_config != NULL) {
+ has_timeout = true;
+ if (!strcmp(timeout_config, "no"))
+ skip_timeout = true;
+ else
+ timeout = strtoui(timeout_config, NULL, 10);
+ }
+ }
+
+#if defined (UEFI)
+ if (!has_timeout) {
+ has_timeout = bli_update_timeout(&timeout, &skip_timeout);
}
+#endif
#if defined(UEFI)
bool reboot_to_firmware_supported = reboot_to_fw_ui_supported();
