On 7/18/26 23:11, Daniel Golle wrote:
The console input used a single wait event for both the
EFI_SIMPLE_TEXT_INPUT_PROTOCOL and the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
by aliasing wait_for_key_ex to wait_for_key. The UEFI specification
describes these as separate events, and a client that opens ConInEx and
drives WaitForKeyEx independently of the base protocol (the Windows Boot
Manager does this) can then desynchronise against the shared object and
never observe a keystroke, even though GRUB and systemd-boot, which lean
on the base wait event, work.
Create a distinct WaitForKeyEx event, and signal and clear both events
together when a key becomes available or is consumed, so every client
sees a consistent wait event regardless of which protocol it uses.
Signed-off-by: Daniel Golle <[email protected]>
Hello Daniel,
Thank you for addressing this issue.
Could you, please, create a test case in lib/efi_selftest/ that fails
without the patch and succeeds with it.
Best regards
Heinrich
---
lib/efi_loader/efi_console.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 8d076058280..2c8adfcb2d1 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -681,6 +681,7 @@ struct efi_cin_notify_function {
static bool key_available;
static struct efi_key_data next_key;
static LIST_HEAD(cin_notify_functions);
+static struct efi_simple_text_input_ex_protocol efi_con_in_ex;
/**
* set_shift_mask() - set shift mask
@@ -937,6 +938,7 @@ static void efi_cin_check(void)
if (key_available) {
efi_signal_event(efi_con_in.wait_for_key);
+ efi_signal_event(efi_con_in_ex.wait_for_key_ex);
return;
}
@@ -949,8 +951,10 @@ static void efi_cin_check(void)
efi_cin_notify();
/* Queue the wait for key event */
- if (key_available)
+ if (key_available) {
efi_signal_event(efi_con_in.wait_for_key);
+ efi_signal_event(efi_con_in_ex.wait_for_key_ex);
+ }
}
}
}
@@ -1058,6 +1062,7 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
*key_data = next_key;
key_available = false;
efi_con_in.wait_for_key->is_signaled = false;
+ efi_con_in_ex.wait_for_key_ex->is_signaled = false;
out:
return EFI_EXIT(ret);
@@ -1259,6 +1264,7 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke
*key = next_key.key;
key_available = false;
efi_con_in.wait_for_key->is_signaled = false;
+ efi_con_in_ex.wait_for_key_ex->is_signaled = false;
out:
return EFI_EXIT(ret);
}
@@ -1351,7 +1357,12 @@ efi_status_t efi_console_register(void)
printf("ERROR: Failed to register WaitForKey event\n");
return r;
}
- efi_con_in_ex.wait_for_key_ex = efi_con_in.wait_for_key;
+ r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
+ NULL, NULL, &efi_con_in_ex.wait_for_key_ex);
+ if (r != EFI_SUCCESS) {
+ printf("ERROR: Failed to register WaitForKeyEx event\n");
+ return r;
+ }
r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
efi_console_timer_notify, NULL, NULL,
&console_timer_event);