From 9bba284f4de0268356af8c004bf8482e079eb842 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 23 May 2016 23:06:55 +0800 Subject: [PATCH] Clib/EFI: Add standard input descriptor support This patch implements stdin for EFI environment using SIMPLE_INPUT_INTERFACE. Lv Zheng. Signed-off-by: Lv Zheng --- source/include/platform/acefi.h | 10 +- source/include/platform/acefiex.h | 21 +++- source/os_specific/service_layers/oseficlib.c | 118 ++++++++++++++++-- 3 files changed, 134 insertions(+), 15 deletions(-) diff --git a/source/include/platform/acefi.h b/source/include/platform/acefi.h index 172fac47a..567df9ff1 100644 --- a/source/include/platform/acefi.h +++ b/source/include/platform/acefi.h @@ -324,9 +324,11 @@ struct _EFI_SYSTEM_TABLE; extern struct _EFI_SYSTEM_TABLE *ST; extern struct _EFI_BOOT_SERVICES *BS; -#define FILE struct _SIMPLE_TEXT_OUTPUT_INTERFACE -#define stdout ST->ConOut -#define stderr ST->ConOut -#define stdin NULL +typedef union acpi_efi_file ACPI_EFI_FILE; + +#define FILE ACPI_EFI_FILE +#define stdout ((FILE *) (ST)->ConOut) +#define stderr ((FILE *) (ST)->ConOut) +#define stdin ((FILE *) (ST)->ConIn) #endif /* __ACEFI_H__ */ diff --git a/source/include/platform/acefiex.h b/source/include/platform/acefiex.h index 1fc58f752..17f347221 100644 --- a/source/include/platform/acefiex.h +++ b/source/include/platform/acefiex.h @@ -516,6 +516,15 @@ EFI_STATUS EFI_HANDLE ImageHandle); +typedef +EFI_STATUS +(EFIAPI *EFI_SET_WATCHDOG_TIMER) ( + UINTN Timeout, + UINT64 WatchdogCode, + UINTN DataSize, + CHAR16 *WatchdogData); + + #define EFI_IMAGE_INFORMATION_REVISION 0x1000 typedef struct { UINT32 Revision; @@ -803,13 +812,12 @@ typedef struct _EFI_BOOT_SERVICES { EFI_EXIT_BOOT_SERVICES ExitBootServices; EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount; EFI_STALL Stall; - EFI_SET_WATCHDOG_TIMER SetWatchdogTimer; #else EFI_UNKNOWN_INTERFACE ExitBootServices; EFI_UNKNOWN_INTERFACE GetNextMonotonicCount; EFI_UNKNOWN_INTERFACE Stall; - EFI_UNKNOWN_INTERFACE SetWatchdogTimer; #endif + EFI_SET_WATCHDOG_TIMER SetWatchdogTimer; #if 0 EFI_CONNECT_CONTROLLER ConnectController; @@ -890,6 +898,15 @@ typedef struct _EFI_SYSTEM_TABLE { } EFI_SYSTEM_TABLE; +/* FILE abstraction */ + +union acpi_efi_file { + struct _EFI_FILE_IO_INTERFACE File; + struct _SIMPLE_TEXT_OUTPUT_INTERFACE ConOut; + struct _SIMPLE_INPUT_INTERFACE ConIn; +}; + + /* GNU EFI definitions */ #if defined(_GNU_EFI) diff --git a/source/os_specific/service_layers/oseficlib.c b/source/os_specific/service_layers/oseficlib.c index 00b787447..5d6b1a7f4 100644 --- a/source/os_specific/service_layers/oseficlib.c +++ b/source/os_specific/service_layers/oseficlib.c @@ -125,6 +125,17 @@ #define ACPI_EFI_PRINT_LENGTH 256 +#define ACPI_EFI_KEY_ESC 0x0000 +#define ACPI_EFI_KEY_BACKSPACE 0x0008 +#define ACPI_EFI_KEY_ENTER 0x000D +#define ACPI_EFI_KEY_CTRL_C 0x0003 + +#define ACPI_EFI_ASCII_NULL 0x00 +#define ACPI_EFI_ASCII_DEL 0x7F +#define ACPI_EFI_ASCII_ESC 0x1B +#define ACPI_EFI_ASCII_CR '\r' +#define ACPI_EFI_ASCII_NL '\n' + /* Local prototypes */ @@ -322,7 +333,8 @@ fclose ( EFI_FILE_HANDLE EfiFile; - if (File == stdout || File == stderr) + if (File == stdin || File == stdout || + File == stderr) { return; } @@ -425,14 +437,87 @@ fread ( ACPI_SIZE Count, FILE *File) { - int Length = -1; + int Length = -EINVAL; EFI_FILE_HANDLE EfiFile; + SIMPLE_INPUT_INTERFACE *In; UINTN ReadSize; EFI_STATUS EfiStatus; + EFI_INPUT_KEY Key; + ACPI_SIZE Pos = 0; + if (!Buffer) + { + errno = EINVAL; + goto ErrorExit; + } + + ReadSize = Size * Count; + if (File == stdout || File == stderr) { + /* Do not support read operations on output console */ + } + else if (File == stdin) + { + In = ACPI_CAST_PTR (SIMPLE_INPUT_INTERFACE, File); + + while (Pos < ReadSize) + { +WaitKey: + EfiStatus = uefi_call_wrapper (In->ReadKeyStroke, 2, In, &Key); + if (EFI_ERROR (EfiStatus)) + { + if (EfiStatus == EFI_NOT_READY) + { + goto WaitKey; + } + errno = EIO; + Length = -EIO; + fprintf (stderr, + "SIMPLE_INPUT_INTERFACE->ReadKeyStroke() failure.\n"); + goto ErrorExit; + } + + switch (Key.UnicodeChar) + { + case ACPI_EFI_KEY_CTRL_C: + + break; + + case ACPI_EFI_KEY_ENTER: + + *(ACPI_ADD_PTR (UINT8, Buffer, Pos)) = (UINT8) ACPI_EFI_ASCII_CR; + if (Pos < ReadSize - 1) + { + /* Drop CR in case we don't have sufficient buffer */ + + Pos++; + } + *(ACPI_ADD_PTR (UINT8, Buffer, Pos)) = (UINT8) ACPI_EFI_ASCII_NL; + Pos++; + break; + + case ACPI_EFI_KEY_BACKSPACE: + + *(ACPI_ADD_PTR (UINT8, Buffer, Pos)) = (UINT8) ACPI_EFI_ASCII_DEL; + Pos++; + break; + + case ACPI_EFI_KEY_ESC: + + *(ACPI_ADD_PTR (UINT8, Buffer, Pos)) = (UINT8) ACPI_EFI_ASCII_ESC; + Pos++; + break; + + default: + + *(ACPI_ADD_PTR (UINT8, Buffer, Pos)) = (UINT8) Key.UnicodeChar; + Pos++; + break; + } + } + Length = Pos; } else { @@ -442,7 +527,6 @@ fread ( errno = EINVAL; goto ErrorExit; } - ReadSize = Size * Count; EfiStatus = uefi_call_wrapper (AcpiGbl_EfiCurrentVolume->Read, 3, EfiFile, &ReadSize, Buffer); @@ -450,6 +534,7 @@ fread ( { fprintf (stderr, "EFI_FILE_HANDLE->Read() failure.\n"); errno = EIO; + Length = -EIO; goto ErrorExit; } Length = ReadSize; @@ -485,12 +570,19 @@ AcpiEfiFlushFile ( CHAR16 *Pos, BOOLEAN FlushAll) { + SIMPLE_TEXT_OUTPUT_INTERFACE *Out; - if (FlushAll || Pos >= (End - 1)) + + if (File == stdout || File == stderr) { - *Pos = 0; - uefi_call_wrapper (File->OutputString, 2, File, Begin); - Pos = Begin; + Out = ACPI_CAST_PTR (SIMPLE_TEXT_OUTPUT_INTERFACE, File); + + if (FlushAll || Pos >= (End - 1)) + { + *Pos = 0; + uefi_call_wrapper (Out->OutputString, 2, Out, Begin); + Pos = Begin; + } } return (Pos); @@ -519,7 +611,7 @@ fwrite ( ACPI_SIZE Count, FILE *File) { - int Length = -1; + int Length = -EINVAL; CHAR16 String[ACPI_EFI_PRINT_LENGTH]; const char *Ascii; CHAR16 *End; @@ -530,7 +622,11 @@ fwrite ( EFI_STATUS EfiStatus; - if (File == stdout || File == stderr) + if (File == stdin) + { + /* Do not support write operations on input console */ + } + else if (File == stdout || File == stderr) { Pos = String; End = String + ACPI_EFI_PRINT_LENGTH - 1; @@ -898,6 +994,10 @@ efi_main ( ST = SystemTab; BS = SystemTab->BootServices; + /* Disable the platform watchdog timer if we go interactive */ + + uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x0, 0, NULL); + /* Retrieve image information */ EfiStatus = uefi_call_wrapper (BS->HandleProtocol, 3,