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