Skip to content

Commit

Permalink
Detect and add keyboard input workaround for early AMI UEFI v2.0 systems
Browse files Browse the repository at this point in the history
* Early AMI UEFI v2.0 firmwares, such as the ones found in Dell Optiplex 390s,
  are unable to process USB keyboard input when the USB bus is simultaneously
  being used to read data at high speed.
* To work around this, we need to stall the system at regular intervals, so
  that it gets a chance to process USB keyboard cancellation.
* A 5 ms delay for each 1 MB read appears to be enough (and should only add
  about 5 seconds extra time for each GB of data being read).
  • Loading branch information
pbatard committed Mar 19, 2024
1 parent 86290ac commit 5d5e216
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 1 deletion.
13 changes: 13 additions & 0 deletions src/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ EFI_HANDLE gMainImageHandle = NULL;
*/
BOOLEAN gIsTestMode = FALSE;

/*
* Amount of time to pause after a read, in order to give buggy UEFI
* firmwares enough time to process USB keyboard input (in μs).
*/
UINTN gPauseAfterRead = 0;

/* Strings used for platform identification */
#if defined(_M_X64) || defined(__x86_64__)
STATIC CHAR16* Arch = L"x64";
Expand Down Expand Up @@ -316,6 +322,13 @@ EFI_STATUS EFIAPI efi_main(
goto out;
}

// Detect if we are booting on an early AMI UEFI v2.0 system
if (IsEarlyAmiUefi()) {
PrintWarning(L"Early AMI UEFI firmware detected!");
PrintWarning(L"This system may have trouble processing keyboard input.");
gPauseAfterRead = 5000;
}

// Detect if we are booting from an NTFS partition served by the buggy
// AMI NTFS driver and alert the user if that is the case.
if (IsProblematicNtfsDriver(DeviceHandle)) {
Expand Down
12 changes: 12 additions & 0 deletions src/boot.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ extern EFI_HANDLE gMainImageHandle;
/* Set to true when we are running the GitHub Actions tests */
extern BOOLEAN gIsTestMode;

/* Amount of time to pause after a read (in μs) */
extern UINTN gPauseAfterRead;

/* Dimensions of the UEFI text console */
typedef struct {
UINTN Cols;
Expand Down Expand Up @@ -378,6 +381,15 @@ STATIC __inline VOID _SafeStrCat(CHAR16* Destination, UINTN DestMax,
**/
BOOLEAN IsTestSystem(VOID);

/**
Detect if we are running an early AMI UEFI v2.0 system, that can't process USB
keyboard inputs unless we give it time to breathe.
@retval TRUE An AMI v2.0 UEFI firmware was detected.
@retval FALSE The system is not AMI v2.0 UEFI.
**/
BOOLEAN IsEarlyAmiUefi(VOID);

/**
Detect if we are running of an NTFS partition with the buggy AMI NTFS file system
driver (See: https://github.com/pbatard/AmiNtfsBug)
Expand Down
7 changes: 7 additions & 0 deletions src/hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,13 @@ EFI_STATUS HashFile(
for (ReadBytes = 0; ; ReadBytes += ReadSize) {
ReadSize = READ_BUFFERSIZE;
Status = File->Read(File, &ReadSize, Buffer);
// Early AMI UEFI v2.0 firmwares, such as the ones found in Dell
// Optiplex 390s, are unable to process USB keyboard input when
// the USB bus is simultaneously used to read data at high speed.
// So we pause these systems, to give them enough time to "breathe"
// and process USB keyboard cancellation.
if (gPauseAfterRead != 0)
Sleep(gPauseAfterRead);
if (EFI_ERROR(Status))
goto out;
if (ReadSize == 0)
Expand Down
15 changes: 14 additions & 1 deletion src/system.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* uefi-md5sum: UEFI MD5Sum validator - System Information
* Copyright © 2014-2023 Pete Batard <pete@akeo.ie>
* Copyright © 2014-2024 Pete Batard <pete@akeo.ie>
* With parts from EDK © 1998 Intel Corporation
*
* This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -142,6 +142,19 @@ BOOLEAN IsTestSystem(VOID)
return FALSE;
}

/**
Detect if we are running an early AMI UEFI v2.0 system, that can't
process USB keyboard inputs unless we give it time to breathe.
@retval TRUE An AMI v2.0 UEFI firmware was detected.
@retval FALSE The system is not AMI v2.0 UEFI.
**/
BOOLEAN IsEarlyAmiUefi(VOID)
{
return (StrCmp(gST->FirmwareVendor, L"American Megatrends") == 0 &&
gST->Hdr.Revision == 0x20000);
}

/**
Return a driver name from a driver handle.
Note that this call does not attempt to resolve the name of drivers
Expand Down

0 comments on commit 5d5e216

Please sign in to comment.