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

Reply via email to