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>
68 #define MODE0_COLUMN_COUNT 80
69 #define MODE0_ROW_COUNT 25
74 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
75 IN BOOLEAN ExtendedVerification
81 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
82 OUT EFI_INPUT_KEY
*Key
88 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
89 IN BOOLEAN ExtendedVerification
94 SafeUnicodeStrToAsciiStr (
95 IN CONST CHAR16
*Source
,
96 OUT CHAR8
*Destination
102 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
109 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
116 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
125 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
132 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
139 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
145 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
153 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
157 EFI_SIMPLE_TEXT_INPUT_PROTOCOL mSimpleTextIn
= {
163 EFI_SIMPLE_TEXT_OUTPUT_MODE mSimpleTextOutMode
= {
166 EFI_TEXT_ATTR (EFI_LIGHTGRAY
,EFI_BLACK
),
172 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL mSimpleTextOut
= {
185 EFI_HANDLE mInstallHandle
= NULL
;
188 VENDOR_DEVICE_PATH Guid
;
189 UART_DEVICE_PATH Uart
;
190 EFI_DEVICE_PATH_PROTOCOL End
;
191 } SIMPLE_TEXT_OUT_DEVICE_PATH
;
193 SIMPLE_TEXT_OUT_DEVICE_PATH mDevicePath
= {
195 { HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, { sizeof (VENDOR_DEVICE_PATH
), 0 }
200 { MESSAGING_DEVICE_PATH
, MSG_UART_DP
, { sizeof (UART_DEVICE_PATH
), 0 }
203 FixedPcdGet64 (PcdUartDefaultBaudRate
), // BaudRate
204 FixedPcdGet8 (PcdUartDefaultDataBits
), // DataBits
205 FixedPcdGet8 (PcdUartDefaultParity
), // Parity (N)
206 FixedPcdGet8 (PcdUartDefaultStopBits
) // StopBits
208 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
, { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 }
213 TextOutIsValidAscii (
218 // valid ASCII code lies in the extent of 0x20 - 0x7F
220 if ((Ascii
>= 0x20) && (Ascii
<= 0x7F)) {
228 TextOutIsValidEfiCntlChar (
233 // only support four control characters.
235 if ((Char
== CHAR_NULL
) ||
236 (Char
== CHAR_BACKSPACE
) ||
237 (Char
== CHAR_LINEFEED
) ||
238 (Char
== CHAR_CARRIAGE_RETURN
) ||
254 if (SerialPortPoll ()) {
255 gBS
->SignalEvent (Event
);
262 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
263 IN BOOLEAN ExtendedVerification
272 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
273 OUT EFI_INPUT_KEY
*Key
278 if (!SerialPortPoll ()) {
279 return EFI_NOT_READY
;
282 SerialPortRead ((UINT8
*)&Char
, 1);
285 // Check for ESC sequence. This code is not technically correct VT100 code.
286 // An illegal ESC sequence represents an ESC and the characters that follow.
287 // This code will eat one or two chars after an escape. This is done to
288 // prevent some complex FIFOing of the data. It is good enough to get
289 // the arrow and delete keys working
291 Key
->UnicodeChar
= 0;
292 Key
->ScanCode
= SCAN_NULL
;
294 SerialPortRead ((UINT8
*)&Char
, 1);
296 SerialPortRead ((UINT8
*)&Char
, 1);
299 Key
->ScanCode
= SCAN_UP
;
302 Key
->ScanCode
= SCAN_DOWN
;
305 Key
->ScanCode
= SCAN_RIGHT
;
308 Key
->ScanCode
= SCAN_LEFT
;
311 Key
->ScanCode
= SCAN_HOME
;
315 Key
->ScanCode
= SCAN_END
;
319 Key
->ScanCode
= SCAN_INSERT
;
323 Key
->ScanCode
= SCAN_DELETE
;
328 Key
->ScanCode
= SCAN_PAGE_DOWN
;
333 Key
->ScanCode
= SCAN_PAGE_UP
;
336 // PCANSI that does not conflict with VT100
338 Key
->ScanCode
= SCAN_F1
;
341 Key
->ScanCode
= SCAN_F2
;
344 Key
->ScanCode
= SCAN_F3
;
347 Key
->ScanCode
= SCAN_F5
;
350 Key
->ScanCode
= SCAN_F6
;
353 Key
->ScanCode
= SCAN_F7
;
356 Key
->ScanCode
= SCAN_F8
;
360 Key
->UnicodeChar
= Char
;
363 } else if (Char
== '0') {
364 SerialPortRead ((UINT8
*)&Char
, 1);
367 Key
->ScanCode
= SCAN_F1
;
370 Key
->ScanCode
= SCAN_F2
;
373 Key
->ScanCode
= SCAN_F3
;
376 Key
->ScanCode
= SCAN_F4
;
379 Key
->ScanCode
= SCAN_F5
;
382 Key
->ScanCode
= SCAN_F6
;
385 Key
->ScanCode
= SCAN_F7
;
388 Key
->ScanCode
= SCAN_F8
;
391 Key
->ScanCode
= SCAN_F9
;
394 Key
->ScanCode
= SCAN_F10
;
400 } else if (Char
< ' ') {
401 if ((Char
== CHAR_BACKSPACE
) ||
402 (Char
== CHAR_TAB
) ||
403 (Char
== CHAR_LINEFEED
) ||
404 (Char
== CHAR_CARRIAGE_RETURN
))
406 // Only let through EFI required control characters
407 Key
->UnicodeChar
= (CHAR16
)Char
;
409 } else if (Char
== 0x7f) {
410 Key
->ScanCode
= SCAN_DELETE
;
412 Key
->UnicodeChar
= (CHAR16
)Char
;
421 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
422 IN BOOLEAN ExtendedVerification
429 EFI_TEXT_ATTR (This
->Mode
->Attribute
& 0x0F, EFI_BACKGROUND_BLACK
)
432 Status
= This
->SetMode (This
, 0);
439 SafeUnicodeStrToAsciiStr (
440 IN CONST CHAR16
*Source
,
441 OUT CHAR8
*Destination
446 ASSERT (Destination
!= NULL
);
449 // ASSERT if Source is long than PcdMaximumUnicodeStringLength.
450 // Length tests are performed inside StrLen().
452 ASSERT (StrSize (Source
) != 0);
455 // Source and Destination should not overlap
457 ASSERT ((UINTN
)((CHAR16
*)Destination
- Source
) > StrLen (Source
));
458 ASSERT ((UINTN
)((CHAR8
*)Source
- Destination
) > StrLen (Source
));
460 ReturnValue
= Destination
;
461 while (*Source
!= '\0') {
463 // If any non-ascii characters in Source then replace it with '?'.
465 if (*Source
< 0x80) {
466 *Destination
= (CHAR8
)*Source
;
470 // Surrogate pair check.
471 if ((*Source
>= 0xD800) && (*Source
<= 0xDFFF)) {
483 // ASSERT Original Destination is less long than PcdMaximumAsciiStringLength.
484 // Length tests are performed inside AsciiStrLen().
486 ASSERT (AsciiStrSize (ReturnValue
) != 0);
494 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
501 EFI_SIMPLE_TEXT_OUTPUT_MODE
*Mode
;
505 Size
= StrLen (String
) + 1;
506 OutputString
= AllocatePool (Size
);
508 // If there is any non-ascii characters in String buffer then replace it with '?'
509 // Eventually, UnicodeStrToAsciiStr API should be fixed.
510 SafeUnicodeStrToAsciiStr (String
, OutputString
);
511 SerialPortWrite ((UINT8
*)OutputString
, Size
- 1);
514 // Parse each character of the string to output
515 // to update the cursor position information
519 Status
= This
->QueryMode (
525 if (EFI_ERROR (Status
)) {
529 for ( ; *String
!= CHAR_NULL
; String
++) {
532 if (Mode
->CursorColumn
> 0) {
533 Mode
->CursorColumn
--;
539 if (Mode
->CursorRow
< (INT32
)(MaxRow
- 1)) {
545 case CHAR_CARRIAGE_RETURN
:
546 Mode
->CursorColumn
= 0;
550 if (Mode
->CursorColumn
>= (INT32
)(MaxColumn
- 1)) {
551 // Move the cursor as if we print CHAR_CARRIAGE_RETURN & CHAR_LINE_FEED
553 if (Mode
->CursorRow
< (INT32
)(MaxRow
- 1)) {
557 // CHAR_CARIAGE_RETURN
558 Mode
->CursorColumn
= 0;
560 Mode
->CursorColumn
++;
567 FreePool (OutputString
);
575 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
581 for ( ; *String
!= CHAR_NULL
; String
++) {
582 Character
= (CHAR8
)*String
;
583 if (!(TextOutIsValidAscii (Character
) || TextOutIsValidEfiCntlChar (Character
))) {
584 return EFI_UNSUPPORTED
;
594 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
600 if (This
->Mode
->MaxMode
> 1) {
601 return EFI_DEVICE_ERROR
;
604 if (ModeNumber
== 0) {
605 *Columns
= MODE0_COLUMN_COUNT
;
606 *Rows
= MODE0_ROW_COUNT
;
610 return EFI_UNSUPPORTED
;
616 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
620 if (ModeNumber
!= 0) {
621 return EFI_UNSUPPORTED
;
624 This
->Mode
->Mode
= 0;
625 This
->ClearScreen (This
);
632 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
636 This
->Mode
->Attribute
= (INT32
)Attribute
;
643 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
648 Status
= This
->SetCursorPosition (This
, 0, 0);
655 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
660 EFI_SIMPLE_TEXT_OUTPUT_MODE
*Mode
;
667 Status
= This
->QueryMode (
673 if (EFI_ERROR (Status
)) {
674 return EFI_UNSUPPORTED
;
677 if ((Column
>= MaxColumn
) || (Row
>= MaxRow
)) {
678 return EFI_UNSUPPORTED
;
681 Mode
->CursorColumn
= (INT32
)Column
;
682 Mode
->CursorRow
= (INT32
)Row
;
690 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
695 return EFI_UNSUPPORTED
;
703 SimpleTextInOutEntryPoint (
704 IN EFI_HANDLE ImageHandle
,
705 IN EFI_SYSTEM_TABLE
*SystemTable
710 Status
= gBS
->CreateEvent (
715 &mSimpleTextIn
.WaitForKey
717 ASSERT_EFI_ERROR (Status
);
719 Status
= gBS
->InstallMultipleProtocolInterfaces (
721 &gEfiSimpleTextInProtocolGuid
,
723 &gEfiSimpleTextOutProtocolGuid
,
725 &gEfiDevicePathProtocolGuid
,
729 if (!EFI_ERROR (Status
)) {
730 gST
->ConOut
= &mSimpleTextOut
;
731 gST
->ConIn
= &mSimpleTextIn
;