:: commit 6ae26ba1f1e411c4bfee26e9a623df1253053406

programmerlexi <lexi@reyer.name> — 2026-04-11 16:58

parents: 5ad7d2769d

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 fa2c9ae0..99bd3fad 100644
--- a/common/menu.c
+++ b/common/menu.c
@@ -1133,56 +1133,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;
             }
         }
     }
@@ -1477,6 +1513,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);
tab: 248 wrap: offon