From 8a8904aaddcc9497b2c3d110785b52e4d1dca336 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 15 Jul 2025 16:56:11 +0100 Subject: [PATCH] [efi] Check only the non-extended WaitForKey event The WaitForKeyEx event in EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL is redundant: by definition it has to signal under exactly the same conditions as the WaitForKey event in EFI_SIMPLE_TEXT_INPUT_PROTOCOL and cannot provide any "extended" information since EFI events do not convey any information beyond their own occurrence. UEFI keyboard drivers such as Ps2KeyboardDxe and UsbKbDxe invariably use a single notification function to implement both events. The console multiplexer driver ConSplitterDxe uses a single notification function for both events, which ends up checking only the WaitForKey event on the underlying console devices. (Since all console input is routed through the console multiplexer, this means that in practice nothing will ever check the underlying devices' WaitForKeyEx events.) UEFI console consumers such as the UEFI shell tend to use only the EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance provided as ConIn in the EFI system table. With the exception of the UEFI text editor (the "edit" command in the UEFI shell), almost nothing bothers to open the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance on the same handle. The Lenovo ThinkPad T14s Gen 5 has a very peculiar firmware bug. Enabling the "UEFI Wi-Fi Network Boot" feature in the BIOS setup will cause the completely unrelated WaitForKeyEx event pointer to be overwritten with a pointer to a FAT_DIRENT structure representing the "BOOT" directory in the EFI system partition. This happens with 100% repeatability. It is not necessary to attempt to boot from Wi-Fi: it is only necessary to have the feature enabled. The root cause is unknown, but is presumably an uninitialised pointer or similar memory-related bug in Lenovo's UEFI Wi-Fi driver. Work around this Lenovo firmware bug by checking only the WaitForKey event, ignoring the WaitForKeyEx event even if we will subsequently use ReadKeyStrokeEx() to read the keypress. Since almost all other UEFI console consumers use only WaitForKey, this ensures that we will be using code paths that the firmware vendor is likely to have tested at least once. Signed-off-by: Michael Brown --- src/interface/efi/efi_console.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/interface/efi/efi_console.c b/src/interface/efi/efi_console.c index c5a3f24ca..e896c5d88 100644 --- a/src/interface/efi/efi_console.c +++ b/src/interface/efi/efi_console.c @@ -386,8 +386,6 @@ static int efi_getchar ( void ) { static int efi_iskey ( void ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn; - EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *conin_ex = efi_conin_ex; - EFI_EVENT event; EFI_STATUS efirc; /* If we are mid-sequence, we are always ready */ @@ -395,8 +393,7 @@ static int efi_iskey ( void ) { return 1; /* Check to see if the WaitForKey event has fired */ - event = ( conin_ex ? conin_ex->WaitForKeyEx : conin->WaitForKey ); - if ( ( efirc = bs->CheckEvent ( event ) ) == 0 ) + if ( ( efirc = bs->CheckEvent ( conin->WaitForKey ) ) == 0 ) return 1; return 0; -- 2.47.2