VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOut.c@ 85788

Last change on this file since 85788 was 85718, checked in by vboxsync, 4 years ago

Devices/EFI: Merge edk-stable202005 and make it build, bugref:4643

  • Property svn:eol-style set to native
File size: 16.1 KB
Line 
1/** @file
2 Simple Console that sits on a SerialLib.
3
4 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
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>
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>
62
63#include <Protocol/SerialIo.h>
64#include <Protocol/SimpleTextIn.h>
65#include <Protocol/SimpleTextOut.h>
66#include <Protocol/DevicePath.h>
67
68
69#define MODE0_COLUMN_COUNT 80
70#define MODE0_ROW_COUNT 25
71
72
73EFI_STATUS
74EFIAPI
75TextInReset(
76 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
77 IN BOOLEAN ExtendedVerification
78 );
79
80
81EFI_STATUS
82EFIAPI
83ReadKeyStroke(
84 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
85 OUT EFI_INPUT_KEY *Key
86 );
87
88
89EFI_STATUS
90EFIAPI
91TextOutReset(
92 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
93 IN BOOLEAN ExtendedVerification
94 );
95
96CHAR8 *
97EFIAPI
98SafeUnicodeStrToAsciiStr (
99 IN CONST CHAR16 *Source,
100 OUT CHAR8 *Destination
101 );
102
103EFI_STATUS
104EFIAPI
105OutputString (
106 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
107 IN CHAR16 *String
108 );
109
110
111EFI_STATUS
112EFIAPI
113TestString (
114 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
115 IN CHAR16 *String
116 );
117
118
119EFI_STATUS
120EFIAPI
121QueryMode (
122 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
123 IN UINTN ModeNumber,
124 OUT UINTN *Columns,
125 OUT UINTN *Rows
126 );
127
128
129EFI_STATUS
130EFIAPI
131SetMode(
132 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
133 IN UINTN ModeNumber
134 );
135
136
137EFI_STATUS
138EFIAPI
139SetAttribute(
140 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
141 IN UINTN Attribute
142 );
143
144
145EFI_STATUS
146EFIAPI
147ClearScreen (
148 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
149 );
150
151
152EFI_STATUS
153EFIAPI
154SetCursorPosition (
155 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
156 IN UINTN Column,
157 IN UINTN Row
158 );
159
160
161EFI_STATUS
162EFIAPI
163EnableCursor (
164 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
165 IN BOOLEAN Enable
166 );
167
168
169 EFI_SIMPLE_TEXT_INPUT_PROTOCOL mSimpleTextIn = {
170 TextInReset,
171 ReadKeyStroke,
172 NULL
173};
174
175 EFI_SIMPLE_TEXT_OUTPUT_MODE mSimpleTextOutMode = {
176 1,
177 0,
178 EFI_TEXT_ATTR( EFI_LIGHTGRAY, EFI_BLACK ),
179 0,
180 0,
181 TRUE
182};
183
184EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL mSimpleTextOut = {
185 TextOutReset,
186 OutputString,
187 TestString,
188 QueryMode,
189 SetMode,
190 SetAttribute,
191 ClearScreen,
192 SetCursorPosition,
193 EnableCursor,
194 &mSimpleTextOutMode
195};
196
197EFI_HANDLE mInstallHandle = NULL;
198
199typedef struct {
200 VENDOR_DEVICE_PATH Guid;
201 UART_DEVICE_PATH Uart;
202 EFI_DEVICE_PATH_PROTOCOL End;
203} SIMPLE_TEXT_OUT_DEVICE_PATH;
204
205SIMPLE_TEXT_OUT_DEVICE_PATH mDevicePath = {
206 {
207 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0} },
208 EFI_CALLER_ID_GUID
209 },
210 {
211 { MESSAGING_DEVICE_PATH, MSG_UART_DP, { sizeof (UART_DEVICE_PATH), 0} },
212 0, // Reserved
213 FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
214 FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
215 FixedPcdGet8 (PcdUartDefaultParity), // Parity (N)
216 FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
217 },
218 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0} }
219};
220
221
222
223
224BOOLEAN
225TextOutIsValidAscii (
226 IN CHAR16 Ascii
227 )
228{
229 //
230 // valid ASCII code lies in the extent of 0x20 - 0x7F
231 //
232 if ((Ascii >= 0x20) && (Ascii <= 0x7F)) {
233 return TRUE;
234 }
235
236 return FALSE;
237}
238
239
240BOOLEAN
241TextOutIsValidEfiCntlChar (
242 IN CHAR16 Char
243 )
244{
245 //
246 // only support four control characters.
247 //
248 if (Char == CHAR_NULL ||
249 Char == CHAR_BACKSPACE ||
250 Char == CHAR_LINEFEED ||
251 Char == CHAR_CARRIAGE_RETURN ||
252 Char == CHAR_TAB ) {
253 return TRUE;
254 }
255
256 return FALSE;
257}
258
259
260VOID
261EFIAPI
262WaitForKeyEvent (
263 IN EFI_EVENT Event,
264 IN VOID *Context
265 )
266{
267 if (SerialPortPoll ()) {
268 gBS->SignalEvent (Event);
269 }
270}
271
272
273EFI_STATUS
274EFIAPI
275TextInReset (
276 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
277 IN BOOLEAN ExtendedVerification
278 )
279{
280 return EFI_SUCCESS;
281}
282
283
284EFI_STATUS
285EFIAPI
286ReadKeyStroke (
287 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
288 OUT EFI_INPUT_KEY *Key
289 )
290{
291 CHAR8 Char;
292
293 if (!SerialPortPoll ()) {
294 return EFI_NOT_READY;
295 }
296
297 SerialPortRead ((UINT8 *)&Char, 1);
298
299 //
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
305 //
306 Key->UnicodeChar = 0;
307 Key->ScanCode = SCAN_NULL;
308 if (Char == 0x1b) {
309 SerialPortRead ((UINT8 *)&Char, 1);
310 if (Char == '[') {
311 SerialPortRead ((UINT8 *)&Char, 1);
312 switch (Char) {
313 case 'A':
314 Key->ScanCode = SCAN_UP;
315 break;
316 case 'B':
317 Key->ScanCode = SCAN_DOWN;
318 break;
319 case 'C':
320 Key->ScanCode = SCAN_RIGHT;
321 break;
322 case 'D':
323 Key->ScanCode = SCAN_LEFT;
324 break;
325 case 'H':
326 Key->ScanCode = SCAN_HOME;
327 break;
328 case 'K':
329 case 'F': // PC ANSI
330 Key->ScanCode = SCAN_END;
331 break;
332 case '@':
333 case 'L':
334 Key->ScanCode = SCAN_INSERT;
335 break;
336 case 'P':
337 case 'X': // PC ANSI
338 Key->ScanCode = SCAN_DELETE;
339 break;
340 case 'U':
341 case '/':
342 case 'G': // PC ANSI
343 Key->ScanCode = SCAN_PAGE_DOWN;
344 break;
345 case 'V':
346 case '?':
347 case 'I': // PC ANSI
348 Key->ScanCode = SCAN_PAGE_UP;
349 break;
350
351 // PCANSI that does not conflict with VT100
352 case 'M':
353 Key->ScanCode = SCAN_F1;
354 break;
355 case 'N':
356 Key->ScanCode = SCAN_F2;
357 break;
358 case 'O':
359 Key->ScanCode = SCAN_F3;
360 break;
361 case 'Q':
362 Key->ScanCode = SCAN_F5;
363 break;
364 case 'R':
365 Key->ScanCode = SCAN_F6;
366 break;
367 case 'S':
368 Key->ScanCode = SCAN_F7;
369 break;
370 case 'T':
371 Key->ScanCode = SCAN_F8;
372 break;
373
374 default:
375 Key->UnicodeChar = Char;
376 break;
377 }
378 } else if (Char == '0') {
379 SerialPortRead ((UINT8 *)&Char, 1);
380 switch (Char) {
381 case 'P':
382 Key->ScanCode = SCAN_F1;
383 break;
384 case 'Q':
385 Key->ScanCode = SCAN_F2;
386 break;
387 case 'w':
388 Key->ScanCode = SCAN_F3;
389 break;
390 case 'x':
391 Key->ScanCode = SCAN_F4;
392 break;
393 case 't':
394 Key->ScanCode = SCAN_F5;
395 break;
396 case 'u':
397 Key->ScanCode = SCAN_F6;
398 break;
399 case 'q':
400 Key->ScanCode = SCAN_F7;
401 break;
402 case 'r':
403 Key->ScanCode = SCAN_F8;
404 break;
405 case 'p':
406 Key->ScanCode = SCAN_F9;
407 break;
408 case 'm':
409 Key->ScanCode = SCAN_F10;
410 break;
411 default :
412 break;
413 }
414 }
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;
422 }
423 } else if (Char == 0x7f) {
424 Key->ScanCode = SCAN_DELETE;
425 } else {
426 Key->UnicodeChar = (CHAR16)Char;
427 }
428
429 return EFI_SUCCESS;
430}
431
432
433EFI_STATUS
434EFIAPI
435TextOutReset (
436 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
437 IN BOOLEAN ExtendedVerification
438 )
439{
440 EFI_STATUS Status;
441
442 This->SetAttribute(
443 This,
444 EFI_TEXT_ATTR(This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK)
445 );
446
447 Status = This->SetMode (This, 0);
448
449 return Status;
450}
451
452CHAR8 *
453EFIAPI
454SafeUnicodeStrToAsciiStr (
455 IN CONST CHAR16 *Source,
456 OUT CHAR8 *Destination
457 )
458{
459 CHAR8 *ReturnValue;
460
461 ASSERT (Destination != NULL);
462
463 //
464 // ASSERT if Source is long than PcdMaximumUnicodeStringLength.
465 // Length tests are performed inside StrLen().
466 //
467 ASSERT (StrSize (Source) != 0);
468
469 //
470 // Source and Destination should not overlap
471 //
472 ASSERT ((UINTN) ((CHAR16 *) Destination - Source) > StrLen (Source));
473 ASSERT ((UINTN) ((CHAR8 *) Source - Destination) > StrLen (Source));
474
475
476 ReturnValue = Destination;
477 while (*Source != '\0') {
478 //
479 // If any non-ascii characters in Source then replace it with '?'.
480 //
481 if (*Source < 0x80) {
482 *Destination = (CHAR8) *Source;
483 } else {
484 *Destination = '?';
485
486 //Surrogate pair check.
487 if ((*Source >= 0xD800) && (*Source <= 0xDFFF)) {
488 Source++;
489 }
490 }
491
492 Destination++;
493 Source++;
494 }
495
496 *Destination = '\0';
497
498 //
499 // ASSERT Original Destination is less long than PcdMaximumAsciiStringLength.
500 // Length tests are performed inside AsciiStrLen().
501 //
502 ASSERT (AsciiStrSize (ReturnValue) != 0);
503
504 return ReturnValue;
505}
506
507EFI_STATUS
508EFIAPI
509OutputString (
510 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
511 IN CHAR16 *String
512 )
513{
514 UINTN Size;
515 CHAR8* OutputString;
516 EFI_STATUS Status;
517 EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
518 UINTN MaxColumn;
519 UINTN MaxRow;
520
521 Size = StrLen(String) + 1;
522 OutputString = AllocatePool(Size);
523
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);
528
529 //
530 // Parse each character of the string to output
531 // to update the cursor position information
532 //
533 Mode = This->Mode;
534
535 Status = This->QueryMode (
536 This,
537 Mode->Mode,
538 &MaxColumn,
539 &MaxRow
540 );
541 if (EFI_ERROR (Status)) {
542 return Status;
543 }
544
545 for (; *String != CHAR_NULL; String++) {
546
547 switch (*String) {
548 case CHAR_BACKSPACE:
549 if (Mode->CursorColumn > 0) {
550 Mode->CursorColumn--;
551 }
552 break;
553
554 case CHAR_LINEFEED:
555 if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
556 Mode->CursorRow++;
557 }
558 break;
559
560 case CHAR_CARRIAGE_RETURN:
561 Mode->CursorColumn = 0;
562 break;
563
564 default:
565 if (Mode->CursorColumn >= (INT32) (MaxColumn - 1)) {
566 // Move the cursor as if we print CHAR_CARRIAGE_RETURN & CHAR_LINE_FEED
567 // CHAR_LINEFEED
568 if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
569 Mode->CursorRow++;
570 }
571 // CHAR_CARIAGE_RETURN
572 Mode->CursorColumn = 0;
573 } else {
574 Mode->CursorColumn++;
575 }
576 break;
577 }
578 }
579
580 FreePool(OutputString);
581
582 return EFI_SUCCESS;
583}
584
585
586EFI_STATUS
587EFIAPI
588TestString (
589 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
590 IN CHAR16 *String
591 )
592{
593 CHAR8 Character;
594
595 for ( ; *String != CHAR_NULL; String++) {
596 Character = (CHAR8)*String;
597 if (!(TextOutIsValidAscii (Character) || TextOutIsValidEfiCntlChar (Character))) {
598 return EFI_UNSUPPORTED;
599 }
600 }
601
602 return EFI_SUCCESS;
603}
604
605
606EFI_STATUS
607EFIAPI
608QueryMode (
609 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
610 IN UINTN ModeNumber,
611 OUT UINTN *Columns,
612 OUT UINTN *Rows
613 )
614{
615 if (This->Mode->MaxMode > 1) {
616 return EFI_DEVICE_ERROR;
617 }
618
619 if (ModeNumber == 0) {
620 *Columns = MODE0_COLUMN_COUNT;
621 *Rows = MODE0_ROW_COUNT;
622 return EFI_SUCCESS;
623 }
624
625 return EFI_UNSUPPORTED;
626}
627
628
629EFI_STATUS
630EFIAPI
631SetMode (
632 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
633 IN UINTN ModeNumber
634 )
635{
636 if (ModeNumber != 0) {
637 return EFI_UNSUPPORTED;
638 }
639
640 This->Mode->Mode = 0;
641 This->ClearScreen (This);
642 return EFI_SUCCESS;
643}
644
645
646EFI_STATUS
647EFIAPI
648SetAttribute(
649 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
650 IN UINTN Attribute
651 )
652{
653 This->Mode->Attribute = (INT32)Attribute;
654 return EFI_SUCCESS;
655}
656
657
658EFI_STATUS
659EFIAPI
660ClearScreen (
661 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
662 )
663{
664 EFI_STATUS Status;
665
666 Status = This->SetCursorPosition (This, 0, 0);
667 return Status;
668}
669
670
671EFI_STATUS
672EFIAPI
673SetCursorPosition (
674 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
675 IN UINTN Column,
676 IN UINTN Row
677 )
678{
679 EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
680 EFI_STATUS Status;
681 UINTN MaxColumn;
682 UINTN MaxRow;
683
684 Mode = This->Mode;
685
686 Status = This->QueryMode(
687 This,
688 Mode->Mode,
689 &MaxColumn,
690 &MaxRow
691 );
692 if (EFI_ERROR(Status)) {
693 return EFI_UNSUPPORTED;
694 }
695
696 if ((Column >= MaxColumn) || (Row >= MaxRow)) {
697 return EFI_UNSUPPORTED;
698 }
699
700 Mode->CursorColumn = (INT32)Column;
701 Mode->CursorRow = (INT32)Row;
702
703 return EFI_SUCCESS;
704}
705
706
707EFI_STATUS
708EFIAPI
709EnableCursor (
710 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
711 IN BOOLEAN Enable
712 )
713{
714 if (!Enable) {
715 return EFI_UNSUPPORTED;
716 }
717
718 return EFI_SUCCESS;
719}
720
721
722EFI_STATUS
723EFIAPI
724SimpleTextInOutEntryPoint (
725 IN EFI_HANDLE ImageHandle,
726 IN EFI_SYSTEM_TABLE *SystemTable
727 )
728{
729 EFI_STATUS Status;
730
731 Status = gBS->CreateEvent (
732 EVT_NOTIFY_WAIT,
733 TPL_NOTIFY,
734 WaitForKeyEvent,
735 NULL,
736 &mSimpleTextIn.WaitForKey
737 );
738 ASSERT_EFI_ERROR (Status);
739
740 Status = gBS->InstallMultipleProtocolInterfaces(
741 &mInstallHandle,
742 &gEfiSimpleTextInProtocolGuid, &mSimpleTextIn,
743 &gEfiSimpleTextOutProtocolGuid, &mSimpleTextOut,
744 &gEfiDevicePathProtocolGuid, &mDevicePath,
745 NULL
746 );
747 if (!EFI_ERROR (Status)) {
748 gST->ConOut = &mSimpleTextOut;
749 gST->ConIn = &mSimpleTextIn;
750 }
751
752 return Status;
753}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette