]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOut.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / EmbeddedPkg / SimpleTextInOutSerial / SimpleTextInOut.c
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 #define MODE0_COLUMN_COUNT 80
69 #define MODE0_ROW_COUNT 25
70
71 EFI_STATUS
72 EFIAPI
73 TextInReset (
74 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
75 IN BOOLEAN ExtendedVerification
76 );
77
78 EFI_STATUS
79 EFIAPI
80 ReadKeyStroke (
81 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
82 OUT EFI_INPUT_KEY *Key
83 );
84
85 EFI_STATUS
86 EFIAPI
87 TextOutReset (
88 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
89 IN BOOLEAN ExtendedVerification
90 );
91
92 CHAR8 *
93 EFIAPI
94 SafeUnicodeStrToAsciiStr (
95 IN CONST CHAR16 *Source,
96 OUT CHAR8 *Destination
97 );
98
99 EFI_STATUS
100 EFIAPI
101 OutputString (
102 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
103 IN CHAR16 *String
104 );
105
106 EFI_STATUS
107 EFIAPI
108 TestString (
109 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
110 IN CHAR16 *String
111 );
112
113 EFI_STATUS
114 EFIAPI
115 QueryMode (
116 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
117 IN UINTN ModeNumber,
118 OUT UINTN *Columns,
119 OUT UINTN *Rows
120 );
121
122 EFI_STATUS
123 EFIAPI
124 SetMode (
125 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
126 IN UINTN ModeNumber
127 );
128
129 EFI_STATUS
130 EFIAPI
131 SetAttribute (
132 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
133 IN UINTN Attribute
134 );
135
136 EFI_STATUS
137 EFIAPI
138 ClearScreen (
139 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
140 );
141
142 EFI_STATUS
143 EFIAPI
144 SetCursorPosition (
145 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
146 IN UINTN Column,
147 IN UINTN Row
148 );
149
150 EFI_STATUS
151 EFIAPI
152 EnableCursor (
153 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
154 IN BOOLEAN Enable
155 );
156
157 EFI_SIMPLE_TEXT_INPUT_PROTOCOL mSimpleTextIn = {
158 TextInReset,
159 ReadKeyStroke,
160 NULL
161 };
162
163 EFI_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
172 EFI_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
185 EFI_HANDLE mInstallHandle = NULL;
186
187 typedef struct {
188 VENDOR_DEVICE_PATH Guid;
189 UART_DEVICE_PATH Uart;
190 EFI_DEVICE_PATH_PROTOCOL End;
191 } SIMPLE_TEXT_OUT_DEVICE_PATH;
192
193 SIMPLE_TEXT_OUT_DEVICE_PATH mDevicePath = {
194 {
195 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 }
196 },
197 EFI_CALLER_ID_GUID
198 },
199 {
200 { MESSAGING_DEVICE_PATH, MSG_UART_DP, { sizeof (UART_DEVICE_PATH), 0 }
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
212 BOOLEAN
213 TextOutIsValidAscii (
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
227 BOOLEAN
228 TextOutIsValidEfiCntlChar (
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
247 VOID
248 EFIAPI
249 WaitForKeyEvent (
250 IN EFI_EVENT Event,
251 IN VOID *Context
252 )
253 {
254 if (SerialPortPoll ()) {
255 gBS->SignalEvent (Event);
256 }
257 }
258
259 EFI_STATUS
260 EFIAPI
261 TextInReset (
262 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
263 IN BOOLEAN ExtendedVerification
264 )
265 {
266 return EFI_SUCCESS;
267 }
268
269 EFI_STATUS
270 EFIAPI
271 ReadKeyStroke (
272 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
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
418 EFI_STATUS
419 EFIAPI
420 TextOutReset (
421 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
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
437 CHAR8 *
438 EFIAPI
439 SafeUnicodeStrToAsciiStr (
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
491 EFI_STATUS
492 EFIAPI
493 OutputString (
494 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
495 IN CHAR16 *String
496 )
497 {
498 UINTN Size;
499 CHAR8 *OutputString;
500 EFI_STATUS Status;
501 EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
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
572 EFI_STATUS
573 EFIAPI
574 TestString (
575 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
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
591 EFI_STATUS
592 EFIAPI
593 QueryMode (
594 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
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
613 EFI_STATUS
614 EFIAPI
615 SetMode (
616 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
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
629 EFI_STATUS
630 EFIAPI
631 SetAttribute (
632 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
633 IN UINTN Attribute
634 )
635 {
636 This->Mode->Attribute = (INT32)Attribute;
637 return EFI_SUCCESS;
638 }
639
640 EFI_STATUS
641 EFIAPI
642 ClearScreen (
643 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
644 )
645 {
646 EFI_STATUS Status;
647
648 Status = This->SetCursorPosition (This, 0, 0);
649 return Status;
650 }
651
652 EFI_STATUS
653 EFIAPI
654 SetCursorPosition (
655 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
656 IN UINTN Column,
657 IN UINTN Row
658 )
659 {
660 EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
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
687 EFI_STATUS
688 EFIAPI
689 EnableCursor (
690 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
691 IN BOOLEAN Enable
692 )
693 {
694 if (!Enable) {
695 return EFI_UNSUPPORTED;
696 }
697
698 return EFI_SUCCESS;
699 }
700
701 EFI_STATUS
702 EFIAPI
703 SimpleTextInOutEntryPoint (
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 }