mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-25 23:21:33 +03:00
Merge pull request #10804 from poettering/sd-boot-updates
various sd-boot/EFI fixes (split out from #10495)
This commit is contained in:
commit
1b259a5bf3
@ -256,8 +256,12 @@
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>LoaderConfigTimeout</varname></term>
|
||||
<listitem><para>The menu time-out. Read by the boot loader. (Also, modified by it when the
|
||||
<keycap>t</keycap>/<keycap>T</keycap> keys are used, see above.)</para></listitem>
|
||||
<term><varname>LoaderConfigTimeoutOneShot</varname></term>
|
||||
<listitem><para>The menu time-out in seconds. Read by the boot loader. <varname>LoaderConfigTimeout</varname>
|
||||
is maintained persistently, while <varname>LoaderConfigTimeoutOneShot</varname> is a one-time override which is
|
||||
read once (in which case it takes precedence over <varname>LoaderConfigTimeout</varname>) and then
|
||||
removed. <varname>LoaderConfigTimeout</varname> may be manipulated with the
|
||||
<keycap>t</keycap>/<keycap>T</keycap> keys, see above.)</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -297,6 +301,14 @@
|
||||
loader.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>LoaderFeatures</varname></term>
|
||||
|
||||
<listitem><para>A set of flags indicating the features the boot loader supports. Set by the boot loader. Use
|
||||
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> to view this
|
||||
data.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>LoaderFirmwareInfo</varname></term>
|
||||
<term><varname>LoaderFirmwareType</varname></term>
|
||||
|
@ -62,6 +62,7 @@ typedef struct {
|
||||
BOOLEAN editor;
|
||||
BOOLEAN auto_entries;
|
||||
BOOLEAN auto_firmware;
|
||||
BOOLEAN force_menu;
|
||||
UINTN console_mode;
|
||||
enum console_mode_change_type console_mode_change;
|
||||
} Config;
|
||||
@ -385,10 +386,10 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
|
||||
Print(L"\n--- press key ---\n\n");
|
||||
console_key_read(&key, TRUE);
|
||||
|
||||
Print(L"timeout: %d\n", config->timeout_sec);
|
||||
Print(L"timeout: %u\n", config->timeout_sec);
|
||||
if (config->timeout_sec_efivar >= 0)
|
||||
Print(L"timeout (EFI var): %d\n", config->timeout_sec_efivar);
|
||||
Print(L"timeout (config): %d\n", config->timeout_sec_config);
|
||||
Print(L"timeout (config): %u\n", config->timeout_sec_config);
|
||||
if (config->entry_default_pattern)
|
||||
Print(L"default pattern: '%s'\n", config->entry_default_pattern);
|
||||
Print(L"editor: %s\n", yes_no(config->editor));
|
||||
@ -403,7 +404,8 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
|
||||
Print(L"\n");
|
||||
|
||||
if (efivar_get_int(L"LoaderConfigTimeout", &i) == EFI_SUCCESS)
|
||||
Print(L"LoaderConfigTimeout: %d\n", i);
|
||||
Print(L"LoaderConfigTimeout: %u\n", i);
|
||||
|
||||
if (config->entry_oneshot)
|
||||
Print(L"LoaderEntryOneShot: %s\n", config->entry_oneshot);
|
||||
if (efivar_get(L"LoaderDevicePartUUID", &partstr) == EFI_SUCCESS)
|
||||
@ -1402,9 +1404,11 @@ static VOID config_load_defaults(Config *config, EFI_FILE *root_dir) {
|
||||
UINTN sec;
|
||||
EFI_STATUS err;
|
||||
|
||||
config->editor = TRUE;
|
||||
config->auto_entries = TRUE;
|
||||
config->auto_firmware = TRUE;
|
||||
*config = (Config) {
|
||||
.editor = TRUE,
|
||||
.auto_entries = TRUE,
|
||||
.auto_firmware = TRUE,
|
||||
};
|
||||
|
||||
err = file_read(root_dir, L"\\loader\\loader.conf", 0, 0, &content, NULL);
|
||||
if (!EFI_ERROR(err))
|
||||
@ -1412,10 +1416,19 @@ static VOID config_load_defaults(Config *config, EFI_FILE *root_dir) {
|
||||
|
||||
err = efivar_get_int(L"LoaderConfigTimeout", &sec);
|
||||
if (!EFI_ERROR(err)) {
|
||||
config->timeout_sec_efivar = sec;
|
||||
config->timeout_sec_efivar = sec > INTN_MAX ? INTN_MAX : sec;
|
||||
config->timeout_sec = sec;
|
||||
} else
|
||||
config->timeout_sec_efivar = -1;
|
||||
|
||||
err = efivar_get_int(L"LoaderConfigTimeoutOneShot", &sec);
|
||||
if (!EFI_ERROR(err)) {
|
||||
/* Unset variable now, after all it's "one shot". */
|
||||
(void) efivar_set(L"LoaderConfigTimeoutOneShot", NULL, TRUE);
|
||||
|
||||
config->timeout_sec = sec;
|
||||
config->force_menu = TRUE; /* force the menu when this is set */
|
||||
}
|
||||
}
|
||||
|
||||
static VOID config_load_entries(
|
||||
@ -2061,6 +2074,14 @@ static VOID config_write_entries_to_variable(Config *config) {
|
||||
}
|
||||
|
||||
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
static const UINT64 loader_features =
|
||||
(1ULL << 0) | /* I honour the LoaderConfigTimeout variable */
|
||||
(1ULL << 1) | /* I honour the LoaderConfigTimeoutOneShot variable */
|
||||
(1ULL << 2) | /* I honour the LoaderEntryDefault variable */
|
||||
(1ULL << 3) | /* I honour the LoaderEntryOneShot variable */
|
||||
(1ULL << 4) | /* I support boot counting */
|
||||
0;
|
||||
|
||||
_cleanup_freepool_ CHAR16 *infostr = NULL, *typestr = NULL;
|
||||
CHAR8 *b;
|
||||
UINTN size;
|
||||
@ -2084,6 +2105,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
typestr = PoolPrint(L"UEFI %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
|
||||
efivar_set(L"LoaderFirmwareType", typestr, FALSE);
|
||||
|
||||
(void) efivar_set_raw(&loader_guid, L"LoaderFeatures", &loader_features, sizeof(loader_features), FALSE);
|
||||
|
||||
err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
|
||||
image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (EFI_ERROR(err)) {
|
||||
@ -2116,7 +2139,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
loaded_image_path = DevicePathToStr(loaded_image->FilePath);
|
||||
efivar_set(L"LoaderImageIdentifier", loaded_image_path, FALSE);
|
||||
|
||||
ZeroMem(&config, sizeof(Config));
|
||||
config_load_defaults(&config, root_dir);
|
||||
|
||||
/* scan /EFI/Linux/ directory */
|
||||
@ -2141,7 +2163,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
UINT64 osind = (UINT64)*b;
|
||||
|
||||
if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI)
|
||||
config_entry_add_call(&config, L"auto-reboot-into-firmware-ui", L"Reboot Into Firmware Interface", reboot_into_firmware);
|
||||
config_entry_add_call(&config, L"auto-reboot-to-firmware-setup", L"Reboot Into Firmware Interface", reboot_into_firmware);
|
||||
FreePool(b);
|
||||
}
|
||||
|
||||
@ -2166,7 +2188,9 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
}
|
||||
|
||||
/* select entry or show menu when key is pressed or timeout is set */
|
||||
if (config.timeout_sec == 0) {
|
||||
if (config.force_menu || config.timeout_sec > 0)
|
||||
menu = TRUE;
|
||||
else {
|
||||
UINT64 key;
|
||||
|
||||
err = console_key_read(&key, FALSE);
|
||||
@ -2180,8 +2204,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
else
|
||||
menu = TRUE;
|
||||
}
|
||||
} else
|
||||
menu = TRUE;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
ConfigEntry *entry;
|
||||
@ -2192,12 +2215,12 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x10000, 0, NULL);
|
||||
if (!menu_run(&config, &entry, loaded_image_path))
|
||||
break;
|
||||
}
|
||||
|
||||
/* run special entry like "reboot" */
|
||||
if (entry->call) {
|
||||
entry->call();
|
||||
continue;
|
||||
}
|
||||
/* run special entry like "reboot" */
|
||||
if (entry->call) {
|
||||
entry->call();
|
||||
continue;
|
||||
}
|
||||
|
||||
config_entry_bump_counters(entry, root_dir);
|
||||
|
@ -59,7 +59,10 @@ UINT64 time_usec(VOID) {
|
||||
return 1000UL * 1000UL * ticks / freq;
|
||||
}
|
||||
|
||||
EFI_STATUS parse_boolean(CHAR8 *v, BOOLEAN *b) {
|
||||
EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b) {
|
||||
if (!v)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
if (strcmpa(v, (CHAR8 *)"1") == 0 ||
|
||||
strcmpa(v, (CHAR8 *)"yes") == 0 ||
|
||||
strcmpa(v, (CHAR8 *)"y") == 0 ||
|
||||
@ -79,46 +82,61 @@ EFI_STATUS parse_boolean(CHAR8 *v, BOOLEAN *b) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, CHAR16 *name, VOID *buf, UINTN size, BOOLEAN persistent) {
|
||||
EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const CHAR16 *name, const VOID *buf, UINTN size, BOOLEAN persistent) {
|
||||
UINT32 flags;
|
||||
|
||||
flags = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
|
||||
if (persistent)
|
||||
flags |= EFI_VARIABLE_NON_VOLATILE;
|
||||
|
||||
return uefi_call_wrapper(RT->SetVariable, 5, name, (EFI_GUID *)vendor, flags, size, buf);
|
||||
return uefi_call_wrapper(RT->SetVariable, 5, (CHAR16*) name, (EFI_GUID *)vendor, flags, size, (VOID*) buf);
|
||||
}
|
||||
|
||||
EFI_STATUS efivar_set(CHAR16 *name, CHAR16 *value, BOOLEAN persistent) {
|
||||
EFI_STATUS efivar_set(const CHAR16 *name, const CHAR16 *value, BOOLEAN persistent) {
|
||||
return efivar_set_raw(&loader_guid, name, value, value ? (StrLen(value)+1) * sizeof(CHAR16) : 0, persistent);
|
||||
}
|
||||
|
||||
EFI_STATUS efivar_set_int(CHAR16 *name, UINTN i, BOOLEAN persistent) {
|
||||
CHAR16 str[32];
|
||||
|
||||
SPrint(str, 32, L"%d", i);
|
||||
SPrint(str, 32, L"%u", i);
|
||||
return efivar_set(name, str, persistent);
|
||||
}
|
||||
|
||||
EFI_STATUS efivar_get(CHAR16 *name, CHAR16 **value) {
|
||||
EFI_STATUS efivar_get(const CHAR16 *name, CHAR16 **value) {
|
||||
_cleanup_freepool_ CHAR8 *buf = NULL;
|
||||
EFI_STATUS err;
|
||||
CHAR16 *val;
|
||||
UINTN size;
|
||||
EFI_STATUS err;
|
||||
|
||||
err = efivar_get_raw(&loader_guid, name, &buf, &size);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
val = StrDuplicate((CHAR16 *)buf);
|
||||
/* Make sure there are no incomplete characters in the buffer */
|
||||
if ((size % 2) != 0)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
/* Return buffer directly if it happens to be NUL terminated already */
|
||||
if (size >= 2 && buf[size-2] == 0 && buf[size-1] == 0) {
|
||||
*value = (CHAR16*) buf;
|
||||
buf = NULL;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/* Make sure a terminating NUL is available at the end */
|
||||
val = AllocatePool(size + 2);
|
||||
if (!val)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
CopyMem(val, buf, size);
|
||||
val[size/2] = 0; /* NUL terminate */
|
||||
|
||||
*value = val;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS efivar_get_int(CHAR16 *name, UINTN *i) {
|
||||
EFI_STATUS efivar_get_int(const CHAR16 *name, UINTN *i) {
|
||||
_cleanup_freepool_ CHAR16 *val = NULL;
|
||||
EFI_STATUS err;
|
||||
|
||||
@ -129,7 +147,7 @@ EFI_STATUS efivar_get_int(CHAR16 *name, UINTN *i) {
|
||||
return err;
|
||||
}
|
||||
|
||||
EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size) {
|
||||
EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const CHAR16 *name, CHAR8 **buffer, UINTN *size) {
|
||||
_cleanup_freepool_ CHAR8 *buf = NULL;
|
||||
UINTN l;
|
||||
EFI_STATUS err;
|
||||
@ -139,7 +157,7 @@ EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer,
|
||||
if (!buf)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
err = uefi_call_wrapper(RT->GetVariable, 5, name, (EFI_GUID *)vendor, NULL, &l, buf);
|
||||
err = uefi_call_wrapper(RT->GetVariable, 5, (CHAR16*) name, (EFI_GUID *)vendor, NULL, &l, buf);
|
||||
if (!EFI_ERROR(err)) {
|
||||
*buffer = buf;
|
||||
buf = NULL;
|
||||
@ -287,12 +305,12 @@ CHAR8 *strchra(CHAR8 *s, CHAR8 c) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EFI_STATUS file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content, UINTN *content_size) {
|
||||
EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN size, CHAR8 **content, UINTN *content_size) {
|
||||
EFI_FILE_HANDLE handle;
|
||||
_cleanup_freepool_ CHAR8 *buf = NULL;
|
||||
EFI_STATUS err;
|
||||
|
||||
err = uefi_call_wrapper(dir->Open, 5, dir, &handle, name, EFI_FILE_MODE_READ, 0ULL);
|
||||
err = uefi_call_wrapper(dir->Open, 5, dir, &handle, (CHAR16*) name, EFI_FILE_MODE_READ, 0ULL);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
|
@ -11,26 +11,26 @@ static inline const CHAR16 *yes_no(BOOLEAN b) {
|
||||
return b ? L"yes" : L"no";
|
||||
}
|
||||
|
||||
EFI_STATUS parse_boolean(CHAR8 *v, BOOLEAN *b);
|
||||
EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b);
|
||||
|
||||
UINT64 ticks_read(void);
|
||||
UINT64 ticks_freq(void);
|
||||
UINT64 time_usec(void);
|
||||
|
||||
EFI_STATUS efivar_set(CHAR16 *name, CHAR16 *value, BOOLEAN persistent);
|
||||
EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, CHAR16 *name, VOID *buf, UINTN size, BOOLEAN persistent);
|
||||
EFI_STATUS efivar_set(const CHAR16 *name, const CHAR16 *value, BOOLEAN persistent);
|
||||
EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const CHAR16 *name, const VOID *buf, UINTN size, BOOLEAN persistent);
|
||||
EFI_STATUS efivar_set_int(CHAR16 *name, UINTN i, BOOLEAN persistent);
|
||||
VOID efivar_set_time_usec(CHAR16 *name, UINT64 usec);
|
||||
|
||||
EFI_STATUS efivar_get(CHAR16 *name, CHAR16 **value);
|
||||
EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size);
|
||||
EFI_STATUS efivar_get_int(CHAR16 *name, UINTN *i);
|
||||
EFI_STATUS efivar_get(const CHAR16 *name, CHAR16 **value);
|
||||
EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const CHAR16 *name, CHAR8 **buffer, UINTN *size);
|
||||
EFI_STATUS efivar_get_int(const CHAR16 *name, UINTN *i);
|
||||
|
||||
CHAR8 *strchra(CHAR8 *s, CHAR8 c);
|
||||
CHAR16 *stra_to_path(CHAR8 *stra);
|
||||
CHAR16 *stra_to_str(CHAR8 *stra);
|
||||
|
||||
EFI_STATUS file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content, UINTN *content_size);
|
||||
EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN size, CHAR8 **content, UINTN *content_size);
|
||||
|
||||
static inline void FreePoolp(void *p) {
|
||||
void *q = *(void**) p;
|
||||
@ -52,3 +52,6 @@ static inline void FileHandleClosep(EFI_FILE_HANDLE *handle) {
|
||||
}
|
||||
|
||||
const EFI_GUID loader_guid;
|
||||
|
||||
#define UINTN_MAX (~(UINTN)0)
|
||||
#define INTN_MAX ((INTN)(UINTN_MAX>>1))
|
||||
|
Loading…
Reference in New Issue
Block a user