TianoCore EDK2 master
Loading...
Searching...
No Matches
SimpleTextInOut.c
Go to the documentation of this file.
1
10/*
11 Symbols used in table below
12===========================
13 ESC = 0x1B
14 CSI = 0x9B
15 DEL = 0x7f
16 ^ = CTRL
17
18+=========+======+===========+==========+==========+
19| | EFI | UEFI 2.0 | | |
20| | Scan | | VT100+ | |
21| KEY | Code | PC ANSI | VTUTF8 | VT100 |
22+=========+======+===========+==========+==========+
23| NULL | 0x00 | | | |
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 |
34| | | | | ESC [ ? |
35| PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
36| | | | | ESC [ / |
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+=========+======+===========+==========+==========+
51
52*/
53
54#include <PiDxe.h>
55#include <Library/UefiLib.h>
57#include <Library/BaseLib.h>
59#include <Library/DebugLib.h>
61#include <Library/PcdLib.h>
62
63#include <Protocol/SerialIo.h>
66#include <Protocol/DevicePath.h>
67
68#define MODE0_COLUMN_COUNT 80
69#define MODE0_ROW_COUNT 25
70
72EFIAPI
73TextInReset (
75 IN BOOLEAN ExtendedVerification
76 );
77
79EFIAPI
80ReadKeyStroke (
83 );
84
86EFIAPI
87TextOutReset (
89 IN BOOLEAN ExtendedVerification
90 );
91
92CHAR8 *
93EFIAPI
94SafeUnicodeStrToAsciiStr (
95 IN CONST CHAR16 *Source,
96 OUT CHAR8 *Destination
97 );
98
100EFIAPI
101OutputString (
103 IN CHAR16 *String
104 );
105
107EFIAPI
108TestString (
110 IN CHAR16 *String
111 );
112
114EFIAPI
115QueryMode (
117 IN UINTN ModeNumber,
118 OUT UINTN *Columns,
119 OUT UINTN *Rows
120 );
121
123EFIAPI
124SetMode (
126 IN UINTN ModeNumber
127 );
128
130EFIAPI
131SetAttribute (
133 IN UINTN Attribute
134 );
135
137EFIAPI
138ClearScreen (
140 );
141
143EFIAPI
144SetCursorPosition (
146 IN UINTN Column,
147 IN UINTN Row
148 );
149
151EFIAPI
152EnableCursor (
154 IN BOOLEAN Enable
155 );
156
157EFI_SIMPLE_TEXT_INPUT_PROTOCOL mSimpleTextIn = {
158 TextInReset,
159 ReadKeyStroke,
160 NULL
161};
162
163EFI_SIMPLE_TEXT_OUTPUT_MODE mSimpleTextOutMode = {
164 1,
165 0,
166 EFI_TEXT_ATTR (EFI_LIGHTGRAY,EFI_BLACK),
167 0,
168 0,
169 TRUE
170};
171
172EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL mSimpleTextOut = {
173 TextOutReset,
174 OutputString,
175 TestString,
176 QueryMode,
177 SetMode,
178 SetAttribute,
179 ClearScreen,
180 SetCursorPosition,
181 EnableCursor,
182 &mSimpleTextOutMode
183};
184
185EFI_HANDLE mInstallHandle = NULL;
186
187typedef struct {
189 UART_DEVICE_PATH Uart;
192
193SIMPLE_TEXT_OUT_DEVICE_PATH mDevicePath = {
194 {
196 },
197 EFI_CALLER_ID_GUID
198 },
199 {
201 },
202 0, // Reserved
203 FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
204 FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
205 FixedPcdGet8 (PcdUartDefaultParity), // Parity (N)
206 FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
207 },
208 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
209 }
210};
211
212BOOLEAN
213TextOutIsValidAscii (
214 IN CHAR16 Ascii
215 )
216{
217 //
218 // valid ASCII code lies in the extent of 0x20 - 0x7F
219 //
220 if ((Ascii >= 0x20) && (Ascii <= 0x7F)) {
221 return TRUE;
222 }
223
224 return FALSE;
225}
226
227BOOLEAN
228TextOutIsValidEfiCntlChar (
229 IN CHAR16 Char
230 )
231{
232 //
233 // only support four control characters.
234 //
235 if ((Char == CHAR_NULL) ||
236 (Char == CHAR_BACKSPACE) ||
237 (Char == CHAR_LINEFEED) ||
238 (Char == CHAR_CARRIAGE_RETURN) ||
239 (Char == CHAR_TAB))
240 {
241 return TRUE;
242 }
243
244 return FALSE;
245}
246
247VOID
248EFIAPI
249WaitForKeyEvent (
250 IN EFI_EVENT Event,
251 IN VOID *Context
252 )
253{
254 if (SerialPortPoll ()) {
255 gBS->SignalEvent (Event);
256 }
257}
258
260EFIAPI
261TextInReset (
263 IN BOOLEAN ExtendedVerification
264 )
265{
266 return EFI_SUCCESS;
267}
268
270EFIAPI
271ReadKeyStroke (
273 OUT EFI_INPUT_KEY *Key
274 )
275{
276 CHAR8 Char;
277
278 if (!SerialPortPoll ()) {
279 return EFI_NOT_READY;
280 }
281
282 SerialPortRead ((UINT8 *)&Char, 1);
283
284 //
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
290 //
291 Key->UnicodeChar = 0;
292 Key->ScanCode = SCAN_NULL;
293 if (Char == 0x1b) {
294 SerialPortRead ((UINT8 *)&Char, 1);
295 if (Char == '[') {
296 SerialPortRead ((UINT8 *)&Char, 1);
297 switch (Char) {
298 case 'A':
299 Key->ScanCode = SCAN_UP;
300 break;
301 case 'B':
302 Key->ScanCode = SCAN_DOWN;
303 break;
304 case 'C':
305 Key->ScanCode = SCAN_RIGHT;
306 break;
307 case 'D':
308 Key->ScanCode = SCAN_LEFT;
309 break;
310 case 'H':
311 Key->ScanCode = SCAN_HOME;
312 break;
313 case 'K':
314 case 'F': // PC ANSI
315 Key->ScanCode = SCAN_END;
316 break;
317 case '@':
318 case 'L':
319 Key->ScanCode = SCAN_INSERT;
320 break;
321 case 'P':
322 case 'X': // PC ANSI
323 Key->ScanCode = SCAN_DELETE;
324 break;
325 case 'U':
326 case '/':
327 case 'G': // PC ANSI
328 Key->ScanCode = SCAN_PAGE_DOWN;
329 break;
330 case 'V':
331 case '?':
332 case 'I': // PC ANSI
333 Key->ScanCode = SCAN_PAGE_UP;
334 break;
335
336 // PCANSI that does not conflict with VT100
337 case 'M':
338 Key->ScanCode = SCAN_F1;
339 break;
340 case 'N':
341 Key->ScanCode = SCAN_F2;
342 break;
343 case 'O':
344 Key->ScanCode = SCAN_F3;
345 break;
346 case 'Q':
347 Key->ScanCode = SCAN_F5;
348 break;
349 case 'R':
350 Key->ScanCode = SCAN_F6;
351 break;
352 case 'S':
353 Key->ScanCode = SCAN_F7;
354 break;
355 case 'T':
356 Key->ScanCode = SCAN_F8;
357 break;
358
359 default:
360 Key->UnicodeChar = Char;
361 break;
362 }
363 } else if (Char == '0') {
364 SerialPortRead ((UINT8 *)&Char, 1);
365 switch (Char) {
366 case 'P':
367 Key->ScanCode = SCAN_F1;
368 break;
369 case 'Q':
370 Key->ScanCode = SCAN_F2;
371 break;
372 case 'w':
373 Key->ScanCode = SCAN_F3;
374 break;
375 case 'x':
376 Key->ScanCode = SCAN_F4;
377 break;
378 case 't':
379 Key->ScanCode = SCAN_F5;
380 break;
381 case 'u':
382 Key->ScanCode = SCAN_F6;
383 break;
384 case 'q':
385 Key->ScanCode = SCAN_F7;
386 break;
387 case 'r':
388 Key->ScanCode = SCAN_F8;
389 break;
390 case 'p':
391 Key->ScanCode = SCAN_F9;
392 break;
393 case 'm':
394 Key->ScanCode = SCAN_F10;
395 break;
396 default:
397 break;
398 }
399 }
400 } else if (Char < ' ') {
401 if ((Char == CHAR_BACKSPACE) ||
402 (Char == CHAR_TAB) ||
403 (Char == CHAR_LINEFEED) ||
404 (Char == CHAR_CARRIAGE_RETURN))
405 {
406 // Only let through EFI required control characters
407 Key->UnicodeChar = (CHAR16)Char;
408 }
409 } else if (Char == 0x7f) {
410 Key->ScanCode = SCAN_DELETE;
411 } else {
412 Key->UnicodeChar = (CHAR16)Char;
413 }
414
415 return EFI_SUCCESS;
416}
417
419EFIAPI
420TextOutReset (
422 IN BOOLEAN ExtendedVerification
423 )
424{
425 EFI_STATUS Status;
426
427 This->SetAttribute (
428 This,
429 EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK)
430 );
431
432 Status = This->SetMode (This, 0);
433
434 return Status;
435}
436
437CHAR8 *
438EFIAPI
439SafeUnicodeStrToAsciiStr (
440 IN CONST CHAR16 *Source,
441 OUT CHAR8 *Destination
442 )
443{
444 CHAR8 *ReturnValue;
445
446 ASSERT (Destination != NULL);
447
448 //
449 // ASSERT if Source is long than PcdMaximumUnicodeStringLength.
450 // Length tests are performed inside StrLen().
451 //
452 ASSERT (StrSize (Source) != 0);
453
454 //
455 // Source and Destination should not overlap
456 //
457 ASSERT ((UINTN)((CHAR16 *)Destination - Source) > StrLen (Source));
458 ASSERT ((UINTN)((CHAR8 *)Source - Destination) > StrLen (Source));
459
460 ReturnValue = Destination;
461 while (*Source != '\0') {
462 //
463 // If any non-ascii characters in Source then replace it with '?'.
464 //
465 if (*Source < 0x80) {
466 *Destination = (CHAR8)*Source;
467 } else {
468 *Destination = '?';
469
470 // Surrogate pair check.
471 if ((*Source >= 0xD800) && (*Source <= 0xDFFF)) {
472 Source++;
473 }
474 }
475
476 Destination++;
477 Source++;
478 }
479
480 *Destination = '\0';
481
482 //
483 // ASSERT Original Destination is less long than PcdMaximumAsciiStringLength.
484 // Length tests are performed inside AsciiStrLen().
485 //
486 ASSERT (AsciiStrSize (ReturnValue) != 0);
487
488 return ReturnValue;
489}
490
492EFIAPI
493OutputString (
495 IN CHAR16 *String
496 )
497{
498 UINTN Size;
499 CHAR8 *OutputString;
500 EFI_STATUS Status;
502 UINTN MaxColumn;
503 UINTN MaxRow;
504
505 Size = StrLen (String) + 1;
506 OutputString = AllocatePool (Size);
507
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);
512
513 //
514 // Parse each character of the string to output
515 // to update the cursor position information
516 //
517 Mode = This->Mode;
518
519 Status = This->QueryMode (
520 This,
521 Mode->Mode,
522 &MaxColumn,
523 &MaxRow
524 );
525 if (EFI_ERROR (Status)) {
526 return Status;
527 }
528
529 for ( ; *String != CHAR_NULL; String++) {
530 switch (*String) {
531 case CHAR_BACKSPACE:
532 if (Mode->CursorColumn > 0) {
533 Mode->CursorColumn--;
534 }
535
536 break;
537
538 case CHAR_LINEFEED:
539 if (Mode->CursorRow < (INT32)(MaxRow - 1)) {
540 Mode->CursorRow++;
541 }
542
543 break;
544
545 case CHAR_CARRIAGE_RETURN:
546 Mode->CursorColumn = 0;
547 break;
548
549 default:
550 if (Mode->CursorColumn >= (INT32)(MaxColumn - 1)) {
551 // Move the cursor as if we print CHAR_CARRIAGE_RETURN & CHAR_LINE_FEED
552 // CHAR_LINEFEED
553 if (Mode->CursorRow < (INT32)(MaxRow - 1)) {
554 Mode->CursorRow++;
555 }
556
557 // CHAR_CARIAGE_RETURN
558 Mode->CursorColumn = 0;
559 } else {
560 Mode->CursorColumn++;
561 }
562
563 break;
564 }
565 }
566
567 FreePool (OutputString);
568
569 return EFI_SUCCESS;
570}
571
573EFIAPI
574TestString (
576 IN CHAR16 *String
577 )
578{
579 CHAR8 Character;
580
581 for ( ; *String != CHAR_NULL; String++) {
582 Character = (CHAR8)*String;
583 if (!(TextOutIsValidAscii (Character) || TextOutIsValidEfiCntlChar (Character))) {
584 return EFI_UNSUPPORTED;
585 }
586 }
587
588 return EFI_SUCCESS;
589}
590
592EFIAPI
593QueryMode (
595 IN UINTN ModeNumber,
596 OUT UINTN *Columns,
597 OUT UINTN *Rows
598 )
599{
600 if (This->Mode->MaxMode > 1) {
601 return EFI_DEVICE_ERROR;
602 }
603
604 if (ModeNumber == 0) {
605 *Columns = MODE0_COLUMN_COUNT;
606 *Rows = MODE0_ROW_COUNT;
607 return EFI_SUCCESS;
608 }
609
610 return EFI_UNSUPPORTED;
611}
612
614EFIAPI
615SetMode (
617 IN UINTN ModeNumber
618 )
619{
620 if (ModeNumber != 0) {
621 return EFI_UNSUPPORTED;
622 }
623
624 This->Mode->Mode = 0;
625 This->ClearScreen (This);
626 return EFI_SUCCESS;
627}
628
630EFIAPI
631SetAttribute (
633 IN UINTN Attribute
634 )
635{
636 This->Mode->Attribute = (INT32)Attribute;
637 return EFI_SUCCESS;
638}
639
641EFIAPI
642ClearScreen (
644 )
645{
646 EFI_STATUS Status;
647
648 Status = This->SetCursorPosition (This, 0, 0);
649 return Status;
650}
651
653EFIAPI
654SetCursorPosition (
656 IN UINTN Column,
657 IN UINTN Row
658 )
659{
661 EFI_STATUS Status;
662 UINTN MaxColumn;
663 UINTN MaxRow;
664
665 Mode = This->Mode;
666
667 Status = This->QueryMode (
668 This,
669 Mode->Mode,
670 &MaxColumn,
671 &MaxRow
672 );
673 if (EFI_ERROR (Status)) {
674 return EFI_UNSUPPORTED;
675 }
676
677 if ((Column >= MaxColumn) || (Row >= MaxRow)) {
678 return EFI_UNSUPPORTED;
679 }
680
681 Mode->CursorColumn = (INT32)Column;
682 Mode->CursorRow = (INT32)Row;
683
684 return EFI_SUCCESS;
685}
686
688EFIAPI
689EnableCursor (
691 IN BOOLEAN Enable
692 )
693{
694 if (!Enable) {
695 return EFI_UNSUPPORTED;
696 }
697
698 return EFI_SUCCESS;
699}
700
702EFIAPI
703SimpleTextInOutEntryPoint (
704 IN EFI_HANDLE ImageHandle,
705 IN EFI_SYSTEM_TABLE *SystemTable
706 )
707{
708 EFI_STATUS Status;
709
710 Status = gBS->CreateEvent (
711 EVT_NOTIFY_WAIT,
712 TPL_NOTIFY,
713 WaitForKeyEvent,
714 NULL,
715 &mSimpleTextIn.WaitForKey
716 );
717 ASSERT_EFI_ERROR (Status);
718
719 Status = gBS->InstallMultipleProtocolInterfaces (
720 &mInstallHandle,
721 &gEfiSimpleTextInProtocolGuid,
722 &mSimpleTextIn,
723 &gEfiSimpleTextOutProtocolGuid,
724 &mSimpleTextOut,
725 &gEfiDevicePathProtocolGuid,
726 &mDevicePath,
727 NULL
728 );
729 if (!EFI_ERROR (Status)) {
730 gST->ConOut = &mSimpleTextOut;
731 gST->ConIn = &mSimpleTextIn;
732 }
733
734 return Status;
735}
UINT64 UINTN
BOOLEAN EFIAPI SerialPortPoll(VOID)
UINTN EFIAPI SerialPortRead(OUT UINT8 *Buffer, IN UINTN NumberOfBytes)
UINTN EFIAPI SerialPortWrite(IN UINT8 *Buffer, IN UINTN NumberOfBytes)
Definition: SerialPortLib.c:52
UINTN EFIAPI StrSize(IN CONST CHAR16 *String)
Definition: String.c:72
UINTN EFIAPI AsciiStrSize(IN CONST CHAR8 *String)
Definition: String.c:681
UINTN EFIAPI StrLen(IN CONST CHAR16 *String)
Definition: String.c:30
#define HARDWARE_DEVICE_PATH
Definition: DevicePath.h:68
#define HW_VENDOR_DP
Definition: DevicePath.h:133
#define MSG_UART_DP
Definition: DevicePath.h:692
#define MESSAGING_DEVICE_PATH
Definition: DevicePath.h:321
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define FixedPcdGet64(TokenName)
Definition: PcdLib.h:106
#define FixedPcdGet8(TokenName)
Definition: PcdLib.h:64
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_SYSTEM_TABLE * gST
EFI_BOOT_SERVICES * gBS
EFI_SIMPLE_TEXT_INPUT_PROTOCOL * ConIn
Definition: UefiSpec.h:2053
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * ConOut
Definition: UefiSpec.h:2064