123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735 |
- /** @file
- Simple Console that sits on a SerialLib.
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- /*
- Symbols used in table below
- ===========================
- ESC = 0x1B
- CSI = 0x9B
- DEL = 0x7f
- ^ = CTRL
- +=========+======+===========+==========+==========+
- | | EFI | UEFI 2.0 | | |
- | | Scan | | VT100+ | |
- | KEY | Code | PC ANSI | VTUTF8 | VT100 |
- +=========+======+===========+==========+==========+
- | NULL | 0x00 | | | |
- | UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |
- | DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |
- | RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C |
- | LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |
- | HOME | 0x05 | ESC [ H | ESC h | ESC [ H |
- | END | 0x06 | ESC [ F | ESC k | ESC [ K |
- | INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |
- | | | ESC [ L | | ESC [ L |
- | DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |
- | PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |
- | | | | | ESC [ ? |
- | PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
- | | | | | ESC [ / |
- | F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |
- | F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |
- | F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |
- | F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |
- | F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |
- | F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |
- | F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |
- | F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |
- | F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |
- | F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |
- | Escape | 0x17 | ESC | ESC | ESC |
- | F11 | 0x15 | | ESC ! | |
- | F12 | 0x16 | | ESC @ | |
- +=========+======+===========+==========+==========+
- */
- #include <PiDxe.h>
- #include <Library/UefiLib.h>
- #include <Library/UefiBootServicesTableLib.h>
- #include <Library/BaseLib.h>
- #include <Library/MemoryAllocationLib.h>
- #include <Library/DebugLib.h>
- #include <Library/SerialPortLib.h>
- #include <Library/PcdLib.h>
- #include <Protocol/SerialIo.h>
- #include <Protocol/SimpleTextIn.h>
- #include <Protocol/SimpleTextOut.h>
- #include <Protocol/DevicePath.h>
- #define MODE0_COLUMN_COUNT 80
- #define MODE0_ROW_COUNT 25
- EFI_STATUS
- EFIAPI
- TextInReset (
- IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
- IN BOOLEAN ExtendedVerification
- );
- EFI_STATUS
- EFIAPI
- ReadKeyStroke (
- IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
- OUT EFI_INPUT_KEY *Key
- );
- EFI_STATUS
- EFIAPI
- TextOutReset (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN BOOLEAN ExtendedVerification
- );
- CHAR8 *
- EFIAPI
- SafeUnicodeStrToAsciiStr (
- IN CONST CHAR16 *Source,
- OUT CHAR8 *Destination
- );
- EFI_STATUS
- EFIAPI
- OutputString (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN CHAR16 *String
- );
- EFI_STATUS
- EFIAPI
- TestString (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN CHAR16 *String
- );
- EFI_STATUS
- EFIAPI
- QueryMode (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN UINTN ModeNumber,
- OUT UINTN *Columns,
- OUT UINTN *Rows
- );
- EFI_STATUS
- EFIAPI
- SetMode (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN UINTN ModeNumber
- );
- EFI_STATUS
- EFIAPI
- SetAttribute (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN UINTN Attribute
- );
- EFI_STATUS
- EFIAPI
- ClearScreen (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
- );
- EFI_STATUS
- EFIAPI
- SetCursorPosition (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN UINTN Column,
- IN UINTN Row
- );
- EFI_STATUS
- EFIAPI
- EnableCursor (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN BOOLEAN Enable
- );
- EFI_SIMPLE_TEXT_INPUT_PROTOCOL mSimpleTextIn = {
- TextInReset,
- ReadKeyStroke,
- NULL
- };
- EFI_SIMPLE_TEXT_OUTPUT_MODE mSimpleTextOutMode = {
- 1,
- 0,
- EFI_TEXT_ATTR (EFI_LIGHTGRAY,EFI_BLACK),
- 0,
- 0,
- TRUE
- };
- EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL mSimpleTextOut = {
- TextOutReset,
- OutputString,
- TestString,
- QueryMode,
- SetMode,
- SetAttribute,
- ClearScreen,
- SetCursorPosition,
- EnableCursor,
- &mSimpleTextOutMode
- };
- EFI_HANDLE mInstallHandle = NULL;
- typedef struct {
- VENDOR_DEVICE_PATH Guid;
- UART_DEVICE_PATH Uart;
- EFI_DEVICE_PATH_PROTOCOL End;
- } SIMPLE_TEXT_OUT_DEVICE_PATH;
- SIMPLE_TEXT_OUT_DEVICE_PATH mDevicePath = {
- {
- { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 }
- },
- EFI_CALLER_ID_GUID
- },
- {
- { MESSAGING_DEVICE_PATH, MSG_UART_DP, { sizeof (UART_DEVICE_PATH), 0 }
- },
- 0, // Reserved
- FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
- FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
- FixedPcdGet8 (PcdUartDefaultParity), // Parity (N)
- FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
- },
- { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
- }
- };
- BOOLEAN
- TextOutIsValidAscii (
- IN CHAR16 Ascii
- )
- {
- //
- // valid ASCII code lies in the extent of 0x20 - 0x7F
- //
- if ((Ascii >= 0x20) && (Ascii <= 0x7F)) {
- return TRUE;
- }
- return FALSE;
- }
- BOOLEAN
- TextOutIsValidEfiCntlChar (
- IN CHAR16 Char
- )
- {
- //
- // only support four control characters.
- //
- if ((Char == CHAR_NULL) ||
- (Char == CHAR_BACKSPACE) ||
- (Char == CHAR_LINEFEED) ||
- (Char == CHAR_CARRIAGE_RETURN) ||
- (Char == CHAR_TAB))
- {
- return TRUE;
- }
- return FALSE;
- }
- VOID
- EFIAPI
- WaitForKeyEvent (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- if (SerialPortPoll ()) {
- gBS->SignalEvent (Event);
- }
- }
- EFI_STATUS
- EFIAPI
- TextInReset (
- IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
- IN BOOLEAN ExtendedVerification
- )
- {
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EFIAPI
- ReadKeyStroke (
- IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
- OUT EFI_INPUT_KEY *Key
- )
- {
- CHAR8 Char;
- if (!SerialPortPoll ()) {
- return EFI_NOT_READY;
- }
- SerialPortRead ((UINT8 *)&Char, 1);
- //
- // Check for ESC sequence. This code is not technically correct VT100 code.
- // An illegal ESC sequence represents an ESC and the characters that follow.
- // This code will eat one or two chars after an escape. This is done to
- // prevent some complex FIFOing of the data. It is good enough to get
- // the arrow and delete keys working
- //
- Key->UnicodeChar = 0;
- Key->ScanCode = SCAN_NULL;
- if (Char == 0x1b) {
- SerialPortRead ((UINT8 *)&Char, 1);
- if (Char == '[') {
- SerialPortRead ((UINT8 *)&Char, 1);
- switch (Char) {
- case 'A':
- Key->ScanCode = SCAN_UP;
- break;
- case 'B':
- Key->ScanCode = SCAN_DOWN;
- break;
- case 'C':
- Key->ScanCode = SCAN_RIGHT;
- break;
- case 'D':
- Key->ScanCode = SCAN_LEFT;
- break;
- case 'H':
- Key->ScanCode = SCAN_HOME;
- break;
- case 'K':
- case 'F': // PC ANSI
- Key->ScanCode = SCAN_END;
- break;
- case '@':
- case 'L':
- Key->ScanCode = SCAN_INSERT;
- break;
- case 'P':
- case 'X': // PC ANSI
- Key->ScanCode = SCAN_DELETE;
- break;
- case 'U':
- case '/':
- case 'G': // PC ANSI
- Key->ScanCode = SCAN_PAGE_DOWN;
- break;
- case 'V':
- case '?':
- case 'I': // PC ANSI
- Key->ScanCode = SCAN_PAGE_UP;
- break;
- // PCANSI that does not conflict with VT100
- case 'M':
- Key->ScanCode = SCAN_F1;
- break;
- case 'N':
- Key->ScanCode = SCAN_F2;
- break;
- case 'O':
- Key->ScanCode = SCAN_F3;
- break;
- case 'Q':
- Key->ScanCode = SCAN_F5;
- break;
- case 'R':
- Key->ScanCode = SCAN_F6;
- break;
- case 'S':
- Key->ScanCode = SCAN_F7;
- break;
- case 'T':
- Key->ScanCode = SCAN_F8;
- break;
- default:
- Key->UnicodeChar = Char;
- break;
- }
- } else if (Char == '0') {
- SerialPortRead ((UINT8 *)&Char, 1);
- switch (Char) {
- case 'P':
- Key->ScanCode = SCAN_F1;
- break;
- case 'Q':
- Key->ScanCode = SCAN_F2;
- break;
- case 'w':
- Key->ScanCode = SCAN_F3;
- break;
- case 'x':
- Key->ScanCode = SCAN_F4;
- break;
- case 't':
- Key->ScanCode = SCAN_F5;
- break;
- case 'u':
- Key->ScanCode = SCAN_F6;
- break;
- case 'q':
- Key->ScanCode = SCAN_F7;
- break;
- case 'r':
- Key->ScanCode = SCAN_F8;
- break;
- case 'p':
- Key->ScanCode = SCAN_F9;
- break;
- case 'm':
- Key->ScanCode = SCAN_F10;
- break;
- default:
- break;
- }
- }
- } else if (Char < ' ') {
- if ((Char == CHAR_BACKSPACE) ||
- (Char == CHAR_TAB) ||
- (Char == CHAR_LINEFEED) ||
- (Char == CHAR_CARRIAGE_RETURN))
- {
- // Only let through EFI required control characters
- Key->UnicodeChar = (CHAR16)Char;
- }
- } else if (Char == 0x7f) {
- Key->ScanCode = SCAN_DELETE;
- } else {
- Key->UnicodeChar = (CHAR16)Char;
- }
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EFIAPI
- TextOutReset (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN BOOLEAN ExtendedVerification
- )
- {
- EFI_STATUS Status;
- This->SetAttribute (
- This,
- EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK)
- );
- Status = This->SetMode (This, 0);
- return Status;
- }
- CHAR8 *
- EFIAPI
- SafeUnicodeStrToAsciiStr (
- IN CONST CHAR16 *Source,
- OUT CHAR8 *Destination
- )
- {
- CHAR8 *ReturnValue;
- ASSERT (Destination != NULL);
- //
- // ASSERT if Source is long than PcdMaximumUnicodeStringLength.
- // Length tests are performed inside StrLen().
- //
- ASSERT (StrSize (Source) != 0);
- //
- // Source and Destination should not overlap
- //
- ASSERT ((UINTN)((CHAR16 *)Destination - Source) > StrLen (Source));
- ASSERT ((UINTN)((CHAR8 *)Source - Destination) > StrLen (Source));
- ReturnValue = Destination;
- while (*Source != '\0') {
- //
- // If any non-ascii characters in Source then replace it with '?'.
- //
- if (*Source < 0x80) {
- *Destination = (CHAR8)*Source;
- } else {
- *Destination = '?';
- // Surrogate pair check.
- if ((*Source >= 0xD800) && (*Source <= 0xDFFF)) {
- Source++;
- }
- }
- Destination++;
- Source++;
- }
- *Destination = '\0';
- //
- // ASSERT Original Destination is less long than PcdMaximumAsciiStringLength.
- // Length tests are performed inside AsciiStrLen().
- //
- ASSERT (AsciiStrSize (ReturnValue) != 0);
- return ReturnValue;
- }
- EFI_STATUS
- EFIAPI
- OutputString (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN CHAR16 *String
- )
- {
- UINTN Size;
- CHAR8 *OutputString;
- EFI_STATUS Status;
- EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
- UINTN MaxColumn;
- UINTN MaxRow;
- Size = StrLen (String) + 1;
- OutputString = AllocatePool (Size);
- // If there is any non-ascii characters in String buffer then replace it with '?'
- // Eventually, UnicodeStrToAsciiStr API should be fixed.
- SafeUnicodeStrToAsciiStr (String, OutputString);
- SerialPortWrite ((UINT8 *)OutputString, Size - 1);
- //
- // Parse each character of the string to output
- // to update the cursor position information
- //
- Mode = This->Mode;
- Status = This->QueryMode (
- This,
- Mode->Mode,
- &MaxColumn,
- &MaxRow
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- for ( ; *String != CHAR_NULL; String++) {
- switch (*String) {
- case CHAR_BACKSPACE:
- if (Mode->CursorColumn > 0) {
- Mode->CursorColumn--;
- }
- break;
- case CHAR_LINEFEED:
- if (Mode->CursorRow < (INT32)(MaxRow - 1)) {
- Mode->CursorRow++;
- }
- break;
- case CHAR_CARRIAGE_RETURN:
- Mode->CursorColumn = 0;
- break;
- default:
- if (Mode->CursorColumn >= (INT32)(MaxColumn - 1)) {
- // Move the cursor as if we print CHAR_CARRIAGE_RETURN & CHAR_LINE_FEED
- // CHAR_LINEFEED
- if (Mode->CursorRow < (INT32)(MaxRow - 1)) {
- Mode->CursorRow++;
- }
- // CHAR_CARIAGE_RETURN
- Mode->CursorColumn = 0;
- } else {
- Mode->CursorColumn++;
- }
- break;
- }
- }
- FreePool (OutputString);
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EFIAPI
- TestString (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN CHAR16 *String
- )
- {
- CHAR8 Character;
- for ( ; *String != CHAR_NULL; String++) {
- Character = (CHAR8)*String;
- if (!(TextOutIsValidAscii (Character) || TextOutIsValidEfiCntlChar (Character))) {
- return EFI_UNSUPPORTED;
- }
- }
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EFIAPI
- QueryMode (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN UINTN ModeNumber,
- OUT UINTN *Columns,
- OUT UINTN *Rows
- )
- {
- if (This->Mode->MaxMode > 1) {
- return EFI_DEVICE_ERROR;
- }
- if (ModeNumber == 0) {
- *Columns = MODE0_COLUMN_COUNT;
- *Rows = MODE0_ROW_COUNT;
- return EFI_SUCCESS;
- }
- return EFI_UNSUPPORTED;
- }
- EFI_STATUS
- EFIAPI
- SetMode (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN UINTN ModeNumber
- )
- {
- if (ModeNumber != 0) {
- return EFI_UNSUPPORTED;
- }
- This->Mode->Mode = 0;
- This->ClearScreen (This);
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EFIAPI
- SetAttribute (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN UINTN Attribute
- )
- {
- This->Mode->Attribute = (INT32)Attribute;
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EFIAPI
- ClearScreen (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
- )
- {
- EFI_STATUS Status;
- Status = This->SetCursorPosition (This, 0, 0);
- return Status;
- }
- EFI_STATUS
- EFIAPI
- SetCursorPosition (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN UINTN Column,
- IN UINTN Row
- )
- {
- EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
- EFI_STATUS Status;
- UINTN MaxColumn;
- UINTN MaxRow;
- Mode = This->Mode;
- Status = This->QueryMode (
- This,
- Mode->Mode,
- &MaxColumn,
- &MaxRow
- );
- if (EFI_ERROR (Status)) {
- return EFI_UNSUPPORTED;
- }
- if ((Column >= MaxColumn) || (Row >= MaxRow)) {
- return EFI_UNSUPPORTED;
- }
- Mode->CursorColumn = (INT32)Column;
- Mode->CursorRow = (INT32)Row;
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EFIAPI
- EnableCursor (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN BOOLEAN Enable
- )
- {
- if (!Enable) {
- return EFI_UNSUPPORTED;
- }
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EFIAPI
- SimpleTextInOutEntryPoint (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- EFI_STATUS Status;
- Status = gBS->CreateEvent (
- EVT_NOTIFY_WAIT,
- TPL_NOTIFY,
- WaitForKeyEvent,
- NULL,
- &mSimpleTextIn.WaitForKey
- );
- ASSERT_EFI_ERROR (Status);
- Status = gBS->InstallMultipleProtocolInterfaces (
- &mInstallHandle,
- &gEfiSimpleTextInProtocolGuid,
- &mSimpleTextIn,
- &gEfiSimpleTextOutProtocolGuid,
- &mSimpleTextOut,
- &gEfiDevicePathProtocolGuid,
- &mDevicePath,
- NULL
- );
- if (!EFI_ERROR (Status)) {
- gST->ConOut = &mSimpleTextOut;
- gST->ConIn = &mSimpleTextIn;
- }
- return Status;
- }
|