blob: bdc67fbda03241b4bc00dd0e8ceb26b180ee064a [file] [log] [blame]
AJFISH2ef2b012009-12-06 01:57:05 +00001/** @file
2 Simple Console that sits on a SerialLib.
3
4 Copyright (c) 2008-2009, Apple Inc. All rights reserved.
5
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14**/
15
16/*
17 Symbols used in table below
18===========================
19 ESC = 0x1B
20 CSI = 0x9B
21 DEL = 0x7f
22 ^ = CTRL
23
24+=========+======+===========+==========+==========+
25| | EFI | UEFI 2.0 | | |
26| | Scan | | VT100+ | |
27| KEY | Code | PC ANSI | VTUTF8 | VT100 |
28+=========+======+===========+==========+==========+
29| NULL | 0x00 | | | |
30| UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |
31| DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |
32| RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C |
33| LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |
34| HOME | 0x05 | ESC [ H | ESC h | ESC [ H |
35| END | 0x06 | ESC [ F | ESC k | ESC [ K |
36| INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |
37| | | ESC [ L | | ESC [ L |
38| DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |
39| PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |
40| | | | | ESC [ ? |
41| PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
42| | | | | ESC [ / |
43| F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |
44| F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |
45| F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |
46| F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |
47| F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |
48| F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |
49| F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |
50| F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |
51| F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |
52| F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |
53| Escape | 0x17 | ESC | ESC | ESC |
54| F11 | 0x15 | | ESC ! | |
55| F12 | 0x16 | | ESC @ | |
56+=========+======+===========+==========+==========+
57
58*/
59
60#include <PiDxe.h>
61#include <Library/UefiLib.h>
62#include <Library/UefiBootServicesTableLib.h>
63#include <Library/BaseLib.h>
64#include <Library/MemoryAllocationLib.h>
65#include <Library/DebugLib.h>
66#include <Library/SerialPortLib.h>
andrewfish026e30c2010-02-15 20:40:51 +000067#include <Library/PcdLib.h>
AJFISH2ef2b012009-12-06 01:57:05 +000068
69#include <Protocol/SerialIo.h>
70#include <Protocol/SimpleTextIn.h>
71#include <Protocol/SimpleTextOut.h>
andrewfish026e30c2010-02-15 20:40:51 +000072#include <Protocol/DevicePath.h>
AJFISH2ef2b012009-12-06 01:57:05 +000073
74
75#define MODE0_COLUMN_COUNT 80
76#define MODE0_ROW_COUNT 25
77
78
79EFI_STATUS
80EFIAPI
81TextInReset(
82 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
83 IN BOOLEAN ExtendedVerification
84 );
85
86
87EFI_STATUS
88EFIAPI
89ReadKeyStroke(
90 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
91 OUT EFI_INPUT_KEY *Key
92 );
93
94
95EFI_STATUS
96EFIAPI
97TextOutReset(
98 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
99 IN BOOLEAN ExtendedVerification
100 );
101
102CHAR8 *
103EFIAPI
104SafeUnicodeStrToAsciiStr (
105 IN CONST CHAR16 *Source,
106 OUT CHAR8 *Destination
107 );
108
109EFI_STATUS
110EFIAPI
111OutputString (
112 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
113 IN CHAR16 *String
114 );
115
116
117EFI_STATUS
118EFIAPI
119TestString (
120 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
121 IN CHAR16 *String
122 );
123
124
125EFI_STATUS
126EFIAPI
127QueryMode (
128 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
129 IN UINTN ModeNumber,
130 OUT UINTN *Columns,
131 OUT UINTN *Rows
132 );
133
134
135EFI_STATUS
136EFIAPI
137SetMode(
138 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
139 IN UINTN ModeNumber
140 );
141
142
143EFI_STATUS
144EFIAPI
145SetAttribute(
146 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
147 IN UINTN Attribute
148 );
149
150
151EFI_STATUS
152EFIAPI
153ClearScreen (
154 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
155 );
156
157
158EFI_STATUS
159EFIAPI
160SetCursorPosition (
161 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
162 IN UINTN Column,
163 IN UINTN Row
164 );
165
166
167EFI_STATUS
168EFIAPI
169EnableCursor (
170 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
171 IN BOOLEAN Enable
172 );
173
174
175 EFI_SIMPLE_TEXT_INPUT_PROTOCOL mSimpleTextIn = {
176 TextInReset,
177 ReadKeyStroke,
178 NULL
179};
180
181 EFI_SIMPLE_TEXT_OUTPUT_MODE mSimpleTextOutMode = {
182 1,
183 0,
184 EFI_TEXT_ATTR( EFI_LIGHTGRAY, EFI_BLACK ),
185 0,
186 0,
187 TRUE
188};
189
190EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL mSimpleTextOut = {
191 TextOutReset,
192 OutputString,
193 TestString,
194 QueryMode,
195 SetMode,
196 SetAttribute,
197 ClearScreen,
198 SetCursorPosition,
199 EnableCursor,
200 &mSimpleTextOutMode
201};
202
andrewfish026e30c2010-02-15 20:40:51 +0000203EFI_HANDLE mInstallHandle = NULL;
204
205typedef struct {
206 VENDOR_DEVICE_PATH Guid;
207 UART_DEVICE_PATH Uart;
208 EFI_DEVICE_PATH_PROTOCOL End;
209} SIMPLE_TEXT_OUT_DEVICE_PATH;
210
211SIMPLE_TEXT_OUT_DEVICE_PATH mDevicePath = {
212 {
213 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH), 0},
214 EFI_CALLER_ID_GUID
215 },
216 {
217 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, sizeof (UART_DEVICE_PATH), 0},
218 0, // Reserved
219 FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
220 FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
221 FixedPcdGet8 (PcdUartDefaultParity), // Parity (N)
222 FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
223 },
224 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, sizeof (EFI_DEVICE_PATH_PROTOCOL), 0}
225};
226
AJFISH2ef2b012009-12-06 01:57:05 +0000227
228
229
230BOOLEAN
231TextOutIsValidAscii (
232 IN CHAR16 Ascii
233 )
234{
235 //
236 // valid ASCII code lies in the extent of 0x20 - 0x7F
237 //
238 if ((Ascii >= 0x20) && (Ascii <= 0x7F)) {
239 return TRUE;
240 }
241
242 return FALSE;
243}
244
245
246BOOLEAN
247TextOutIsValidEfiCntlChar (
248 IN CHAR16 Char
249 )
250{
251 //
252 // only support four control characters.
253 //
254 if (Char == CHAR_NULL ||
255 Char == CHAR_BACKSPACE ||
256 Char == CHAR_LINEFEED ||
257 Char == CHAR_CARRIAGE_RETURN ||
258 Char == CHAR_TAB ) {
259 return TRUE;
260 }
261
262 return FALSE;
263}
264
265
266VOID
267EFIAPI
268WaitForKeyEvent (
269 IN EFI_EVENT Event,
270 IN VOID *Context
271 )
272{
273 if (SerialPortPoll ()) {
274 gBS->SignalEvent (Event);
275 }
276}
277
278
279EFI_STATUS
280EFIAPI
281TextInReset (
282 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
283 IN BOOLEAN ExtendedVerification
284 )
285{
286 return EFI_SUCCESS;
287}
288
289
290EFI_STATUS
291EFIAPI
292ReadKeyStroke (
293 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
294 OUT EFI_INPUT_KEY *Key
295 )
296{
297 CHAR8 Char;
298
andrewfish026e30c2010-02-15 20:40:51 +0000299 if (!SerialPortPoll ()) {
300 return EFI_NOT_READY;
301 }
302
AJFISH2ef2b012009-12-06 01:57:05 +0000303 SerialPortRead ((UINT8 *)&Char, 1);
304
305 //
306 // Check for ESC sequence. This code is not techincally correct VT100 code.
307 // An illegal ESC sequence represents an ESC and the characters that follow.
308 // This code will eat one or two chars after an escape. This is done to
309 // prevent some complex FIFOing of the data. It is good enough to get
310 // the arrow and delete keys working
311 //
312 Key->UnicodeChar = 0;
313 Key->ScanCode = SCAN_NULL;
314 if (Char == 0x1b) {
315 SerialPortRead ((UINT8 *)&Char, 1);
316 if (Char == '[') {
317 SerialPortRead ((UINT8 *)&Char, 1);
318 switch (Char) {
319 case 'A':
320 Key->ScanCode = SCAN_UP;
321 break;
322 case 'B':
323 Key->ScanCode = SCAN_DOWN;
324 break;
325 case 'C':
326 Key->ScanCode = SCAN_RIGHT;
327 break;
328 case 'D':
329 Key->ScanCode = SCAN_LEFT;
330 break;
331 case 'H':
332 Key->ScanCode = SCAN_HOME;
333 break;
334 case 'K':
335 case 'F': // PC ANSI
336 Key->ScanCode = SCAN_END;
337 break;
338 case '@':
339 case 'L':
340 Key->ScanCode = SCAN_INSERT;
341 break;
342 case 'P':
343 case 'X': // PC ANSI
344 Key->ScanCode = SCAN_DELETE;
345 break;
346 case 'U':
347 case '/':
348 case 'G': // PC ANSI
349 Key->ScanCode = SCAN_PAGE_DOWN;
350 break;
351 case 'V':
352 case '?':
353 case 'I': // PC ANSI
354 Key->ScanCode = SCAN_PAGE_UP;
355 break;
356
357 // PCANSI that does not conflict with VT100
358 case 'M':
359 Key->ScanCode = SCAN_F1;
360 break;
361 case 'N':
362 Key->ScanCode = SCAN_F2;
363 break;
364 case 'O':
365 Key->ScanCode = SCAN_F3;
366 break;
367 case 'Q':
368 Key->ScanCode = SCAN_F5;
369 break;
370 case 'R':
371 Key->ScanCode = SCAN_F6;
372 break;
373 case 'S':
374 Key->ScanCode = SCAN_F7;
375 break;
376 case 'T':
377 Key->ScanCode = SCAN_F8;
378 break;
379
380 default:
381 Key->UnicodeChar = Char;
382 break;
383 }
384 } else if (Char == '0') {
385 SerialPortRead ((UINT8 *)&Char, 1);
386 switch (Char) {
387 case 'P':
388 Key->ScanCode = SCAN_F1;
389 break;
390 case 'Q':
391 Key->ScanCode = SCAN_F2;
392 break;
393 case 'w':
394 Key->ScanCode = SCAN_F3;
395 break;
396 case 'x':
397 Key->ScanCode = SCAN_F4;
398 break;
399 case 't':
400 Key->ScanCode = SCAN_F5;
401 break;
402 case 'u':
403 Key->ScanCode = SCAN_F6;
404 break;
405 case 'q':
406 Key->ScanCode = SCAN_F7;
407 break;
408 case 'r':
409 Key->ScanCode = SCAN_F8;
410 break;
411 case 'p':
412 Key->ScanCode = SCAN_F9;
413 break;
414 case 'm':
415 Key->ScanCode = SCAN_F10;
416 break;
417 default :
418 break;
419 }
420 }
421 } else if (Char < ' ') {
422 if ((Char == CHAR_BACKSPACE) ||
423 (Char == CHAR_TAB) ||
424 (Char == CHAR_LINEFEED) ||
425 (Char == CHAR_CARRIAGE_RETURN)) {
426 // Only let through EFI required control characters
427 Key->UnicodeChar = (CHAR16)Char;
428 }
429 } else if (Char == 0x7f) {
430 Key->ScanCode = SCAN_DELETE;
431 } else {
432 Key->UnicodeChar = (CHAR16)Char;
433 }
434
435 return EFI_SUCCESS;
436}
437
438
439EFI_STATUS
440EFIAPI
441TextOutReset (
442 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
443 IN BOOLEAN ExtendedVerification
444 )
445{
446 EFI_STATUS Status;
447
448 This->SetAttribute(
449 This,
450 EFI_TEXT_ATTR(This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK)
451 );
452
453 Status = This->SetMode (This, 0);
454
455 return Status;
456}
457
458CHAR8 *
459EFIAPI
460SafeUnicodeStrToAsciiStr (
461 IN CONST CHAR16 *Source,
462 OUT CHAR8 *Destination
463 )
464{
465 CHAR8 *ReturnValue;
466
467 ASSERT (Destination != NULL);
468
469 //
470 // ASSERT if Source is long than PcdMaximumUnicodeStringLength.
471 // Length tests are performed inside StrLen().
472 //
473 ASSERT (StrSize (Source) != 0);
474
475 //
476 // Source and Destination should not overlap
477 //
478 ASSERT ((UINTN) ((CHAR16 *) Destination - Source) > StrLen (Source));
479 ASSERT ((UINTN) ((CHAR8 *) Source - Destination) > StrLen (Source));
480
481
482 ReturnValue = Destination;
483 while (*Source != '\0') {
484 //
485 // If any non-ascii characters in Source then replace it with '?'.
486 //
487 if (*Source < 0x80) {
488 *Destination = (CHAR8) *Source;
489 } else {
490 *Destination = '?';
491
492 //Surrogate pair check.
493 if ((*Source >= 0xD800) && (*Source <= 0xDFFF)) {
494 Source++;
495 }
496 }
497
498 Destination++;
499 Source++;
500 }
501
502 *Destination = '\0';
503
504 //
505 // ASSERT Original Destination is less long than PcdMaximumAsciiStringLength.
506 // Length tests are performed inside AsciiStrLen().
507 //
508 ASSERT (AsciiStrSize (ReturnValue) != 0);
509
510 return ReturnValue;
511}
512
513EFI_STATUS
514EFIAPI
515OutputString (
516 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
517 IN CHAR16 *String
518 )
519{
520 UINTN Size = StrLen(String) + 1;
521 CHAR8 *OutputString = AllocatePool(Size);
522
523 //If there is any non-ascii characters in String buffer then replace it with '?'
524 //Eventually, UnicodeStrToAsciiStr API should be fixed.
525 SafeUnicodeStrToAsciiStr(String, OutputString);
526 SerialPortWrite ((UINT8 *)OutputString, Size - 1);
527
528 FreePool(OutputString);
529
530 return EFI_SUCCESS;
531}
532
533
534EFI_STATUS
535EFIAPI
536TestString (
537 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
538 IN CHAR16 *String
539 )
540{
541 CHAR8 Character;
542
543 for ( ; *String != CHAR_NULL; String++) {
544 Character = (CHAR8)*String;
545 if (!(TextOutIsValidAscii (Character) || TextOutIsValidEfiCntlChar (Character))) {
546 return EFI_UNSUPPORTED;
547 }
548 }
549
550 return EFI_SUCCESS;
551}
552
553
554EFI_STATUS
555EFIAPI
556QueryMode (
557 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
558 IN UINTN ModeNumber,
559 OUT UINTN *Columns,
560 OUT UINTN *Rows
561 )
562{
563 if (This->Mode->MaxMode > 1) {
564 return EFI_DEVICE_ERROR;
565 }
566
567 if (ModeNumber == 0) {
568 *Columns = MODE0_COLUMN_COUNT;
569 *Rows = MODE0_ROW_COUNT;
570 return EFI_SUCCESS;
571 }
572
573 return EFI_UNSUPPORTED;
574}
575
576
577EFI_STATUS
578EFIAPI
579SetMode (
580 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
581 IN UINTN ModeNumber
582 )
583{
584 if (ModeNumber != 0) {
585 return EFI_UNSUPPORTED;
586 }
587
588 This->Mode->Mode = 0;
589 This->ClearScreen (This);
590 return EFI_SUCCESS;
591}
592
593
594EFI_STATUS
595EFIAPI
596SetAttribute(
597 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
598 IN UINTN Attribute
599 )
600{
601 This->Mode->Attribute = (INT32)Attribute;
602 return EFI_SUCCESS;
603}
604
605
606EFI_STATUS
607EFIAPI
608ClearScreen (
609 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
610 )
611{
612 EFI_STATUS Status;
613
614 Status = This->SetCursorPosition (This, 0, 0);
615 return Status;
616}
617
618
619EFI_STATUS
620EFIAPI
621SetCursorPosition (
622 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
623 IN UINTN Column,
624 IN UINTN Row
625 )
626{
627 EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
628 EFI_STATUS Status;
629 UINTN MaxColumn;
630 UINTN MaxRow;
631
632 Mode = This->Mode;
633
634 Status = This->QueryMode(
635 This,
636 Mode->Mode,
637 &MaxColumn,
638 &MaxRow
639 );
640 if (EFI_ERROR(Status)) {
641 return EFI_UNSUPPORTED;
642 }
643
644 if ((Column >= MaxColumn) || (Row >= MaxRow)) {
645 return EFI_UNSUPPORTED;
646 }
647
648 Mode->CursorColumn = (INT32)Column;
649 Mode->CursorRow = (INT32)Row;
650
651 return EFI_SUCCESS;
652}
653
654
655EFI_STATUS
656EFIAPI
657EnableCursor (
658 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
659 IN BOOLEAN Enable
660 )
661{
662 if (!Enable) {
663 return EFI_UNSUPPORTED;
664 }
665
666 return EFI_SUCCESS;
667}
668
669
670EFI_STATUS
671EFIAPI
672SimpleTextInOutEntryPoint (
673 IN EFI_HANDLE ImageHandle,
674 IN EFI_SYSTEM_TABLE *SystemTable
675 )
676{
677 EFI_STATUS Status;
678
679 Status = gBS->CreateEvent (
680 EVT_NOTIFY_WAIT,
681 TPL_NOTIFY,
682 WaitForKeyEvent,
683 NULL,
684 &mSimpleTextIn.WaitForKey
685 );
686 ASSERT_EFI_ERROR (Status);
687
688 Status = gBS->InstallMultipleProtocolInterfaces(
689 &mInstallHandle,
690 &gEfiSimpleTextInProtocolGuid, &mSimpleTextIn,
691 &gEfiSimpleTextOutProtocolGuid, &mSimpleTextOut,
andrewfish026e30c2010-02-15 20:40:51 +0000692 &gEfiDevicePathProtocolGuid, &mDevicePath,
693 NULL
AJFISH2ef2b012009-12-06 01:57:05 +0000694 );
695 if (!EFI_ERROR (Status)) {
696 gST->ConOut = &mSimpleTextOut;
697 gST->ConIn = &mSimpleTextIn;
698 }
699
700 return Status;
701}