lib/bli: implement entry control
diff --git a/common/lib/bli.c b/common/lib/bli.c
index 80676fb0..5e6c1b4c 100644
--- a/common/lib/bli.c
+++ b/common/lib/bli.c
@@ -91,6 +91,8 @@ void init_bli(void) {
uint64_t features = (1 << 0) | // Timeout control
(1 << 1) | // Oneshot timeout control
+ (1 << 2) | // Default entry control
+ (1 << 3) | // Oneshot entry control
(1 << 13); // menu-disabled support
gRT->SetVariable(L"LoaderFeatures",
&bli_vendor_guid,
@@ -160,4 +162,51 @@ bool bli_update_timeout(size_t *timeout, bool *skip_timeout) {
return handle_timeout(L"LoaderConfigTimeout", false, timeout, skip_timeout);
}
+static bool handle_entry(wchar_t *variable, bool erase, char *path, size_t buf_size) {
+ wchar_t wide_path[256];
+ UINTN getvar_size = sizeof(wide_path) - 2;
+ uint32_t attrs;
+ if (gRT->GetVariable(variable,
+ &bli_vendor_guid,
+ &attrs,
+ &getvar_size,
+ wide_path) == 0 && getvar_size > 0) {
+ if (erase) {
+ gRT->SetVariable(variable, &bli_vendor_guid,
+ attrs,
+ 0, NULL);
+ }
+
+ size_t i;
+ for (i = 0; i < buf_size-1 && i * 2 < getvar_size; i++) {
+ path[i] = wide_path[i] & 0xff; // Assume 0x00 - 0x7f
+ }
+ path[i] = 0;
+
+ return true;
+ }
+ return false;
+}
+
+bool bli_get_default_entry(char *path, size_t buf_size) {
+ return handle_entry(L"LoaderEntryDefault", false, path, buf_size);
+}
+
+bool bli_get_oneshot_entry(char *path, size_t buf_size) {
+ return handle_entry(L"LoaderEntryOneShot", true, path, buf_size);
+}
+
+void bli_set_selected_entry(const char *path) {
+ wchar_t wide_path[256];
+ size_t pos = 0;
+ for (; pos < 256 && pos < strlen(path); pos++) {
+ wide_path[pos] = path[pos];
+ }
+ gRT->SetVariable(L"LoaderEntrySelected",
+ &bli_vendor_guid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ strlen(path)*2 + 1,
+ wide_path);
+}
+
#endif
diff --git a/common/lib/bli.h b/common/lib/bli.h
index d970d836..11c9cfa8 100644
--- a/common/lib/bli.h
+++ b/common/lib/bli.h
@@ -7,6 +7,9 @@ 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);
+void bli_set_selected_entry(const char *path);
+bool bli_get_default_entry(char *path, size_t buf_size);
+bool bli_get_oneshot_entry(char *path, size_t buf_size);
#endif
diff --git a/common/menu.c b/common/menu.c
index 955785d8..c5742ca0 100644
--- a/common/menu.c
+++ b/common/menu.c
@@ -1125,56 +1125,92 @@ noreturn void _menu(bool first_run) {
size_t selected_entry = 0;
- char *default_entry = config_get_value(NULL, 0, "DEFAULT_ENTRY");
- if (default_entry != NULL) {
- bool is_index = true;
- for (const char *p = default_entry; *p != '\0'; p++) {
- if (*p < '0' || *p > '9') {
- is_index = false;
- break;
- }
- }
- if (is_index) {
- selected_entry = strtoui(default_entry, NULL, 10);
- if (selected_entry)
- selected_entry--;
- } else {
- // Copy the path since find_entry_by_path calls config_get_value
- // internally (via should_skip_entry), which clobbers the static buffer.
- char default_entry_path[256];
- size_t len = strlen(default_entry);
- if (len >= sizeof(default_entry_path)) {
- len = sizeof(default_entry_path) - 1;
- }
- memcpy(default_entry_path, default_entry, len);
- default_entry_path[len] = '\0';
+ bool has_entry = false;
+
+#if defined (UEFI)
+ {
+ char path[256];
+ if (bli_get_oneshot_entry(path, 256)) {
+ // Find the entry with this path, expand directories, and get its index.
struct menu_entry *found_entry = NULL;
size_t found_index = 0;
- find_entry_by_path(default_entry_path, menu_tree, 0, &found_entry, &found_index, true);
+ find_entry_by_path(path, menu_tree, 0, &found_entry, &found_index, true);
if (found_entry != NULL) {
selected_entry = found_index;
+ has_entry = true;
+ }
+ }
+ }
+#endif
+
+ if (!has_entry) {
+ char *default_entry = config_get_value(NULL, 0, "DEFAULT_ENTRY");
+ if (default_entry != NULL) {
+ bool is_index = true;
+ for (const char *p = default_entry; *p != '\0'; p++) {
+ if (*p < '0' || *p > '9') {
+ is_index = false;
+ break;
+ }
+ }
+ if (is_index) {
+ selected_entry = strtoui(default_entry, NULL, 10);
+ if (selected_entry)
+ selected_entry--;
+ } else {
+ // Copy the path since find_entry_by_path calls config_get_value
+ // internally (via should_skip_entry), which clobbers the static buffer.
+ char default_entry_path[256];
+ size_t len = strlen(default_entry);
+ if (len >= sizeof(default_entry_path)) {
+ len = sizeof(default_entry_path) - 1;
+ }
+ memcpy(default_entry_path, default_entry, len);
+ default_entry_path[len] = '\0';
+ struct menu_entry *found_entry = NULL;
+ size_t found_index = 0;
+ find_entry_by_path(default_entry_path, menu_tree, 0, &found_entry, &found_index, true);
+ if (found_entry != NULL) {
+ selected_entry = found_index;
+ }
}
}
}
#if defined (UEFI)
- char *remember_last = config_get_value(NULL, 0, "REMEMBER_LAST_ENTRY");
- if (remember_last != NULL && strcasecmp(remember_last, "yes") == 0) {
- char last_entry_path[256];
- UINTN getvar_size = sizeof(last_entry_path);
- if (gRT->GetVariable(L"LimineLastBootedEntry",
- &limine_efi_vendor_guid,
- NULL,
- &getvar_size,
- last_entry_path) == 0 && getvar_size > 0) {
- // Ensure NUL termination
- last_entry_path[getvar_size < sizeof(last_entry_path) ? getvar_size : sizeof(last_entry_path) - 1] = '\0';
+ if (!has_entry) {
+ char *remember_last = config_get_value(NULL, 0, "REMEMBER_LAST_ENTRY");
+ if (remember_last != NULL && strcasecmp(remember_last, "yes") == 0) {
+ char last_entry_path[256];
+ UINTN getvar_size = sizeof(last_entry_path);
+ if (gRT->GetVariable(L"LimineLastBootedEntry",
+ &limine_efi_vendor_guid,
+ NULL,
+ &getvar_size,
+ last_entry_path) == 0 && getvar_size > 0) {
+ // Ensure NUL termination
+ last_entry_path[getvar_size < sizeof(last_entry_path) ? getvar_size : sizeof(last_entry_path) - 1] = '\0';
+ // Find the entry with this path, expand directories, and get its index.
+ struct menu_entry *found_entry = NULL;
+ size_t found_index = 0;
+ find_entry_by_path(last_entry_path, menu_tree, 0, &found_entry, &found_index, true);
+ if (found_entry != NULL) {
+ selected_entry = found_index;
+ has_entry = true;
+ }
+ }
+ }
+ }
+ if (!has_entry) {
+ char path[256];
+ if (bli_get_default_entry(path, 256)) {
// Find the entry with this path, expand directories, and get its index.
struct menu_entry *found_entry = NULL;
size_t found_index = 0;
- find_entry_by_path(last_entry_path, menu_tree, 0, &found_entry, &found_index, true);
+ find_entry_by_path(path, menu_tree, 0, &found_entry, &found_index, true);
if (found_entry != NULL) {
selected_entry = found_index;
+ has_entry = true;
}
}
}
@@ -1469,6 +1505,7 @@ timeout_aborted:
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
strlen(entry_path) + 1,
entry_path);
+ bli_set_selected_entry(entry_path);
#endif
boot(selected_menu_entry->body);
