2 Simple Console that sits on a SerialLib.
4 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
11 Symbols used in table below
12 ===========================
18 +=========+======+===========+==========+==========+
19 | | EFI | UEFI 2.0 | | |
20 | | Scan | | VT100+ | |
21 | KEY | Code | PC ANSI | VTUTF8 | VT100 |
22 +=========+======+===========+==========+==========+
24 | UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |
25 | DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |
26 | RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C |
27 | LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |
28 | HOME | 0x05 | ESC [ H | ESC h | ESC [ H |
29 | END | 0x06 | ESC [ F | ESC k | ESC [ K |
30 | INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |
31 | | | ESC [ L | | ESC [ L |
32 | DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |
33 | PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |
35 | PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
37 | F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |
38 | F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |
39 | F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |
40 | F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |
41 | F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |
42 | F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |
43 | F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |
44 | F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |
45 | F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |
46 | F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |
47 | Escape | 0x17 | ESC | ESC | ESC |
48 | F11 | 0x15 | | ESC ! | |
49 | F12 | 0x16 | | ESC @ | |
50 +=========+======+===========+==========+==========+
55 #include <Library/UefiLib.h>
56 #include <Library/UefiBootServicesTableLib.h>
57 #include <Library/BaseLib.h>
58 #include <Library/MemoryAllocationLib.h>
59 #include <Library/DebugLib.h>
60 #include <Library/SerialPortLib.h>
61 #include <Library/PcdLib.h>
63 #include <Protocol/SerialIo.h>
64 #include <Protocol/SimpleTextIn.h>
65 #include <Protocol/SimpleTextOut.h>
66 #include <Protocol/DevicePath.h>
69 #define MODE0_COLUMN_COUNT 80
70 #define MODE0_ROW_COUNT 25
76 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
77 IN BOOLEAN ExtendedVerification
84 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
85 OUT EFI_INPUT_KEY
*Key
92 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
93 IN BOOLEAN ExtendedVerification
98 SafeUnicodeStrToAsciiStr (
99 IN CONST CHAR16
*Source
,
100 OUT CHAR8
*Destination
106 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
114 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
122 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
132 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
140 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
148 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
155 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
164 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
169 EFI_SIMPLE_TEXT_INPUT_PROTOCOL mSimpleTextIn
= {
175 EFI_SIMPLE_TEXT_OUTPUT_MODE mSimpleTextOutMode
= {
178 EFI_TEXT_ATTR( EFI_LIGHTGRAY
, EFI_BLACK
),
184 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL mSimpleTextOut
= {
197 EFI_HANDLE mInstallHandle
= NULL
;
200 VENDOR_DEVICE_PATH Guid
;
201 UART_DEVICE_PATH Uart
;
202 EFI_DEVICE_PATH_PROTOCOL End
;
203 } SIMPLE_TEXT_OUT_DEVICE_PATH
;
205 SIMPLE_TEXT_OUT_DEVICE_PATH mDevicePath
= {
207 { HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, { sizeof (VENDOR_DEVICE_PATH
), 0} },
211 { MESSAGING_DEVICE_PATH
, MSG_UART_DP
, { sizeof (UART_DEVICE_PATH
), 0} },
213 FixedPcdGet64 (PcdUartDefaultBaudRate
), // BaudRate
214 FixedPcdGet8 (PcdUartDefaultDataBits
), // DataBits
215 FixedPcdGet8 (PcdUartDefaultParity
), // Parity (N)
216 FixedPcdGet8 (PcdUartDefaultStopBits
) // StopBits
218 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
, { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0} }
225 TextOutIsValidAscii (
230 // valid ASCII code lies in the extent of 0x20 - 0x7F
232 if ((Ascii
>= 0x20) && (Ascii
<= 0x7F)) {
241 TextOutIsValidEfiCntlChar (
246 // only support four control characters.
248 if (Char
== CHAR_NULL
||
249 Char
== CHAR_BACKSPACE
||
250 Char
== CHAR_LINEFEED
||
251 Char
== CHAR_CARRIAGE_RETURN
||
267 if (SerialPortPoll ()) {
268 gBS
->SignalEvent (Event
);
276 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
277 IN BOOLEAN ExtendedVerification
287 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
288 OUT EFI_INPUT_KEY
*Key
293 if (!SerialPortPoll ()) {
294 return EFI_NOT_READY
;
297 SerialPortRead ((UINT8
*)&Char
, 1);
300 // Check for ESC sequence. This code is not technically correct VT100 code.
301 // An illegal ESC sequence represents an ESC and the characters that follow.
302 // This code will eat one or two chars after an escape. This is done to
303 // prevent some complex FIFOing of the data. It is good enough to get
304 // the arrow and delete keys working
306 Key
->UnicodeChar
= 0;
307 Key
->ScanCode
= SCAN_NULL
;
309 SerialPortRead ((UINT8
*)&Char
, 1);
311 SerialPortRead ((UINT8
*)&Char
, 1);
314 Key
->ScanCode
= SCAN_UP
;
317 Key
->ScanCode
= SCAN_DOWN
;
320 Key
->ScanCode
= SCAN_RIGHT
;
323 Key
->ScanCode
= SCAN_LEFT
;
326 Key
->ScanCode
= SCAN_HOME
;
330 Key
->ScanCode
= SCAN_END
;
334 Key
->ScanCode
= SCAN_INSERT
;
338 Key
->ScanCode
= SCAN_DELETE
;
343 Key
->ScanCode
= SCAN_PAGE_DOWN
;
348 Key
->ScanCode
= SCAN_PAGE_UP
;
351 // PCANSI that does not conflict with VT100
353 Key
->ScanCode
= SCAN_F1
;
356 Key
->ScanCode
= SCAN_F2
;
359 Key
->ScanCode
= SCAN_F3
;
362 Key
->ScanCode
= SCAN_F5
;
365 Key
->ScanCode
= SCAN_F6
;
368 Key
->ScanCode
= SCAN_F7
;
371 Key
->ScanCode
= SCAN_F8
;
375 Key
->UnicodeChar
= Char
;
378 } else if (Char
== '0') {
379 SerialPortRead ((UINT8
*)&Char
, 1);
382 Key
->ScanCode
= SCAN_F1
;
385 Key
->ScanCode
= SCAN_F2
;
388 Key
->ScanCode
= SCAN_F3
;
391 Key
->ScanCode
= SCAN_F4
;
394 Key
->ScanCode
= SCAN_F5
;
397 Key
->ScanCode
= SCAN_F6
;
400 Key
->ScanCode
= SCAN_F7
;
403 Key
->ScanCode
= SCAN_F8
;
406 Key
->ScanCode
= SCAN_F9
;
409 Key
->ScanCode
= SCAN_F10
;
415 } else if (Char
< ' ') {
416 if ((Char
== CHAR_BACKSPACE
) ||
417 (Char
== CHAR_TAB
) ||
418 (Char
== CHAR_LINEFEED
) ||
419 (Char
== CHAR_CARRIAGE_RETURN
)) {
420 // Only let through EFI required control characters
421 Key
->UnicodeChar
= (CHAR16
)Char
;
423 } else if (Char
== 0x7f) {
424 Key
->ScanCode
= SCAN_DELETE
;
426 Key
->UnicodeChar
= (CHAR16
)Char
;
436 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
437 IN BOOLEAN ExtendedVerification
444 EFI_TEXT_ATTR(This
->Mode
->Attribute
& 0x0F, EFI_BACKGROUND_BLACK
)
447 Status
= This
->SetMode (This
, 0);
454 SafeUnicodeStrToAsciiStr (
455 IN CONST CHAR16
*Source
,
456 OUT CHAR8
*Destination
461 ASSERT (Destination
!= NULL
);
464 // ASSERT if Source is long than PcdMaximumUnicodeStringLength.
465 // Length tests are performed inside StrLen().
467 ASSERT (StrSize (Source
) != 0);
470 // Source and Destination should not overlap
472 ASSERT ((UINTN
) ((CHAR16
*) Destination
- Source
) > StrLen (Source
));
473 ASSERT ((UINTN
) ((CHAR8
*) Source
- Destination
) > StrLen (Source
));
476 ReturnValue
= Destination
;
477 while (*Source
!= '\0') {
479 // If any non-ascii characters in Source then replace it with '?'.
481 if (*Source
< 0x80) {
482 *Destination
= (CHAR8
) *Source
;
486 //Surrogate pair check.
487 if ((*Source
>= 0xD800) && (*Source
<= 0xDFFF)) {
499 // ASSERT Original Destination is less long than PcdMaximumAsciiStringLength.
500 // Length tests are performed inside AsciiStrLen().
502 ASSERT (AsciiStrSize (ReturnValue
) != 0);
510 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
517 EFI_SIMPLE_TEXT_OUTPUT_MODE
*Mode
;
521 Size
= StrLen(String
) + 1;
522 OutputString
= AllocatePool(Size
);
524 //If there is any non-ascii characters in String buffer then replace it with '?'
525 //Eventually, UnicodeStrToAsciiStr API should be fixed.
526 SafeUnicodeStrToAsciiStr(String
, OutputString
);
527 SerialPortWrite ((UINT8
*)OutputString
, Size
- 1);
530 // Parse each character of the string to output
531 // to update the cursor position information
535 Status
= This
->QueryMode (
541 if (EFI_ERROR (Status
)) {
545 for (; *String
!= CHAR_NULL
; String
++) {
549 if (Mode
->CursorColumn
> 0) {
550 Mode
->CursorColumn
--;
555 if (Mode
->CursorRow
< (INT32
) (MaxRow
- 1)) {
560 case CHAR_CARRIAGE_RETURN
:
561 Mode
->CursorColumn
= 0;
565 if (Mode
->CursorColumn
>= (INT32
) (MaxColumn
- 1)) {
566 // Move the cursor as if we print CHAR_CARRIAGE_RETURN & CHAR_LINE_FEED
568 if (Mode
->CursorRow
< (INT32
) (MaxRow
- 1)) {
571 // CHAR_CARIAGE_RETURN
572 Mode
->CursorColumn
= 0;
574 Mode
->CursorColumn
++;
580 FreePool(OutputString
);
589 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
595 for ( ; *String
!= CHAR_NULL
; String
++) {
596 Character
= (CHAR8
)*String
;
597 if (!(TextOutIsValidAscii (Character
) || TextOutIsValidEfiCntlChar (Character
))) {
598 return EFI_UNSUPPORTED
;
609 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
615 if (This
->Mode
->MaxMode
> 1) {
616 return EFI_DEVICE_ERROR
;
619 if (ModeNumber
== 0) {
620 *Columns
= MODE0_COLUMN_COUNT
;
621 *Rows
= MODE0_ROW_COUNT
;
625 return EFI_UNSUPPORTED
;
632 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
636 if (ModeNumber
!= 0) {
637 return EFI_UNSUPPORTED
;
640 This
->Mode
->Mode
= 0;
641 This
->ClearScreen (This
);
649 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
653 This
->Mode
->Attribute
= (INT32
)Attribute
;
661 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
666 Status
= This
->SetCursorPosition (This
, 0, 0);
674 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
679 EFI_SIMPLE_TEXT_OUTPUT_MODE
*Mode
;
686 Status
= This
->QueryMode(
692 if (EFI_ERROR(Status
)) {
693 return EFI_UNSUPPORTED
;
696 if ((Column
>= MaxColumn
) || (Row
>= MaxRow
)) {
697 return EFI_UNSUPPORTED
;
700 Mode
->CursorColumn
= (INT32
)Column
;
701 Mode
->CursorRow
= (INT32
)Row
;
710 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
715 return EFI_UNSUPPORTED
;
724 SimpleTextInOutEntryPoint (
725 IN EFI_HANDLE ImageHandle
,
726 IN EFI_SYSTEM_TABLE
*SystemTable
731 Status
= gBS
->CreateEvent (
736 &mSimpleTextIn
.WaitForKey
738 ASSERT_EFI_ERROR (Status
);
740 Status
= gBS
->InstallMultipleProtocolInterfaces(
742 &gEfiSimpleTextInProtocolGuid
, &mSimpleTextIn
,
743 &gEfiSimpleTextOutProtocolGuid
, &mSimpleTextOut
,
744 &gEfiDevicePathProtocolGuid
, &mDevicePath
,
747 if (!EFI_ERROR (Status
)) {
748 gST
->ConOut
= &mSimpleTextOut
;
749 gST
->ConIn
= &mSimpleTextIn
;