parent
e06734eac7
commit
84a769c071
@ -1,401 +0,0 @@ |
||||
From 3cf1b5fb6d1dc342e836cf0990df3170d2e9db49 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Janssen <medhefgo@web.de>
|
||||
Date: Wed, 11 Aug 2021 14:59:46 +0200
|
||||
Subject: [PATCH 20/21] sd-boot: Unify error handling
|
||||
|
||||
log_error_stall() and log_error_status_stall() will ensure the user has
|
||||
a chance to catch an error message by stalling and also forcing a
|
||||
lightred/black color on it. Also, convert several Print() calls to it
|
||||
since they are actually error messages.
|
||||
|
||||
(cherry picked from commit 8aba0eec499b762657f528988c2f093ac490620d)
|
||||
---
|
||||
src/boot/efi/boot.c | 62 ++++++++++----------------------
|
||||
src/boot/efi/random-seed.c | 73 +++++++++++++-------------------------
|
||||
src/boot/efi/stub.c | 24 ++++---------
|
||||
src/boot/efi/util.c | 17 +++++++--
|
||||
src/boot/efi/util.h | 9 +++++
|
||||
5 files changed, 75 insertions(+), 110 deletions(-)
|
||||
|
||||
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
|
||||
index 13940a6df7..54d704f0d1 100644
|
||||
--- a/src/boot/efi/boot.c
|
||||
+++ b/src/boot/efi/boot.c
|
||||
@@ -527,7 +527,7 @@ static BOOLEAN menu_run(
|
||||
err = console_set_mode(&config->console_mode, config->console_mode_change);
|
||||
if (EFI_ERROR(err)) {
|
||||
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
|
||||
- Print(L"Error switching console mode to %ld: %r.\r", (UINT64)config->console_mode, err);
|
||||
+ log_error_stall(L"Error switching console mode to %lu: %r", (UINT64)config->console_mode, err);
|
||||
}
|
||||
} else
|
||||
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
|
||||
@@ -1221,8 +1221,7 @@ static VOID config_entry_bump_counters(
|
||||
break;
|
||||
|
||||
if (r != EFI_BUFFER_TOO_SMALL || file_info_size * 2 < file_info_size) {
|
||||
- Print(L"\nFailed to get file info for '%s': %r\n", old_path, r);
|
||||
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
+ log_error_stall(L"Failed to get file info for '%s': %r", old_path, r);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1234,8 +1233,7 @@ static VOID config_entry_bump_counters(
|
||||
StrCpy(file_info->FileName, entry->next_name);
|
||||
r = uefi_call_wrapper(handle->SetInfo, 4, handle, &EfiFileInfoGuid, file_info_size, file_info);
|
||||
if (EFI_ERROR(r)) {
|
||||
- Print(L"\nFailed to rename '%s' to '%s', ignoring: %r\n", old_path, entry->next_name, r);
|
||||
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
+ log_error_stall(L"Failed to rename '%s' to '%s', ignoring: %r", old_path, entry->next_name, r);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2165,18 +2163,12 @@ static EFI_STATUS image_start(
|
||||
EFI_STATUS err;
|
||||
|
||||
path = FileDevicePath(entry->device, entry->loader);
|
||||
- if (!path) {
|
||||
- Print(L"Error getting device path.");
|
||||
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
- return EFI_INVALID_PARAMETER;
|
||||
- }
|
||||
+ if (!path)
|
||||
+ return log_error_status_stall(EFI_INVALID_PARAMETER, L"Error getting device path.");
|
||||
|
||||
err = uefi_call_wrapper(BS->LoadImage, 6, FALSE, parent_image, path, NULL, 0, &image);
|
||||
- if (EFI_ERROR(err)) {
|
||||
- Print(L"Error loading %s: %r", entry->loader, err);
|
||||
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
- return err;
|
||||
- }
|
||||
+ if (EFI_ERROR(err))
|
||||
+ return log_error_status_stall(err, L"Error loading %s: %r", entry->loader, err);
|
||||
|
||||
if (config->options_edit)
|
||||
options = config->options_edit;
|
||||
@@ -2190,8 +2182,7 @@ static EFI_STATUS image_start(
|
||||
err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
|
||||
parent_image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (EFI_ERROR(err)) {
|
||||
- Print(L"Error getting LoadedImageProtocol handle: %r", err);
|
||||
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
+ log_error_stall(L"Error getting LoadedImageProtocol handle: %r", err);
|
||||
goto out_unload;
|
||||
}
|
||||
loaded_image->LoadOptions = options;
|
||||
@@ -2202,10 +2193,8 @@ static EFI_STATUS image_start(
|
||||
err = tpm_log_event(SD_TPM_PCR,
|
||||
(EFI_PHYSICAL_ADDRESS) (UINTN) loaded_image->LoadOptions,
|
||||
loaded_image->LoadOptionsSize, loaded_image->LoadOptions);
|
||||
- if (EFI_ERROR(err)) {
|
||||
- Print(L"Unable to add image options measurement: %r", err);
|
||||
- uefi_call_wrapper(BS->Stall, 1, 200 * 1000);
|
||||
- }
|
||||
+ if (EFI_ERROR(err))
|
||||
+ log_error_stall(L"Unable to add image options measurement: %r", err);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2231,9 +2220,7 @@ static EFI_STATUS reboot_into_firmware(VOID) {
|
||||
return err;
|
||||
|
||||
err = uefi_call_wrapper(RT->ResetSystem, 4, EfiResetCold, EFI_SUCCESS, 0, NULL);
|
||||
- Print(L"Error calling ResetSystem: %r", err);
|
||||
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
- return err;
|
||||
+ return log_error_status_stall(err, L"Error calling ResetSystem: %r", err);
|
||||
}
|
||||
|
||||
static VOID config_free(Config *config) {
|
||||
@@ -2305,30 +2292,21 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
|
||||
err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
|
||||
image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
- if (EFI_ERROR(err)) {
|
||||
- Print(L"Error getting a LoadedImageProtocol handle: %r", err);
|
||||
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
- return err;
|
||||
- }
|
||||
+ if (EFI_ERROR(err))
|
||||
+ return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
|
||||
|
||||
/* export the device path this image is started from */
|
||||
if (disk_get_part_uuid(loaded_image->DeviceHandle, uuid) == EFI_SUCCESS)
|
||||
efivar_set(LOADER_GUID, L"LoaderDevicePartUUID", uuid, 0);
|
||||
|
||||
root_dir = LibOpenRoot(loaded_image->DeviceHandle);
|
||||
- if (!root_dir) {
|
||||
- Print(L"Unable to open root directory.");
|
||||
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
- return EFI_LOAD_ERROR;
|
||||
- }
|
||||
+ if (!root_dir)
|
||||
+ return log_error_status_stall(EFI_LOAD_ERROR, L"Unable to open root directory.", EFI_LOAD_ERROR);
|
||||
|
||||
if (secure_boot_enabled() && shim_loaded()) {
|
||||
err = security_policy_install();
|
||||
- if (EFI_ERROR(err)) {
|
||||
- Print(L"Error installing security policy: %r ", err);
|
||||
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
- return err;
|
||||
- }
|
||||
+ if (EFI_ERROR(err))
|
||||
+ return log_error_status_stall(err, L"Error installing security policy: %r", err);
|
||||
}
|
||||
|
||||
/* the filesystem path to this image, to prevent adding ourselves to the menu */
|
||||
@@ -2367,8 +2345,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
}
|
||||
|
||||
if (config.entry_count == 0) {
|
||||
- Print(L"No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
|
||||
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
+ log_error_stall(L"No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2440,8 +2417,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
err = image_start(image, &config, entry);
|
||||
if (EFI_ERROR(err)) {
|
||||
graphics_mode(FALSE);
|
||||
- Print(L"\nFailed to execute %s (%s): %r\n", entry->title, entry->loader, err);
|
||||
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
+ log_error_stall(L"Failed to execute %s (%s): %r", entry->title, entry->loader, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
diff --git a/src/boot/efi/random-seed.c b/src/boot/efi/random-seed.c
|
||||
index 3e179851b0..939daf3e41 100644
|
||||
--- a/src/boot/efi/random-seed.c
|
||||
+++ b/src/boot/efi/random-seed.c
|
||||
@@ -35,10 +35,8 @@ static EFI_STATUS acquire_rng(UINTN size, VOID **ret) {
|
||||
return log_oom();
|
||||
|
||||
err = uefi_call_wrapper(rng->GetRNG, 3, rng, NULL, size, data);
|
||||
- if (EFI_ERROR(err)) {
|
||||
- Print(L"Failed to acquire RNG data: %r\n", err);
|
||||
- return err;
|
||||
- }
|
||||
+ if (EFI_ERROR(err))
|
||||
+ return log_error_status_stall(err, L"Failed to acquire RNG data: %r", err);
|
||||
|
||||
*ret = TAKE_PTR(data);
|
||||
return EFI_SUCCESS;
|
||||
@@ -149,14 +147,12 @@ static EFI_STATUS acquire_system_token(VOID **ret, UINTN *ret_size) {
|
||||
err = efivar_get_raw(LOADER_GUID, L"LoaderSystemToken", &data, &size);
|
||||
if (EFI_ERROR(err)) {
|
||||
if (err != EFI_NOT_FOUND)
|
||||
- Print(L"Failed to read LoaderSystemToken EFI variable: %r", err);
|
||||
+ log_error_stall(L"Failed to read LoaderSystemToken EFI variable: %r", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
- if (size <= 0) {
|
||||
- Print(L"System token too short, ignoring.");
|
||||
- return EFI_NOT_FOUND;
|
||||
- }
|
||||
+ if (size <= 0)
|
||||
+ return log_error_status_stall(EFI_NOT_FOUND, L"System token too short, ignoring.");
|
||||
|
||||
*ret = TAKE_PTR(data);
|
||||
*ret_size = size;
|
||||
@@ -209,8 +205,7 @@ static VOID validate_sha256(void) {
|
||||
sha256_finish_ctx(&hash, result);
|
||||
|
||||
if (CompareMem(result, array[i].hash, HASH_VALUE_SIZE) != 0) {
|
||||
- Print(L"SHA256 failed validation.\n");
|
||||
- uefi_call_wrapper(BS->Stall, 1, 120 * 1000 * 1000);
|
||||
+ log_error_stall(L"SHA256 failed validation.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -246,7 +241,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
|
||||
err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &handle, (CHAR16*) L"\\loader\\random-seed", EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0ULL);
|
||||
if (EFI_ERROR(err)) {
|
||||
if (err != EFI_NOT_FOUND && err != EFI_WRITE_PROTECTED)
|
||||
- Print(L"Failed to open random seed file: %r\n", err);
|
||||
+ log_error_stall(L"Failed to open random seed file: %r", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -255,15 +250,11 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
|
||||
return log_oom();
|
||||
|
||||
size = info->FileSize;
|
||||
- if (size < RANDOM_MAX_SIZE_MIN) {
|
||||
- Print(L"Random seed file is too short?\n");
|
||||
- return EFI_INVALID_PARAMETER;
|
||||
- }
|
||||
+ if (size < RANDOM_MAX_SIZE_MIN)
|
||||
+ return log_error_status_stall(EFI_INVALID_PARAMETER, L"Random seed file is too short.");
|
||||
|
||||
- if (size > RANDOM_MAX_SIZE_MAX) {
|
||||
- Print(L"Random seed file is too large?\n");
|
||||
- return EFI_INVALID_PARAMETER;
|
||||
- }
|
||||
+ if (size > RANDOM_MAX_SIZE_MAX)
|
||||
+ return log_error_status_stall(EFI_INVALID_PARAMETER, L"Random seed file is too large.");
|
||||
|
||||
seed = AllocatePool(size);
|
||||
if (!seed)
|
||||
@@ -271,20 +262,14 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
|
||||
|
||||
rsize = size;
|
||||
err = uefi_call_wrapper(handle->Read, 3, handle, &rsize, seed);
|
||||
- if (EFI_ERROR(err)) {
|
||||
- Print(L"Failed to read random seed file: %r\n", err);
|
||||
- return err;
|
||||
- }
|
||||
- if (rsize != size) {
|
||||
- Print(L"Short read on random seed file\n");
|
||||
- return EFI_PROTOCOL_ERROR;
|
||||
- }
|
||||
+ if (EFI_ERROR(err))
|
||||
+ return log_error_status_stall(err, L"Failed to read random seed file: %r", err);
|
||||
+ if (rsize != size)
|
||||
+ return log_error_status_stall(EFI_PROTOCOL_ERROR, L"Short read on random seed file.");
|
||||
|
||||
err = uefi_call_wrapper(handle->SetPosition, 2, handle, 0);
|
||||
- if (EFI_ERROR(err)) {
|
||||
- Print(L"Failed to seek to beginning of random seed file: %r\n", err);
|
||||
- return err;
|
||||
- }
|
||||
+ if (EFI_ERROR(err))
|
||||
+ return log_error_status_stall(err, L"Failed to seek to beginning of random seed file: %r", err);
|
||||
|
||||
/* Request some random data from the UEFI RNG. We don't need this to work safely, but it's a good
|
||||
* idea to use it because it helps us for cases where users mistakenly include a random seed in
|
||||
@@ -299,27 +284,19 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
|
||||
/* Update the random seed on disk before we use it */
|
||||
wsize = size;
|
||||
err = uefi_call_wrapper(handle->Write, 3, handle, &wsize, new_seed);
|
||||
- if (EFI_ERROR(err)) {
|
||||
- Print(L"Failed to write random seed file: %r\n", err);
|
||||
- return err;
|
||||
- }
|
||||
- if (wsize != size) {
|
||||
- Print(L"Short write on random seed file\n");
|
||||
- return EFI_PROTOCOL_ERROR;
|
||||
- }
|
||||
+ if (EFI_ERROR(err))
|
||||
+ return log_error_status_stall(err, L"Failed to write random seed file: %r", err);
|
||||
+ if (wsize != size)
|
||||
+ return log_error_status_stall(EFI_PROTOCOL_ERROR, L"Short write on random seed file.");
|
||||
|
||||
err = uefi_call_wrapper(handle->Flush, 1, handle);
|
||||
- if (EFI_ERROR(err)) {
|
||||
- Print(L"Failed to flush random seed file: %r\n");
|
||||
- return err;
|
||||
- }
|
||||
+ if (EFI_ERROR(err))
|
||||
+ return log_error_status_stall(err, L"Failed to flush random seed file: %r", err);
|
||||
|
||||
/* We are good to go */
|
||||
err = efivar_set_raw(LOADER_GUID, L"LoaderRandomSeed", for_kernel, size, 0);
|
||||
- if (EFI_ERROR(err)) {
|
||||
- Print(L"Failed to write random seed to EFI variable: %r\n", err);
|
||||
- return err;
|
||||
- }
|
||||
+ if (EFI_ERROR(err))
|
||||
+ return log_error_status_stall(err, L"Failed to write random seed to EFI variable: %r", err);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
|
||||
index 082fe91c9e..82da1d3ec4 100644
|
||||
--- a/src/boot/efi/stub.c
|
||||
+++ b/src/boot/efi/stub.c
|
||||
@@ -36,18 +36,12 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
|
||||
err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
|
||||
image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
- if (EFI_ERROR(err)) {
|
||||
- Print(L"Error getting a LoadedImageProtocol handle: %r ", err);
|
||||
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
- return err;
|
||||
- }
|
||||
+ if (EFI_ERROR(err))
|
||||
+ return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
|
||||
|
||||
err = pe_memory_locate_sections(loaded_image->ImageBase, sections, addrs, offs, szs);
|
||||
- if (EFI_ERROR(err)) {
|
||||
- Print(L"Unable to locate embedded .linux section: %r ", err);
|
||||
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
- return err;
|
||||
- }
|
||||
+ if (EFI_ERROR(err))
|
||||
+ return log_error_status_stall(err, L"Unable to locate embedded .linux section: %r", err);
|
||||
|
||||
if (szs[0] > 0)
|
||||
cmdline = (CHAR8 *)(loaded_image->ImageBase) + addrs[0];
|
||||
@@ -72,10 +66,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
err = tpm_log_event(SD_TPM_PCR,
|
||||
(EFI_PHYSICAL_ADDRESS) (UINTN) loaded_image->LoadOptions,
|
||||
loaded_image->LoadOptionsSize, loaded_image->LoadOptions);
|
||||
- if (EFI_ERROR(err)) {
|
||||
- Print(L"Unable to add image options measurement: %r", err);
|
||||
- uefi_call_wrapper(BS->Stall, 1, 200 * 1000);
|
||||
- }
|
||||
+ if (EFI_ERROR(err))
|
||||
+ log_error_stall(L"Unable to add image options measurement: %r", err);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -126,7 +118,5 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
(UINTN)loaded_image->ImageBase + addrs[2], szs[2]);
|
||||
|
||||
graphics_mode(FALSE);
|
||||
- Print(L"Execution of embedded linux image failed: %r\n", err);
|
||||
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
- return err;
|
||||
+ return log_error_status_stall(err, L"Execution of embedded linux image failed: %r", err);
|
||||
}
|
||||
diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c
|
||||
index 6f4e5933d3..aee076060b 100644
|
||||
--- a/src/boot/efi/util.c
|
||||
+++ b/src/boot/efi/util.c
|
||||
@@ -411,8 +411,21 @@ EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN s
|
||||
return err;
|
||||
}
|
||||
|
||||
+VOID log_error_stall(const CHAR16 *fmt, ...) {
|
||||
+ va_list args;
|
||||
+
|
||||
+ uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTRED|EFI_BACKGROUND_BLACK);
|
||||
+
|
||||
+ Print(L"\n");
|
||||
+ va_start(args, fmt);
|
||||
+ VPrint(fmt, args);
|
||||
+ va_end(args);
|
||||
+ Print(L"\n");
|
||||
+
|
||||
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
+}
|
||||
+
|
||||
EFI_STATUS log_oom(void) {
|
||||
- Print(L"Out of memory.");
|
||||
- (void) uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
+ log_error_stall(L"Out of memory.");
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
|
||||
index 1a42b01033..d3bf848a95 100644
|
||||
--- a/src/boot/efi/util.h
|
||||
+++ b/src/boot/efi/util.h
|
||||
@@ -74,4 +74,13 @@ static inline void FileHandleClosep(EFI_FILE_HANDLE *handle) {
|
||||
#define UINT64_MAX ((UINT64) -1)
|
||||
#endif
|
||||
|
||||
+VOID log_error_stall(const CHAR16 *fmt, ...);
|
||||
EFI_STATUS log_oom(void);
|
||||
+
|
||||
+/* This works just like log_error_errno() from userspace, but requires you
|
||||
+ * to provide err a second time if you want to use %r in the message! */
|
||||
+#define log_error_status_stall(err, fmt, ...) \
|
||||
+ ({ \
|
||||
+ log_error_stall(fmt, ##__VA_ARGS__); \
|
||||
+ err; \
|
||||
+ })
|
||||
--
|
||||
2.33.0
|
||||
|
@ -1,320 +0,0 @@ |
||||
From 2d9fcfcfa38667ada306e095599944f941576e53 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Janssen <medhefgo@web.de>
|
||||
Date: Wed, 11 Aug 2021 14:59:46 +0200
|
||||
Subject: [PATCH 21/21] sd-boot: Rework console input handling
|
||||
|
||||
Fixes: #15847
|
||||
Probably fixes: #19191
|
||||
|
||||
(cherry picked from commit e98d271e57f3d0356e444b6ea2d48836ee2769b0)
|
||||
---
|
||||
src/boot/efi/boot.c | 55 +++++++---------------
|
||||
src/boot/efi/console.c | 102 +++++++++++++++++++++++++++++------------
|
||||
src/boot/efi/console.h | 2 +-
|
||||
3 files changed, 91 insertions(+), 68 deletions(-)
|
||||
|
||||
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
|
||||
index 54d704f0d1..b4f3b9605a 100644
|
||||
--- a/src/boot/efi/boot.c
|
||||
+++ b/src/boot/efi/boot.c
|
||||
@@ -134,7 +134,7 @@ static BOOLEAN line_edit(
|
||||
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, print);
|
||||
uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos);
|
||||
|
||||
- err = console_key_read(&key, TRUE);
|
||||
+ err = console_key_read(&key, 0);
|
||||
if (EFI_ERROR(err))
|
||||
continue;
|
||||
|
||||
@@ -387,7 +387,7 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
|
||||
Print(L"OsIndicationsSupported: %d\n", indvar);
|
||||
|
||||
Print(L"\n--- press key ---\n\n");
|
||||
- console_key_read(&key, TRUE);
|
||||
+ console_key_read(&key, 0);
|
||||
|
||||
Print(L"timeout: %u\n", config->timeout_sec);
|
||||
if (config->timeout_sec_efivar >= 0)
|
||||
@@ -432,7 +432,7 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
|
||||
Print(L"LoaderEntryDefault: %s\n", defaultstr);
|
||||
|
||||
Print(L"\n--- press key ---\n\n");
|
||||
- console_key_read(&key, TRUE);
|
||||
+ console_key_read(&key, 0);
|
||||
|
||||
for (UINTN i = 0; i < config->entry_count; i++) {
|
||||
ConfigEntry *entry;
|
||||
@@ -482,7 +482,7 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
|
||||
entry->path, entry->next_name);
|
||||
|
||||
Print(L"\n--- press key ---\n\n");
|
||||
- console_key_read(&key, TRUE);
|
||||
+ console_key_read(&key, 0);
|
||||
}
|
||||
|
||||
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
|
||||
@@ -509,11 +509,10 @@ static BOOLEAN menu_run(
|
||||
UINTN y_max;
|
||||
CHAR16 *status;
|
||||
CHAR16 *clearline;
|
||||
- INTN timeout_remain;
|
||||
+ UINTN timeout_remain = config->timeout_sec;
|
||||
INT16 idx;
|
||||
BOOLEAN exit = FALSE;
|
||||
BOOLEAN run = TRUE;
|
||||
- BOOLEAN wait = FALSE;
|
||||
|
||||
graphics_mode(FALSE);
|
||||
uefi_call_wrapper(ST->ConIn->Reset, 2, ST->ConIn, FALSE);
|
||||
@@ -538,12 +537,6 @@ static BOOLEAN menu_run(
|
||||
y_max = 25;
|
||||
}
|
||||
|
||||
- /* we check 10 times per second for a keystroke */
|
||||
- if (config->timeout_sec > 0)
|
||||
- timeout_remain = config->timeout_sec * 10;
|
||||
- else
|
||||
- timeout_remain = -1;
|
||||
-
|
||||
idx_highlight = config->idx_default;
|
||||
idx_highlight_prev = 0;
|
||||
|
||||
@@ -643,7 +636,7 @@ static BOOLEAN menu_run(
|
||||
|
||||
if (timeout_remain > 0) {
|
||||
FreePool(status);
|
||||
- status = PoolPrint(L"Boot in %d sec.", (timeout_remain + 5) / 10);
|
||||
+ status = PoolPrint(L"Boot in %d s.", timeout_remain);
|
||||
}
|
||||
|
||||
/* print status at last line of screen */
|
||||
@@ -664,27 +657,18 @@ static BOOLEAN menu_run(
|
||||
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1 + x + len);
|
||||
}
|
||||
|
||||
- err = console_key_read(&key, wait);
|
||||
- if (EFI_ERROR(err)) {
|
||||
- /* timeout reached */
|
||||
+ err = console_key_read(&key, timeout_remain > 0 ? 1000 * 1000 : 0);
|
||||
+ if (err == EFI_TIMEOUT) {
|
||||
+ timeout_remain--;
|
||||
if (timeout_remain == 0) {
|
||||
exit = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
- /* sleep and update status */
|
||||
- if (timeout_remain > 0) {
|
||||
- uefi_call_wrapper(BS->Stall, 1, 100 * 1000);
|
||||
- timeout_remain--;
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- /* timeout disabled, wait for next key */
|
||||
- wait = TRUE;
|
||||
+ /* update status */
|
||||
continue;
|
||||
- }
|
||||
-
|
||||
- timeout_remain = -1;
|
||||
+ } else
|
||||
+ timeout_remain = 0;
|
||||
|
||||
/* clear status after keystroke */
|
||||
if (status) {
|
||||
@@ -787,7 +771,7 @@ static BOOLEAN menu_run(
|
||||
config->timeout_sec_efivar,
|
||||
EFI_VARIABLE_NON_VOLATILE);
|
||||
if (config->timeout_sec_efivar > 0)
|
||||
- status = PoolPrint(L"Menu timeout set to %d sec.", config->timeout_sec_efivar);
|
||||
+ status = PoolPrint(L"Menu timeout set to %d s.", config->timeout_sec_efivar);
|
||||
else
|
||||
status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu.");
|
||||
} else if (config->timeout_sec_efivar <= 0){
|
||||
@@ -795,7 +779,7 @@ static BOOLEAN menu_run(
|
||||
efivar_set(
|
||||
LOADER_GUID, L"LoaderConfigTimeout", NULL, EFI_VARIABLE_NON_VOLATILE);
|
||||
if (config->timeout_sec_config > 0)
|
||||
- status = PoolPrint(L"Menu timeout of %d sec is defined by configuration file.",
|
||||
+ status = PoolPrint(L"Menu timeout of %d s is defined by configuration file.",
|
||||
config->timeout_sec_config);
|
||||
else
|
||||
status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu.");
|
||||
@@ -813,7 +797,7 @@ static BOOLEAN menu_run(
|
||||
config->timeout_sec_efivar,
|
||||
EFI_VARIABLE_NON_VOLATILE);
|
||||
if (config->timeout_sec_efivar > 0)
|
||||
- status = PoolPrint(L"Menu timeout set to %d sec.",
|
||||
+ status = PoolPrint(L"Menu timeout set to %d s.",
|
||||
config->timeout_sec_efivar);
|
||||
else
|
||||
status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu.");
|
||||
@@ -2369,13 +2353,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
else {
|
||||
UINT64 key;
|
||||
|
||||
- err = console_key_read(&key, FALSE);
|
||||
-
|
||||
- if (err == EFI_NOT_READY) {
|
||||
- uefi_call_wrapper(BS->Stall, 1, 100 * 1000);
|
||||
- err = console_key_read(&key, FALSE);
|
||||
- }
|
||||
-
|
||||
+ /* Block up to 100ms to give firmware time to get input working. */
|
||||
+ err = console_key_read(&key, 100 * 1000);
|
||||
if (!EFI_ERROR(err)) {
|
||||
INT16 idx;
|
||||
|
||||
diff --git a/src/boot/efi/console.c b/src/boot/efi/console.c
|
||||
index 83619d2147..369c549daf 100644
|
||||
--- a/src/boot/efi/console.c
|
||||
+++ b/src/boot/efi/console.c
|
||||
@@ -11,61 +11,105 @@
|
||||
|
||||
#define EFI_SIMPLE_TEXT_INPUT_EX_GUID &(EFI_GUID) EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID
|
||||
|
||||
-EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait) {
|
||||
+static inline void EventClosep(EFI_EVENT *event) {
|
||||
+ if (!*event)
|
||||
+ return;
|
||||
+
|
||||
+ uefi_call_wrapper(BS->CloseEvent, 1, *event);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Reading input from the console sounds like an easy task to do, but thanks to broken
|
||||
+ * firmware it is actually a nightmare.
|
||||
+ *
|
||||
+ * There is a ConIn and TextInputEx API for this. Ideally we want to use TextInputEx,
|
||||
+ * because that gives us Ctrl/Alt/Shift key state information. Unfortunately, it is not
|
||||
+ * always available and sometimes just non-functional.
|
||||
+ *
|
||||
+ * On the other hand we have ConIn, where some firmware likes to just freeze on us
|
||||
+ * if we call ReadKeyStroke on it.
|
||||
+ *
|
||||
+ * Therefore, we use WaitForEvent on both ConIn and TextInputEx (if available) along
|
||||
+ * with a timer event. The timer ensures there is no need to call into functions
|
||||
+ * that might freeze on us, while still allowing us to show a timeout counter.
|
||||
+ */
|
||||
+EFI_STATUS console_key_read(UINT64 *key, UINT64 timeout_usec) {
|
||||
static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInputEx;
|
||||
static BOOLEAN checked;
|
||||
UINTN index;
|
||||
EFI_INPUT_KEY k;
|
||||
EFI_STATUS err;
|
||||
+ _cleanup_(EventClosep) EFI_EVENT timer = NULL;
|
||||
+ EFI_EVENT events[3] = { ST->ConIn->WaitForKey };
|
||||
+ UINTN n_events = 1;
|
||||
|
||||
if (!checked) {
|
||||
err = LibLocateProtocol(EFI_SIMPLE_TEXT_INPUT_EX_GUID, (VOID **)&TextInputEx);
|
||||
- if (EFI_ERROR(err))
|
||||
+ if (EFI_ERROR(err) ||
|
||||
+ uefi_call_wrapper(BS->CheckEvent, 1, TextInputEx->WaitForKeyEx) == EFI_INVALID_PARAMETER)
|
||||
+ /* If WaitForKeyEx fails here, the firmware pretends it talks this
|
||||
+ * protocol, but it really doesn't. */
|
||||
TextInputEx = NULL;
|
||||
+ else
|
||||
+ events[n_events++] = TextInputEx->WaitForKeyEx;
|
||||
|
||||
checked = TRUE;
|
||||
}
|
||||
|
||||
- /* wait until key is pressed */
|
||||
- if (wait)
|
||||
- uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &index);
|
||||
+ if (timeout_usec > 0) {
|
||||
+ err = uefi_call_wrapper(BS->CreateEvent, 5, EVT_TIMER, 0, NULL, NULL, &timer);
|
||||
+ if (EFI_ERROR(err))
|
||||
+ return log_error_status_stall(err, L"Error creating timer event: %r", err);
|
||||
+
|
||||
+ /* SetTimer expects 100ns units for some reason. */
|
||||
+ err = uefi_call_wrapper(BS->SetTimer, 3, timer, TimerRelative, timeout_usec * 10);
|
||||
+ if (EFI_ERROR(err))
|
||||
+ return log_error_status_stall(err, L"Error arming timer event: %r", err);
|
||||
|
||||
- if (TextInputEx) {
|
||||
+ events[n_events++] = timer;
|
||||
+ }
|
||||
+
|
||||
+ err = uefi_call_wrapper(BS->WaitForEvent, 3, n_events, events, &index);
|
||||
+ if (EFI_ERROR(err))
|
||||
+ return log_error_status_stall(err, L"Error waiting for events: %r", err);
|
||||
+
|
||||
+ if (timeout_usec > 0 && timer == events[index])
|
||||
+ return EFI_TIMEOUT;
|
||||
+
|
||||
+ /* TextInputEx might be ready too even if ConIn got to signal first. */
|
||||
+ if (TextInputEx && !EFI_ERROR(uefi_call_wrapper(BS->CheckEvent, 1, TextInputEx->WaitForKeyEx))) {
|
||||
EFI_KEY_DATA keydata;
|
||||
UINT64 keypress;
|
||||
+ UINT32 shift = 0;
|
||||
|
||||
err = uefi_call_wrapper(TextInputEx->ReadKeyStrokeEx, 2, TextInputEx, &keydata);
|
||||
- if (!EFI_ERROR(err)) {
|
||||
- UINT32 shift = 0;
|
||||
-
|
||||
- /* do not distinguish between left and right keys */
|
||||
- if (keydata.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) {
|
||||
- if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED))
|
||||
- shift |= EFI_CONTROL_PRESSED;
|
||||
- if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED))
|
||||
- shift |= EFI_ALT_PRESSED;
|
||||
- };
|
||||
-
|
||||
- /* 32 bit modifier keys + 16 bit scan code + 16 bit unicode */
|
||||
- keypress = KEYPRESS(shift, keydata.Key.ScanCode, keydata.Key.UnicodeChar);
|
||||
- if (keypress > 0) {
|
||||
- *key = keypress;
|
||||
- return 0;
|
||||
- }
|
||||
+ if (EFI_ERROR(err))
|
||||
+ return err;
|
||||
+
|
||||
+ /* do not distinguish between left and right keys */
|
||||
+ if (keydata.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) {
|
||||
+ if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED))
|
||||
+ shift |= EFI_CONTROL_PRESSED;
|
||||
+ if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED))
|
||||
+ shift |= EFI_ALT_PRESSED;
|
||||
+ };
|
||||
+
|
||||
+ /* 32 bit modifier keys + 16 bit scan code + 16 bit unicode */
|
||||
+ keypress = KEYPRESS(shift, keydata.Key.ScanCode, keydata.Key.UnicodeChar);
|
||||
+ if (keypress > 0) {
|
||||
+ *key = keypress;
|
||||
+ return EFI_SUCCESS;
|
||||
}
|
||||
+
|
||||
+ return EFI_NOT_READY;
|
||||
}
|
||||
|
||||
- /* fallback for firmware which does not support SimpleTextInputExProtocol
|
||||
- *
|
||||
- * This is also called in case ReadKeyStrokeEx did not return a key, because
|
||||
- * some broken firmwares offer SimpleTextInputExProtocol, but never actually
|
||||
- * handle any key. */
|
||||
err = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &k);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
*key = KEYPRESS(0, k.ScanCode, k.UnicodeChar);
|
||||
- return 0;
|
||||
+ return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static EFI_STATUS change_mode(UINTN mode) {
|
||||
diff --git a/src/boot/efi/console.h b/src/boot/efi/console.h
|
||||
index 2c69af552a..23848a9c58 100644
|
||||
--- a/src/boot/efi/console.h
|
||||
+++ b/src/boot/efi/console.h
|
||||
@@ -16,5 +16,5 @@ enum console_mode_change_type {
|
||||
CONSOLE_MODE_MAX,
|
||||
};
|
||||
|
||||
-EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait);
|
||||
+EFI_STATUS console_key_read(UINT64 *key, UINT64 timeout_usec);
|
||||
EFI_STATUS console_set_mode(UINTN *mode, enum console_mode_change_type how);
|
||||
--
|
||||
2.33.0
|
||||
|
Loading…
Reference in new issue