From dc9ee344787fb2f81db479530ea71093c5807fbc Mon Sep 17 00:00:00 2001 From: Ahmed Arif Date: Sun, 8 Mar 2026 19:40:15 +0100 Subject: [PATCH] [FREELDR:UEFI] Fix broken boot menu countdown (#8714) The UEFI boot menu countdown was broken for two reasons: - StallExecutionProcessor and UefiHwIdle were empty stubs, so the countdown had no actual delay and no proper idle, it ran instantly without waiting KbHit used ReadKeyStroke to poll for input, which consumed the keystroke before GetCh could read it. This fixes both: StallExecutionProcessor and UefiHwIdle now have real implementations using BootServices->Stall and a timer event. KbHit is changed to use CheckEvent(WaitForKey) which polls availability without consuming the key. CORE-11954 --- boot/freeldr/freeldr/arch/uefi/stubs.c | 12 -------- boot/freeldr/freeldr/arch/uefi/ueficon.c | 14 +++++---- boot/freeldr/freeldr/arch/uefi/uefihw.c | 37 ++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/boot/freeldr/freeldr/arch/uefi/stubs.c b/boot/freeldr/freeldr/arch/uefi/stubs.c index f63bd4d2105..ddafac47345 100644 --- a/boot/freeldr/freeldr/arch/uefi/stubs.c +++ b/boot/freeldr/freeldr/arch/uefi/stubs.c @@ -16,12 +16,6 @@ DriveMapGetBiosDriveNumber(PCSTR DeviceName) } #endif -VOID -StallExecutionProcessor(ULONG Microseconds) -{ - -} - VOID UefiVideoGetFontsFromFirmware(PULONG RomFontPointers) { @@ -46,9 +40,3 @@ UefiPcBeep(VOID) { /* Not possible on UEFI, for now */ } - -VOID -UefiHwIdle(VOID) -{ - -} diff --git a/boot/freeldr/freeldr/arch/uefi/ueficon.c b/boot/freeldr/freeldr/arch/uefi/ueficon.c index 18ba8d8ab3b..1c029a3a29f 100644 --- a/boot/freeldr/freeldr/arch/uefi/ueficon.c +++ b/boot/freeldr/freeldr/arch/uefi/ueficon.c @@ -17,7 +17,6 @@ static unsigned CurrentCursorY = 0; static UCHAR CurrentAttr = ATTR(COLOR_GRAY, COLOR_BLACK); extern EFI_SYSTEM_TABLE* GlobalSystemTable; -static EFI_INPUT_KEY Key; static BOOLEAN ExtendedKey = FALSE; static char ExtendedScanCode = 0; @@ -121,12 +120,15 @@ ConvertToBiosExtValue(UCHAR KeyIn) BOOLEAN UefiConsKbHit(VOID) { - return (GlobalSystemTable->ConIn->ReadKeyStroke(GlobalSystemTable->ConIn, &Key) != EFI_NOT_READY); + return (GlobalSystemTable->BootServices->CheckEvent( + GlobalSystemTable->ConIn->WaitForKey) == EFI_SUCCESS); } int UefiConsGetCh(VOID) { + EFI_INPUT_KEY Key; + EFI_STATUS Status; UCHAR KeyOutput = 0; /* If an extended key press was detected the last time we were called @@ -137,6 +139,10 @@ UefiConsGetCh(VOID) return ExtendedScanCode; } + Status = GlobalSystemTable->ConIn->ReadKeyStroke(GlobalSystemTable->ConIn, &Key); + if (EFI_ERROR(Status)) + return 0; + if (Key.UnicodeChar != 0) { KeyOutput = Key.UnicodeChar; @@ -147,9 +153,5 @@ UefiConsGetCh(VOID) ExtendedScanCode = ConvertToBiosExtValue(Key.ScanCode); KeyOutput = KEY_EXTENDED; } - - /* UEFI will stack input requests, we have to clear it */ - Key.UnicodeChar = 0; - Key.ScanCode = 0; return KeyOutput; } diff --git a/boot/freeldr/freeldr/arch/uefi/uefihw.c b/boot/freeldr/freeldr/arch/uefi/uefihw.c index 3f5edb2322e..933fce60ee4 100644 --- a/boot/freeldr/freeldr/arch/uefi/uefihw.c +++ b/boot/freeldr/freeldr/arch/uefi/uefihw.c @@ -25,9 +25,46 @@ extern ULONG VramSize; extern PCM_FRAMEBUF_DEVICE_DATA FrameBufferData; BOOLEAN AcpiPresent = FALSE; +static EFI_EVENT IdleTimerEvent = NULL; /* FUNCTIONS *****************************************************************/ +VOID +StallExecutionProcessor(ULONG Microseconds) +{ + GlobalSystemTable->BootServices->Stall(Microseconds); +} + +VOID +UefiHwIdle(VOID) +{ + UINTN Index; + EFI_STATUS Status; + EFI_BOOT_SERVICES *BootServices = GlobalSystemTable->BootServices; + + /* Keep one timer event around and arm it each idle tick */ + if (IdleTimerEvent == NULL) + { + Status = BootServices->CreateEvent(EVT_TIMER, + TPL_APPLICATION, + NULL, + NULL, + &IdleTimerEvent); + if (EFI_ERROR(Status)) + { + StallExecutionProcessor(10000); /* 10 ms fallback */ + return; + } + } + + /* Set a 10ms (100,000 * 100ns) relative timer */ + Status = BootServices->SetTimer(IdleTimerEvent, TimerRelative, 100000); + if (!EFI_ERROR(Status)) + Status = BootServices->WaitForEvent(1, &IdleTimerEvent, &Index); + if (EFI_ERROR(Status)) + StallExecutionProcessor(10000); /* 10 ms fallback */ +} + BOOLEAN IsAcpiPresent(VOID) { return AcpiPresent;