Merge pull request #10804 from poettering/sd-boot-updates

various sd-boot/EFI fixes (split out from #10495)
This commit is contained in:
Lennart Poettering 2018-11-16 17:52:37 +01:00 committed by GitHub
commit 1b259a5bf3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 95 additions and 39 deletions

View file

@ -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>

View file

@ -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);

View file

@ -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;

View file

@ -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))