efi_loader: rename utf16_strlen, utf16_strnlen
[platform/kernel/u-boot.git] / lib / efi_loader / efi_console.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  EFI application console interface
4  *
5  *  Copyright (c) 2016 Alexander Graf
6  */
7
8 #include <common.h>
9 #include <charset.h>
10 #include <dm/device.h>
11 #include <efi_loader.h>
12 #include <stdio_dev.h>
13 #include <video_console.h>
14
15 #define EFI_COUT_MODE_2 2
16 #define EFI_MAX_COUT_MODE 3
17
18 struct cout_mode {
19         unsigned long columns;
20         unsigned long rows;
21         int present;
22 };
23
24 static struct cout_mode efi_cout_modes[] = {
25         /* EFI Mode 0 is 80x25 and always present */
26         {
27                 .columns = 80,
28                 .rows = 25,
29                 .present = 1,
30         },
31         /* EFI Mode 1 is always 80x50 */
32         {
33                 .columns = 80,
34                 .rows = 50,
35                 .present = 0,
36         },
37         /* Value are unknown until we query the console */
38         {
39                 .columns = 0,
40                 .rows = 0,
41                 .present = 0,
42         },
43 };
44
45 const efi_guid_t efi_guid_text_output_protocol =
46                         EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
47 const efi_guid_t efi_guid_text_input_protocol =
48                         EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
49
50 #define cESC '\x1b'
51 #define ESC "\x1b"
52
53 /* Default to mode 0 */
54 static struct simple_text_output_mode efi_con_mode = {
55         .max_mode = 1,
56         .mode = 0,
57         .attribute = 0,
58         .cursor_column = 0,
59         .cursor_row = 0,
60         .cursor_visible = 1,
61 };
62
63 /*
64  * Receive and parse a reply from the terminal.
65  *
66  * @n:          array of return values
67  * @num:        number of return values expected
68  * @end_char:   character indicating end of terminal message
69  * @return:     non-zero indicates error
70  */
71 static int term_read_reply(int *n, int num, char end_char)
72 {
73         char c;
74         int i = 0;
75
76         c = getc();
77         if (c != cESC)
78                 return -1;
79         c = getc();
80         if (c != '[')
81                 return -1;
82
83         n[0] = 0;
84         while (1) {
85                 c = getc();
86                 if (c == ';') {
87                         i++;
88                         if (i >= num)
89                                 return -1;
90                         n[i] = 0;
91                         continue;
92                 } else if (c == end_char) {
93                         break;
94                 } else if (c > '9' || c < '0') {
95                         return -1;
96                 }
97
98                 /* Read one more decimal position */
99                 n[i] *= 10;
100                 n[i] += c - '0';
101         }
102         if (i != num - 1)
103                 return -1;
104
105         return 0;
106 }
107
108 static efi_status_t EFIAPI efi_cout_output_string(
109                         struct efi_simple_text_output_protocol *this,
110                         const efi_string_t string)
111 {
112         struct simple_text_output_mode *con = &efi_con_mode;
113         struct cout_mode *mode = &efi_cout_modes[con->mode];
114
115         EFI_ENTRY("%p, %p", this, string);
116
117         unsigned int n16 = u16_strlen(string);
118         char buf[MAX_UTF8_PER_UTF16 * n16 + 1];
119         u16 *p;
120
121         *utf16_to_utf8((u8 *)buf, string, n16) = '\0';
122
123         fputs(stdout, buf);
124
125         /*
126          * Update the cursor position.
127          *
128          * The UEFI spec provides advance rules for U+0000, U+0008, U+000A,
129          * and U000D. All other characters, including control characters
130          * U+0007 (bel) and U+0009 (tab), have to increase the column by one.
131          */
132         for (p = string; *p; ++p) {
133                 switch (*p) {
134                 case '\b':      /* U+0008, backspace */
135                         con->cursor_column = max(0, con->cursor_column - 1);
136                         break;
137                 case '\n':      /* U+000A, newline */
138                         con->cursor_column = 0;
139                         con->cursor_row++;
140                         break;
141                 case '\r':      /* U+000D, carriage-return */
142                         con->cursor_column = 0;
143                         break;
144                 case 0xd800 ... 0xdbff:
145                         /*
146                          * Ignore high surrogates, we do not want to count a
147                          * Unicode character twice.
148                          */
149                         break;
150                 default:
151                         con->cursor_column++;
152                         break;
153                 }
154                 if (con->cursor_column >= mode->columns) {
155                         con->cursor_column = 0;
156                         con->cursor_row++;
157                 }
158                 con->cursor_row = min(con->cursor_row, (s32)mode->rows - 1);
159         }
160
161         return EFI_EXIT(EFI_SUCCESS);
162 }
163
164 static efi_status_t EFIAPI efi_cout_test_string(
165                         struct efi_simple_text_output_protocol *this,
166                         const efi_string_t string)
167 {
168         EFI_ENTRY("%p, %p", this, string);
169         return EFI_EXIT(EFI_SUCCESS);
170 }
171
172 static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)
173 {
174         if (!mode->present)
175                 return false;
176
177         return (mode->rows == rows) && (mode->columns == cols);
178 }
179
180 static int query_console_serial(int *rows, int *cols)
181 {
182         /* Ask the terminal about its size */
183         int n[3];
184         u64 timeout;
185
186         /* Empty input buffer */
187         while (tstc())
188                 getc();
189
190         printf(ESC"[18t");
191
192         /* Check if we have a terminal that understands */
193         timeout = timer_get_us() + 1000000;
194         while (!tstc())
195                 if (timer_get_us() > timeout)
196                         return -1;
197
198         /* Read {depth,rows,cols} */
199         if (term_read_reply(n, 3, 't'))
200                 return -1;
201
202         *cols = n[2];
203         *rows = n[1];
204
205         return 0;
206 }
207
208 /*
209  * Update the mode table.
210  *
211  * By default the only mode available is 80x25. If the console has at least 50
212  * lines, enable mode 80x50. If we can query the console size and it is neither
213  * 80x25 nor 80x50, set it as an additional mode.
214  */
215 static void query_console_size(void)
216 {
217         const char *stdout_name = env_get("stdout");
218         int rows = 25, cols = 80;
219
220         if (stdout_name && !strcmp(stdout_name, "vidconsole") &&
221             IS_ENABLED(CONFIG_DM_VIDEO)) {
222                 struct stdio_dev *stdout_dev =
223                         stdio_get_by_name("vidconsole");
224                 struct udevice *dev = stdout_dev->priv;
225                 struct vidconsole_priv *priv =
226                         dev_get_uclass_priv(dev);
227                 rows = priv->rows;
228                 cols = priv->cols;
229         } else if (query_console_serial(&rows, &cols)) {
230                 return;
231         }
232
233         /* Test if we can have Mode 1 */
234         if (cols >= 80 && rows >= 50) {
235                 efi_cout_modes[1].present = 1;
236                 efi_con_mode.max_mode = 2;
237         }
238
239         /*
240          * Install our mode as mode 2 if it is different
241          * than mode 0 or 1 and set it as the currently selected mode
242          */
243         if (!cout_mode_matches(&efi_cout_modes[0], rows, cols) &&
244             !cout_mode_matches(&efi_cout_modes[1], rows, cols)) {
245                 efi_cout_modes[EFI_COUT_MODE_2].columns = cols;
246                 efi_cout_modes[EFI_COUT_MODE_2].rows = rows;
247                 efi_cout_modes[EFI_COUT_MODE_2].present = 1;
248                 efi_con_mode.max_mode = EFI_MAX_COUT_MODE;
249                 efi_con_mode.mode = EFI_COUT_MODE_2;
250         }
251 }
252
253 static efi_status_t EFIAPI efi_cout_query_mode(
254                         struct efi_simple_text_output_protocol *this,
255                         unsigned long mode_number, unsigned long *columns,
256                         unsigned long *rows)
257 {
258         EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
259
260         if (mode_number >= efi_con_mode.max_mode)
261                 return EFI_EXIT(EFI_UNSUPPORTED);
262
263         if (efi_cout_modes[mode_number].present != 1)
264                 return EFI_EXIT(EFI_UNSUPPORTED);
265
266         if (columns)
267                 *columns = efi_cout_modes[mode_number].columns;
268         if (rows)
269                 *rows = efi_cout_modes[mode_number].rows;
270
271         return EFI_EXIT(EFI_SUCCESS);
272 }
273
274 static efi_status_t EFIAPI efi_cout_set_mode(
275                         struct efi_simple_text_output_protocol *this,
276                         unsigned long mode_number)
277 {
278         EFI_ENTRY("%p, %ld", this, mode_number);
279
280
281         if (mode_number > efi_con_mode.max_mode)
282                 return EFI_EXIT(EFI_UNSUPPORTED);
283
284         efi_con_mode.mode = mode_number;
285         efi_con_mode.cursor_column = 0;
286         efi_con_mode.cursor_row = 0;
287
288         return EFI_EXIT(EFI_SUCCESS);
289 }
290
291 static const struct {
292         unsigned int fg;
293         unsigned int bg;
294 } color[] = {
295         { 30, 40 },     /* 0: black */
296         { 34, 44 },     /* 1: blue */
297         { 32, 42 },     /* 2: green */
298         { 36, 46 },     /* 3: cyan */
299         { 31, 41 },     /* 4: red */
300         { 35, 45 },     /* 5: magenta */
301         { 33, 43 },     /* 6: brown, map to yellow as edk2 does*/
302         { 37, 47 },     /* 7: light grey, map to white */
303 };
304
305 /* See EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute(). */
306 static efi_status_t EFIAPI efi_cout_set_attribute(
307                         struct efi_simple_text_output_protocol *this,
308                         unsigned long attribute)
309 {
310         unsigned int bold = EFI_ATTR_BOLD(attribute);
311         unsigned int fg = EFI_ATTR_FG(attribute);
312         unsigned int bg = EFI_ATTR_BG(attribute);
313
314         EFI_ENTRY("%p, %lx", this, attribute);
315
316         if (attribute)
317                 printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
318         else
319                 printf(ESC"[0;37;40m");
320
321         return EFI_EXIT(EFI_SUCCESS);
322 }
323
324 static efi_status_t EFIAPI efi_cout_clear_screen(
325                         struct efi_simple_text_output_protocol *this)
326 {
327         EFI_ENTRY("%p", this);
328
329         printf(ESC"[2J");
330         efi_con_mode.cursor_column = 0;
331         efi_con_mode.cursor_row = 0;
332
333         return EFI_EXIT(EFI_SUCCESS);
334 }
335
336 static efi_status_t EFIAPI efi_cout_reset(
337                         struct efi_simple_text_output_protocol *this,
338                         char extended_verification)
339 {
340         EFI_ENTRY("%p, %d", this, extended_verification);
341
342         /* Clear screen */
343         EFI_CALL(efi_cout_clear_screen(this));
344         /* Set default colors */
345         printf(ESC "[0;37;40m");
346
347         return EFI_EXIT(EFI_SUCCESS);
348 }
349
350 static efi_status_t EFIAPI efi_cout_set_cursor_position(
351                         struct efi_simple_text_output_protocol *this,
352                         unsigned long column, unsigned long row)
353 {
354         EFI_ENTRY("%p, %ld, %ld", this, column, row);
355
356         printf(ESC"[%d;%df", (int)row, (int)column);
357         efi_con_mode.cursor_column = column;
358         efi_con_mode.cursor_row = row;
359
360         return EFI_EXIT(EFI_SUCCESS);
361 }
362
363 static efi_status_t EFIAPI efi_cout_enable_cursor(
364                         struct efi_simple_text_output_protocol *this,
365                         bool enable)
366 {
367         EFI_ENTRY("%p, %d", this, enable);
368
369         printf(ESC"[?25%c", enable ? 'h' : 'l');
370
371         return EFI_EXIT(EFI_SUCCESS);
372 }
373
374 struct efi_simple_text_output_protocol efi_con_out = {
375         .reset = efi_cout_reset,
376         .output_string = efi_cout_output_string,
377         .test_string = efi_cout_test_string,
378         .query_mode = efi_cout_query_mode,
379         .set_mode = efi_cout_set_mode,
380         .set_attribute = efi_cout_set_attribute,
381         .clear_screen = efi_cout_clear_screen,
382         .set_cursor_position = efi_cout_set_cursor_position,
383         .enable_cursor = efi_cout_enable_cursor,
384         .mode = (void*)&efi_con_mode,
385 };
386
387 static efi_status_t EFIAPI efi_cin_reset(
388                         struct efi_simple_input_interface *this,
389                         bool extended_verification)
390 {
391         EFI_ENTRY("%p, %d", this, extended_verification);
392
393         /* Empty input buffer */
394         while (tstc())
395                 getc();
396
397         return EFI_EXIT(EFI_SUCCESS);
398 }
399
400 /*
401  * Analyze modifiers (shift, alt, ctrl) for function keys.
402  * This gets called when we have already parsed CSI.
403  *
404  * @modifiers:  bitmask (shift, alt, ctrl)
405  * @return:     the unmodified code
406  */
407 static char skip_modifiers(int *modifiers)
408 {
409         char c, mod = 0, ret = 0;
410
411         c = getc();
412
413         if (c != ';') {
414                 ret = c;
415                 if (c == '~')
416                         goto out;
417                 c = getc();
418         }
419         for (;;) {
420                 switch (c) {
421                 case '0'...'9':
422                         mod *= 10;
423                         mod += c - '0';
424                 /* fall through */
425                 case ';':
426                         c = getc();
427                         break;
428                 default:
429                         goto out;
430                 }
431         }
432 out:
433         if (mod)
434                 --mod;
435         if (modifiers)
436                 *modifiers = mod;
437         if (!ret)
438                 ret = c;
439         return ret;
440 }
441
442 static efi_status_t EFIAPI efi_cin_read_key_stroke(
443                         struct efi_simple_input_interface *this,
444                         struct efi_input_key *key)
445 {
446         struct efi_input_key pressed_key = {
447                 .scan_code = 0,
448                 .unicode_char = 0,
449         };
450         char ch;
451
452         EFI_ENTRY("%p, %p", this, key);
453
454         /* We don't do interrupts, so check for timers cooperatively */
455         efi_timer_check();
456
457         if (!tstc()) {
458                 /* No key pressed */
459                 return EFI_EXIT(EFI_NOT_READY);
460         }
461
462         ch = getc();
463         if (ch == cESC) {
464                 /*
465                  * Xterm Control Sequences
466                  * https://www.xfree86.org/4.8.0/ctlseqs.html
467                  */
468                 ch = getc();
469                 switch (ch) {
470                 case cESC: /* ESC */
471                         pressed_key.scan_code = 23;
472                         break;
473                 case 'O': /* F1 - F4 */
474                         ch = getc();
475                         /* skip modifiers */
476                         if (ch <= '9')
477                                 ch = getc();
478                         pressed_key.scan_code = ch - 'P' + 11;
479                         break;
480                 case 'a'...'z':
481                         ch = ch - 'a';
482                         break;
483                 case '[':
484                         ch = getc();
485                         switch (ch) {
486                         case 'A'...'D': /* up, down right, left */
487                                 pressed_key.scan_code = ch - 'A' + 1;
488                                 break;
489                         case 'F': /* End */
490                                 pressed_key.scan_code = 6;
491                                 break;
492                         case 'H': /* Home */
493                                 pressed_key.scan_code = 5;
494                                 break;
495                         case '1':
496                                 ch = skip_modifiers(NULL);
497                                 switch (ch) {
498                                 case '1'...'5': /* F1 - F5 */
499                                         pressed_key.scan_code = ch - '1' + 11;
500                                         break;
501                                 case '7'...'9': /* F6 - F8 */
502                                         pressed_key.scan_code = ch - '7' + 16;
503                                         break;
504                                 case 'A'...'D': /* up, down right, left */
505                                         pressed_key.scan_code = ch - 'A' + 1;
506                                         break;
507                                 case 'F':
508                                         pressed_key.scan_code = 6; /* End */
509                                         break;
510                                 case 'H':
511                                         pressed_key.scan_code = 5; /* Home */
512                                         break;
513                                 }
514                                 break;
515                         case '2':
516                                 ch = skip_modifiers(NULL);
517                                 switch (ch) {
518                                 case '0'...'1': /* F9 - F10 */
519                                         pressed_key.scan_code = ch - '0' + 19;
520                                         break;
521                                 case '3'...'4': /* F11 - F12 */
522                                         pressed_key.scan_code = ch - '3' + 21;
523                                         break;
524                                 case '~': /* INS */
525                                         pressed_key.scan_code = 7;
526                                         break;
527                                 }
528                                 break;
529                         case '3': /* DEL */
530                                 pressed_key.scan_code = 8;
531                                 skip_modifiers(NULL);
532                                 break;
533                         case '5': /* PG UP */
534                                 pressed_key.scan_code = 9;
535                                 skip_modifiers(NULL);
536                                 break;
537                         case '6': /* PG DOWN */
538                                 pressed_key.scan_code = 10;
539                                 skip_modifiers(NULL);
540                                 break;
541                         }
542                         break;
543                 }
544         } else if (ch == 0x7f) {
545                 /* Backspace */
546                 ch = 0x08;
547         }
548         if (!pressed_key.scan_code)
549                 pressed_key.unicode_char = ch;
550         *key = pressed_key;
551
552         return EFI_EXIT(EFI_SUCCESS);
553 }
554
555 struct efi_simple_input_interface efi_con_in = {
556         .reset = efi_cin_reset,
557         .read_key_stroke = efi_cin_read_key_stroke,
558         .wait_for_key = NULL,
559 };
560
561 static struct efi_event *console_timer_event;
562
563 static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
564 {
565 }
566
567 /*
568  * Notification function of the console timer event.
569  *
570  * event:       console timer event
571  * context:     not used
572  */
573 static void EFIAPI efi_console_timer_notify(struct efi_event *event,
574                                             void *context)
575 {
576         EFI_ENTRY("%p, %p", event, context);
577
578         /* Check if input is available */
579         if (tstc()) {
580                 /* Queue the wait for key event */
581                 efi_con_in.wait_for_key->is_signaled = true;
582                 efi_signal_event(efi_con_in.wait_for_key, true);
583         }
584         EFI_EXIT(EFI_SUCCESS);
585 }
586
587 /* This gets called from do_bootefi_exec(). */
588 int efi_console_register(void)
589 {
590         efi_status_t r;
591         struct efi_object *efi_console_output_obj;
592         struct efi_object *efi_console_input_obj;
593
594         /* Set up mode information */
595         query_console_size();
596
597         /* Create handles */
598         r = efi_create_handle((efi_handle_t *)&efi_console_output_obj);
599         if (r != EFI_SUCCESS)
600                 goto out_of_memory;
601         r = efi_add_protocol(efi_console_output_obj->handle,
602                              &efi_guid_text_output_protocol, &efi_con_out);
603         if (r != EFI_SUCCESS)
604                 goto out_of_memory;
605         r = efi_create_handle((efi_handle_t *)&efi_console_input_obj);
606         if (r != EFI_SUCCESS)
607                 goto out_of_memory;
608         r = efi_add_protocol(efi_console_input_obj->handle,
609                              &efi_guid_text_input_protocol, &efi_con_in);
610         if (r != EFI_SUCCESS)
611                 goto out_of_memory;
612
613         /* Create console events */
614         r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
615                              NULL, NULL, &efi_con_in.wait_for_key);
616         if (r != EFI_SUCCESS) {
617                 printf("ERROR: Failed to register WaitForKey event\n");
618                 return r;
619         }
620         r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
621                              efi_console_timer_notify, NULL, NULL,
622                              &console_timer_event);
623         if (r != EFI_SUCCESS) {
624                 printf("ERROR: Failed to register console event\n");
625                 return r;
626         }
627         /* 5000 ns cycle is sufficient for 2 MBaud */
628         r = efi_set_timer(console_timer_event, EFI_TIMER_PERIODIC, 50);
629         if (r != EFI_SUCCESS)
630                 printf("ERROR: Failed to set console timer\n");
631         return r;
632 out_of_memory:
633         printf("ERROR: Out of meemory\n");
634         return r;
635 }