blob: 426de779517c9896aa15b0d8e029b5f49906d3de [file] [log] [blame]
Tom Rinif739fcd2018-05-07 17:02:21 -04001// SPDX-License-Identifier: GPL-2.0+
Alexander Grafc1311ad2016-03-04 01:10:00 +01002/*
3 * EFI application console interface
4 *
5 * Copyright (c) 2016 Alexander Graf
Alexander Grafc1311ad2016-03-04 01:10:00 +01006 */
7
8#include <common.h>
Rob Clark78178bb2017-09-09 06:47:40 -04009#include <charset.h>
Simon Glass336d4612020-02-03 07:36:16 -070010#include <malloc.h>
Simon Glass10453152019-11-14 12:57:30 -070011#include <time.h>
Rob Clarka18c5a82017-09-13 18:05:43 -040012#include <dm/device.h>
Alexander Grafc1311ad2016-03-04 01:10:00 +010013#include <efi_loader.h>
Simon Glass7b51b572019-08-01 09:46:52 -060014#include <env.h>
Rob Clarka18c5a82017-09-13 18:05:43 -040015#include <stdio_dev.h>
16#include <video_console.h>
Alexander Grafc1311ad2016-03-04 01:10:00 +010017
Emmanuel Vadot5be8b0a2016-11-08 06:03:29 +010018#define EFI_COUT_MODE_2 2
19#define EFI_MAX_COUT_MODE 3
20
21struct cout_mode {
22 unsigned long columns;
23 unsigned long rows;
24 int present;
25};
26
27static struct cout_mode efi_cout_modes[] = {
28 /* EFI Mode 0 is 80x25 and always present */
29 {
30 .columns = 80,
31 .rows = 25,
32 .present = 1,
33 },
34 /* EFI Mode 1 is always 80x50 */
35 {
36 .columns = 80,
37 .rows = 50,
38 .present = 0,
39 },
40 /* Value are unknown until we query the console */
41 {
42 .columns = 0,
43 .rows = 0,
44 .present = 0,
45 },
46};
47
Heinrich Schuchardt110c6282018-09-11 22:38:08 +020048const efi_guid_t efi_guid_text_input_ex_protocol =
49 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +020050const efi_guid_t efi_guid_text_input_protocol =
51 EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
Heinrich Schuchardt110c6282018-09-11 22:38:08 +020052const efi_guid_t efi_guid_text_output_protocol =
53 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
Alexander Grafc1311ad2016-03-04 01:10:00 +010054
55#define cESC '\x1b'
56#define ESC "\x1b"
57
Emmanuel Vadot5be8b0a2016-11-08 06:03:29 +010058/* Default to mode 0 */
Alexander Grafc1311ad2016-03-04 01:10:00 +010059static struct simple_text_output_mode efi_con_mode = {
Emmanuel Vadot5be8b0a2016-11-08 06:03:29 +010060 .max_mode = 1,
Alexander Grafc1311ad2016-03-04 01:10:00 +010061 .mode = 0,
62 .attribute = 0,
63 .cursor_column = 0,
64 .cursor_row = 0,
65 .cursor_visible = 1,
66};
67
Matthias Bruggerdd1a1ec2019-03-05 12:50:18 +010068static int term_get_char(s32 *c)
69{
70 u64 timeout;
71
72 /* Wait up to 100 ms for a character */
73 timeout = timer_get_us() + 100000;
74
75 while (!tstc())
76 if (timer_get_us() > timeout)
77 return 1;
78
79 *c = getc();
80 return 0;
81}
82
Heinrich Schuchardt325567d2020-06-04 18:40:44 +020083/**
Heinrich Schuchardt62217292018-05-16 18:17:38 +020084 * Receive and parse a reply from the terminal.
85 *
86 * @n: array of return values
87 * @num: number of return values expected
88 * @end_char: character indicating end of terminal message
Heinrich Schuchardt325567d2020-06-04 18:40:44 +020089 * Return: non-zero indicates error
Heinrich Schuchardt62217292018-05-16 18:17:38 +020090 */
91static int term_read_reply(int *n, int num, char end_char)
Alexander Grafc1311ad2016-03-04 01:10:00 +010092{
Matthias Bruggerdd1a1ec2019-03-05 12:50:18 +010093 s32 c;
Alexander Grafc1311ad2016-03-04 01:10:00 +010094 int i = 0;
95
Matthias Bruggerdd1a1ec2019-03-05 12:50:18 +010096 if (term_get_char(&c) || c != cESC)
Alexander Grafc1311ad2016-03-04 01:10:00 +010097 return -1;
Matthias Bruggerdd1a1ec2019-03-05 12:50:18 +010098
99 if (term_get_char(&c) || c != '[')
Alexander Grafc1311ad2016-03-04 01:10:00 +0100100 return -1;
101
102 n[0] = 0;
103 while (1) {
Matthias Bruggerdd1a1ec2019-03-05 12:50:18 +0100104 if (!term_get_char(&c)) {
105 if (c == ';') {
106 i++;
107 if (i >= num)
108 return -1;
109 n[i] = 0;
110 continue;
111 } else if (c == end_char) {
112 break;
113 } else if (c > '9' || c < '0') {
Alexander Grafc1311ad2016-03-04 01:10:00 +0100114 return -1;
Matthias Bruggerdd1a1ec2019-03-05 12:50:18 +0100115 }
116
117 /* Read one more decimal position */
118 n[i] *= 10;
119 n[i] += c - '0';
120 } else {
Alexander Grafc1311ad2016-03-04 01:10:00 +0100121 return -1;
122 }
Alexander Grafc1311ad2016-03-04 01:10:00 +0100123 }
Heinrich Schuchardt62217292018-05-16 18:17:38 +0200124 if (i != num - 1)
125 return -1;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100126
127 return 0;
128}
129
Heinrich Schuchardt325567d2020-06-04 18:40:44 +0200130/**
131 * efi_cout_output_string() - write Unicode string to console
132 *
133 * This function implements the OutputString service of the simple text output
134 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
135 * for details.
136 *
137 * @this: simple text output protocol
138 * @string: u16 string
139 * Return: status code
140 */
Alexander Grafc1311ad2016-03-04 01:10:00 +0100141static efi_status_t EFIAPI efi_cout_output_string(
142 struct efi_simple_text_output_protocol *this,
Rob Clark3a45bc72017-09-13 18:05:44 -0400143 const efi_string_t string)
Alexander Grafc1311ad2016-03-04 01:10:00 +0100144{
Rob Clark3a45bc72017-09-13 18:05:44 -0400145 struct simple_text_output_mode *con = &efi_con_mode;
146 struct cout_mode *mode = &efi_cout_modes[con->mode];
Heinrich Schuchardtba7bd5c2018-08-31 21:31:32 +0200147 char *buf, *pos;
148 u16 *p;
149 efi_status_t ret = EFI_SUCCESS;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100150
151 EFI_ENTRY("%p, %p", this, string);
Rob Clark3a45bc72017-09-13 18:05:44 -0400152
Heinrich Schuchardtb31ca6b2019-05-18 18:11:54 +0200153 if (!this || !string) {
154 ret = EFI_INVALID_PARAMETER;
155 goto out;
156 }
157
Heinrich Schuchardtba7bd5c2018-08-31 21:31:32 +0200158 buf = malloc(utf16_utf8_strlen(string) + 1);
159 if (!buf) {
160 ret = EFI_OUT_OF_RESOURCES;
161 goto out;
162 }
163 pos = buf;
164 utf16_utf8_strcpy(&pos, string);
Rob Clark3a45bc72017-09-13 18:05:44 -0400165 fputs(stdout, buf);
Heinrich Schuchardtba7bd5c2018-08-31 21:31:32 +0200166 free(buf);
Rob Clark3a45bc72017-09-13 18:05:44 -0400167
Heinrich Schuchardt7ca7c3c2018-04-29 16:24:25 +0200168 /*
169 * Update the cursor position.
170 *
171 * The UEFI spec provides advance rules for U+0000, U+0008, U+000A,
Heinrich Schuchardt97ea0692019-09-04 21:13:45 +0200172 * and U000D. All other control characters are ignored. Any non-control
173 * character increase the column by one.
Heinrich Schuchardt7ca7c3c2018-04-29 16:24:25 +0200174 */
175 for (p = string; *p; ++p) {
Rob Clark3a45bc72017-09-13 18:05:44 -0400176 switch (*p) {
Heinrich Schuchardt7ca7c3c2018-04-29 16:24:25 +0200177 case '\b': /* U+0008, backspace */
Heinrich Schuchardt97ea0692019-09-04 21:13:45 +0200178 if (con->cursor_column)
179 con->cursor_column--;
Rob Clark3a45bc72017-09-13 18:05:44 -0400180 break;
Heinrich Schuchardt7ca7c3c2018-04-29 16:24:25 +0200181 case '\n': /* U+000A, newline */
Rob Clark3a45bc72017-09-13 18:05:44 -0400182 con->cursor_column = 0;
183 con->cursor_row++;
184 break;
Heinrich Schuchardt7ca7c3c2018-04-29 16:24:25 +0200185 case '\r': /* U+000D, carriage-return */
186 con->cursor_column = 0;
Rob Clark3a45bc72017-09-13 18:05:44 -0400187 break;
Heinrich Schuchardt7ca7c3c2018-04-29 16:24:25 +0200188 case 0xd800 ... 0xdbff:
189 /*
190 * Ignore high surrogates, we do not want to count a
191 * Unicode character twice.
192 */
Rob Clark3a45bc72017-09-13 18:05:44 -0400193 break;
194 default:
Heinrich Schuchardt97ea0692019-09-04 21:13:45 +0200195 /* Exclude control codes */
196 if (*p > 0x1f)
197 con->cursor_column++;
Rob Clark3a45bc72017-09-13 18:05:44 -0400198 break;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100199 }
Rob Clark3a45bc72017-09-13 18:05:44 -0400200 if (con->cursor_column >= mode->columns) {
201 con->cursor_column = 0;
202 con->cursor_row++;
203 }
Heinrich Schuchardt97ea0692019-09-04 21:13:45 +0200204 /*
205 * When we exceed the row count the terminal will scroll up one
206 * line. We have to adjust the cursor position.
207 */
208 if (con->cursor_row >= mode->rows && con->cursor_row)
209 con->cursor_row--;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100210 }
211
Heinrich Schuchardtba7bd5c2018-08-31 21:31:32 +0200212out:
213 return EFI_EXIT(ret);
Alexander Grafc1311ad2016-03-04 01:10:00 +0100214}
215
Heinrich Schuchardt325567d2020-06-04 18:40:44 +0200216/**
217 * efi_cout_test_string() - test writing Unicode string to console
218 *
219 * This function implements the TestString service of the simple text output
220 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
221 * for details.
222 *
223 * As in OutputString we simply convert UTF-16 to UTF-8 there are no unsupported
224 * code points and we can always return EFI_SUCCESS.
225 *
226 * @this: simple text output protocol
227 * @string: u16 string
228 * Return: status code
229 */
Alexander Grafc1311ad2016-03-04 01:10:00 +0100230static efi_status_t EFIAPI efi_cout_test_string(
231 struct efi_simple_text_output_protocol *this,
Rob Clark3a45bc72017-09-13 18:05:44 -0400232 const efi_string_t string)
Alexander Grafc1311ad2016-03-04 01:10:00 +0100233{
234 EFI_ENTRY("%p, %p", this, string);
235 return EFI_EXIT(EFI_SUCCESS);
236}
237
Heinrich Schuchardt325567d2020-06-04 18:40:44 +0200238/**
239 * cout_mode_matches() - check if mode has given terminal size
240 *
241 * @mode: text mode
242 * @rows: number of rows
243 * @cols: number of columns
244 * Return: true if number of rows and columns matches the mode and
245 * the mode is present
246 */
Emmanuel Vadot5be8b0a2016-11-08 06:03:29 +0100247static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)
248{
249 if (!mode->present)
250 return false;
251
252 return (mode->rows == rows) && (mode->columns == cols);
253}
254
Heinrich Schuchardt6bb591f2018-09-15 23:52:07 +0200255/**
256 * query_console_serial() - query console size
257 *
Heinrich Schuchardt325567d2020-06-04 18:40:44 +0200258 * When using a serial console or the net console we can only devise the
259 * terminal size by querying the terminal using ECMA-48 control sequences.
260 *
Heinrich Schuchardtfe1a81c2019-09-05 20:37:13 +0200261 * @rows: pointer to return number of rows
262 * @cols: pointer to return number of columns
263 * Returns: 0 on success
Heinrich Schuchardt6bb591f2018-09-15 23:52:07 +0200264 */
Rob Clark71cc25c2017-09-13 18:05:42 -0400265static int query_console_serial(int *rows, int *cols)
266{
Heinrich Schuchardt6bb591f2018-09-15 23:52:07 +0200267 int ret = 0;
268 int n[2];
Rob Clark71cc25c2017-09-13 18:05:42 -0400269
270 /* Empty input buffer */
271 while (tstc())
272 getc();
273
Heinrich Schuchardt6bb591f2018-09-15 23:52:07 +0200274 /*
275 * Not all terminals understand CSI [18t for querying the console size.
276 * We should adhere to escape sequences documented in the console_codes
Heinrich Schuchardte1fec152018-10-18 21:51:38 +0200277 * man page and the ECMA-48 standard.
Heinrich Schuchardt6bb591f2018-09-15 23:52:07 +0200278 *
279 * So here we follow a different approach. We position the cursor to the
280 * bottom right and query its position. Before leaving the function we
281 * restore the original cursor position.
282 */
283 printf(ESC "7" /* Save cursor position */
284 ESC "[r" /* Set scrolling region to full window */
285 ESC "[999;999H" /* Move to bottom right corner */
286 ESC "[6n"); /* Query cursor position */
Rob Clark71cc25c2017-09-13 18:05:42 -0400287
Heinrich Schuchardt6bb591f2018-09-15 23:52:07 +0200288 /* Read {rows,cols} */
289 if (term_read_reply(n, 2, 'R')) {
290 ret = 1;
291 goto out;
292 }
Rob Clark71cc25c2017-09-13 18:05:42 -0400293
Heinrich Schuchardt6bb591f2018-09-15 23:52:07 +0200294 *cols = n[1];
295 *rows = n[0];
296out:
297 printf(ESC "8"); /* Restore cursor position */
298 return ret;
Rob Clark71cc25c2017-09-13 18:05:42 -0400299}
300
Heinrich Schuchardt325567d2020-06-04 18:40:44 +0200301/**
302 * query_console_size() - update the mode table.
Heinrich Schuchardta4aa7be2018-04-29 20:02:46 +0200303 *
304 * By default the only mode available is 80x25. If the console has at least 50
305 * lines, enable mode 80x50. If we can query the console size and it is neither
306 * 80x25 nor 80x50, set it as an additional mode.
307 */
308static void query_console_size(void)
309{
310 const char *stdout_name = env_get("stdout");
Alexander Graf80483b22018-06-03 15:51:17 +0200311 int rows = 25, cols = 80;
Heinrich Schuchardta4aa7be2018-04-29 20:02:46 +0200312
313 if (stdout_name && !strcmp(stdout_name, "vidconsole") &&
314 IS_ENABLED(CONFIG_DM_VIDEO)) {
315 struct stdio_dev *stdout_dev =
316 stdio_get_by_name("vidconsole");
317 struct udevice *dev = stdout_dev->priv;
318 struct vidconsole_priv *priv =
319 dev_get_uclass_priv(dev);
320 rows = priv->rows;
321 cols = priv->cols;
322 } else if (query_console_serial(&rows, &cols)) {
323 return;
324 }
325
326 /* Test if we can have Mode 1 */
327 if (cols >= 80 && rows >= 50) {
328 efi_cout_modes[1].present = 1;
329 efi_con_mode.max_mode = 2;
330 }
331
332 /*
333 * Install our mode as mode 2 if it is different
334 * than mode 0 or 1 and set it as the currently selected mode
335 */
336 if (!cout_mode_matches(&efi_cout_modes[0], rows, cols) &&
337 !cout_mode_matches(&efi_cout_modes[1], rows, cols)) {
338 efi_cout_modes[EFI_COUT_MODE_2].columns = cols;
339 efi_cout_modes[EFI_COUT_MODE_2].rows = rows;
340 efi_cout_modes[EFI_COUT_MODE_2].present = 1;
341 efi_con_mode.max_mode = EFI_MAX_COUT_MODE;
342 efi_con_mode.mode = EFI_COUT_MODE_2;
343 }
344}
345
Heinrich Schuchardt325567d2020-06-04 18:40:44 +0200346
347/**
348 * efi_cout_query_mode() - get terminal size for a text mode
349 *
350 * This function implements the QueryMode service of the simple text output
351 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
352 * for details.
353 *
354 * @this: simple text output protocol
355 * @mode_number: mode number to retrieve information on
356 * @columns: number of columns
357 * @rows: number of rows
358 * Return: status code
359 */
Alexander Grafc1311ad2016-03-04 01:10:00 +0100360static efi_status_t EFIAPI efi_cout_query_mode(
361 struct efi_simple_text_output_protocol *this,
362 unsigned long mode_number, unsigned long *columns,
363 unsigned long *rows)
364{
365 EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
366
Emmanuel Vadot5be8b0a2016-11-08 06:03:29 +0100367 if (mode_number >= efi_con_mode.max_mode)
368 return EFI_EXIT(EFI_UNSUPPORTED);
369
370 if (efi_cout_modes[mode_number].present != 1)
371 return EFI_EXIT(EFI_UNSUPPORTED);
372
Alexander Grafc1311ad2016-03-04 01:10:00 +0100373 if (columns)
Emmanuel Vadot5be8b0a2016-11-08 06:03:29 +0100374 *columns = efi_cout_modes[mode_number].columns;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100375 if (rows)
Emmanuel Vadot5be8b0a2016-11-08 06:03:29 +0100376 *rows = efi_cout_modes[mode_number].rows;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100377
378 return EFI_EXIT(EFI_SUCCESS);
379}
380
Rob Clark2d5dc2a2017-10-10 08:23:01 -0400381static const struct {
382 unsigned int fg;
383 unsigned int bg;
384} color[] = {
385 { 30, 40 }, /* 0: black */
386 { 34, 44 }, /* 1: blue */
387 { 32, 42 }, /* 2: green */
388 { 36, 46 }, /* 3: cyan */
389 { 31, 41 }, /* 4: red */
390 { 35, 45 }, /* 5: magenta */
Heinrich Schuchardt14d103b2018-09-08 19:57:24 +0200391 { 33, 43 }, /* 6: brown, map to yellow as EDK2 does*/
392 { 37, 47 }, /* 7: light gray, map to white */
Rob Clark2d5dc2a2017-10-10 08:23:01 -0400393};
394
Heinrich Schuchardt325567d2020-06-04 18:40:44 +0200395/**
396 * efi_cout_set_attribute() - set fore- and background color
397 *
398 * This function implements the SetAttribute service of the simple text output
399 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
400 * for details.
401 *
402 * @this: simple text output protocol
403 * @attribute: foreground color - bits 0-3, background color - bits 4-6
404 * Return: status code
405 */
Alexander Grafc1311ad2016-03-04 01:10:00 +0100406static efi_status_t EFIAPI efi_cout_set_attribute(
407 struct efi_simple_text_output_protocol *this,
408 unsigned long attribute)
409{
Rob Clark2d5dc2a2017-10-10 08:23:01 -0400410 unsigned int bold = EFI_ATTR_BOLD(attribute);
411 unsigned int fg = EFI_ATTR_FG(attribute);
412 unsigned int bg = EFI_ATTR_BG(attribute);
413
Alexander Grafc1311ad2016-03-04 01:10:00 +0100414 EFI_ENTRY("%p, %lx", this, attribute);
415
Heinrich Schuchardt3950f0f2019-06-14 07:16:57 +0200416 efi_con_mode.attribute = attribute;
Rob Clark2d5dc2a2017-10-10 08:23:01 -0400417 if (attribute)
418 printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
419 else
420 printf(ESC"[0;37;40m");
421
422 return EFI_EXIT(EFI_SUCCESS);
Alexander Grafc1311ad2016-03-04 01:10:00 +0100423}
424
Heinrich Schuchardtb0ad9b52019-12-22 07:15:55 +0000425/**
426 * efi_cout_clear_screen() - clear screen
427 *
Heinrich Schuchardt325567d2020-06-04 18:40:44 +0200428 * This function implements the ClearScreen service of the simple text output
429 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
430 * for details.
Heinrich Schuchardtb0ad9b52019-12-22 07:15:55 +0000431 *
432 * @this: pointer to the protocol instance
433 * Return: status code
434 */
Alexander Grafc1311ad2016-03-04 01:10:00 +0100435static efi_status_t EFIAPI efi_cout_clear_screen(
436 struct efi_simple_text_output_protocol *this)
437{
438 EFI_ENTRY("%p", this);
439
Heinrich Schuchardtb0ad9b52019-12-22 07:15:55 +0000440 /*
441 * The Linux console wants both a clear and a home command. The video
442 * uclass does not support <ESC>[H without coordinates, yet.
443 */
444 printf(ESC "[2J" ESC "[1;1H");
Heinrich Schuchardte67ff942018-07-05 08:18:00 +0200445 efi_con_mode.cursor_column = 0;
446 efi_con_mode.cursor_row = 0;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100447
448 return EFI_EXIT(EFI_SUCCESS);
449}
450
Heinrich Schuchardt325567d2020-06-04 18:40:44 +0200451/**
452 * efi_cout_clear_set_mode() - set text model
453 *
454 * This function implements the SetMode service of the simple text output
455 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
456 * for details.
457 *
458 * @this: pointer to the protocol instance
459 * @mode_number: number of the text mode to set
460 * Return: status code
461 */
Heinrich Schuchardt2ad238f2019-06-14 07:20:51 +0200462static efi_status_t EFIAPI efi_cout_set_mode(
463 struct efi_simple_text_output_protocol *this,
464 unsigned long mode_number)
465{
466 EFI_ENTRY("%p, %ld", this, mode_number);
467
468 if (mode_number >= efi_con_mode.max_mode)
469 return EFI_EXIT(EFI_UNSUPPORTED);
Heinrich Schuchardt03446982019-09-04 22:46:13 +0200470
471 if (!efi_cout_modes[mode_number].present)
472 return EFI_EXIT(EFI_UNSUPPORTED);
473
Heinrich Schuchardt2ad238f2019-06-14 07:20:51 +0200474 efi_con_mode.mode = mode_number;
475 EFI_CALL(efi_cout_clear_screen(this));
476
477 return EFI_EXIT(EFI_SUCCESS);
478}
479
Heinrich Schuchardt325567d2020-06-04 18:40:44 +0200480/**
481 * efi_cout_reset() - reset the terminal
482 *
483 * This function implements the Reset service of the simple text output
484 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
485 * for details.
486 *
487 * @this: pointer to the protocol instance
488 * @extended_verification: if set an extended verification may be executed
489 * Return: status code
490 */
Heinrich Schuchardt9d12daf2018-07-05 19:58:07 +0200491static efi_status_t EFIAPI efi_cout_reset(
492 struct efi_simple_text_output_protocol *this,
493 char extended_verification)
494{
495 EFI_ENTRY("%p, %d", this, extended_verification);
496
497 /* Clear screen */
498 EFI_CALL(efi_cout_clear_screen(this));
499 /* Set default colors */
Heinrich Schuchardt3950f0f2019-06-14 07:16:57 +0200500 efi_con_mode.attribute = 0x07;
Heinrich Schuchardt9d12daf2018-07-05 19:58:07 +0200501 printf(ESC "[0;37;40m");
502
503 return EFI_EXIT(EFI_SUCCESS);
504}
505
Heinrich Schuchardt325567d2020-06-04 18:40:44 +0200506/**
507 * efi_cout_set_cursor_position() - reset the terminal
508 *
509 * This function implements the SetCursorPosition service of the simple text
510 * output protocol. See the Unified Extensible Firmware Interface (UEFI)
511 * specification for details.
512 *
513 * @this: pointer to the protocol instance
514 * @column: column to move to
515 * @row: row to move to
516 * Return: status code
517 */
Alexander Grafc1311ad2016-03-04 01:10:00 +0100518static efi_status_t EFIAPI efi_cout_set_cursor_position(
519 struct efi_simple_text_output_protocol *this,
520 unsigned long column, unsigned long row)
521{
Heinrich Schuchardtaaace4b2018-09-14 18:49:26 +0200522 efi_status_t ret = EFI_SUCCESS;
523 struct simple_text_output_mode *con = &efi_con_mode;
524 struct cout_mode *mode = &efi_cout_modes[con->mode];
525
Alexander Grafc1311ad2016-03-04 01:10:00 +0100526 EFI_ENTRY("%p, %ld, %ld", this, column, row);
527
Heinrich Schuchardtaaace4b2018-09-14 18:49:26 +0200528 /* Check parameters */
529 if (!this) {
530 ret = EFI_INVALID_PARAMETER;
531 goto out;
532 }
533 if (row >= mode->rows || column >= mode->columns) {
534 ret = EFI_UNSUPPORTED;
535 goto out;
536 }
537
538 /*
539 * Set cursor position by sending CSI H.
540 * EFI origin is [0, 0], terminal origin is [1, 1].
541 */
542 printf(ESC "[%d;%dH", (int)row + 1, (int)column + 1);
Alexander Grafc1311ad2016-03-04 01:10:00 +0100543 efi_con_mode.cursor_column = column;
544 efi_con_mode.cursor_row = row;
Heinrich Schuchardtaaace4b2018-09-14 18:49:26 +0200545out:
546 return EFI_EXIT(ret);
Alexander Grafc1311ad2016-03-04 01:10:00 +0100547}
548
Heinrich Schuchardt325567d2020-06-04 18:40:44 +0200549/**
550 * efi_cout_enable_cursor() - enable the cursor
551 *
552 * This function implements the EnableCursor service of the simple text output
553 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
554 * for details.
555 *
556 * @this: pointer to the protocol instance
557 * @enable: if true enable, if false disable the cursor
558 * Return: status code
559 */
Alexander Grafc1311ad2016-03-04 01:10:00 +0100560static efi_status_t EFIAPI efi_cout_enable_cursor(
561 struct efi_simple_text_output_protocol *this,
562 bool enable)
563{
564 EFI_ENTRY("%p, %d", this, enable);
565
566 printf(ESC"[?25%c", enable ? 'h' : 'l');
Heinrich Schuchardt25e6fb52019-06-02 22:54:28 +0200567 efi_con_mode.cursor_visible = !!enable;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100568
569 return EFI_EXIT(EFI_SUCCESS);
570}
571
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +0200572struct efi_simple_text_output_protocol efi_con_out = {
Alexander Grafc1311ad2016-03-04 01:10:00 +0100573 .reset = efi_cout_reset,
574 .output_string = efi_cout_output_string,
575 .test_string = efi_cout_test_string,
576 .query_mode = efi_cout_query_mode,
577 .set_mode = efi_cout_set_mode,
578 .set_attribute = efi_cout_set_attribute,
579 .clear_screen = efi_cout_clear_screen,
580 .set_cursor_position = efi_cout_set_cursor_position,
581 .enable_cursor = efi_cout_enable_cursor,
582 .mode = (void*)&efi_con_mode,
583};
584
Heinrich Schuchardt4fdcf062018-09-11 22:38:12 +0200585/**
586 * struct efi_cin_notify_function - registered console input notify function
587 *
588 * @link: link to list
Heinrich Schuchardtfe1a81c2019-09-05 20:37:13 +0200589 * @key: key to notify
Heinrich Schuchardt4fdcf062018-09-11 22:38:12 +0200590 * @function: function to call
591 */
592struct efi_cin_notify_function {
593 struct list_head link;
594 struct efi_key_data key;
595 efi_status_t (EFIAPI *function)
596 (struct efi_key_data *key_data);
597};
598
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +0200599static bool key_available;
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200600static struct efi_key_data next_key;
Heinrich Schuchardt4fdcf062018-09-11 22:38:12 +0200601static LIST_HEAD(cin_notify_functions);
Heinrich Schuchardt4f187892018-07-05 08:17:59 +0200602
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +0200603/**
Heinrich Schuchardt55fbdf92018-09-11 22:38:09 +0200604 * set_shift_mask() - set shift mask
605 *
606 * @mod: Xterm shift mask
Heinrich Schuchardtfe1a81c2019-09-05 20:37:13 +0200607 * @key_state: receives the state of the shift, alt, control, and logo keys
Heinrich Schuchardt55fbdf92018-09-11 22:38:09 +0200608 */
609void set_shift_mask(int mod, struct efi_key_state *key_state)
610{
611 key_state->key_shift_state = EFI_SHIFT_STATE_VALID;
612 if (mod) {
613 --mod;
614 if (mod & 1)
615 key_state->key_shift_state |= EFI_LEFT_SHIFT_PRESSED;
616 if (mod & 2)
617 key_state->key_shift_state |= EFI_LEFT_ALT_PRESSED;
618 if (mod & 4)
619 key_state->key_shift_state |= EFI_LEFT_CONTROL_PRESSED;
Heinrich Schuchardt3b435c12019-06-16 22:33:20 +0200620 if (!mod || (mod & 8))
Heinrich Schuchardt55fbdf92018-09-11 22:38:09 +0200621 key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
Heinrich Schuchardt55fbdf92018-09-11 22:38:09 +0200622 }
623}
624
625/**
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200626 * analyze_modifiers() - analyze modifiers (shift, alt, ctrl) for function keys
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +0200627 *
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100628 * This gets called when we have already parsed CSI.
629 *
Heinrich Schuchardtfe1a81c2019-09-05 20:37:13 +0200630 * @key_state: receives the state of the shift, alt, control, and logo keys
Heinrich Schuchardt325567d2020-06-04 18:40:44 +0200631 * Return: the unmodified code
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100632 */
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200633static int analyze_modifiers(struct efi_key_state *key_state)
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100634{
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200635 int c, mod = 0, ret = 0;
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100636
637 c = getc();
638
639 if (c != ';') {
640 ret = c;
641 if (c == '~')
642 goto out;
643 c = getc();
644 }
645 for (;;) {
646 switch (c) {
647 case '0'...'9':
648 mod *= 10;
649 mod += c - '0';
650 /* fall through */
651 case ';':
652 c = getc();
653 break;
654 default:
655 goto out;
656 }
657 }
658out:
Heinrich Schuchardt55fbdf92018-09-11 22:38:09 +0200659 set_shift_mask(mod, key_state);
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100660 if (!ret)
661 ret = c;
662 return ret;
663}
664
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +0200665/**
666 * efi_cin_read_key() - read a key from the console input
667 *
668 * @key: - key received
669 * Return: - status code
670 */
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200671static efi_status_t efi_cin_read_key(struct efi_key_data *key)
Alexander Grafc1311ad2016-03-04 01:10:00 +0100672{
673 struct efi_input_key pressed_key = {
674 .scan_code = 0,
675 .unicode_char = 0,
676 };
Heinrich Schuchardt35cbb792018-09-12 00:05:32 +0200677 s32 ch;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100678
Heinrich Schuchardt55fbdf92018-09-11 22:38:09 +0200679 if (console_read_unicode(&ch))
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +0200680 return EFI_NOT_READY;
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200681
682 key->key_state.key_shift_state = EFI_SHIFT_STATE_INVALID;
683 key->key_state.key_toggle_state = EFI_TOGGLE_STATE_INVALID;
684
Heinrich Schuchardt35cbb792018-09-12 00:05:32 +0200685 /* We do not support multi-word codes */
686 if (ch >= 0x10000)
687 ch = '?';
Heinrich Schuchardt55fbdf92018-09-11 22:38:09 +0200688
689 switch (ch) {
690 case 0x1b:
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100691 /*
692 * Xterm Control Sequences
693 * https://www.xfree86.org/4.8.0/ctlseqs.html
694 */
Alexander Grafc1311ad2016-03-04 01:10:00 +0100695 ch = getc();
696 switch (ch) {
697 case cESC: /* ESC */
698 pressed_key.scan_code = 23;
699 break;
Heinrich Schuchardt3b2b2de2019-06-16 21:41:13 +0200700 case 'O': /* F1 - F4, End */
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100701 ch = getc();
Heinrich Schuchardt55fbdf92018-09-11 22:38:09 +0200702 /* consider modifiers */
Heinrich Schuchardt3b2b2de2019-06-16 21:41:13 +0200703 if (ch == 'F') { /* End */
704 pressed_key.scan_code = 6;
705 break;
706 } else if (ch < 'P') {
Heinrich Schuchardt55fbdf92018-09-11 22:38:09 +0200707 set_shift_mask(ch - '0', &key->key_state);
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100708 ch = getc();
Heinrich Schuchardt55fbdf92018-09-11 22:38:09 +0200709 }
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100710 pressed_key.scan_code = ch - 'P' + 11;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100711 break;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100712 case '[':
713 ch = getc();
714 switch (ch) {
715 case 'A'...'D': /* up, down right, left */
716 pressed_key.scan_code = ch - 'A' + 1;
717 break;
718 case 'F': /* End */
719 pressed_key.scan_code = 6;
720 break;
721 case 'H': /* Home */
722 pressed_key.scan_code = 5;
723 break;
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100724 case '1':
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200725 ch = analyze_modifiers(&key->key_state);
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100726 switch (ch) {
727 case '1'...'5': /* F1 - F5 */
728 pressed_key.scan_code = ch - '1' + 11;
729 break;
Heinrich Schuchardt3b2b2de2019-06-16 21:41:13 +0200730 case '6'...'9': /* F5 - F8 */
731 pressed_key.scan_code = ch - '6' + 15;
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100732 break;
733 case 'A'...'D': /* up, down right, left */
734 pressed_key.scan_code = ch - 'A' + 1;
735 break;
Heinrich Schuchardt3b2b2de2019-06-16 21:41:13 +0200736 case 'F': /* End */
737 pressed_key.scan_code = 6;
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100738 break;
Heinrich Schuchardt3b2b2de2019-06-16 21:41:13 +0200739 case 'H': /* Home */
740 pressed_key.scan_code = 5;
741 break;
742 case '~': /* Home */
743 pressed_key.scan_code = 5;
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100744 break;
745 }
Alexander Grafc1311ad2016-03-04 01:10:00 +0100746 break;
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100747 case '2':
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200748 ch = analyze_modifiers(&key->key_state);
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100749 switch (ch) {
750 case '0'...'1': /* F9 - F10 */
751 pressed_key.scan_code = ch - '0' + 19;
752 break;
753 case '3'...'4': /* F11 - F12 */
754 pressed_key.scan_code = ch - '3' + 21;
755 break;
756 case '~': /* INS */
757 pressed_key.scan_code = 7;
758 break;
759 }
Alexander Grafc1311ad2016-03-04 01:10:00 +0100760 break;
761 case '3': /* DEL */
762 pressed_key.scan_code = 8;
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200763 analyze_modifiers(&key->key_state);
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100764 break;
765 case '5': /* PG UP */
766 pressed_key.scan_code = 9;
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200767 analyze_modifiers(&key->key_state);
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100768 break;
769 case '6': /* PG DOWN */
770 pressed_key.scan_code = 10;
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200771 analyze_modifiers(&key->key_state);
Alexander Grafc1311ad2016-03-04 01:10:00 +0100772 break;
Heinrich Schuchardt55fbdf92018-09-11 22:38:09 +0200773 } /* [ */
Alexander Grafc1311ad2016-03-04 01:10:00 +0100774 break;
Heinrich Schuchardt55fbdf92018-09-11 22:38:09 +0200775 default:
776 /* ALT key */
777 set_shift_mask(3, &key->key_state);
Alexander Grafc1311ad2016-03-04 01:10:00 +0100778 }
Heinrich Schuchardt55fbdf92018-09-11 22:38:09 +0200779 break;
780 case 0x7f:
Alexander Grafc1311ad2016-03-04 01:10:00 +0100781 /* Backspace */
782 ch = 0x08;
783 }
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200784 if (pressed_key.scan_code) {
785 key->key_state.key_shift_state |= EFI_SHIFT_STATE_VALID;
786 } else {
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100787 pressed_key.unicode_char = ch;
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200788
789 /*
790 * Assume left control key for control characters typically
791 * entered using the control key.
792 */
793 if (ch >= 0x01 && ch <= 0x1f) {
Heinrich Schuchardt55fbdf92018-09-11 22:38:09 +0200794 key->key_state.key_shift_state |=
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200795 EFI_SHIFT_STATE_VALID;
796 switch (ch) {
797 case 0x01 ... 0x07:
798 case 0x0b ... 0x0c:
799 case 0x0e ... 0x1f:
800 key->key_state.key_shift_state |=
801 EFI_LEFT_CONTROL_PRESSED;
802 }
803 }
804 }
805 key->key = pressed_key;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100806
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +0200807 return EFI_SUCCESS;
808}
809
810/**
Heinrich Schuchardt4fdcf062018-09-11 22:38:12 +0200811 * efi_cin_notify() - notify registered functions
812 */
813static void efi_cin_notify(void)
814{
815 struct efi_cin_notify_function *item;
816
817 list_for_each_entry(item, &cin_notify_functions, link) {
818 bool match = true;
819
820 /* We do not support toggle states */
821 if (item->key.key.unicode_char || item->key.key.scan_code) {
822 if (item->key.key.unicode_char !=
823 next_key.key.unicode_char ||
824 item->key.key.scan_code != next_key.key.scan_code)
825 match = false;
826 }
827 if (item->key.key_state.key_shift_state &&
828 item->key.key_state.key_shift_state !=
829 next_key.key_state.key_shift_state)
830 match = false;
831
832 if (match)
833 /* We don't bother about the return code */
834 EFI_CALL(item->function(&next_key));
835 }
836}
837
838/**
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +0200839 * efi_cin_check() - check if keyboard input is available
840 */
841static void efi_cin_check(void)
842{
843 efi_status_t ret;
844
845 if (key_available) {
Heinrich Schuchardt7eaa9002019-06-07 06:47:01 +0200846 efi_signal_event(efi_con_in.wait_for_key);
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +0200847 return;
848 }
849
850 if (tstc()) {
851 ret = efi_cin_read_key(&next_key);
852 if (ret == EFI_SUCCESS) {
853 key_available = true;
854
Heinrich Schuchardt4fdcf062018-09-11 22:38:12 +0200855 /* Notify registered functions */
856 efi_cin_notify();
857
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +0200858 /* Queue the wait for key event */
Heinrich Schuchardt4fdcf062018-09-11 22:38:12 +0200859 if (key_available)
Heinrich Schuchardt7eaa9002019-06-07 06:47:01 +0200860 efi_signal_event(efi_con_in.wait_for_key);
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +0200861 }
862 }
863}
864
865/**
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200866 * efi_cin_empty_buffer() - empty input buffer
867 */
868static void efi_cin_empty_buffer(void)
869{
870 while (tstc())
871 getc();
872 key_available = false;
873}
874
875/**
876 * efi_cin_reset_ex() - reset console input
877 *
878 * @this: - the extended simple text input protocol
879 * @extended_verification: - extended verification
880 *
881 * This function implements the reset service of the
882 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
883 *
884 * See the Unified Extensible Firmware Interface (UEFI) specification for
885 * details.
886 *
887 * Return: old value of the task priority level
888 */
889static efi_status_t EFIAPI efi_cin_reset_ex(
890 struct efi_simple_text_input_ex_protocol *this,
891 bool extended_verification)
892{
893 efi_status_t ret = EFI_SUCCESS;
894
895 EFI_ENTRY("%p, %d", this, extended_verification);
896
897 /* Check parameters */
898 if (!this) {
899 ret = EFI_INVALID_PARAMETER;
900 goto out;
901 }
902
903 efi_cin_empty_buffer();
904out:
905 return EFI_EXIT(ret);
906}
907
908/**
909 * efi_cin_read_key_stroke_ex() - read key stroke
910 *
911 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
912 * @key_data: key read from console
913 * Return: status code
914 *
915 * This function implements the ReadKeyStrokeEx service of the
916 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
917 *
918 * See the Unified Extensible Firmware Interface (UEFI) specification for
919 * details.
920 */
921static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
922 struct efi_simple_text_input_ex_protocol *this,
923 struct efi_key_data *key_data)
924{
925 efi_status_t ret = EFI_SUCCESS;
926
927 EFI_ENTRY("%p, %p", this, key_data);
928
929 /* Check parameters */
930 if (!this || !key_data) {
931 ret = EFI_INVALID_PARAMETER;
932 goto out;
933 }
934
935 /* We don't do interrupts, so check for timers cooperatively */
936 efi_timer_check();
937
938 /* Enable console input after ExitBootServices */
939 efi_cin_check();
940
941 if (!key_available) {
942 ret = EFI_NOT_READY;
943 goto out;
944 }
Heinrich Schuchardtbfc2dd52019-04-06 20:59:24 +0200945 /*
946 * CTRL+A - CTRL+Z have to be signaled as a - z.
947 * SHIFT+CTRL+A - SHIFT+CTRL+Z have to be signaled as A - Z.
948 */
949 switch (next_key.key.unicode_char) {
950 case 0x01 ... 0x07:
951 case 0x0b ... 0x0c:
952 case 0x0e ... 0x1a:
953 if (!(next_key.key_state.key_toggle_state &
954 EFI_CAPS_LOCK_ACTIVE) ^
955 !(next_key.key_state.key_shift_state &
956 (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)))
957 next_key.key.unicode_char += 0x40;
958 else
959 next_key.key.unicode_char += 0x60;
960 }
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200961 *key_data = next_key;
962 key_available = false;
963 efi_con_in.wait_for_key->is_signaled = false;
Heinrich Schuchardtbfc2dd52019-04-06 20:59:24 +0200964
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200965out:
966 return EFI_EXIT(ret);
967}
968
969/**
970 * efi_cin_set_state() - set toggle key state
971 *
972 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
Heinrich Schuchardtacee9652019-05-18 17:07:52 +0200973 * @key_toggle_state: pointer to key toggle state
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200974 * Return: status code
975 *
976 * This function implements the SetState service of the
977 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
978 *
979 * See the Unified Extensible Firmware Interface (UEFI) specification for
980 * details.
981 */
982static efi_status_t EFIAPI efi_cin_set_state(
983 struct efi_simple_text_input_ex_protocol *this,
Heinrich Schuchardtacee9652019-05-18 17:07:52 +0200984 u8 *key_toggle_state)
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200985{
Heinrich Schuchardtacee9652019-05-18 17:07:52 +0200986 EFI_ENTRY("%p, %p", this, key_toggle_state);
Heinrich Schuchardt110c6282018-09-11 22:38:08 +0200987 /*
988 * U-Boot supports multiple console input sources like serial and
989 * net console for which a key toggle state cannot be set at all.
990 *
991 * According to the UEFI specification it is allowable to not implement
992 * this service.
993 */
994 return EFI_EXIT(EFI_UNSUPPORTED);
995}
996
997/**
998 * efi_cin_register_key_notify() - register key notification function
999 *
1000 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1001 * @key_data: key to be notified
1002 * @key_notify_function: function to be called if the key is pressed
1003 * @notify_handle: handle for unregistering the notification
1004 * Return: status code
1005 *
1006 * This function implements the SetState service of the
1007 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1008 *
1009 * See the Unified Extensible Firmware Interface (UEFI) specification for
1010 * details.
1011 */
1012static efi_status_t EFIAPI efi_cin_register_key_notify(
1013 struct efi_simple_text_input_ex_protocol *this,
1014 struct efi_key_data *key_data,
1015 efi_status_t (EFIAPI *key_notify_function)(
1016 struct efi_key_data *key_data),
1017 void **notify_handle)
1018{
Heinrich Schuchardt4fdcf062018-09-11 22:38:12 +02001019 efi_status_t ret = EFI_SUCCESS;
1020 struct efi_cin_notify_function *notify_function;
1021
Heinrich Schuchardt110c6282018-09-11 22:38:08 +02001022 EFI_ENTRY("%p, %p, %p, %p",
1023 this, key_data, key_notify_function, notify_handle);
Heinrich Schuchardt4fdcf062018-09-11 22:38:12 +02001024
1025 /* Check parameters */
1026 if (!this || !key_data || !key_notify_function || !notify_handle) {
1027 ret = EFI_INVALID_PARAMETER;
1028 goto out;
1029 }
1030
1031 EFI_PRINT("u+%04x, sc %04x, sh %08x, tg %02x\n",
1032 key_data->key.unicode_char,
1033 key_data->key.scan_code,
1034 key_data->key_state.key_shift_state,
1035 key_data->key_state.key_toggle_state);
1036
1037 notify_function = calloc(1, sizeof(struct efi_cin_notify_function));
1038 if (!notify_function) {
1039 ret = EFI_OUT_OF_RESOURCES;
1040 goto out;
1041 }
1042 notify_function->key = *key_data;
1043 notify_function->function = key_notify_function;
1044 list_add_tail(&notify_function->link, &cin_notify_functions);
1045 *notify_handle = notify_function;
1046out:
1047 return EFI_EXIT(ret);
Heinrich Schuchardt110c6282018-09-11 22:38:08 +02001048}
1049
1050/**
1051 * efi_cin_unregister_key_notify() - unregister key notification function
1052 *
1053 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1054 * @notification_handle: handle received when registering
1055 * Return: status code
1056 *
1057 * This function implements the SetState service of the
1058 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1059 *
1060 * See the Unified Extensible Firmware Interface (UEFI) specification for
1061 * details.
1062 */
1063static efi_status_t EFIAPI efi_cin_unregister_key_notify(
1064 struct efi_simple_text_input_ex_protocol *this,
1065 void *notification_handle)
1066{
Heinrich Schuchardt4fdcf062018-09-11 22:38:12 +02001067 efi_status_t ret = EFI_INVALID_PARAMETER;
1068 struct efi_cin_notify_function *item, *notify_function =
1069 notification_handle;
1070
Heinrich Schuchardt110c6282018-09-11 22:38:08 +02001071 EFI_ENTRY("%p, %p", this, notification_handle);
Heinrich Schuchardt4fdcf062018-09-11 22:38:12 +02001072
1073 /* Check parameters */
1074 if (!this || !notification_handle)
1075 goto out;
1076
1077 list_for_each_entry(item, &cin_notify_functions, link) {
1078 if (item == notify_function) {
1079 ret = EFI_SUCCESS;
1080 break;
1081 }
1082 }
1083 if (ret != EFI_SUCCESS)
1084 goto out;
1085
1086 /* Remove the notify function */
1087 list_del(&notify_function->link);
1088 free(notify_function);
1089out:
1090 return EFI_EXIT(ret);
Heinrich Schuchardt110c6282018-09-11 22:38:08 +02001091}
1092
1093
1094/**
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +02001095 * efi_cin_reset() - drain the input buffer
1096 *
1097 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1098 * @extended_verification: allow for exhaustive verification
1099 * Return: status code
1100 *
1101 * This function implements the Reset service of the
1102 * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1103 *
1104 * See the Unified Extensible Firmware Interface (UEFI) specification for
1105 * details.
1106 */
1107static efi_status_t EFIAPI efi_cin_reset
1108 (struct efi_simple_text_input_protocol *this,
1109 bool extended_verification)
1110{
1111 efi_status_t ret = EFI_SUCCESS;
1112
1113 EFI_ENTRY("%p, %d", this, extended_verification);
1114
1115 /* Check parameters */
1116 if (!this) {
1117 ret = EFI_INVALID_PARAMETER;
1118 goto out;
1119 }
1120
Heinrich Schuchardt110c6282018-09-11 22:38:08 +02001121 efi_cin_empty_buffer();
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +02001122out:
1123 return EFI_EXIT(ret);
1124}
1125
1126/**
Heinrich Schuchardt110c6282018-09-11 22:38:08 +02001127 * efi_cin_read_key_stroke() - read key stroke
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +02001128 *
1129 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1130 * @key: key read from console
1131 * Return: status code
1132 *
1133 * This function implements the ReadKeyStroke service of the
1134 * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1135 *
1136 * See the Unified Extensible Firmware Interface (UEFI) specification for
1137 * details.
1138 */
1139static efi_status_t EFIAPI efi_cin_read_key_stroke
1140 (struct efi_simple_text_input_protocol *this,
1141 struct efi_input_key *key)
1142{
1143 efi_status_t ret = EFI_SUCCESS;
1144
1145 EFI_ENTRY("%p, %p", this, key);
1146
1147 /* Check parameters */
1148 if (!this || !key) {
1149 ret = EFI_INVALID_PARAMETER;
1150 goto out;
1151 }
1152
1153 /* We don't do interrupts, so check for timers cooperatively */
1154 efi_timer_check();
1155
1156 /* Enable console input after ExitBootServices */
1157 efi_cin_check();
1158
1159 if (!key_available) {
1160 ret = EFI_NOT_READY;
1161 goto out;
1162 }
Heinrich Schuchardt110c6282018-09-11 22:38:08 +02001163 *key = next_key.key;
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +02001164 key_available = false;
1165 efi_con_in.wait_for_key->is_signaled = false;
1166out:
1167 return EFI_EXIT(ret);
Alexander Grafc1311ad2016-03-04 01:10:00 +01001168}
1169
Heinrich Schuchardt110c6282018-09-11 22:38:08 +02001170static struct efi_simple_text_input_ex_protocol efi_con_in_ex = {
1171 .reset = efi_cin_reset_ex,
1172 .read_key_stroke_ex = efi_cin_read_key_stroke_ex,
1173 .wait_for_key_ex = NULL,
1174 .set_state = efi_cin_set_state,
1175 .register_key_notify = efi_cin_register_key_notify,
1176 .unregister_key_notify = efi_cin_unregister_key_notify,
1177};
1178
Heinrich Schuchardt3e603ec2018-09-08 10:20:10 +02001179struct efi_simple_text_input_protocol efi_con_in = {
Alexander Grafc1311ad2016-03-04 01:10:00 +01001180 .reset = efi_cin_reset,
1181 .read_key_stroke = efi_cin_read_key_stroke,
1182 .wait_for_key = NULL,
1183};
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +02001184
1185static struct efi_event *console_timer_event;
1186
Heinrich Schuchardt9bc96642018-01-19 20:24:51 +01001187/*
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +02001188 * efi_console_timer_notify() - notify the console timer event
Heinrich Schuchardt9bc96642018-01-19 20:24:51 +01001189 *
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +02001190 * @event: console timer event
1191 * @context: not used
Heinrich Schuchardt9bc96642018-01-19 20:24:51 +01001192 */
xypron.glpk@gmx.deff925932017-07-20 05:26:07 +02001193static void EFIAPI efi_console_timer_notify(struct efi_event *event,
1194 void *context)
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +02001195{
1196 EFI_ENTRY("%p, %p", event, context);
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +02001197 efi_cin_check();
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +02001198 EFI_EXIT(EFI_SUCCESS);
1199}
1200
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +02001201/**
1202 * efi_key_notify() - notify the wait for key event
1203 *
1204 * @event: wait for key event
1205 * @context: not used
1206 */
1207static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
1208{
1209 EFI_ENTRY("%p, %p", event, context);
1210 efi_cin_check();
1211 EFI_EXIT(EFI_SUCCESS);
1212}
1213
1214/**
1215 * efi_console_register() - install the console protocols
1216 *
1217 * This function is called from do_bootefi_exec().
Heinrich Schuchardt6f566c22018-10-02 06:08:26 +02001218 *
1219 * Return: status code
Heinrich Schuchardt0dfd13a2018-09-11 22:38:05 +02001220 */
Heinrich Schuchardt6f566c22018-10-02 06:08:26 +02001221efi_status_t efi_console_register(void)
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +02001222{
1223 efi_status_t r;
Heinrich Schuchardtfae01182018-09-26 05:27:55 +02001224 efi_handle_t console_output_handle;
1225 efi_handle_t console_input_handle;
Rob Clarka17e62c2017-07-24 10:39:01 -04001226
Heinrich Schuchardta4aa7be2018-04-29 20:02:46 +02001227 /* Set up mode information */
1228 query_console_size();
1229
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +02001230 /* Create handles */
Heinrich Schuchardtfae01182018-09-26 05:27:55 +02001231 r = efi_create_handle(&console_output_handle);
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +02001232 if (r != EFI_SUCCESS)
1233 goto out_of_memory;
Alexander Graf40e3e752018-09-04 14:59:11 +02001234
Heinrich Schuchardtfae01182018-09-26 05:27:55 +02001235 r = efi_add_protocol(console_output_handle,
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +02001236 &efi_guid_text_output_protocol, &efi_con_out);
1237 if (r != EFI_SUCCESS)
1238 goto out_of_memory;
Heinrich Schuchardtfae01182018-09-26 05:27:55 +02001239 systab.con_out_handle = console_output_handle;
1240 systab.stderr_handle = console_output_handle;
Alexander Graf40e3e752018-09-04 14:59:11 +02001241
Heinrich Schuchardtfae01182018-09-26 05:27:55 +02001242 r = efi_create_handle(&console_input_handle);
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +02001243 if (r != EFI_SUCCESS)
1244 goto out_of_memory;
Alexander Graf40e3e752018-09-04 14:59:11 +02001245
Heinrich Schuchardtfae01182018-09-26 05:27:55 +02001246 r = efi_add_protocol(console_input_handle,
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +02001247 &efi_guid_text_input_protocol, &efi_con_in);
1248 if (r != EFI_SUCCESS)
1249 goto out_of_memory;
Heinrich Schuchardtfae01182018-09-26 05:27:55 +02001250 systab.con_in_handle = console_input_handle;
1251 r = efi_add_protocol(console_input_handle,
Heinrich Schuchardt110c6282018-09-11 22:38:08 +02001252 &efi_guid_text_input_ex_protocol, &efi_con_in_ex);
1253 if (r != EFI_SUCCESS)
1254 goto out_of_memory;
Rob Clarka17e62c2017-07-24 10:39:01 -04001255
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +02001256 /* Create console events */
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +01001257 r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
1258 NULL, NULL, &efi_con_in.wait_for_key);
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +02001259 if (r != EFI_SUCCESS) {
1260 printf("ERROR: Failed to register WaitForKey event\n");
1261 return r;
1262 }
Heinrich Schuchardt110c6282018-09-11 22:38:08 +02001263 efi_con_in_ex.wait_for_key_ex = efi_con_in.wait_for_key;
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +02001264 r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +01001265 efi_console_timer_notify, NULL, NULL,
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +02001266 &console_timer_event);
1267 if (r != EFI_SUCCESS) {
1268 printf("ERROR: Failed to register console event\n");
1269 return r;
1270 }
1271 /* 5000 ns cycle is sufficient for 2 MBaud */
1272 r = efi_set_timer(console_timer_event, EFI_TIMER_PERIODIC, 50);
1273 if (r != EFI_SUCCESS)
1274 printf("ERROR: Failed to set console timer\n");
1275 return r;
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +02001276out_of_memory:
Heinrich Schuchardt14d103b2018-09-08 19:57:24 +02001277 printf("ERROR: Out of memory\n");
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +02001278 return r;
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +02001279}