protos/efi_boot_entry: Make it use its own proto.
This commit is contained in:
@@ -202,7 +202,7 @@ Editor control options:
|
||||
bootloader on the menu when an entry is selected.
|
||||
* `protocol` - The boot protocol that will be used to boot the
|
||||
kernel/executable. Valid protocols are: `linux`, `limine`, `multiboot`
|
||||
(or `multiboot1`), `multiboot2`, `efi`, and `bios`.
|
||||
(or `multiboot1`), `multiboot2`, `efi`, `efi_boot_entry` and `bios`.
|
||||
* `cmdline` - The command line string to be passed to the kernel/executable.
|
||||
Can be omitted.
|
||||
* `kernel_cmdline` - Alias of `cmdline`.
|
||||
@@ -276,8 +276,8 @@ Editor control options:
|
||||
* `resolution` - The resolution to be used. This setting takes the form of
|
||||
`<width>x<height>x<bpp>`. If the resolution is not available, Limine will
|
||||
pick another one automatically. Omitting `<bpp>` will default to 32.
|
||||
* `reboot_for_bitlocker` - When set to true, Limine will set the `BootNext` UEFI Variable to the Windows Boot Manager boot entry and reboot.
|
||||
|
||||
* EFI Boot Entry protocol:
|
||||
* `entry` - The name of the EFI boot entry to reboot into.
|
||||
* BIOS Chainload protocol:
|
||||
* `drive` - The 1-based drive to chainload, if omitted, assume boot drive.
|
||||
* `partition` - The 1-based partition to chainload, if omitted, or set to 0,
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <protos/chainload.h>
|
||||
#include <protos/multiboot1.h>
|
||||
#include <protos/multiboot2.h>
|
||||
#include <protos/efi_boot_entry.h>
|
||||
#include <protos/limine.h>
|
||||
#include <sys/cpu.h>
|
||||
#include <lib/misc.h>
|
||||
@@ -556,7 +557,8 @@ static inline bool should_skip_entry(struct menu_entry *entry) {
|
||||
#elif defined (BIOS)
|
||||
if (strcmp(cur_entry_protocol, "efi") == 0
|
||||
|| strcmp(cur_entry_protocol, "uefi") == 0
|
||||
|| strcmp(cur_entry_protocol, "efi_chainload") == 0) {
|
||||
|| strcmp(cur_entry_protocol, "efi_chainload") == 0
|
||||
|| strcmp(cur_entry_protocol, "efi_boot_entry") == 0) {
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
@@ -1395,6 +1397,11 @@ noreturn void boot(char *config) {
|
||||
#endif
|
||||
chainload(config, cmdline);
|
||||
}
|
||||
#if defined (UEFI)
|
||||
else if (!strcmp(proto, "efi_boot_entry")) {
|
||||
efi_boot_entry(config);
|
||||
}
|
||||
#endif
|
||||
|
||||
panic(true, "Unsupported protocol specified.");
|
||||
}
|
||||
|
||||
118
common/protos/efi_boot_entry.c
Normal file
118
common/protos/efi_boot_entry.c
Normal file
@@ -0,0 +1,118 @@
|
||||
#include <protos/efi_boot_entry.h>
|
||||
|
||||
#if defined(UEFI)
|
||||
#include <efi.h>
|
||||
#include <lib/config.h>
|
||||
#include <lib/misc.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
static bool uefi_string_matches(CHAR16 *desc, CHAR16 *target) {
|
||||
while (*target) {
|
||||
CHAR16 a = *desc >= L'a' && *desc <= L'z' ? *desc - 32 : *desc;
|
||||
CHAR16 b = *target >= L'a' && *target <= L'z' ? *target - 32 : *target;
|
||||
if (a != b)
|
||||
return false;
|
||||
desc++;
|
||||
target++;
|
||||
}
|
||||
return *desc == L'\0';
|
||||
}
|
||||
|
||||
static void format_boot_var(CHAR16 *out, UINT16 num) {
|
||||
out[0] = L'B';
|
||||
out[1] = L'o';
|
||||
out[2] = L'o';
|
||||
out[3] = L't';
|
||||
out[4] = L"0123456789ABCDEF"[(num >> 12) & 0xF];
|
||||
out[5] = L"0123456789ABCDEF"[(num >> 8) & 0xF];
|
||||
out[6] = L"0123456789ABCDEF"[(num >> 4) & 0xF];
|
||||
out[7] = L"0123456789ABCDEF"[(num >> 0) & 0xF];
|
||||
out[8] = L'\0';
|
||||
}
|
||||
|
||||
static bool find_boot_entry(CHAR16 *entry, uint16_t *out) {
|
||||
EFI_STATUS status;
|
||||
uint16_t boot_order[128];
|
||||
size_t size = sizeof(boot_order);
|
||||
EFI_GUID global_variable = EFI_GLOBAL_VARIABLE;
|
||||
|
||||
status =
|
||||
gRT->GetVariable(L"BootOrder", &global_variable, NULL, &size, boot_order);
|
||||
|
||||
if (EFI_ERROR(status)) {
|
||||
panic(true, "reboot_for_bitlocker: Failed to get BootOrder variable (%X)",
|
||||
(uint64_t)status);
|
||||
}
|
||||
|
||||
size_t count = size / sizeof(uint16_t);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
CHAR16 var_name[9];
|
||||
|
||||
format_boot_var(var_name, boot_order[i]);
|
||||
|
||||
uint8_t buf[128];
|
||||
size_t buf_size = sizeof(buf);
|
||||
|
||||
status = gRT->GetVariable(var_name, &global_variable, NULL, &buf_size, buf);
|
||||
if (EFI_ERROR(status)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get the description */
|
||||
CHAR16 *desc = (CHAR16 *)(buf + sizeof(uint32_t) + sizeof(uint16_t));
|
||||
|
||||
if (uefi_string_matches(desc, entry)) {
|
||||
*out = boot_order[i];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
noreturn void efi_boot_entry(char *config) {
|
||||
char *boot_entry = config_get_value(config, 0, "entry");
|
||||
|
||||
if (boot_entry == NULL) {
|
||||
panic(true, "efi: No entry specified for efi_boot_entry protocol");
|
||||
}
|
||||
|
||||
/* Convert entry string to UTF-16 */
|
||||
CHAR16 boot_entry_utf16[128];
|
||||
size_t i;
|
||||
|
||||
for (i = 0;
|
||||
i < sizeof(boot_entry_utf16) / sizeof(CHAR16) - 1 && boot_entry[i];
|
||||
i++) {
|
||||
boot_entry_utf16[i] = (CHAR16)boot_entry[i];
|
||||
}
|
||||
|
||||
boot_entry_utf16[i] = L'\0';
|
||||
|
||||
/* Find the desired boot entry */
|
||||
uint16_t boot_next = 0;
|
||||
|
||||
if (!find_boot_entry(boot_entry_utf16, &boot_next)) {
|
||||
panic(true, "efi_boot_entry: Failed to find boot entry '%s'", boot_entry);
|
||||
}
|
||||
|
||||
EFI_GUID global_variable = EFI_GLOBAL_VARIABLE;
|
||||
|
||||
/* Set BootNext to it */
|
||||
EFI_STATUS status = gRT->SetVariable(L"BootNext", &global_variable,
|
||||
EFI_VARIABLE_NON_VOLATILE |
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||
EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
sizeof(boot_next), &boot_next);
|
||||
|
||||
if (status) {
|
||||
panic(true, "efi_boot_entry: Failed to set BootNext variable (%X)",
|
||||
(uint64_t)status);
|
||||
}
|
||||
|
||||
/* Now reboot */
|
||||
gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
8
common/protos/efi_boot_entry.h
Normal file
8
common/protos/efi_boot_entry.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef PROTOS__EFI_BOOT_ENTRY_H__
|
||||
#define PROTOS__EFI_BOOT_ENTRY_H__
|
||||
|
||||
#include <stdnoreturn.h>
|
||||
|
||||
noreturn void efi_boot_entry(char *config);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user